forked from TrueCloudLab/frostfs-node
Airat Arifullin
7cc368e188
* Soft APE check means that APE should allow request even it gets status NoRuleFound for a request. Otherwise, it is interpreted as Deny. * Soft APE check is performed if basic ACL mask is not set. Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
159 lines
3.9 KiB
Go
159 lines
3.9 KiB
Go
package v2
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"fmt"
|
|
|
|
sessionV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
|
sessionSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
)
|
|
|
|
// RequestInfo groups parsed version-independent (from SDK library)
|
|
// request information and raw API request.
|
|
type RequestInfo struct {
|
|
basicACL acl.Basic
|
|
requestRole acl.Role
|
|
operation acl.Op // put, get, head, etc.
|
|
cnrOwner user.ID // container owner
|
|
|
|
// cnrNamespace defined to which namespace a container is belonged.
|
|
cnrNamespace string
|
|
|
|
idCnr cid.ID
|
|
|
|
// optional for some request
|
|
// e.g. Put, Search
|
|
obj *oid.ID
|
|
|
|
senderKey []byte
|
|
|
|
bearer *bearer.Token // bearer token of request
|
|
|
|
srcRequest any
|
|
}
|
|
|
|
func (r *RequestInfo) SetBasicACL(basicACL acl.Basic) {
|
|
r.basicACL = basicACL
|
|
}
|
|
|
|
func (r *RequestInfo) SetRequestRole(requestRole acl.Role) {
|
|
r.requestRole = requestRole
|
|
}
|
|
|
|
func (r *RequestInfo) SetSenderKey(senderKey []byte) {
|
|
r.senderKey = senderKey
|
|
}
|
|
|
|
// Request returns raw API request.
|
|
func (r RequestInfo) Request() any {
|
|
return r.srcRequest
|
|
}
|
|
|
|
// ContainerOwner returns owner if the container.
|
|
func (r RequestInfo) ContainerOwner() user.ID {
|
|
return r.cnrOwner
|
|
}
|
|
|
|
func (r RequestInfo) ContainerNamespace() string {
|
|
return r.cnrNamespace
|
|
}
|
|
|
|
// ObjectID return object ID.
|
|
func (r RequestInfo) ObjectID() *oid.ID {
|
|
return r.obj
|
|
}
|
|
|
|
// ContainerID return container ID.
|
|
func (r RequestInfo) ContainerID() cid.ID {
|
|
return r.idCnr
|
|
}
|
|
|
|
// CleanBearer forces cleaning bearer token information.
|
|
func (r *RequestInfo) CleanBearer() {
|
|
r.bearer = nil
|
|
}
|
|
|
|
// Bearer returns bearer token of the request.
|
|
func (r RequestInfo) Bearer() *bearer.Token {
|
|
return r.bearer
|
|
}
|
|
|
|
// BasicACL returns basic ACL of the container.
|
|
func (r RequestInfo) BasicACL() acl.Basic {
|
|
return r.basicACL
|
|
}
|
|
|
|
// SenderKey returns public key of the request's sender.
|
|
func (r RequestInfo) SenderKey() []byte {
|
|
return r.senderKey
|
|
}
|
|
|
|
// Operation returns request's operation.
|
|
func (r RequestInfo) Operation() acl.Op {
|
|
return r.operation
|
|
}
|
|
|
|
// RequestRole returns request sender's role.
|
|
func (r RequestInfo) RequestRole() acl.Role {
|
|
return r.requestRole
|
|
}
|
|
|
|
// IsSoftAPECheck states if APE should perform soft checks.
|
|
// Soft APE check allows a request if CheckAPE returns NoRuleFound for it,
|
|
// otherwise it denies the request.
|
|
func (r RequestInfo) IsSoftAPECheck() bool {
|
|
return r.BasicACL().Bits() != 0
|
|
}
|
|
|
|
// MetaWithToken groups session and bearer tokens,
|
|
// verification header and raw API request.
|
|
type MetaWithToken struct {
|
|
vheader *sessionV2.RequestVerificationHeader
|
|
token *sessionSDK.Object
|
|
bearer *bearer.Token
|
|
src any
|
|
}
|
|
|
|
// RequestOwner returns ownerID and its public key
|
|
// according to internal meta information.
|
|
func (r MetaWithToken) RequestOwner() (*user.ID, *keys.PublicKey, error) {
|
|
if r.vheader == nil {
|
|
return nil, nil, errEmptyVerificationHeader
|
|
}
|
|
|
|
if r.bearer != nil && r.bearer.Impersonate() {
|
|
return unmarshalPublicKeyWithOwner(r.bearer.SigningKeyBytes())
|
|
}
|
|
|
|
// if session token is presented, use it as truth source
|
|
if r.token != nil {
|
|
// verify signature of session token
|
|
return ownerFromToken(r.token)
|
|
}
|
|
|
|
// otherwise get original body signature
|
|
bodySignature := originalBodySignature(r.vheader)
|
|
if bodySignature == nil {
|
|
return nil, nil, errEmptyBodySig
|
|
}
|
|
|
|
return unmarshalPublicKeyWithOwner(bodySignature.GetKey())
|
|
}
|
|
|
|
func unmarshalPublicKeyWithOwner(rawKey []byte) (*user.ID, *keys.PublicKey, error) {
|
|
key, err := unmarshalPublicKey(rawKey)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("invalid signature key: %w", err)
|
|
}
|
|
|
|
var idSender user.ID
|
|
user.IDFromKey(&idSender, (ecdsa.PublicKey)(*key))
|
|
|
|
return &idSender, key, nil
|
|
}
|