mirror of
https://github.com/cubefs/cubefs.git
synced 2026-08-02 02:00:56 +00:00
Enhancement: compatible with older version s3 credential
Added compatibility with 1.5 version of credential information for signature verification and policy check of s3 interface. In version 1.5, each volume has its own access key, which is stored in the view information center of the volume to which it belongs. In version 2.0, user security and authorization are added. Each user has their own access key, and users can use this access key to operate all their own volumes. Increase the compatibility with the old version authentication method to reduce the impact of online version 1.5 cluster upgrade to 2.0 on online services. Signed-off-by: Mofei Zhang <mofei2816@gmail.com>
This commit is contained in:
parent
26248fd42f
commit
43561c35b0
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@ -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()}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user