package auth import ( "context" "fmt" "net/http" "strings" "testing" "time" v4a "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth/signer/v4asdk2" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/tokens" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" "github.com/aws/aws-sdk-go-v2/aws" credentialsv2 "github.com/aws/aws-sdk-go-v2/credentials" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" ) var _ tokens.Credentials = (*credentialsMock)(nil) type credentialsMock struct { boxes map[string]*accessbox.Box } func newTokensFrostfsMock() *credentialsMock { return &credentialsMock{ boxes: make(map[string]*accessbox.Box), } } func (m credentialsMock) addBox(addr oid.Address, box *accessbox.Box) { m.boxes[getAccessKeyID(addr)] = box } func (m credentialsMock) GetBox(_ context.Context, _ cid.ID, accessKeyID string) (*accessbox.Box, []object.Attribute, error) { box, ok := m.boxes[accessKeyID] if !ok { return nil, nil, &apistatus.ObjectNotFound{} } return box, nil, nil } func (m credentialsMock) Put(context.Context, tokens.CredentialsParam) (oid.Address, error) { return oid.Address{}, nil } func (m credentialsMock) Update(context.Context, tokens.CredentialsParam) (oid.Address, error) { return oid.Address{}, nil } func TestCheckSign(t *testing.T) { ctx := context.Background() var accessKeyAddr oid.Address err := accessKeyAddr.DecodeString("8N7CYBY74kxZXoyvA5UNdmovaXqFpwNfvEPsqaN81es2/3tDwq5tR8fByrJcyJwyiuYX7Dae8tyDT7pd8oaL1MBto") require.NoError(t, err) accessKeyID := strings.ReplaceAll(accessKeyAddr.String(), "/", "0") secretKey := "713d0a0b9efc7d22923e17b0402a6a89b4273bc711c8bacb2da1b643d0006aeb" awsCreds := aws.Credentials{AccessKeyID: accessKeyID, SecretAccessKey: secretKey} reqData := RequestData{ Method: "GET", Endpoint: "http://localhost:8084", Bucket: "my-bucket", Object: "@obj/name", } presignData := PresignData{ Service: "s3", Region: "spb", Lifetime: 10 * time.Minute, SignTime: time.Now().UTC(), Headers: map[string]string{ ContentTypeHdr: "text/plain", AmzContentSHA256: UnsignedPayload, }, } req, err := PresignRequest(ctx, awsCreds, reqData, presignData, zaptest.NewLogger(t)) require.NoError(t, err) expBox := &accessbox.Box{ Gate: &accessbox.GateData{ SecretKey: secretKey, }, } mock := newTokensFrostfsMock() mock.addBox(accessKeyAddr, expBox) c := &Center{ cli: mock, reg: NewRegexpMatcher(AuthorizationFieldRegexp), postReg: NewRegexpMatcher(postPolicyCredentialRegexp), settings: ¢erSettingsMock{}, } box, err := c.Authenticate(req) require.NoError(t, err) require.EqualValues(t, expBox, box.AccessBox) } func TestCheckSignV4a(t *testing.T) { var accessKeyAddr oid.Address err := accessKeyAddr.DecodeString("8N7CYBY74kxZXoyvA5UNdmovaXqFpwNfvEPsqaN81es2/3tDwq5tR8fByrJcyJwyiuYX7Dae8tyDT7pd8oaL1MBto") require.NoError(t, err) accessKeyID := strings.ReplaceAll(accessKeyAddr.String(), "/", "0") secretKey := "713d0a0b9efc7d22923e17b0402a6a89b4273bc711c8bacb2da1b643d0006aeb" awsCreds := aws.Credentials{AccessKeyID: accessKeyID, SecretAccessKey: secretKey} reqData := RequestData{ Method: "GET", Endpoint: "http://localhost:8084", Bucket: "my-bucket", Object: "@obj/name", } presignData := PresignData{ Service: "s3", Region: "spb", Lifetime: 10 * time.Minute, SignTime: time.Now().UTC(), Headers: map[string]string{ ContentTypeHdr: "text/plain", }, } req, err := PresignRequestV4a(awsCreds, reqData, presignData, zaptest.NewLogger(t)) require.NoError(t, err) req.Header.Set(ContentTypeHdr, "text/plain") expBox := &accessbox.Box{ Gate: &accessbox.GateData{ SecretKey: secretKey, }, } mock := newTokensFrostfsMock() mock.addBox(accessKeyAddr, expBox) c := &Center{ cli: mock, regV4a: NewRegexpMatcher(authorizationFieldV4aRegexp), postReg: NewRegexpMatcher(postPolicyCredentialRegexp), } box, err := c.Authenticate(req) require.NoError(t, err) require.EqualValues(t, expBox, box.AccessBox) } func TestPresignRequestV4a(t *testing.T) { var accessKeyAddr oid.Address err := accessKeyAddr.DecodeString("8N7CYBY74kxZXoyvA5UNdmovaXqFpwNfvEPsqaN81es2/3tDwq5tR8fByrJcyJwyiuYX7Dae8tyDT7pd8oaL1MBto") require.NoError(t, err) accessKeyID := strings.ReplaceAll(accessKeyAddr.String(), "/", "0") secretKey := "713d0a0b9efc7d22923e17b0402a6a89b4273bc711c8bacb2da1b643d0006aeb" signer := v4a.NewSigner(func(options *v4a.SignerOptions) { options.DisableURIPathEscaping = true options.LogSigning = true options.Logger = zaptest.NewLogger(t) }) credAdapter := v4a.SymmetricCredentialAdaptor{ SymmetricProvider: credentialsv2.NewStaticCredentialsProvider(accessKeyID, secretKey, ""), } creds, err := credAdapter.RetrievePrivateKey(context.TODO()) require.NoError(t, err) signingTime := time.Now() service := "s3" regionSet := []string{"spb"} req, err := http.NewRequest("GET", "http://localhost:8084/bucket/object", nil) require.NoError(t, err) req.Header.Set(AmzExpires, "600") presignedURL, hdr, err := signer.PresignHTTP(req.Context(), creds, req, "", service, regionSet, signingTime) require.NoError(t, err) fmt.Println(presignedURL) fmt.Println(hdr) signature := req.URL.Query().Get(AmzSignature) r, err := http.NewRequest("GET", presignedURL, nil) require.NoError(t, err) query := r.URL.Query() query.Del(AmzSignature) r.URL.RawQuery = query.Encode() err = signer.VerifyPresigned(creds, r, "", service, regionSet, signingTime, signature) require.NoError(t, err) }