diff options
| author | chrislu <chris.lu@gmail.com> | 2023-09-25 09:16:35 -0700 |
|---|---|---|
| committer | chrislu <chris.lu@gmail.com> | 2023-09-25 09:16:35 -0700 |
| commit | 3d07895518b2b6e816518be0a2355c1f0a98ff15 (patch) | |
| tree | f06fda180691efb0b58c9ac0e82988e1cea31e14 /weed/s3api/auth_credentials.go | |
| parent | a6e35e4f685b7713cb863d3f28c85a4b8ae89ab8 (diff) | |
| parent | a132d445568f4de6dba617b83b42d9b9cfb1cbd2 (diff) | |
| download | seaweedfs-3d07895518b2b6e816518be0a2355c1f0a98ff15.tar.xz seaweedfs-3d07895518b2b6e816518be0a2355c1f0a98ff15.zip | |
Merge branch 'master' of https://github.com/seaweedfs/seaweedfs
Diffstat (limited to 'weed/s3api/auth_credentials.go')
| -rw-r--r-- | weed/s3api/auth_credentials.go | 137 |
1 files changed, 118 insertions, 19 deletions
diff --git a/weed/s3api/auth_credentials.go b/weed/s3api/auth_credentials.go index 38ff2b5ca..a2b1fd90f 100644 --- a/weed/s3api/auth_credentials.go +++ b/weed/s3api/auth_credentials.go @@ -7,8 +7,6 @@ import ( "strings" "sync" - "github.com/seaweedfs/seaweedfs/weed/s3api/s3account" - "github.com/seaweedfs/seaweedfs/weed/filer" "github.com/seaweedfs/seaweedfs/weed/glog" "github.com/seaweedfs/seaweedfs/weed/pb" @@ -29,6 +27,8 @@ type IdentityAccessManagement struct { identities []*Identity accessKeyIdent map[string]*Identity + accounts map[string]*Account + emailAccount map[string]*Account hashes map[string]*sync.Pool hashCounters map[string]*int32 identityAnonymous *Identity @@ -39,20 +39,50 @@ type IdentityAccessManagement struct { type Identity struct { Name string - AccountId string + Account *Account Credentials []*Credential Actions []Action } -func (i *Identity) isAnonymous() bool { - return i.Name == s3account.AccountAnonymous.Name +// Account represents a system user, a system user can +// configure multiple IAM-Users, IAM-Users can configure +// permissions respectively, and each IAM-User can +// configure multiple security credentials +type Account struct { + //Name is also used to display the "DisplayName" as the owner of the bucket or object + DisplayName string + EmailAddress string + + //Id is used to identify an Account when granting cross-account access(ACLs) to buckets and objects + Id string } +// Predefined Accounts +var ( + // AccountAdmin is used as the default account for IAM-Credentials access without Account configured + AccountAdmin = Account{ + DisplayName: "admin", + EmailAddress: "admin@example.com", + Id: s3_constants.AccountAdminId, + } + + // AccountAnonymous is used to represent the account for anonymous access + AccountAnonymous = Account{ + DisplayName: "anonymous", + EmailAddress: "anonymous@example.com", + Id: s3_constants.AccountAnonymousId, + } +) + type Credential struct { AccessKey string SecretKey string } +func (i *Identity) isAnonymous() bool { + return i.Account.Id == s3_constants.AccountAnonymousId +} + func (action Action) isAdmin() bool { return strings.HasPrefix(string(action), s3_constants.ACTION_ADMIN) } @@ -65,14 +95,19 @@ func (action Action) overBucket(bucket string) bool { return strings.HasSuffix(string(action), ":"+bucket) || strings.HasSuffix(string(action), ":*") } +// "Permission": "FULL_CONTROL"|"WRITE"|"WRITE_ACP"|"READ"|"READ_ACP" func (action Action) getPermission() Permission { switch act := strings.Split(string(action), ":")[0]; act { case s3_constants.ACTION_ADMIN: return Permission("FULL_CONTROL") case s3_constants.ACTION_WRITE: return Permission("WRITE") + case s3_constants.ACTION_WRITE_ACP: + return Permission("WRITE_ACP") case s3_constants.ACTION_READ: return Permission("READ") + case s3_constants.ACTION_READ_ACP: + return Permission("READ_ACP") default: return Permission("") } @@ -138,26 +173,69 @@ func (iam *IdentityAccessManagement) loadS3ApiConfiguration(config *iam_pb.S3Api var identities []*Identity var identityAnonymous *Identity accessKeyIdent := make(map[string]*Identity) + accounts := make(map[string]*Account) + emailAccount := make(map[string]*Account) + foundAccountAdmin := false + foundAccountAnonymous := false + + for _, account := range config.Accounts { + switch account.Id { + case AccountAdmin.Id: + AccountAdmin = Account{ + Id: account.Id, + DisplayName: account.DisplayName, + EmailAddress: account.EmailAddress, + } + accounts[account.Id] = &AccountAdmin + foundAccountAdmin = true + case AccountAnonymous.Id: + AccountAnonymous = Account{ + Id: account.Id, + DisplayName: account.DisplayName, + EmailAddress: account.EmailAddress, + } + accounts[account.Id] = &AccountAnonymous + foundAccountAnonymous = true + default: + t := Account{ + Id: account.Id, + DisplayName: account.DisplayName, + EmailAddress: account.EmailAddress, + } + accounts[account.Id] = &t + } + if account.EmailAddress != "" { + emailAccount[account.EmailAddress] = accounts[account.Id] + } + } + if !foundAccountAdmin { + accounts[AccountAdmin.Id] = &AccountAdmin + emailAccount[AccountAdmin.EmailAddress] = &AccountAdmin + } + if !foundAccountAnonymous { + accounts[AccountAnonymous.Id] = &AccountAnonymous + emailAccount[AccountAnonymous.EmailAddress] = &AccountAnonymous + } for _, ident := range config.Identities { t := &Identity{ Name: ident.Name, - AccountId: s3account.AccountAdmin.Id, Credentials: nil, Actions: nil, } - - if ident.Name == s3account.AccountAnonymous.Name { - if ident.AccountId != "" && ident.AccountId != s3account.AccountAnonymous.Id { - glog.Warningf("anonymous identity is associated with a non-anonymous account ID, the association is invalid") - } - t.AccountId = s3account.AccountAnonymous.Id + switch { + case ident.Name == AccountAnonymous.Id: + t.Account = &AccountAnonymous identityAnonymous = t - } else { - if len(ident.AccountId) > 0 { - t.AccountId = ident.AccountId + case ident.Account == nil: + t.Account = &AccountAdmin + default: + if account, ok := accounts[ident.Account.Id]; ok { + t.Account = account + } else { + t.Account = &AccountAdmin + glog.Warningf("identity %s is associated with a non exist account ID, the association is invalid", ident.Name) } } - for _, action := range ident.Actions { t.Actions = append(t.Actions, Action(action)) } @@ -170,15 +248,19 @@ func (iam *IdentityAccessManagement) loadS3ApiConfiguration(config *iam_pb.S3Api } identities = append(identities, t) } + iam.m.Lock() // atomically switch iam.identities = identities iam.identityAnonymous = identityAnonymous + iam.accounts = accounts + iam.emailAccount = emailAccount iam.accessKeyIdent = accessKeyIdent if !iam.isAuthEnabled { // one-directional, no toggling iam.isAuthEnabled = len(identities) > 0 } iam.m.Unlock() + return nil } @@ -209,6 +291,24 @@ func (iam *IdentityAccessManagement) lookupAnonymous() (identity *Identity, foun return nil, false } +func (iam *IdentityAccessManagement) GetAccountNameById(canonicalId string) string { + iam.m.RLock() + defer iam.m.RUnlock() + if account, ok := iam.accounts[canonicalId]; ok { + return account.DisplayName + } + return "" +} + +func (iam *IdentityAccessManagement) GetAccountIdByEmail(email string) string { + iam.m.RLock() + defer iam.m.RUnlock() + if account, ok := iam.emailAccount[email]; ok { + return account.Id + } + return "" +} + func (iam *IdentityAccessManagement) Auth(f http.HandlerFunc, action Action) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if !iam.isEnabled() { @@ -287,9 +387,8 @@ func (iam *IdentityAccessManagement) authRequest(r *http.Request, action Action) return identity, s3err.ErrAccessDenied } - if !identity.isAnonymous() { - r.Header.Set(s3_constants.AmzAccountId, identity.AccountId) - } + r.Header.Set(s3_constants.AmzAccountId, identity.Account.Id) + return identity, s3err.ErrNone } |
