From 3b1fd968f84b378814f8d5e46b0901b7a208c8df Mon Sep 17 00:00:00 2001 From: Evgeniy Kulikov Date: Tue, 13 Oct 2020 12:33:33 +0300 Subject: [PATCH] [#25] Migrate auth package to NeoFS API v2 - upgrade to NeoFS API v2 - upgrade to new Authmate package closes #25 Signed-off-by: Evgeniy Kulikov --- auth/bearer-token.go | 8 +-- auth/center.go | 115 ++++++++++++++----------------------------- 2 files changed, 42 insertions(+), 81 deletions(-) diff --git a/auth/bearer-token.go b/auth/bearer-token.go index 33c25301..a7ef9865 100644 --- a/auth/bearer-token.go +++ b/auth/bearer-token.go @@ -3,7 +3,7 @@ package auth import ( "context" - "github.com/nspcc-dev/neofs-api-go/service" + "github.com/nspcc-dev/neofs-api-go/pkg/token" "github.com/pkg/errors" ) @@ -12,12 +12,12 @@ type contextKey string const bearerTokenContextKey contextKey = "bearer-token" // GetBearerToken returns a bearer token embedded into a context or error, if any. -func GetBearerToken(ctx context.Context) (*service.BearerTokenMsg, error) { +func GetBearerToken(ctx context.Context) (*token.BearerToken, error) { bt := ctx.Value(bearerTokenContextKey) if bt == nil { return nil, errors.New("got nil bearer token") } - v, ok := bt.(*service.BearerTokenMsg) + v, ok := bt.(*token.BearerToken) if !ok { return nil, errors.Errorf("extracted unexpected type other than bearer token's: %T", v) } @@ -25,6 +25,6 @@ func GetBearerToken(ctx context.Context) (*service.BearerTokenMsg, error) { } // SetBearerToken return a context with embedded bearer token. -func SetBearerToken(ctx context.Context, bearerToken *service.BearerTokenMsg) context.Context { +func SetBearerToken(ctx context.Context, bearerToken *token.BearerToken) context.Context { return context.WithValue(ctx, bearerTokenContextKey, bearerToken) } diff --git a/auth/center.go b/auth/center.go index f47582a7..de14d1aa 100644 --- a/auth/center.go +++ b/auth/center.go @@ -11,71 +11,56 @@ import ( "strings" "time" - aws_credentials "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/credentials" v4 "github.com/aws/aws-sdk-go/aws/signer/v4" - "github.com/nspcc-dev/neofs-api-go/refs" - "github.com/nspcc-dev/neofs-api-go/service" + "github.com/nspcc-dev/neofs-api-go/pkg/token" "github.com/nspcc-dev/neofs-authmate/accessbox/hcs" - "github.com/nspcc-dev/neofs-authmate/credentials" - "github.com/nspcc-dev/neofs-authmate/gates" - manager "github.com/nspcc-dev/neofs-authmate/neofsmanager" + "github.com/nspcc-dev/neofs-authmate/agents/s3" + manager "github.com/nspcc-dev/neofs-authmate/manager/neofs" "github.com/pkg/errors" "go.uber.org/zap" ) var authorizationFieldRegexp = regexp.MustCompile(`AWS4-HMAC-SHA256 Credential=(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]*)/(?P[^/]+)/aws4_request,\s*SignedHeaders=(?P.+),\s*Signature=(?P.+)`) -const emptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855` +type ( + Center struct { + man *manager.Manager + reg *regexpSubmatcher -// Center is a central app's authentication/authorization management unit. -type Center struct { - log *zap.Logger - submatcher *regexpSubmatcher - neofsCredentials *credentials.Credentials - manager *manager.Manager - authKeys *hcs.X25519Keys -} + keys *hcs.X25519Keys + } + + Params struct { + Timeout time.Duration + + Log *zap.Logger + Con manager.Connector + + GAKey *hcs.X25519Keys + NFKey *ecdsa.PrivateKey + } +) + +// New creates an instance of AuthCenter. +func New(ctx context.Context, p *Params) (*Center, error) { + m, err := manager.New(ctx, + manager.WithKey(p.NFKey), + manager.WithLogger(p.Log), + manager.WithConnector(p.Con)) -// NewCenter creates an instance of AuthCenter. -func NewCenter(log *zap.Logger, neofsNodeAddress string) (*Center, error) { - m, err := manager.NewManager(neofsNodeAddress) if err != nil { return nil, err } return &Center{ - log: log, - submatcher: ®expSubmatcher{re: authorizationFieldRegexp}, - manager: m, + man: m, + reg: ®expSubmatcher{re: authorizationFieldRegexp}, + + keys: p.GAKey, }, nil } -func (center *Center) SetNeoFSKeys(key *ecdsa.PrivateKey) error { - creds, err := credentials.NewFromKey(key) - if err != nil { - return err - } - center.neofsCredentials = creds - return nil -} - -func (center *Center) GetNeoFSPrivateKey() *ecdsa.PrivateKey { - return center.neofsCredentials.Key() -} - -func (center *Center) GetOwnerID() refs.OwnerID { - return center.neofsCredentials.OwnerID() -} - -func (center *Center) SetAuthKeys(key hcs.X25519PrivateKey) error { - keys, err := hcs.NewKeys(key) - if err != nil { - return err - } - center.authKeys = keys - return nil -} - -func (center *Center) AuthenticationPassed(request *http.Request) (*service.BearerTokenMsg, error) { +func (center *Center) AuthenticationPassed(request *http.Request) (*token.BearerToken, error) { queryValues := request.URL.Query() if queryValues.Get("X-Amz-Algorithm") == "AWS4-HMAC-SHA256" { return nil, errors.New("pre-signed form of request is not supported") @@ -84,7 +69,7 @@ func (center *Center) AuthenticationPassed(request *http.Request) (*service.Bear if len(authHeaderField) != 1 { return nil, errors.New("unsupported request: wrong length of Authorization header field") } - sms1 := center.submatcher.getSubmatches(authHeaderField[0]) + sms1 := center.reg.getSubmatches(authHeaderField[0]) if len(sms1) != 7 { return nil, errors.New("bad Authorization header field") } @@ -97,7 +82,7 @@ func (center *Center) AuthenticationPassed(request *http.Request) (*service.Bear return nil, errors.Wrap(err, "failed to parse x-amz-date header field") } accessKeyID := fmt.Sprintf("%s/%s", sms1["access_key_id_cid"], sms1["access_key_id_oid"]) - bearerToken, secretAccessKey, err := center.fetchBearerToken(accessKeyID) + res, err := s3.NewAgent(center.man).ObtainSecret(request.Context(), center.keys, accessKeyID) if err != nil { return nil, errors.Wrap(err, "failed to fetch bearer token") } @@ -110,7 +95,7 @@ func (center *Center) AuthenticationPassed(request *http.Request) (*service.Bear } } } - awsCreds := aws_credentials.NewStaticCredentials(accessKeyID, secretAccessKey, "") + awsCreds := credentials.NewStaticCredentials(accessKeyID, res.SecretAccessKey, "") signer := v4.NewSigner(awsCreds) body, err := readAndKeepBody(request) if err != nil { @@ -120,31 +105,11 @@ func (center *Center) AuthenticationPassed(request *http.Request) (*service.Bear if err != nil { return nil, errors.Wrap(err, "failed to sign temporary HTTP request") } - sms2 := center.submatcher.getSubmatches(otherRequest.Header.Get("Authorization")) + sms2 := center.reg.getSubmatches(otherRequest.Header.Get("Authorization")) if sms1["v4_signature"] != sms2["v4_signature"] { return nil, errors.Wrap(err, "failed to pass authentication procedure") } - return bearerToken, nil -} - -func (center *Center) fetchBearerToken(accessKeyID string) (*service.BearerTokenMsg, string, error) { - akid := new(refs.Address) - if err := akid.Parse(accessKeyID); err != nil { - return nil, "", errors.Wrap(err, "failed to parse access key id as refs.Address") - } - config := &gates.ObtainingConfig{ - BaseConfig: gates.BaseConfig{ - OperationalCredentials: center.neofsCredentials, - Manager: center.manager, - }, - GateKeys: center.authKeys, - SecretAddress: akid, - } - res, err := gates.ObtainSecret(config) - if err != nil { - return nil, "", errors.Wrap(err, "failed to obtain secret") - } - return res.BearerToken, res.SecretAccessKey, nil + return res.BearerToken, nil } // TODO: Make this write into a smart buffer backed by a file on a fast drive. @@ -160,7 +125,3 @@ func readAndKeepBody(request *http.Request) (*bytes.Reader, error) { request.Body = ioutil.NopCloser(bytes.NewReader(payload)) return bytes.NewReader(payload), nil } - -func LoadGateAuthPrivateKey(path string) (hcs.X25519PrivateKey, error) { - return ioutil.ReadFile(path) -}