mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
Parse and return proper errors with x-amz-security-token (#6766)
This PR also simplifies the token and access key validation across our signature handling.
This commit is contained in:
parent
88959ce600
commit
bf414068a3
@ -150,6 +150,9 @@ const (
|
|||||||
ErrKMSNotConfigured
|
ErrKMSNotConfigured
|
||||||
ErrKMSAuthFailure
|
ErrKMSAuthFailure
|
||||||
|
|
||||||
|
ErrNoAccessKey
|
||||||
|
ErrInvalidToken
|
||||||
|
|
||||||
// Bucket notification related errors.
|
// Bucket notification related errors.
|
||||||
ErrEventNotification
|
ErrEventNotification
|
||||||
ErrARNNotification
|
ErrARNNotification
|
||||||
@ -806,6 +809,16 @@ var errorCodeResponse = map[APIErrorCode]APIError{
|
|||||||
Description: "Server side encryption specified but KMS authorization failed",
|
Description: "Server side encryption specified but KMS authorization failed",
|
||||||
HTTPStatusCode: http.StatusBadRequest,
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
|
ErrNoAccessKey: {
|
||||||
|
Code: "AccessDenied",
|
||||||
|
Description: "No AWSAccessKey was presented",
|
||||||
|
HTTPStatusCode: http.StatusForbidden,
|
||||||
|
},
|
||||||
|
ErrInvalidToken: {
|
||||||
|
Code: "InvalidTokenId",
|
||||||
|
Description: "The security token included in the request is invalid",
|
||||||
|
HTTPStatusCode: http.StatusForbidden,
|
||||||
|
},
|
||||||
|
|
||||||
/// S3 extensions.
|
/// S3 extensions.
|
||||||
ErrContentSHA256Mismatch: {
|
ErrContentSHA256Mismatch: {
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -29,6 +30,7 @@ import (
|
|||||||
|
|
||||||
jwtgo "github.com/dgrijalva/jwt-go"
|
jwtgo "github.com/dgrijalva/jwt-go"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
|
"github.com/minio/minio/pkg/auth"
|
||||||
"github.com/minio/minio/pkg/hash"
|
"github.com/minio/minio/pkg/hash"
|
||||||
"github.com/minio/minio/pkg/iam/policy"
|
"github.com/minio/minio/pkg/iam/policy"
|
||||||
"github.com/minio/minio/pkg/policy"
|
"github.com/minio/minio/pkg/policy"
|
||||||
@ -154,12 +156,41 @@ func getSessionToken(r *http.Request) (token string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch claims in the security token returned by the client and validate the token.
|
// Fetch claims in the security token returned by the client and validate the token.
|
||||||
func getClaimsFromToken(r *http.Request) (map[string]interface{}, APIErrorCode) {
|
func getClaimsFromToken(r *http.Request, cred auth.Credentials) (map[string]interface{}, APIErrorCode) {
|
||||||
|
stsTokenCallback := func(jwtToken *jwtgo.Token) (interface{}, error) {
|
||||||
|
if _, ok := jwtToken.Method.(*jwtgo.SigningMethodHMAC); !ok {
|
||||||
|
return nil, fmt.Errorf("Unexpected signing method: %v", jwtToken.Header["alg"])
|
||||||
|
}
|
||||||
|
if err := jwtToken.Claims.Valid(); err != nil {
|
||||||
|
return nil, errAuthentication
|
||||||
|
}
|
||||||
|
if claims, ok := jwtToken.Claims.(jwtgo.MapClaims); ok {
|
||||||
|
if _, ok = claims["accessKey"].(string); !ok {
|
||||||
|
return nil, errInvalidAccessKeyID
|
||||||
|
}
|
||||||
|
// JWT token for x-amz-security-token is signed with admin
|
||||||
|
// secret key, temporary credentials become invalid if
|
||||||
|
// server admin credentials change. This is done to ensure
|
||||||
|
// that clients cannot decode the token using the temp
|
||||||
|
// secret keys and generate an entirely new claim by essentially
|
||||||
|
// hijacking the policies. We need to make sure that this is
|
||||||
|
// based an admin credential such that token cannot be decoded
|
||||||
|
// on the client side and is treated like an opaque value.
|
||||||
|
return []byte(globalServerConfig.GetCredential().SecretKey), nil
|
||||||
|
}
|
||||||
|
return nil, errAuthentication
|
||||||
|
}
|
||||||
claims := make(map[string]interface{})
|
claims := make(map[string]interface{})
|
||||||
token := getSessionToken(r)
|
token := getSessionToken(r)
|
||||||
if token == "" {
|
if token == "" {
|
||||||
return nil, ErrNone
|
return nil, ErrNone
|
||||||
}
|
}
|
||||||
|
if token != "" && cred.AccessKey == "" {
|
||||||
|
return nil, ErrNoAccessKey
|
||||||
|
}
|
||||||
|
if token != cred.SessionToken {
|
||||||
|
return nil, ErrInvalidToken
|
||||||
|
}
|
||||||
p := &jwtgo.Parser{}
|
p := &jwtgo.Parser{}
|
||||||
jtoken, err := p.ParseWithClaims(token, jwtgo.MapClaims(claims), stsTokenCallback)
|
jtoken, err := p.ParseWithClaims(token, jwtgo.MapClaims(claims), stsTokenCallback)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -177,7 +208,7 @@ func getClaimsFromToken(r *http.Request) (map[string]interface{}, APIErrorCode)
|
|||||||
// for authenticated requests validates IAM policies.
|
// for authenticated requests validates IAM policies.
|
||||||
// returns APIErrorCode if any to be replied to the client.
|
// returns APIErrorCode if any to be replied to the client.
|
||||||
func checkRequestAuthType(ctx context.Context, r *http.Request, action policy.Action, bucketName, objectName string) (s3Err APIErrorCode) {
|
func checkRequestAuthType(ctx context.Context, r *http.Request, action policy.Action, bucketName, objectName string) (s3Err APIErrorCode) {
|
||||||
var accessKey string
|
var cred auth.Credentials
|
||||||
var owner bool
|
var owner bool
|
||||||
switch getRequestAuthType(r) {
|
switch getRequestAuthType(r) {
|
||||||
case authTypeUnknown, authTypeStreamingSigned:
|
case authTypeUnknown, authTypeStreamingSigned:
|
||||||
@ -186,7 +217,7 @@ func checkRequestAuthType(ctx context.Context, r *http.Request, action policy.Ac
|
|||||||
if s3Err = isReqAuthenticatedV2(r); s3Err != ErrNone {
|
if s3Err = isReqAuthenticatedV2(r); s3Err != ErrNone {
|
||||||
return s3Err
|
return s3Err
|
||||||
}
|
}
|
||||||
accessKey, owner, s3Err = getReqAccessKeyV2(r)
|
cred, owner, s3Err = getReqAccessKeyV2(r)
|
||||||
case authTypeSigned, authTypePresigned:
|
case authTypeSigned, authTypePresigned:
|
||||||
region := globalServerConfig.GetRegion()
|
region := globalServerConfig.GetRegion()
|
||||||
switch action {
|
switch action {
|
||||||
@ -196,7 +227,7 @@ func checkRequestAuthType(ctx context.Context, r *http.Request, action policy.Ac
|
|||||||
if s3Err = isReqAuthenticated(r, region); s3Err != ErrNone {
|
if s3Err = isReqAuthenticated(r, region); s3Err != ErrNone {
|
||||||
return s3Err
|
return s3Err
|
||||||
}
|
}
|
||||||
accessKey, owner, s3Err = getReqAccessKeyV4(r, region)
|
cred, owner, s3Err = getReqAccessKeyV4(r, region)
|
||||||
}
|
}
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return s3Err
|
return s3Err
|
||||||
@ -225,14 +256,14 @@ func checkRequestAuthType(ctx context.Context, r *http.Request, action policy.Ac
|
|||||||
r.Body = ioutil.NopCloser(bytes.NewReader(payload))
|
r.Body = ioutil.NopCloser(bytes.NewReader(payload))
|
||||||
}
|
}
|
||||||
|
|
||||||
claims, s3Err := getClaimsFromToken(r)
|
claims, s3Err := getClaimsFromToken(r, cred)
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return s3Err
|
return s3Err
|
||||||
}
|
}
|
||||||
|
|
||||||
if accessKey == "" {
|
if cred.AccessKey == "" {
|
||||||
if globalPolicySys.IsAllowed(policy.Args{
|
if globalPolicySys.IsAllowed(policy.Args{
|
||||||
AccountName: accessKey,
|
AccountName: cred.AccessKey,
|
||||||
Action: action,
|
Action: action,
|
||||||
BucketName: bucketName,
|
BucketName: bucketName,
|
||||||
ConditionValues: getConditionValues(r, locationConstraint),
|
ConditionValues: getConditionValues(r, locationConstraint),
|
||||||
@ -245,7 +276,7 @@ func checkRequestAuthType(ctx context.Context, r *http.Request, action policy.Ac
|
|||||||
}
|
}
|
||||||
|
|
||||||
if globalIAMSys.IsAllowed(iampolicy.Args{
|
if globalIAMSys.IsAllowed(iampolicy.Args{
|
||||||
AccountName: accessKey,
|
AccountName: cred.AccessKey,
|
||||||
Action: iampolicy.Action(action),
|
Action: iampolicy.Action(action),
|
||||||
BucketName: bucketName,
|
BucketName: bucketName,
|
||||||
ConditionValues: getConditionValues(r, ""),
|
ConditionValues: getConditionValues(r, ""),
|
||||||
@ -372,29 +403,29 @@ func (a authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
// call verifies bucket policies and IAM policies, supports multi user
|
// call verifies bucket policies and IAM policies, supports multi user
|
||||||
// checks etc.
|
// checks etc.
|
||||||
func isPutAllowed(atype authType, bucketName, objectName string, r *http.Request) (s3Err APIErrorCode) {
|
func isPutAllowed(atype authType, bucketName, objectName string, r *http.Request) (s3Err APIErrorCode) {
|
||||||
var accessKey string
|
var cred auth.Credentials
|
||||||
var owner bool
|
var owner bool
|
||||||
switch atype {
|
switch atype {
|
||||||
case authTypeUnknown:
|
case authTypeUnknown:
|
||||||
return ErrAccessDenied
|
return ErrAccessDenied
|
||||||
case authTypeSignedV2, authTypePresignedV2:
|
case authTypeSignedV2, authTypePresignedV2:
|
||||||
accessKey, owner, s3Err = getReqAccessKeyV2(r)
|
cred, owner, s3Err = getReqAccessKeyV2(r)
|
||||||
case authTypeStreamingSigned, authTypePresigned, authTypeSigned:
|
case authTypeStreamingSigned, authTypePresigned, authTypeSigned:
|
||||||
region := globalServerConfig.GetRegion()
|
region := globalServerConfig.GetRegion()
|
||||||
accessKey, owner, s3Err = getReqAccessKeyV4(r, region)
|
cred, owner, s3Err = getReqAccessKeyV4(r, region)
|
||||||
}
|
}
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return s3Err
|
return s3Err
|
||||||
}
|
}
|
||||||
|
|
||||||
claims, s3Err := getClaimsFromToken(r)
|
claims, s3Err := getClaimsFromToken(r, cred)
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return s3Err
|
return s3Err
|
||||||
}
|
}
|
||||||
|
|
||||||
if accessKey == "" {
|
if cred.AccessKey == "" {
|
||||||
if globalPolicySys.IsAllowed(policy.Args{
|
if globalPolicySys.IsAllowed(policy.Args{
|
||||||
AccountName: accessKey,
|
AccountName: cred.AccessKey,
|
||||||
Action: policy.PutObjectAction,
|
Action: policy.PutObjectAction,
|
||||||
BucketName: bucketName,
|
BucketName: bucketName,
|
||||||
ConditionValues: getConditionValues(r, ""),
|
ConditionValues: getConditionValues(r, ""),
|
||||||
@ -407,7 +438,7 @@ func isPutAllowed(atype authType, bucketName, objectName string, r *http.Request
|
|||||||
}
|
}
|
||||||
|
|
||||||
if globalIAMSys.IsAllowed(iampolicy.Args{
|
if globalIAMSys.IsAllowed(iampolicy.Args{
|
||||||
AccountName: accessKey,
|
AccountName: cred.AccessKey,
|
||||||
Action: policy.PutObjectAction,
|
Action: policy.PutObjectAction,
|
||||||
BucketName: bucketName,
|
BucketName: bucketName,
|
||||||
ConditionValues: getConditionValues(r, ""),
|
ConditionValues: getConditionValues(r, ""),
|
||||||
|
@ -178,11 +178,11 @@ func getRedirectPostRawQuery(objInfo ObjectInfo) string {
|
|||||||
|
|
||||||
// Returns access key in the request Authorization header.
|
// Returns access key in the request Authorization header.
|
||||||
func getReqAccessKey(r *http.Request, region string) (accessKey string) {
|
func getReqAccessKey(r *http.Request, region string) (accessKey string) {
|
||||||
accessKey, _, _ = getReqAccessKeyV4(r, region)
|
cred, _, _ := getReqAccessKeyV4(r, region)
|
||||||
if accessKey == "" {
|
if cred.AccessKey == "" {
|
||||||
accessKey, _, _ = getReqAccessKeyV2(r)
|
cred, _, _ = getReqAccessKeyV2(r)
|
||||||
}
|
}
|
||||||
return accessKey
|
return cred.AccessKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract request params to be sent with event notifiation.
|
// Extract request params to be sent with event notifiation.
|
||||||
|
28
cmd/jwt.go
28
cmd/jwt.go
@ -110,34 +110,6 @@ func authenticateURL(accessKey, secretKey string) (string, error) {
|
|||||||
return authenticateJWTUsers(accessKey, secretKey, defaultURLJWTExpiry)
|
return authenticateJWTUsers(accessKey, secretKey, defaultURLJWTExpiry)
|
||||||
}
|
}
|
||||||
|
|
||||||
func stsTokenCallback(jwtToken *jwtgo.Token) (interface{}, error) {
|
|
||||||
if _, ok := jwtToken.Method.(*jwtgo.SigningMethodHMAC); !ok {
|
|
||||||
return nil, fmt.Errorf("Unexpected signing method: %v", jwtToken.Header["alg"])
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := jwtToken.Claims.Valid(); err != nil {
|
|
||||||
return nil, errAuthentication
|
|
||||||
}
|
|
||||||
if claims, ok := jwtToken.Claims.(jwtgo.MapClaims); ok {
|
|
||||||
accessKey, ok := claims["accessKey"].(string)
|
|
||||||
if !ok {
|
|
||||||
return nil, errInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
if accessKey == globalServerConfig.GetCredential().AccessKey {
|
|
||||||
return []byte(globalServerConfig.GetCredential().SecretKey), nil
|
|
||||||
}
|
|
||||||
if globalIAMSys == nil {
|
|
||||||
return nil, errInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
_, ok = globalIAMSys.GetUser(accessKey)
|
|
||||||
if !ok {
|
|
||||||
return nil, errInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
return []byte(globalServerConfig.GetCredential().SecretKey), nil
|
|
||||||
}
|
|
||||||
return nil, errAuthentication
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callback function used for parsing
|
// Callback function used for parsing
|
||||||
func webTokenCallback(jwtToken *jwtgo.Token) (interface{}, error) {
|
func webTokenCallback(jwtToken *jwtgo.Token) (interface{}, error) {
|
||||||
if _, ok := jwtToken.Method.(*jwtgo.SigningMethodHMAC); !ok {
|
if _, ok := jwtToken.Method.(*jwtgo.SigningMethodHMAC); !ok {
|
||||||
|
@ -69,15 +69,9 @@ var resourceList = []string{
|
|||||||
func doesPolicySignatureV2Match(formValues http.Header) APIErrorCode {
|
func doesPolicySignatureV2Match(formValues http.Header) APIErrorCode {
|
||||||
cred := globalServerConfig.GetCredential()
|
cred := globalServerConfig.GetCredential()
|
||||||
accessKey := formValues.Get("AWSAccessKeyId")
|
accessKey := formValues.Get("AWSAccessKeyId")
|
||||||
if accessKey != cred.AccessKey {
|
cred, _, s3Err := checkKeyValid(accessKey)
|
||||||
if globalIAMSys == nil {
|
if s3Err != ErrNone {
|
||||||
return ErrInvalidAccessKeyID
|
return s3Err
|
||||||
}
|
|
||||||
var ok bool
|
|
||||||
cred, ok = globalIAMSys.GetUser(accessKey)
|
|
||||||
if !ok {
|
|
||||||
return ErrInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
policy := formValues.Get("Policy")
|
policy := formValues.Get("Policy")
|
||||||
signature := formValues.Get("Signature")
|
signature := formValues.Get("Signature")
|
||||||
@ -153,16 +147,9 @@ func doesPresignV2SignatureMatch(r *http.Request) APIErrorCode {
|
|||||||
return ErrInvalidQueryParams
|
return ErrInvalidQueryParams
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate if access key id same.
|
cred, _, s3Err := checkKeyValid(accessKey)
|
||||||
if accessKey != cred.AccessKey {
|
if s3Err != ErrNone {
|
||||||
if globalIAMSys == nil {
|
return s3Err
|
||||||
return ErrInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
var ok bool
|
|
||||||
cred, ok = globalIAMSys.GetUser(accessKey)
|
|
||||||
if !ok {
|
|
||||||
return ErrInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the request has not expired.
|
// Make sure the request has not expired.
|
||||||
@ -189,27 +176,25 @@ func doesPresignV2SignatureMatch(r *http.Request) APIErrorCode {
|
|||||||
return ErrNone
|
return ErrNone
|
||||||
}
|
}
|
||||||
|
|
||||||
func getReqAccessKeyV2(r *http.Request) (string, bool, APIErrorCode) {
|
func getReqAccessKeyV2(r *http.Request) (auth.Credentials, bool, APIErrorCode) {
|
||||||
if accessKey := r.URL.Query().Get("AWSAccessKeyId"); accessKey != "" {
|
if accessKey := r.URL.Query().Get("AWSAccessKeyId"); accessKey != "" {
|
||||||
owner, s3Err := checkKeyValid(accessKey)
|
return checkKeyValid(accessKey)
|
||||||
return accessKey, owner, s3Err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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).
|
||||||
// Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature
|
// Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature
|
||||||
authFields := strings.Split(r.Header.Get("Authorization"), " ")
|
authFields := strings.Split(r.Header.Get("Authorization"), " ")
|
||||||
if len(authFields) != 2 {
|
if len(authFields) != 2 {
|
||||||
return "", false, ErrMissingFields
|
return auth.Credentials{}, false, ErrMissingFields
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then will be splitting on ":", this will seprate `AWSAccessKeyId` and `Signature` string.
|
// Then will be splitting on ":", this will seprate `AWSAccessKeyId` and `Signature` string.
|
||||||
keySignFields := strings.Split(strings.TrimSpace(authFields[1]), ":")
|
keySignFields := strings.Split(strings.TrimSpace(authFields[1]), ":")
|
||||||
if len(keySignFields) != 2 {
|
if len(keySignFields) != 2 {
|
||||||
return "", false, ErrMissingFields
|
return auth.Credentials{}, false, ErrMissingFields
|
||||||
}
|
}
|
||||||
|
|
||||||
owner, s3Err := checkKeyValid(keySignFields[0])
|
return checkKeyValid(keySignFields[0])
|
||||||
return keySignFields[0], owner, s3Err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature;
|
// Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature;
|
||||||
@ -244,24 +229,11 @@ func validateV2AuthHeader(r *http.Request) (auth.Credentials, APIErrorCode) {
|
|||||||
return cred, ErrSignatureVersionNotSupported
|
return cred, ErrSignatureVersionNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
accessKey, owner, apiErr := getReqAccessKeyV2(r)
|
cred, _, apiErr := getReqAccessKeyV2(r)
|
||||||
if apiErr != ErrNone {
|
if apiErr != ErrNone {
|
||||||
return cred, apiErr
|
return cred, apiErr
|
||||||
}
|
}
|
||||||
|
|
||||||
cred = globalServerConfig.GetCredential()
|
|
||||||
// Access credentials.
|
|
||||||
if !owner {
|
|
||||||
if globalIAMSys == nil {
|
|
||||||
return cred, ErrInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
var ok bool
|
|
||||||
cred, ok = globalIAMSys.GetUser(accessKey)
|
|
||||||
if !ok {
|
|
||||||
return cred, ErrInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cred, ErrNone
|
return cred, ErrNone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,22 +47,21 @@ func (c credentialHeader) getScope() string {
|
|||||||
}, "/")
|
}, "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getReqAccessKeyV4(r *http.Request, region string) (string, bool, APIErrorCode) {
|
func getReqAccessKeyV4(r *http.Request, region string) (auth.Credentials, bool, APIErrorCode) {
|
||||||
ch, err := parseCredentialHeader("Credential="+r.URL.Query().Get("X-Amz-Credential"), region)
|
ch, err := parseCredentialHeader("Credential="+r.URL.Query().Get("X-Amz-Credential"), region)
|
||||||
if err != ErrNone {
|
if err != ErrNone {
|
||||||
// Strip off the Algorithm prefix.
|
// Strip off the Algorithm prefix.
|
||||||
v4Auth := strings.TrimPrefix(r.Header.Get("Authorization"), signV4Algorithm)
|
v4Auth := strings.TrimPrefix(r.Header.Get("Authorization"), signV4Algorithm)
|
||||||
authFields := strings.Split(strings.TrimSpace(v4Auth), ",")
|
authFields := strings.Split(strings.TrimSpace(v4Auth), ",")
|
||||||
if len(authFields) != 3 {
|
if len(authFields) != 3 {
|
||||||
return "", false, ErrMissingFields
|
return auth.Credentials{}, false, ErrMissingFields
|
||||||
}
|
}
|
||||||
ch, err = parseCredentialHeader(authFields[0], region)
|
ch, err = parseCredentialHeader(authFields[0], region)
|
||||||
if err != ErrNone {
|
if err != ErrNone {
|
||||||
return "", false, err
|
return auth.Credentials{}, false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
owner, s3Err := checkKeyValid(ch.accessKey)
|
return checkKeyValid(ch.accessKey)
|
||||||
return ch.accessKey, owner, s3Err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse credentialHeader string into its structured form.
|
// parse credentialHeader string into its structured form.
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/minio/minio/pkg/auth"
|
||||||
"github.com/minio/sha256-simd"
|
"github.com/minio/sha256-simd"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -102,19 +103,21 @@ 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) (bool, APIErrorCode) {
|
func checkKeyValid(accessKey string) (auth.Credentials, bool, APIErrorCode) {
|
||||||
var owner = true
|
var owner = true
|
||||||
if globalServerConfig.GetCredential().AccessKey != accessKey {
|
var cred = globalServerConfig.GetCredential()
|
||||||
|
if cred.AccessKey != accessKey {
|
||||||
if globalIAMSys == nil {
|
if globalIAMSys == nil {
|
||||||
return false, ErrInvalidAccessKeyID
|
return cred, false, ErrInvalidAccessKeyID
|
||||||
}
|
}
|
||||||
// Check if the access key is part of users credentials.
|
// Check if the access key is part of users credentials.
|
||||||
if _, ok := globalIAMSys.GetUser(accessKey); !ok {
|
var ok bool
|
||||||
return false, ErrInvalidAccessKeyID
|
if cred, ok = globalIAMSys.GetUser(accessKey); !ok {
|
||||||
|
return cred, false, ErrInvalidAccessKeyID
|
||||||
}
|
}
|
||||||
owner = false
|
owner = false
|
||||||
}
|
}
|
||||||
return owner, ErrNone
|
return cred, owner, ErrNone
|
||||||
}
|
}
|
||||||
|
|
||||||
// sumHMAC calculate hmac between two input byte array.
|
// sumHMAC calculate hmac between two input byte array.
|
||||||
|
@ -161,9 +161,6 @@ func compareSignatureV4(sig1, sig2 string) bool {
|
|||||||
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html
|
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html
|
||||||
// returns ErrNone if the signature matches.
|
// returns ErrNone if the signature matches.
|
||||||
func doesPolicySignatureV4Match(formValues http.Header) APIErrorCode {
|
func doesPolicySignatureV4Match(formValues http.Header) APIErrorCode {
|
||||||
// Access credentials.
|
|
||||||
cred := globalServerConfig.GetCredential()
|
|
||||||
|
|
||||||
// Server region.
|
// Server region.
|
||||||
region := globalServerConfig.GetRegion()
|
region := globalServerConfig.GetRegion()
|
||||||
|
|
||||||
@ -173,16 +170,9 @@ func doesPolicySignatureV4Match(formValues http.Header) APIErrorCode {
|
|||||||
return ErrMissingFields
|
return ErrMissingFields
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify if the access key id matches.
|
cred, _, s3Err := checkKeyValid(credHeader.accessKey)
|
||||||
if credHeader.accessKey != cred.AccessKey {
|
if s3Err != ErrNone {
|
||||||
if globalIAMSys == nil {
|
return s3Err
|
||||||
return ErrInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
var ok bool
|
|
||||||
cred, ok = globalIAMSys.GetUser(credHeader.accessKey)
|
|
||||||
if !ok {
|
|
||||||
return ErrInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get signing key.
|
// Get signing key.
|
||||||
@ -204,9 +194,6 @@ func doesPolicySignatureV4Match(formValues http.Header) APIErrorCode {
|
|||||||
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
|
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
|
||||||
// returns ErrNone if the signature matches.
|
// returns ErrNone if the signature matches.
|
||||||
func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region string) APIErrorCode {
|
func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region string) APIErrorCode {
|
||||||
// Access credentials.
|
|
||||||
cred := globalServerConfig.GetCredential()
|
|
||||||
|
|
||||||
// Copy request
|
// Copy request
|
||||||
req := *r
|
req := *r
|
||||||
|
|
||||||
@ -216,16 +203,9 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify if the access key id matches.
|
cred, _, s3Err := checkKeyValid(pSignValues.Credential.accessKey)
|
||||||
if pSignValues.Credential.accessKey != cred.AccessKey {
|
if s3Err != ErrNone {
|
||||||
if globalIAMSys == nil {
|
return s3Err
|
||||||
return ErrInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
var ok bool
|
|
||||||
cred, ok = globalIAMSys.GetUser(pSignValues.Credential.accessKey)
|
|
||||||
if !ok {
|
|
||||||
return ErrInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract all the signed headers along with its values.
|
// Extract all the signed headers along with its values.
|
||||||
@ -233,6 +213,7 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s
|
|||||||
if errCode != ErrNone {
|
if errCode != ErrNone {
|
||||||
return errCode
|
return errCode
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct new query.
|
// Construct new query.
|
||||||
query := make(url.Values)
|
query := make(url.Values)
|
||||||
if req.URL.Query().Get("X-Amz-Content-Sha256") != "" {
|
if req.URL.Query().Get("X-Amz-Content-Sha256") != "" {
|
||||||
@ -326,9 +307,6 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s
|
|||||||
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
|
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
|
||||||
// returns ErrNone if signature matches.
|
// returns ErrNone if signature matches.
|
||||||
func doesSignatureMatch(hashedPayload string, r *http.Request, region string) APIErrorCode {
|
func doesSignatureMatch(hashedPayload string, r *http.Request, region string) APIErrorCode {
|
||||||
// Access credentials.
|
|
||||||
cred := globalServerConfig.GetCredential()
|
|
||||||
|
|
||||||
// Copy request.
|
// Copy request.
|
||||||
req := *r
|
req := *r
|
||||||
|
|
||||||
@ -347,16 +325,9 @@ func doesSignatureMatch(hashedPayload string, r *http.Request, region string) AP
|
|||||||
return errCode
|
return errCode
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify if the access key id matches.
|
cred, _, s3Err := checkKeyValid(signV4Values.Credential.accessKey)
|
||||||
if signV4Values.Credential.accessKey != cred.AccessKey {
|
if s3Err != ErrNone {
|
||||||
if globalIAMSys == nil {
|
return s3Err
|
||||||
return ErrInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
var ok bool
|
|
||||||
cred, ok = globalIAMSys.GetUser(signV4Values.Credential.accessKey)
|
|
||||||
if !ok {
|
|
||||||
return ErrInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract date, if not present throw error.
|
// Extract date, if not present throw error.
|
||||||
@ -366,6 +337,7 @@ func doesSignatureMatch(hashedPayload string, r *http.Request, region string) AP
|
|||||||
return ErrMissingDateHeader
|
return ErrMissingDateHeader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse date header.
|
// Parse date header.
|
||||||
t, e := time.Parse(iso8601Format, date)
|
t, e := time.Parse(iso8601Format, date)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
|
@ -91,17 +91,9 @@ func calculateSeedSignature(r *http.Request) (cred auth.Credentials, signature s
|
|||||||
return cred, "", "", time.Time{}, errCode
|
return cred, "", "", time.Time{}, errCode
|
||||||
}
|
}
|
||||||
|
|
||||||
cred = globalServerConfig.GetCredential()
|
cred, _, errCode = checkKeyValid(signV4Values.Credential.accessKey)
|
||||||
// Verify if the access key id matches.
|
if errCode != ErrNone {
|
||||||
if signV4Values.Credential.accessKey != cred.AccessKey {
|
return cred, "", "", time.Time{}, errCode
|
||||||
if globalIAMSys == nil {
|
|
||||||
return cred, "", "", time.Time{}, ErrInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
var ok bool
|
|
||||||
cred, ok = globalIAMSys.GetUser(signV4Values.Credential.accessKey)
|
|
||||||
if !ok {
|
|
||||||
return cred, "", "", time.Time{}, ErrInvalidAccessKeyID
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify if region is valid.
|
// Verify if region is valid.
|
||||||
@ -114,6 +106,7 @@ func calculateSeedSignature(r *http.Request) (cred auth.Credentials, signature s
|
|||||||
return cred, "", "", time.Time{}, ErrMissingDateHeader
|
return cred, "", "", time.Time{}, ErrMissingDateHeader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse date header.
|
// Parse date header.
|
||||||
var err error
|
var err error
|
||||||
date, err = time.Parse(iso8601Format, dateStr)
|
date, err = time.Parse(iso8601Format, dateStr)
|
||||||
|
Loading…
Reference in New Issue
Block a user