diff --git a/objectnode/auth_signature_v2.go b/objectnode/auth_signature_v2.go index 67f1d927f..3f9382f6c 100644 --- a/objectnode/auth_signature_v2.go +++ b/objectnode/auth_signature_v2.go @@ -177,17 +177,35 @@ func (o *ObjectNode) validateHeaderBySignatureAlgorithmV2(r *http.Request) (bool return false, err } - var userInfo *proto.UserInfo - if userInfo, err = o.getUserInfoByAccessKey(authInfo.accessKeyId); err != nil { - log.LogInfof("get secretKey from master error: accessKey(%v), err(%v)", authInfo.accessKeyId, err) + var accessKey = authInfo.accessKeyId + var volume *Volume + if bucket := mux.Vars(r)["bucket"]; len(bucket) > 0 { + volume, _ = o.getVol(bucket) + } + var secretKey string + if userInfo, err := o.getUserInfoByAccessKey(accessKey); err == nil { + secretKey = userInfo.SecretKey + } else if (err == proto.ErrUserNotExists || err == proto.ErrAccessKeyNotExists) && volume != nil { + // In order to be directly compatible with the signature verification of version 1.5 + // (each volume has its own access key and secret key), if the user does not exist and + // the request specifies a volume, try to use the access key and secret key bound in the + // volume information for verification. + if ak, sk := volume.OSSSecure(); ak == accessKey { + secretKey = sk + } else { + return false, nil + } + } else { + log.LogErrorf("validateHeaderBySignatureAlgorithmV4: get secretKey from master fail: accessKey(%v) err(%v)", + accessKey, err) return false, err } // 2. calculate new signature - newSignature, err1 := calculateSignatureV2(authInfo, userInfo.SecretKey, o.wildcards) - if err1 != nil { + newSignature, err := calculateSignatureV2(authInfo, secretKey, o.wildcards) + if err != nil { log.LogInfof("calculute SignatureV2 error: %v, %v", authInfo.r, err) - return false, err1 + return false, err } // 3. compare newSignatrue and reqSignature @@ -252,8 +270,6 @@ func calculateSignatureV2(authInfo *requestAuthInfoV2, secretKey string, wildcar func (o *ObjectNode) validateUrlBySignatureAlgorithmV2(r *http.Request) (bool, error) { - var err error - uris := strings.SplitN(r.RequestURI, "?", 2) if len(uris) < 2 { log.LogInfof("validateUrlBySignatureAlgorithmV2 error, request url invalid %v ", r.RequestURI) @@ -273,10 +289,27 @@ func (o *ObjectNode) validateUrlBySignatureAlgorithmV2(r *http.Request) (bool, e log.LogDebugf("validateUrlBySignatureAlgorithmV2: parse signature info: requestID(%v) url(%v) accessKey(%v) signature(%v) expires(%v)", GetRequestID(r), r.URL.String(), accessKey, signature, expires) - //check access key - var userInfo *proto.UserInfo - if userInfo, err = o.getUserInfoByAccessKey(accessKey); err != nil { - log.LogInfof("get secretKey from master error: accessKey(%v), err(%v)", accessKey, err) + // Checking access key + var volume *Volume + if bucket := mux.Vars(r)["bucket"]; len(bucket) > 0 { + volume, _ = o.getVol(bucket) + } + var secretKey string + if userInfo, err := o.getUserInfoByAccessKey(accessKey); err == nil { + secretKey = userInfo.SecretKey + } else if (err == proto.ErrUserNotExists || err == proto.ErrAccessKeyNotExists) && volume != nil { + // In order to be directly compatible with the signature verification of version 1.5 + // (each volume has its own access key and secret key), if the user does not exist and + // the request specifies a volume, try to use the access key and secret key bound in the + // volume information for verification. + if ak, sk := volume.OSSSecure(); ak == accessKey { + secretKey = sk + } else { + return false, nil + } + } else { + log.LogErrorf("validateHeaderBySignatureAlgorithmV4: get secretKey from master fail: accessKey(%v) err(%v)", + accessKey, err) return false, err } @@ -290,7 +323,7 @@ func (o *ObjectNode) validateUrlBySignatureAlgorithmV2(r *http.Request) (bool, e var canonicalResource string canonicalResource = getCanonicalizedResourceV2(r, o.wildcards) canonicalResourceQuery := getCanonicalQueryV2(canonicalResource, r.URL.Query().Encode()) - calSignature := calPresignedSignatureV2(r.Method, canonicalResourceQuery, expires, userInfo.SecretKey, r.Header) + calSignature := calPresignedSignatureV2(r.Method, canonicalResourceQuery, expires, secretKey, r.Header) if calSignature != signature { log.LogDebugf("validateUrlBySignatureAlgorithmV2: invalid signature: requestID(%v) client(%v) server(%v)", GetRequestID(r), signature, calSignature) diff --git a/objectnode/auth_signature_v4.go b/objectnode/auth_signature_v4.go index 140084e73..a640b8318 100644 --- a/objectnode/auth_signature_v4.go +++ b/objectnode/auth_signature_v4.go @@ -100,12 +100,32 @@ func (o *ObjectNode) validateHeaderBySignatureAlgorithmV4(r *http.Request) (bool if err != nil { return false, err } - var userInfo *proto.UserInfo - if userInfo, err = o.getUserInfoByAccessKey(req.Credential.AccessKey); err != nil { - log.LogInfof("validateHeaderBySignatureAlgorithmV4: get secretKey from master fail: err(%v)", err) + + var accessKey = req.Credential.AccessKey + var volume *Volume + if bucket := mux.Vars(r)["bucket"]; len(bucket) > 0 { + volume, _ = o.getVol(bucket) + } + var secretKey string + if userInfo, err := o.getUserInfoByAccessKey(accessKey); err == nil { + secretKey = userInfo.SecretKey + } else if (err == proto.ErrUserNotExists || err == proto.ErrAccessKeyNotExists) && volume != nil { + // In order to be directly compatible with the signature verification of version 1.5 + // (each volume has its own access key and secret key), if the user does not exist and + // the request specifies a volume, try to use the accesskey and secret key bound in the + // volume information for verification. + if ak, sk := volume.OSSSecure(); ak == accessKey { + secretKey = sk + } else { + return false, nil + } + } else { + log.LogErrorf("validateHeaderBySignatureAlgorithmV4: get secretKey from master fail: accessKey(%v) err(%v)", + accessKey, err) return false, err } - newSignature := calculateSignatureV4(r, req.Credential.Region, userInfo.SecretKey, req.SignedHeaders) + + newSignature := calculateSignatureV4(r, req.Credential.Region, secretKey, req.SignedHeaders) if req.Signature != newSignature { log.LogDebugf("validateHeaderBySignatureAlgorithmV4: invalid signature: requestID(%v) client(%v) server(%v)", GetRequestID(r), req.Signature, newSignature) @@ -139,12 +159,30 @@ func (o *ObjectNode) validateUrlBySignatureAlgorithmV4(r *http.Request) (pass bo return } - // check accessKey valid - var userInfo *proto.UserInfo - if userInfo, err = o.getUserInfoByAccessKey(req.Credential.AccessKey); err != nil { - log.LogInfof("get secretKey from master error: accessKey(%v), err(%v)", req.Credential.AccessKey, err) + var accessKey = req.Credential.AccessKey + var volume *Volume + if bucket := mux.Vars(r)["bucket"]; len(bucket) > 0 { + volume, _ = o.getVol(bucket) + } + var secretKey string + if userInfo, err := o.getUserInfoByAccessKey(accessKey); err == nil { + secretKey = userInfo.SecretKey + } else if (err == proto.ErrUserNotExists || err == proto.ErrAccessKeyNotExists) && volume != nil { + // In order to be directly compatible with the signature verification of version 1.5 + // (each volume has its own access key and secret key), if the user does not exist and + // the request specifies a volume, try to use the accesskey and secret key bound in the + // volume information for verification. + if ak, sk := volume.OSSSecure(); ak == accessKey { + secretKey = sk + } else { + return false, nil + } + } else { + log.LogErrorf("validateHeaderBySignatureAlgorithmV4: get secretKey from master fail: accessKey(%v) err(%v)", + accessKey, err) return false, err } + // create canonicalRequest var canonicalHeader http.Header canonicalHeader, err = req.createCanonicalHeaderV4() @@ -165,7 +203,7 @@ func (o *ObjectNode) validateUrlBySignatureAlgorithmV4(r *http.Request) (pass bo canonicalRequestString) // build signingKey - signingKey := buildSigningKey(SCHEME, userInfo.SecretKey, req.Credential.Date, req.Credential.Region, req.Credential.Service, req.Credential.Request) + signingKey := buildSigningKey(SCHEME, secretKey, req.Credential.Date, req.Credential.Region, req.Credential.Service, req.Credential.Request) // build stringToSign scope := buildScope(req.Credential.Date, req.Credential.Region, req.Credential.Service, req.Credential.Request) diff --git a/objectnode/policy.go b/objectnode/policy.go index aca018929..e24627ee2 100644 --- a/objectnode/policy.go +++ b/objectnode/policy.go @@ -26,6 +26,8 @@ import ( "net/http" "strings" + "github.com/gorilla/mux" + "github.com/chubaofs/chubaofs/proto" "github.com/chubaofs/chubaofs/util/log" ) @@ -212,26 +214,37 @@ func (o *ObjectNode) policyCheck(f http.HandlerFunc) http.HandlerFunc { } // Check user policy + var volume *Volume + if bucket := mux.Vars(r)["bucket"]; len(bucket) > 0 { + volume, _ = o.getVol(bucket) + } var userInfo *proto.UserInfo - if userInfo, err = o.getUserInfoByAccessKey(param.accessKey); err != nil { + if userInfo, err = o.getUserInfoByAccessKey(param.AccessKey()); err == nil { + // White list for admin and root user. + if userInfo.UserType == proto.UserTypeRoot || userInfo.UserType == proto.UserTypeAdmin { + log.LogDebugf("policyCheck: user is admin: requestID(%v) userID(%v) accessKey(%v) volume(%v)", + GetRequestID(r), userInfo.UserID, param.AccessKey(), param.Bucket()) + allowed = true + return + } + var userPolicy = userInfo.Policy + if !userPolicy.IsOwn(param.Bucket()) && !userPolicy.IsAuthorized(param.Bucket(), param.Action()) { + log.LogDebugf("policyCheck: user no permission: requestID(%v) userID(%v) accessKey(%v) volume(%v) action(%v)", + GetRequestID(r), userInfo.UserID, param.AccessKey(), param.Bucket(), param.Action()) + allowed = false + return + } + } else if (err == proto.ErrAccessKeyNotExists || err == proto.ErrUserNotExists) && volume != nil { + if ak, _ := volume.OSSSecure(); ak != param.AccessKey() { + allowed = false + return + } + } else { log.LogErrorf("policyCheck: load user policy from master fail: requestID(%v) accessKey(%v) err(%v)", GetRequestID(r), param.AccessKey(), err) allowed = false return } - if userInfo.UserType == proto.UserTypeRoot || userInfo.UserType == proto.UserTypeAdmin { - log.LogDebugf("policyCheck: user is admin: requestID(%v) userID(%v) accessKey(%v) volume(%v)", - GetRequestID(r), userInfo.UserID, param.AccessKey(), param.Bucket()) - allowed = true - return - } - var userPolicy = userInfo.Policy - if !userPolicy.IsOwn(param.Bucket()) && !userPolicy.IsAuthorized(param.Bucket(), param.Action()) { - log.LogDebugf("policyCheck: user no permission: requestID(%v) userID(%v) accessKey(%v) volume(%v) action(%v)", - GetRequestID(r), userInfo.UserID, param.AccessKey(), param.Bucket(), param.Action()) - allowed = false - return - } var vol *Volume var acl *AccessControlPolicy @@ -255,7 +268,7 @@ func (o *ObjectNode) policyCheck(f http.HandlerFunc) http.HandlerFunc { allowed = policy.IsAllowed(param) if !allowed { log.LogWarnf("policyCheck: bucket policy not allowed: requestID(%v) userID(%v) accessKey(%v) volume(%v) action(%v)", - GetRequestID(r), userInfo.UserID, param.AccessKey(), param.Bucket(), param.Action()) + GetRequestID(r), userInfo, param.AccessKey(), param.Bucket(), param.Action()) return } } @@ -264,13 +277,13 @@ func (o *ObjectNode) policyCheck(f http.HandlerFunc) http.HandlerFunc { allowed = acl.IsAllowed(param) if !allowed { log.LogWarnf("policyCheck: bucket ACL not allowed: requestID(%v) userID(%v) accessKey(%v) volume(%v) action(%v)", - GetRequestID(r), userInfo.UserID, param.AccessKey(), param.Bucket(), param.Action()) + GetRequestID(r), userInfo, param.AccessKey(), param.Bucket(), param.Action()) return } } allowed = true log.LogDebugf("policyCheck: action allowed: requestID(%v) userID(%v) accessKey(%v) volume(%v) action(%v)", - GetRequestID(r), userInfo.UserID, param.AccessKey(), param.Bucket(), param.Action()) + GetRequestID(r), userInfo, param.AccessKey(), param.Bucket(), param.Action()) } } diff --git a/proto/user_proto.go b/proto/user_proto.go index e0beb1031..c3202f05b 100644 --- a/proto/user_proto.go +++ b/proto/user_proto.go @@ -15,6 +15,7 @@ package proto import ( + "fmt" "regexp" "sync" ) @@ -101,6 +102,14 @@ type UserInfo struct { CreateTime string `json:"create_time"` } +func (i *UserInfo) String() string { + if i == nil { + return "nil" + } + return fmt.Sprintf("%v_%v_%v_%v", + i.UserID, i.AccessKey, i.SecretKey, i.UserType) +} + func NewUserInfo() *UserInfo { return &UserInfo{Policy: NewUserPolicy()} }