mirror of
https://github.com/minio/minio.git
synced 2025-01-11 15:03:22 -05:00
disallow sub-credentials based on root credentials to gain priviledges (#12947)
This happens because of a change added where any sub-credential with parentUser == rootCredential i.e (MINIO_ROOT_USER) will always be an owner, you cannot generate credentials with lower session policy to restrict their access. This doesn't affect user service accounts created with regular users, LDAP or OpenID
This commit is contained in:
parent
89febdb3d6
commit
8f2a3efa85
@ -155,12 +155,7 @@ func validateAdminSignature(ctx context.Context, r *http.Request, region string)
|
|||||||
return cred, nil, owner, s3Err
|
return cred, nil, owner, s3Err
|
||||||
}
|
}
|
||||||
|
|
||||||
claims, s3Err := checkClaimsFromToken(r, cred)
|
return cred, cred.Claims, owner, ErrNone
|
||||||
if s3Err != ErrNone {
|
|
||||||
return cred, nil, owner, s3Err
|
|
||||||
}
|
|
||||||
|
|
||||||
return cred, claims, owner, ErrNone
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkAdminRequestAuth checks for authentication and authorization for the incoming
|
// checkAdminRequestAuth checks for authentication and authorization for the incoming
|
||||||
@ -318,12 +313,6 @@ func checkRequestAuthTypeCredential(ctx context.Context, r *http.Request, action
|
|||||||
return cred, owner, s3Err
|
return cred, owner, s3Err
|
||||||
}
|
}
|
||||||
|
|
||||||
var claims map[string]interface{}
|
|
||||||
claims, s3Err = checkClaimsFromToken(r, cred)
|
|
||||||
if s3Err != ErrNone {
|
|
||||||
return cred, owner, s3Err
|
|
||||||
}
|
|
||||||
|
|
||||||
// LocationConstraint is valid only for CreateBucketAction.
|
// LocationConstraint is valid only for CreateBucketAction.
|
||||||
var locationConstraint string
|
var locationConstraint string
|
||||||
if action == policy.CreateBucketAction {
|
if action == policy.CreateBucketAction {
|
||||||
@ -388,10 +377,10 @@ func checkRequestAuthTypeCredential(ctx context.Context, r *http.Request, action
|
|||||||
Groups: cred.Groups,
|
Groups: cred.Groups,
|
||||||
Action: iampolicy.Action(action),
|
Action: iampolicy.Action(action),
|
||||||
BucketName: bucketName,
|
BucketName: bucketName,
|
||||||
ConditionValues: getConditionValues(r, "", cred.AccessKey, claims),
|
ConditionValues: getConditionValues(r, "", cred.AccessKey, cred.Claims),
|
||||||
ObjectName: objectName,
|
ObjectName: objectName,
|
||||||
IsOwner: owner,
|
IsOwner: owner,
|
||||||
Claims: claims,
|
Claims: cred.Claims,
|
||||||
}) {
|
}) {
|
||||||
// Request is allowed return the appropriate access key.
|
// Request is allowed return the appropriate access key.
|
||||||
return cred, owner, ErrNone
|
return cred, owner, ErrNone
|
||||||
@ -405,10 +394,10 @@ func checkRequestAuthTypeCredential(ctx context.Context, r *http.Request, action
|
|||||||
Groups: cred.Groups,
|
Groups: cred.Groups,
|
||||||
Action: iampolicy.ListBucketAction,
|
Action: iampolicy.ListBucketAction,
|
||||||
BucketName: bucketName,
|
BucketName: bucketName,
|
||||||
ConditionValues: getConditionValues(r, "", cred.AccessKey, claims),
|
ConditionValues: getConditionValues(r, "", cred.AccessKey, cred.Claims),
|
||||||
ObjectName: objectName,
|
ObjectName: objectName,
|
||||||
IsOwner: owner,
|
IsOwner: owner,
|
||||||
Claims: claims,
|
Claims: cred.Claims,
|
||||||
}) {
|
}) {
|
||||||
// Request is allowed return the appropriate access key.
|
// Request is allowed return the appropriate access key.
|
||||||
return cred, owner, ErrNone
|
return cred, owner, ErrNone
|
||||||
@ -520,75 +509,39 @@ func setAuthHandler(h http.Handler) http.Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateSignature(atype authType, r *http.Request) (auth.Credentials, bool, map[string]interface{}, APIErrorCode) {
|
func validateSignature(atype authType, r *http.Request) (auth.Credentials, bool, APIErrorCode) {
|
||||||
var cred auth.Credentials
|
var cred auth.Credentials
|
||||||
var owner bool
|
var owner bool
|
||||||
var s3Err APIErrorCode
|
var s3Err APIErrorCode
|
||||||
switch atype {
|
switch atype {
|
||||||
case authTypeUnknown, authTypeStreamingSigned:
|
case authTypeUnknown, authTypeStreamingSigned:
|
||||||
return cred, owner, nil, ErrSignatureVersionNotSupported
|
return cred, owner, ErrSignatureVersionNotSupported
|
||||||
case authTypeSignedV2, authTypePresignedV2:
|
case authTypeSignedV2, authTypePresignedV2:
|
||||||
if s3Err = isReqAuthenticatedV2(r); s3Err != ErrNone {
|
if s3Err = isReqAuthenticatedV2(r); s3Err != ErrNone {
|
||||||
return cred, owner, nil, s3Err
|
return cred, owner, s3Err
|
||||||
}
|
}
|
||||||
cred, owner, s3Err = getReqAccessKeyV2(r)
|
cred, owner, s3Err = getReqAccessKeyV2(r)
|
||||||
case authTypePresigned, authTypeSigned:
|
case authTypePresigned, authTypeSigned:
|
||||||
region := globalServerRegion
|
region := globalServerRegion
|
||||||
if s3Err = isReqAuthenticated(GlobalContext, r, region, serviceS3); s3Err != ErrNone {
|
if s3Err = isReqAuthenticated(GlobalContext, r, region, serviceS3); s3Err != ErrNone {
|
||||||
return cred, owner, nil, s3Err
|
return cred, owner, s3Err
|
||||||
}
|
}
|
||||||
cred, owner, s3Err = getReqAccessKeyV4(r, region, serviceS3)
|
cred, owner, s3Err = getReqAccessKeyV4(r, region, serviceS3)
|
||||||
}
|
}
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return cred, owner, nil, s3Err
|
return cred, owner, s3Err
|
||||||
}
|
}
|
||||||
|
|
||||||
claims, s3Err := checkClaimsFromToken(r, cred)
|
return cred, owner, ErrNone
|
||||||
if s3Err != ErrNone {
|
|
||||||
return cred, owner, nil, s3Err
|
|
||||||
}
|
|
||||||
|
|
||||||
return cred, owner, claims, ErrNone
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isPutRetentionAllowed(bucketName, objectName string, retDays int, retDate time.Time, retMode objectlock.RetMode, byPassSet bool, r *http.Request, cred auth.Credentials, owner bool, claims map[string]interface{}) (s3Err APIErrorCode) {
|
func isPutRetentionAllowed(bucketName, objectName string, retDays int, retDate time.Time, retMode objectlock.RetMode, byPassSet bool, r *http.Request, cred auth.Credentials, owner bool) (s3Err APIErrorCode) {
|
||||||
var retSet bool
|
var retSet bool
|
||||||
if cred.AccessKey == "" {
|
if cred.AccessKey == "" {
|
||||||
conditions := getConditionValues(r, "", "", nil)
|
|
||||||
conditions["object-lock-mode"] = []string{string(retMode)}
|
|
||||||
conditions["object-lock-retain-until-date"] = []string{retDate.Format(time.RFC3339)}
|
|
||||||
if retDays > 0 {
|
|
||||||
conditions["object-lock-remaining-retention-days"] = []string{strconv.Itoa(retDays)}
|
|
||||||
}
|
|
||||||
if retMode == objectlock.RetGovernance && byPassSet {
|
|
||||||
byPassSet = globalPolicySys.IsAllowed(policy.Args{
|
|
||||||
AccountName: cred.AccessKey,
|
|
||||||
Groups: cred.Groups,
|
|
||||||
Action: policy.BypassGovernanceRetentionAction,
|
|
||||||
BucketName: bucketName,
|
|
||||||
ConditionValues: conditions,
|
|
||||||
IsOwner: false,
|
|
||||||
ObjectName: objectName,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if globalPolicySys.IsAllowed(policy.Args{
|
|
||||||
AccountName: cred.AccessKey,
|
|
||||||
Groups: cred.Groups,
|
|
||||||
Action: policy.PutObjectRetentionAction,
|
|
||||||
BucketName: bucketName,
|
|
||||||
ConditionValues: conditions,
|
|
||||||
IsOwner: false,
|
|
||||||
ObjectName: objectName,
|
|
||||||
}) {
|
|
||||||
retSet = true
|
|
||||||
}
|
|
||||||
if byPassSet || retSet {
|
|
||||||
return ErrNone
|
|
||||||
}
|
|
||||||
return ErrAccessDenied
|
return ErrAccessDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
conditions := getConditionValues(r, "", cred.AccessKey, claims)
|
conditions := getConditionValues(r, "", cred.AccessKey, cred.Claims)
|
||||||
conditions["object-lock-mode"] = []string{string(retMode)}
|
conditions["object-lock-mode"] = []string{string(retMode)}
|
||||||
conditions["object-lock-retain-until-date"] = []string{retDate.Format(time.RFC3339)}
|
conditions["object-lock-retain-until-date"] = []string{retDate.Format(time.RFC3339)}
|
||||||
if retDays > 0 {
|
if retDays > 0 {
|
||||||
@ -603,7 +556,7 @@ func isPutRetentionAllowed(bucketName, objectName string, retDays int, retDate t
|
|||||||
ObjectName: objectName,
|
ObjectName: objectName,
|
||||||
ConditionValues: conditions,
|
ConditionValues: conditions,
|
||||||
IsOwner: owner,
|
IsOwner: owner,
|
||||||
Claims: claims,
|
Claims: cred.Claims,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if globalIAMSys.IsAllowed(iampolicy.Args{
|
if globalIAMSys.IsAllowed(iampolicy.Args{
|
||||||
@ -614,7 +567,7 @@ func isPutRetentionAllowed(bucketName, objectName string, retDays int, retDate t
|
|||||||
ConditionValues: conditions,
|
ConditionValues: conditions,
|
||||||
ObjectName: objectName,
|
ObjectName: objectName,
|
||||||
IsOwner: owner,
|
IsOwner: owner,
|
||||||
Claims: claims,
|
Claims: cred.Claims,
|
||||||
}) {
|
}) {
|
||||||
retSet = true
|
retSet = true
|
||||||
}
|
}
|
||||||
@ -643,11 +596,6 @@ func isPutActionAllowed(ctx context.Context, atype authType, bucketName, objectN
|
|||||||
return s3Err
|
return s3Err
|
||||||
}
|
}
|
||||||
|
|
||||||
claims, s3Err := checkClaimsFromToken(r, cred)
|
|
||||||
if s3Err != ErrNone {
|
|
||||||
return s3Err
|
|
||||||
}
|
|
||||||
|
|
||||||
if cred.AccessKey != "" {
|
if cred.AccessKey != "" {
|
||||||
logger.GetReqInfo(ctx).AccessKey = cred.AccessKey
|
logger.GetReqInfo(ctx).AccessKey = cred.AccessKey
|
||||||
}
|
}
|
||||||
@ -681,10 +629,10 @@ func isPutActionAllowed(ctx context.Context, atype authType, bucketName, objectN
|
|||||||
Groups: cred.Groups,
|
Groups: cred.Groups,
|
||||||
Action: action,
|
Action: action,
|
||||||
BucketName: bucketName,
|
BucketName: bucketName,
|
||||||
ConditionValues: getConditionValues(r, "", cred.AccessKey, claims),
|
ConditionValues: getConditionValues(r, "", cred.AccessKey, cred.Claims),
|
||||||
ObjectName: objectName,
|
ObjectName: objectName,
|
||||||
IsOwner: owner,
|
IsOwner: owner,
|
||||||
Claims: claims,
|
Claims: cred.Claims,
|
||||||
}) {
|
}) {
|
||||||
return ErrNone
|
return ErrNone
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/subtle"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
@ -345,9 +344,6 @@ func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.R
|
|||||||
// Set delimiter value for "s3:delimiter" policy conditionals.
|
// Set delimiter value for "s3:delimiter" policy conditionals.
|
||||||
r.Header.Set("delimiter", SlashSeparator)
|
r.Header.Set("delimiter", SlashSeparator)
|
||||||
|
|
||||||
// err will be nil here as we already called this function
|
|
||||||
// earlier in this request.
|
|
||||||
claims, _ := getClaimsFromToken(getSessionToken(r))
|
|
||||||
n := 0
|
n := 0
|
||||||
// Use the following trick to filter in place
|
// Use the following trick to filter in place
|
||||||
// https://github.com/golang/go/wiki/SliceTricks#filter-in-place
|
// https://github.com/golang/go/wiki/SliceTricks#filter-in-place
|
||||||
@ -357,10 +353,10 @@ func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.R
|
|||||||
Groups: cred.Groups,
|
Groups: cred.Groups,
|
||||||
Action: iampolicy.ListBucketAction,
|
Action: iampolicy.ListBucketAction,
|
||||||
BucketName: bucketInfo.Name,
|
BucketName: bucketInfo.Name,
|
||||||
ConditionValues: getConditionValues(r, "", cred.AccessKey, claims),
|
ConditionValues: getConditionValues(r, "", cred.AccessKey, cred.Claims),
|
||||||
IsOwner: owner,
|
IsOwner: owner,
|
||||||
ObjectName: "",
|
ObjectName: "",
|
||||||
Claims: claims,
|
Claims: cred.Claims,
|
||||||
}) {
|
}) {
|
||||||
bucketsInfo[n] = bucketInfo
|
bucketsInfo[n] = bucketInfo
|
||||||
n++
|
n++
|
||||||
@ -899,41 +895,17 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
|||||||
|
|
||||||
// Once signature is validated, check if the user has
|
// Once signature is validated, check if the user has
|
||||||
// explicit permissions for the user.
|
// explicit permissions for the user.
|
||||||
{
|
if !globalIAMSys.IsAllowed(iampolicy.Args{
|
||||||
token := formValues.Get(xhttp.AmzSecurityToken)
|
AccountName: cred.AccessKey,
|
||||||
if token != "" && cred.AccessKey == "" {
|
Action: iampolicy.PutObjectAction,
|
||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNoAccessKey), r.URL)
|
ConditionValues: getConditionValues(r, "", cred.AccessKey, cred.Claims),
|
||||||
return
|
BucketName: bucket,
|
||||||
}
|
ObjectName: object,
|
||||||
|
IsOwner: globalActiveCred.AccessKey == cred.AccessKey,
|
||||||
if cred.IsServiceAccount() && token == "" {
|
Claims: cred.Claims,
|
||||||
token = cred.SessionToken
|
}) {
|
||||||
}
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL)
|
||||||
|
return
|
||||||
if subtle.ConstantTimeCompare([]byte(token), []byte(cred.SessionToken)) != 1 {
|
|
||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidToken), r.URL)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract claims if any.
|
|
||||||
claims, err := getClaimsFromToken(token)
|
|
||||||
if err != nil {
|
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !globalIAMSys.IsAllowed(iampolicy.Args{
|
|
||||||
AccountName: cred.AccessKey,
|
|
||||||
Action: iampolicy.PutObjectAction,
|
|
||||||
ConditionValues: getConditionValues(r, "", cred.AccessKey, claims),
|
|
||||||
BucketName: bucket,
|
|
||||||
ObjectName: object,
|
|
||||||
IsOwner: globalActiveCred.AccessKey == cred.AccessKey,
|
|
||||||
Claims: claims,
|
|
||||||
}) {
|
|
||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
policyBytes, err := base64.StdEncoding.DecodeString(formValues.Get("Policy"))
|
policyBytes, err := base64.StdEncoding.DecodeString(formValues.Get("Policy"))
|
||||||
|
@ -175,7 +175,7 @@ func enforceRetentionBypassForDelete(ctx context.Context, r *http.Request, bucke
|
|||||||
// For objects in "Governance" mode, overwrite is allowed if a) object retention date is past OR
|
// For objects in "Governance" mode, overwrite is allowed if a) object retention date is past OR
|
||||||
// governance bypass headers are set and user has governance bypass permissions.
|
// governance bypass headers are set and user has governance bypass permissions.
|
||||||
// Objects in compliance mode can be overwritten only if retention date is being extended. No mode change is permitted.
|
// Objects in compliance mode can be overwritten only if retention date is being extended. No mode change is permitted.
|
||||||
func enforceRetentionBypassForPut(ctx context.Context, r *http.Request, bucket, object string, getObjectInfoFn GetObjectInfoFn, objRetention *objectlock.ObjectRetention, cred auth.Credentials, owner bool, claims map[string]interface{}) (ObjectInfo, APIErrorCode) {
|
func enforceRetentionBypassForPut(ctx context.Context, r *http.Request, bucket, object string, getObjectInfoFn GetObjectInfoFn, objRetention *objectlock.ObjectRetention, cred auth.Credentials, owner bool) (ObjectInfo, APIErrorCode) {
|
||||||
byPassSet := objectlock.IsObjectLockGovernanceBypassSet(r.Header)
|
byPassSet := objectlock.IsObjectLockGovernanceBypassSet(r.Header)
|
||||||
opts, err := getOpts(ctx, r, bucket, object)
|
opts, err := getOpts(ctx, r, bucket, object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -203,7 +203,7 @@ func enforceRetentionBypassForPut(ctx context.Context, r *http.Request, bucket,
|
|||||||
perm := isPutRetentionAllowed(bucket, object,
|
perm := isPutRetentionAllowed(bucket, object,
|
||||||
days, objRetention.RetainUntilDate.Time,
|
days, objRetention.RetainUntilDate.Time,
|
||||||
objRetention.Mode, byPassSet, r, cred,
|
objRetention.Mode, byPassSet, r, cred,
|
||||||
owner, claims)
|
owner)
|
||||||
return oi, perm
|
return oi, perm
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +211,7 @@ func enforceRetentionBypassForPut(ctx context.Context, r *http.Request, bucket,
|
|||||||
case objectlock.RetGovernance:
|
case objectlock.RetGovernance:
|
||||||
govPerm := isPutRetentionAllowed(bucket, object, days,
|
govPerm := isPutRetentionAllowed(bucket, object, days,
|
||||||
objRetention.RetainUntilDate.Time, objRetention.Mode,
|
objRetention.RetainUntilDate.Time, objRetention.Mode,
|
||||||
byPassSet, r, cred, owner, claims)
|
byPassSet, r, cred, owner)
|
||||||
// Governance mode retention period cannot be shortened, if x-amz-bypass-governance is not set.
|
// Governance mode retention period cannot be shortened, if x-amz-bypass-governance is not set.
|
||||||
if !byPassSet {
|
if !byPassSet {
|
||||||
if objRetention.Mode != objectlock.RetGovernance || objRetention.RetainUntilDate.Before((ret.RetainUntilDate.Time)) {
|
if objRetention.Mode != objectlock.RetGovernance || objRetention.RetainUntilDate.Before((ret.RetainUntilDate.Time)) {
|
||||||
@ -227,7 +227,7 @@ func enforceRetentionBypassForPut(ctx context.Context, r *http.Request, bucket,
|
|||||||
}
|
}
|
||||||
compliancePerm := isPutRetentionAllowed(bucket, object,
|
compliancePerm := isPutRetentionAllowed(bucket, object,
|
||||||
days, objRetention.RetainUntilDate.Time, objRetention.Mode,
|
days, objRetention.RetainUntilDate.Time, objRetention.Mode,
|
||||||
false, r, cred, owner, claims)
|
false, r, cred, owner)
|
||||||
return oi, compliancePerm
|
return oi, compliancePerm
|
||||||
}
|
}
|
||||||
return oi, ErrNone
|
return oi, ErrNone
|
||||||
@ -235,7 +235,7 @@ func enforceRetentionBypassForPut(ctx context.Context, r *http.Request, bucket,
|
|||||||
|
|
||||||
perm := isPutRetentionAllowed(bucket, object,
|
perm := isPutRetentionAllowed(bucket, object,
|
||||||
days, objRetention.RetainUntilDate.Time,
|
days, objRetention.RetainUntilDate.Time,
|
||||||
objRetention.Mode, byPassSet, r, cred, owner, claims)
|
objRetention.Mode, byPassSet, r, cred, owner)
|
||||||
return oi, perm
|
return oi, perm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3502,7 +3502,7 @@ func (api objectAPIHandlers) PutObjectRetentionHandler(w http.ResponseWriter, r
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cred, owner, claims, s3Err := validateSignature(getRequestAuthType(r), r)
|
cred, owner, s3Err := validateSignature(getRequestAuthType(r), r)
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL)
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL)
|
||||||
return
|
return
|
||||||
@ -3542,7 +3542,7 @@ func (api objectAPIHandlers) PutObjectRetentionHandler(w http.ResponseWriter, r
|
|||||||
getObjectInfo = api.CacheAPI().GetObjectInfo
|
getObjectInfo = api.CacheAPI().GetObjectInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
objInfo, s3Err := enforceRetentionBypassForPut(ctx, r, bucket, object, getObjectInfo, objRetention, cred, owner, claims)
|
objInfo, s3Err := enforceRetentionBypassForPut(ctx, r, bucket, object, getObjectInfo, objRetention, cred, owner)
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL)
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL)
|
||||||
return
|
return
|
||||||
|
@ -78,7 +78,9 @@ const (
|
|||||||
// http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationStringToSign
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationStringToSign
|
||||||
func doesPolicySignatureV2Match(formValues http.Header) (auth.Credentials, APIErrorCode) {
|
func doesPolicySignatureV2Match(formValues http.Header) (auth.Credentials, APIErrorCode) {
|
||||||
accessKey := formValues.Get(xhttp.AmzAccessKeyID)
|
accessKey := formValues.Get(xhttp.AmzAccessKeyID)
|
||||||
cred, _, s3Err := checkKeyValid(accessKey)
|
|
||||||
|
r := &http.Request{Header: formValues}
|
||||||
|
cred, _, s3Err := checkKeyValid(r, accessKey)
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return cred, s3Err
|
return cred, s3Err
|
||||||
}
|
}
|
||||||
@ -153,7 +155,7 @@ func doesPresignV2SignatureMatch(r *http.Request) APIErrorCode {
|
|||||||
return ErrInvalidQueryParams
|
return ErrInvalidQueryParams
|
||||||
}
|
}
|
||||||
|
|
||||||
cred, _, s3Err := checkKeyValid(accessKey)
|
cred, _, s3Err := checkKeyValid(r, accessKey)
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return s3Err
|
return s3Err
|
||||||
}
|
}
|
||||||
@ -184,7 +186,7 @@ func doesPresignV2SignatureMatch(r *http.Request) APIErrorCode {
|
|||||||
|
|
||||||
func getReqAccessKeyV2(r *http.Request) (auth.Credentials, bool, APIErrorCode) {
|
func getReqAccessKeyV2(r *http.Request) (auth.Credentials, bool, APIErrorCode) {
|
||||||
if accessKey := r.Form.Get(xhttp.AmzAccessKeyID); accessKey != "" {
|
if accessKey := r.Form.Get(xhttp.AmzAccessKeyID); accessKey != "" {
|
||||||
return checkKeyValid(accessKey)
|
return checkKeyValid(r, accessKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// below is V2 Signed Auth header format, splitting on `space` (after the `AWS` string).
|
// below is V2 Signed Auth header format, splitting on `space` (after the `AWS` string).
|
||||||
@ -200,7 +202,7 @@ func getReqAccessKeyV2(r *http.Request) (auth.Credentials, bool, APIErrorCode) {
|
|||||||
return auth.Credentials{}, false, ErrMissingFields
|
return auth.Credentials{}, false, ErrMissingFields
|
||||||
}
|
}
|
||||||
|
|
||||||
return checkKeyValid(keySignFields[0])
|
return checkKeyValid(r, keySignFields[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature;
|
// Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature;
|
||||||
|
@ -63,7 +63,7 @@ func getReqAccessKeyV4(r *http.Request, region string, stype serviceType) (auth.
|
|||||||
return auth.Credentials{}, false, s3Err
|
return auth.Credentials{}, false, s3Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return checkKeyValid(ch.accessKey)
|
return checkKeyValid(r, ch.accessKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse credentialHeader string into its structured form.
|
// parse credentialHeader string into its structured form.
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
"github.com/minio/minio/internal/auth"
|
"github.com/minio/minio/internal/auth"
|
||||||
xhttp "github.com/minio/minio/internal/http"
|
xhttp "github.com/minio/minio/internal/http"
|
||||||
"github.com/minio/minio/internal/logger"
|
"github.com/minio/minio/internal/logger"
|
||||||
|
iampolicy "github.com/minio/pkg/iam/policy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// http Header "x-amz-content-sha256" == "UNSIGNED-PAYLOAD" indicates that the
|
// http Header "x-amz-content-sha256" == "UNSIGNED-PAYLOAD" indicates that the
|
||||||
@ -120,7 +121,7 @@ func isValidRegion(reqRegion string, confRegion string) bool {
|
|||||||
|
|
||||||
// check if the access key is valid and recognized, additionally
|
// check if the access key is valid and recognized, additionally
|
||||||
// also returns if the access key is owner/admin.
|
// also returns if the access key is owner/admin.
|
||||||
func checkKeyValid(accessKey string) (auth.Credentials, bool, APIErrorCode) {
|
func checkKeyValid(r *http.Request, accessKey string) (auth.Credentials, bool, APIErrorCode) {
|
||||||
if !globalIAMSys.Initialized() && !globalIsGateway {
|
if !globalIAMSys.Initialized() && !globalIsGateway {
|
||||||
// Check if server has initialized, then only proceed
|
// Check if server has initialized, then only proceed
|
||||||
// to check for IAM users otherwise its okay for clients
|
// to check for IAM users otherwise its okay for clients
|
||||||
@ -135,7 +136,17 @@ func checkKeyValid(accessKey string) (auth.Credentials, bool, APIErrorCode) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return cred, false, ErrInvalidAccessKeyID
|
return cred, false, ErrInvalidAccessKeyID
|
||||||
}
|
}
|
||||||
owner = cred.AccessKey == ucred.ParentUser
|
claims, s3Err := checkClaimsFromToken(r, cred)
|
||||||
|
if s3Err != ErrNone {
|
||||||
|
return cred, false, s3Err
|
||||||
|
}
|
||||||
|
ucred.Claims = claims
|
||||||
|
// Now check if we have a sessionPolicy.
|
||||||
|
if _, ok = claims[iampolicy.SessionPolicyName]; ok {
|
||||||
|
owner = false
|
||||||
|
} else {
|
||||||
|
owner = cred.AccessKey == ucred.ParentUser
|
||||||
|
}
|
||||||
cred = ucred
|
cred = ucred
|
||||||
}
|
}
|
||||||
return cred, owner, ErrNone
|
return cred, owner, ErrNone
|
||||||
|
@ -181,7 +181,8 @@ func doesPolicySignatureV4Match(formValues http.Header) (auth.Credentials, APIEr
|
|||||||
return auth.Credentials{}, s3Err
|
return auth.Credentials{}, s3Err
|
||||||
}
|
}
|
||||||
|
|
||||||
cred, _, s3Err := checkKeyValid(credHeader.accessKey)
|
r := &http.Request{Header: formValues}
|
||||||
|
cred, _, s3Err := checkKeyValid(r, credHeader.accessKey)
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return cred, s3Err
|
return cred, s3Err
|
||||||
}
|
}
|
||||||
@ -214,7 +215,7 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cred, _, s3Err := checkKeyValid(pSignValues.Credential.accessKey)
|
cred, _, s3Err := checkKeyValid(r, pSignValues.Credential.accessKey)
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return s3Err
|
return s3Err
|
||||||
}
|
}
|
||||||
@ -349,7 +350,7 @@ func doesSignatureMatch(hashedPayload string, r *http.Request, region string, st
|
|||||||
return errCode
|
return errCode
|
||||||
}
|
}
|
||||||
|
|
||||||
cred, _, s3Err := checkKeyValid(signV4Values.Credential.accessKey)
|
cred, _, s3Err := checkKeyValid(r, signV4Values.Credential.accessKey)
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return s3Err
|
return s3Err
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ func calculateSeedSignature(r *http.Request) (cred auth.Credentials, signature s
|
|||||||
return cred, "", "", time.Time{}, errCode
|
return cred, "", "", time.Time{}, errCode
|
||||||
}
|
}
|
||||||
|
|
||||||
cred, _, errCode = checkKeyValid(signV4Values.Credential.accessKey)
|
cred, _, errCode = checkKeyValid(r, signV4Values.Credential.accessKey)
|
||||||
if errCode != ErrNone {
|
if errCode != ErrNone {
|
||||||
return cred, "", "", time.Time{}, errCode
|
return cred, "", "", time.Time{}, errCode
|
||||||
}
|
}
|
||||||
|
@ -94,13 +94,14 @@ const (
|
|||||||
|
|
||||||
// Credentials holds access and secret keys.
|
// Credentials holds access and secret keys.
|
||||||
type Credentials struct {
|
type Credentials struct {
|
||||||
AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"`
|
AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"`
|
||||||
SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"`
|
SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"`
|
||||||
Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"`
|
Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"`
|
||||||
SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"`
|
SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"`
|
||||||
Status string `xml:"-" json:"status,omitempty"`
|
Status string `xml:"-" json:"status,omitempty"`
|
||||||
ParentUser string `xml:"-" json:"parentUser,omitempty"`
|
ParentUser string `xml:"-" json:"parentUser,omitempty"`
|
||||||
Groups []string `xml:"-" json:"groups,omitempty"`
|
Groups []string `xml:"-" json:"groups,omitempty"`
|
||||||
|
Claims map[string]interface{} `xml:"-" json:"claims,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cred Credentials) String() string {
|
func (cred Credentials) String() string {
|
||||||
|
Loading…
Reference in New Issue
Block a user