[s3acl] Step1: move s3account.AccountManager into to iam.S3ApiConfiguration (#4859)
* move s3account.AccountManager into to iam.S3ApiConfiguration and switch to Interface https://github.com/seaweedfs/seaweedfs/issues/4519 * fix: test bucket acl default and adjust the variable names * fix: s3 api config test --------- Co-authored-by: Konstantin Lebedev <9497591+kmlebedev@users.noreply.github.co> Co-authored-by: Chris Lu <chrislusf@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
c9177c92e5
commit
f8b94cac0e
@@ -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
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user