diff --git a/weed/s3api/auth_credentials.go b/weed/s3api/auth_credentials.go index 48a5ccbc0..662f7e10b 100644 --- a/weed/s3api/auth_credentials.go +++ b/weed/s3api/auth_credentials.go @@ -550,6 +550,14 @@ func (iam *IdentityAccessManagement) mergeS3ApiConfiguration(config *iam_pb.S3Ap } if existingIdx >= 0 { + // Before replacing, remove stale accessKeyIdent entries for the old identity + oldIdentity := identities[existingIdx] + for _, oldCred := range oldIdentity.Credentials { + // Only remove if it still points to this identity + if accessKeyIdent[oldCred.AccessKey] == oldIdentity { + delete(accessKeyIdent, oldCred.AccessKey) + } + } // Replace existing dynamic identity identities[existingIdx] = t } else { @@ -584,6 +592,22 @@ func (iam *IdentityAccessManagement) mergeS3ApiConfiguration(config *iam_pb.S3Ap continue } + // Check if this access key already exists in parent's credentials to avoid duplicates + alreadyExists := false + for _, existingCred := range parentIdent.Credentials { + if existingCred.AccessKey == sa.Credential.AccessKey { + alreadyExists = true + break + } + } + + if alreadyExists { + glog.V(3).Infof("Service account %s credential already exists for parent %s, skipping", sa.Id, sa.ParentUser) + // Ensure accessKeyIdent mapping is correct + accessKeyIdent[sa.Credential.AccessKey] = parentIdent + continue + } + // Add service account credential to parent identity cred := &Credential{ AccessKey: sa.Credential.AccessKey, @@ -634,6 +658,8 @@ func (iam *IdentityAccessManagement) isEnabled() bool { } func (iam *IdentityAccessManagement) IsStaticConfig() bool { + iam.m.RLock() + defer iam.m.RUnlock() return iam.useStaticConfig } diff --git a/weed/s3api/auth_signature_v4_sts_test.go b/weed/s3api/auth_signature_v4_sts_test.go index 077d67770..91051440d 100644 --- a/weed/s3api/auth_signature_v4_sts_test.go +++ b/weed/s3api/auth_signature_v4_sts_test.go @@ -5,6 +5,7 @@ import ( "net/http" "testing" + "github.com/gorilla/mux" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -144,6 +145,17 @@ func TestVerifyV4SignatureWithSTSIdentity(t *testing.T) { require.NoError(t, err) req.Header.Set("Host", "s3.amazonaws.com") + // Set up mux route vars for GetBucketAndObject to work + req = mux.SetURLVars(req, map[string]string{ + "bucket": "test-bucket", + "object": "test-object", + }) + + // For STS identities, add session token header to trigger STS-v4 auth path + if len(tt.identity.Actions) == 0 && tt.iamIntegration != nil { + req.Header.Set("X-Amz-Security-Token", "test-session-token") + } + // Mock the permission check logic from verifyV4Signature (now centralized in VerifyActionPermission) var errCode s3err.ErrorCode if tt.shouldCheckPermissions {