diff --git a/cmd/generic-handlers.go b/cmd/generic-handlers.go index 347112921..0a15a2ba8 100644 --- a/cmd/generic-handlers.go +++ b/cmd/generic-handlers.go @@ -175,12 +175,20 @@ func setBrowserRedirectHandler(h http.Handler) http.Handler { return browserRedirectHandler{handler: h} } +func shouldProxy() bool { + if newObjectLayerFn() == nil { + return true + } + return !globalIAMSys.Initialized() +} + func (h redirectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - switch { - case guessIsRPCReq(r), guessIsBrowserReq(r), guessIsHealthCheckReq(r), guessIsMetricsReq(r), isAdminReq(r): + if guessIsRPCReq(r) || guessIsBrowserReq(r) || + guessIsHealthCheckReq(r) || guessIsMetricsReq(r) || isAdminReq(r) { h.handler.ServeHTTP(w, r) return - case newObjectLayerFn() == nil: + } + if shouldProxy() { // if this server is still initializing, proxy the request // to any other online servers to avoid 503 for any incoming // API calls. diff --git a/cmd/healthcheck-handler.go b/cmd/healthcheck-handler.go index 159a787a6..785de682b 100644 --- a/cmd/healthcheck-handler.go +++ b/cmd/healthcheck-handler.go @@ -30,14 +30,14 @@ const unavailable = "offline" func ClusterCheckHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "ClusterCheckHandler") - objLayer := newObjectLayerFn() - // Service not initialized yet - if objLayer == nil { + if shouldProxy() { w.Header().Set(xhttp.MinIOServerStatus, unavailable) writeResponse(w, http.StatusServiceUnavailable, nil, mimeNone) return } + objLayer := newObjectLayerFn() + ctx, cancel := context.WithTimeout(ctx, globalAPIConfig.getClusterDeadline()) defer cancel() @@ -66,7 +66,7 @@ func ClusterCheckHandler(w http.ResponseWriter, r *http.Request) { // ReadinessCheckHandler Checks if the process is up. Always returns success. func ReadinessCheckHandler(w http.ResponseWriter, r *http.Request) { - if newObjectLayerFn() == nil { + if shouldProxy() { // Service not initialized yet w.Header().Set(xhttp.MinIOServerStatus, unavailable) } @@ -76,7 +76,7 @@ func ReadinessCheckHandler(w http.ResponseWriter, r *http.Request) { // LivenessCheckHandler - Checks if the process is up. Always returns success. func LivenessCheckHandler(w http.ResponseWriter, r *http.Request) { - if newObjectLayerFn() == nil { + if shouldProxy() { // Service not initialized yet w.Header().Set(xhttp.MinIOServerStatus, unavailable) } diff --git a/cmd/iam.go b/cmd/iam.go index c7500dc9a..cd5fa8b40 100644 --- a/cmd/iam.go +++ b/cmd/iam.go @@ -25,6 +25,7 @@ import ( "fmt" "math/rand" "strings" + "sync" "time" humanize "github.com/dustin/go-humanize" @@ -201,6 +202,8 @@ func newMappedPolicy(policy string) MappedPolicy { // IAMSys - config system. type IAMSys struct { + sync.Mutex + usersSysType UsersSysType // map of policy names to policy definitions @@ -282,7 +285,7 @@ type IAMStorageAPI interface { // simplifies the implementation for group removal. This is called // only via IAM notifications. func (sys *IAMSys) LoadGroup(objAPI ObjectLayer, group string) error { - if objAPI == nil || sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -323,7 +326,7 @@ func (sys *IAMSys) LoadGroup(objAPI ObjectLayer, group string) error { // LoadPolicy - reloads a specific canned policy from backend disks or etcd. func (sys *IAMSys) LoadPolicy(objAPI ObjectLayer, policyName string) error { - if objAPI == nil || sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -341,7 +344,7 @@ func (sys *IAMSys) LoadPolicy(objAPI ObjectLayer, policyName string) error { // LoadPolicyMapping - loads the mapped policy for a user or group // from storage into server memory. func (sys *IAMSys) LoadPolicyMapping(objAPI ObjectLayer, userOrGroup string, isGroup bool) error { - if objAPI == nil || sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -367,7 +370,7 @@ func (sys *IAMSys) LoadPolicyMapping(objAPI ObjectLayer, userOrGroup string, isG // LoadUser - reloads a specific user from backend disks or etcd. func (sys *IAMSys) LoadUser(objAPI ObjectLayer, accessKey string, userType IAMUserType) error { - if objAPI == nil || sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -391,7 +394,7 @@ func (sys *IAMSys) LoadUser(objAPI ObjectLayer, accessKey string, userType IAMUs // LoadServiceAccount - reloads a specific service account from backend disks or etcd. func (sys *IAMSys) LoadServiceAccount(accessKey string) error { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -415,6 +418,9 @@ func (sys *IAMSys) doIAMConfigMigration(ctx context.Context) error { // InitStore initializes IAM stores func (sys *IAMSys) InitStore(objAPI ObjectLayer) { + sys.Lock() + defer sys.Unlock() + if globalEtcdClient == nil { sys.store = newIAMObjectStore(objAPI) } else { @@ -426,6 +432,16 @@ func (sys *IAMSys) InitStore(objAPI ObjectLayer) { } } +// Initialized check if IAM is initialized +func (sys *IAMSys) Initialized() bool { + if sys == nil { + return false + } + sys.Lock() + defer sys.Unlock() + return sys.store != nil +} + // Init - initializes config system by reading entries from config/iam func (sys *IAMSys) Init(ctx context.Context, objAPI ObjectLayer) { retryCtx, cancel := context.WithCancel(ctx) @@ -512,7 +528,7 @@ func (sys *IAMSys) Init(ctx context.Context, objAPI ObjectLayer) { // DeletePolicy - deletes a canned policy from backend or etcd. func (sys *IAMSys) DeletePolicy(policyName string) error { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -564,7 +580,7 @@ func (sys *IAMSys) DeletePolicy(policyName string) error { // InfoPolicy - expands the canned policy into its JSON structure. func (sys *IAMSys) InfoPolicy(policyName string) (iampolicy.Policy, error) { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return iampolicy.Policy{}, errServerNotInitialized } @@ -581,7 +597,7 @@ func (sys *IAMSys) InfoPolicy(policyName string) (iampolicy.Policy, error) { // ListPolicies - lists all canned policies. func (sys *IAMSys) ListPolicies() (map[string]iampolicy.Policy, error) { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return nil, errServerNotInitialized } @@ -608,7 +624,7 @@ func (sys *IAMSys) ListPolicies() (map[string]iampolicy.Policy, error) { // SetPolicy - sets a new name policy. func (sys *IAMSys) SetPolicy(policyName string, p iampolicy.Policy) error { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -629,7 +645,7 @@ func (sys *IAMSys) SetPolicy(policyName string, p iampolicy.Policy) error { // DeleteUser - delete user (only for long-term users not STS users). func (sys *IAMSys) DeleteUser(accessKey string) error { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -678,13 +694,14 @@ func (sys *IAMSys) DeleteUser(accessKey string) error { return err } -// returns comma separated policy string, from an input policy -// after validating if there are any current policies which exist -// on MinIO corresponding to the input. -func (sys *IAMSys) currentPolicies(policyName string) string { - if sys.store == nil { +// CurrentPolicies - returns comma separated policy string, from +// an input policy after validating if there are any current +// policies which exist on MinIO corresponding to the input. +func (sys *IAMSys) CurrentPolicies(policyName string) string { + if !sys.Initialized() { return "" } + sys.store.rlock() defer sys.store.runlock() @@ -701,7 +718,7 @@ func (sys *IAMSys) currentPolicies(policyName string) string { // SetTempUser - set temporary user credentials, these credentials have an expiry. func (sys *IAMSys) SetTempUser(accessKey string, cred auth.Credentials, policyName string) error { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -752,7 +769,7 @@ func (sys *IAMSys) SetTempUser(accessKey string, cred auth.Credentials, policyNa // ListUsers - list all users. func (sys *IAMSys) ListUsers() (map[string]madmin.UserInfo, error) { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return nil, errServerNotInitialized } @@ -794,7 +811,7 @@ func (sys *IAMSys) ListUsers() (map[string]madmin.UserInfo, error) { // IsTempUser - returns if given key is a temporary user. func (sys *IAMSys) IsTempUser(name string) (bool, error) { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return false, errServerNotInitialized } @@ -811,7 +828,7 @@ func (sys *IAMSys) IsTempUser(name string) (bool, error) { // IsServiceAccount - returns if given key is a service account func (sys *IAMSys) IsServiceAccount(name string) (bool, string, error) { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return false, "", errServerNotInitialized } @@ -832,7 +849,7 @@ func (sys *IAMSys) IsServiceAccount(name string) (bool, string, error) { // GetUserInfo - get info on a user. func (sys *IAMSys) GetUserInfo(name string) (u madmin.UserInfo, err error) { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return u, errServerNotInitialized } @@ -877,8 +894,7 @@ func (sys *IAMSys) GetUserInfo(name string) (u madmin.UserInfo, err error) { // SetUserStatus - sets current user status, supports disabled or enabled. func (sys *IAMSys) SetUserStatus(accessKey string, status madmin.AccountStatus) error { - - if sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -923,8 +939,7 @@ func (sys *IAMSys) SetUserStatus(accessKey string, status madmin.AccountStatus) // NewServiceAccount - create a new service account func (sys *IAMSys) NewServiceAccount(ctx context.Context, parentUser string, sessionPolicy *iampolicy.Policy) (auth.Credentials, error) { - - if sys == nil || sys.store == nil { + if !sys.Initialized() { return auth.Credentials{}, errServerNotInitialized } @@ -990,8 +1005,7 @@ func (sys *IAMSys) NewServiceAccount(ctx context.Context, parentUser string, ses // ListServiceAccounts - lists all services accounts associated to a specific user func (sys *IAMSys) ListServiceAccounts(ctx context.Context, accessKey string) ([]string, error) { - - if sys == nil || sys.store == nil { + if !sys.Initialized() { return nil, errServerNotInitialized } @@ -1020,8 +1034,7 @@ func (sys *IAMSys) ListServiceAccounts(ctx context.Context, accessKey string) ([ // GetServiceAccountParent - gets information about a service account func (sys *IAMSys) GetServiceAccountParent(ctx context.Context, accessKey string) (string, error) { - - if sys == nil || sys.store == nil { + if !sys.Initialized() { return "", errServerNotInitialized } @@ -1037,8 +1050,7 @@ func (sys *IAMSys) GetServiceAccountParent(ctx context.Context, accessKey string // DeleteServiceAccount - delete a service account func (sys *IAMSys) DeleteServiceAccount(ctx context.Context, accessKey string) error { - - if sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -1066,8 +1078,7 @@ func (sys *IAMSys) DeleteServiceAccount(ctx context.Context, accessKey string) e // SetUser - set user credentials and policy. func (sys *IAMSys) SetUser(accessKey string, uinfo madmin.UserInfo) error { - - if sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -1104,8 +1115,7 @@ func (sys *IAMSys) SetUser(accessKey string, uinfo madmin.UserInfo) error { // SetUserSecretKey - sets user secret key func (sys *IAMSys) SetUserSecretKey(accessKey string, secretKey string) error { - - if sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -1133,7 +1143,7 @@ func (sys *IAMSys) SetUserSecretKey(accessKey string, secretKey string) error { // GetUser - get user credentials func (sys *IAMSys) GetUser(accessKey string) (cred auth.Credentials, ok bool) { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return cred, false } @@ -1199,7 +1209,7 @@ func (sys *IAMSys) GetUser(accessKey string) (cred auth.Credentials, ok bool) { // AddUsersToGroup - adds users to a group, creating the group if // needed. No error if user(s) already are in the group. func (sys *IAMSys) AddUsersToGroup(group string, members []string) error { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -1259,7 +1269,7 @@ func (sys *IAMSys) AddUsersToGroup(group string, members []string) error { // RemoveUsersFromGroup - remove users from group. If no users are // given, and the group is empty, deletes the group as well. func (sys *IAMSys) RemoveUsersFromGroup(group string, members []string) error { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -1339,7 +1349,7 @@ func (sys *IAMSys) RemoveUsersFromGroup(group string, members []string) error { // SetGroupStatus - enable/disabled a group func (sys *IAMSys) SetGroupStatus(group string, enabled bool) error { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -1374,7 +1384,7 @@ func (sys *IAMSys) SetGroupStatus(group string, enabled bool) error { // GetGroupDescription - builds up group description func (sys *IAMSys) GetGroupDescription(group string) (gd madmin.GroupDesc, err error) { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return gd, errServerNotInitialized } @@ -1414,7 +1424,7 @@ func (sys *IAMSys) GetGroupDescription(group string) (gd madmin.GroupDesc, err e // ListGroups - lists groups. func (sys *IAMSys) ListGroups() (r []string, err error) { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return r, errServerNotInitialized } @@ -1445,7 +1455,7 @@ func (sys *IAMSys) ListGroups() (r []string, err error) { // PolicyDBSet - sets a policy for a user or group in the PolicyDB. func (sys *IAMSys) PolicyDBSet(name, policy string, isGroup bool) error { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return errServerNotInitialized } @@ -1511,7 +1521,7 @@ func (sys *IAMSys) policyDBSet(name, policyName string, userType IAMUserType, is // be a member of multiple groups, this function returns an array of // applicable policies (each group is mapped to at most one policy). func (sys *IAMSys) PolicyDBGet(name string, isGroup bool) ([]string, error) { - if sys == nil || sys.store == nil { + if !sys.Initialized() { return nil, errServerNotInitialized } diff --git a/cmd/sts-handlers.go b/cmd/sts-handlers.go index b266b4006..ace9ab712 100644 --- a/cmd/sts-handlers.go +++ b/cmd/sts-handlers.go @@ -328,11 +328,12 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ var policyName string policySet, ok := iampolicy.GetPoliciesFromClaims(m, iamPolicyClaimNameOpenID()) if ok { - policyName = globalIAMSys.currentPolicies(strings.Join(policySet.ToSlice(), ",")) + policyName = globalIAMSys.CurrentPolicies(strings.Join(policySet.ToSlice(), ",")) } if policyName == "" && globalPolicyOPA == nil { - writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("%s claim missing from the JWT token, credentials will not be generated", iamPolicyClaimNameOpenID())) + writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, + fmt.Errorf("%s claim missing from the JWT token, credentials will not be generated", iamPolicyClaimNameOpenID())) return } m[iamPolicyClaimNameOpenID()] = policyName