| 
									
										
										
										
											2016-02-22 09:57:05 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  |  * MinIO Cloud Storage, (C) 2015 MinIO, Inc. | 
					
						
							| 
									
										
										
										
											2016-02-22 09:57:05 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 07:23:42 +08:00
										 |  |  | package cmd | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	"net/url" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2017-11-01 02:54:32 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/minio/minio/pkg/auth" | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-13 08:08:15 +08:00
										 |  |  | // credentialHeader data type represents structured form of Credential
 | 
					
						
							| 
									
										
										
										
											2016-02-22 09:57:05 +08:00
										 |  |  | // string from authorization header.
 | 
					
						
							| 
									
										
										
										
											2016-03-13 08:08:15 +08:00
										 |  |  | type credentialHeader struct { | 
					
						
							|  |  |  | 	accessKey string | 
					
						
							|  |  |  | 	scope     struct { | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 		date    time.Time | 
					
						
							|  |  |  | 		region  string | 
					
						
							|  |  |  | 		service string | 
					
						
							|  |  |  | 		request string | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 05:09:09 +08:00
										 |  |  | // Return scope string.
 | 
					
						
							|  |  |  | func (c credentialHeader) getScope() string { | 
					
						
							|  |  |  | 	return strings.Join([]string{ | 
					
						
							|  |  |  | 		c.scope.date.Format(yyyymmdd), | 
					
						
							|  |  |  | 		c.scope.region, | 
					
						
							|  |  |  | 		c.scope.service, | 
					
						
							|  |  |  | 		c.scope.request, | 
					
						
							| 
									
										
										
										
											2019-08-07 03:08:58 +08:00
										 |  |  | 	}, SlashSeparator) | 
					
						
							| 
									
										
										
										
											2017-02-07 05:09:09 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-28 09:46:55 +08:00
										 |  |  | func getReqAccessKeyV4(r *http.Request, region string, stype serviceType) (auth.Credentials, bool, APIErrorCode) { | 
					
						
							|  |  |  | 	ch, err := parseCredentialHeader("Credential="+r.URL.Query().Get("X-Amz-Credential"), region, stype) | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 	if err != ErrNone { | 
					
						
							|  |  |  | 		// Strip off the Algorithm prefix.
 | 
					
						
							|  |  |  | 		v4Auth := strings.TrimPrefix(r.Header.Get("Authorization"), signV4Algorithm) | 
					
						
							|  |  |  | 		authFields := strings.Split(strings.TrimSpace(v4Auth), ",") | 
					
						
							|  |  |  | 		if len(authFields) != 3 { | 
					
						
							| 
									
										
										
										
											2018-11-07 22:40:03 +08:00
										 |  |  | 			return auth.Credentials{}, false, ErrMissingFields | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-02-28 09:46:55 +08:00
										 |  |  | 		ch, err = parseCredentialHeader(authFields[0], region, stype) | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 		if err != ErrNone { | 
					
						
							| 
									
										
										
										
											2018-11-07 22:40:03 +08:00
										 |  |  | 			return auth.Credentials{}, false, err | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-11-07 22:40:03 +08:00
										 |  |  | 	return checkKeyValid(ch.accessKey) | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-13 08:08:15 +08:00
										 |  |  | // parse credentialHeader string into its structured form.
 | 
					
						
							| 
									
										
										
										
											2019-02-28 09:46:55 +08:00
										 |  |  | func parseCredentialHeader(credElement string, region string, stype serviceType) (ch credentialHeader, aec APIErrorCode) { | 
					
						
							| 
									
										
										
										
											2019-03-17 13:45:42 +08:00
										 |  |  | 	creds := strings.SplitN(strings.TrimSpace(credElement), "=", 2) | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	if len(creds) != 2 { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return ch, ErrMissingFields | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if creds[0] != "Credential" { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return ch, ErrMissingCredTag | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-07 03:08:58 +08:00
										 |  |  | 	credElements := strings.Split(strings.TrimSpace(creds[1]), SlashSeparator) | 
					
						
							| 
									
										
										
										
											2018-09-12 02:17:23 +08:00
										 |  |  | 	if len(credElements) < 5 { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return ch, ErrCredMalformed | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-07 03:08:58 +08:00
										 |  |  | 	accessKey := strings.Join(credElements[:len(credElements)-4], SlashSeparator) // The access key may contain one or more `/`
 | 
					
						
							| 
									
										
										
										
											2018-09-12 02:17:23 +08:00
										 |  |  | 	if !auth.IsAccessKeyValid(accessKey) { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return ch, ErrInvalidAccessKeyID | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-13 08:08:15 +08:00
										 |  |  | 	// Save access key id.
 | 
					
						
							|  |  |  | 	cred := credentialHeader{ | 
					
						
							| 
									
										
										
										
											2018-09-12 02:17:23 +08:00
										 |  |  | 		accessKey: accessKey, | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-09-12 02:17:23 +08:00
										 |  |  | 	credElements = credElements[len(credElements)-4:] | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	var e error | 
					
						
							| 
									
										
										
										
											2018-09-12 02:17:23 +08:00
										 |  |  | 	cred.scope.date, e = time.Parse(yyyymmdd, credElements[0]) | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	if e != nil { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return ch, ErrMalformedCredentialDate | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-10 10:18:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-12 02:17:23 +08:00
										 |  |  | 	cred.scope.region = credElements[1] | 
					
						
							| 
									
										
										
										
											2018-03-10 10:18:57 +08:00
										 |  |  | 	// Verify if region is valid.
 | 
					
						
							|  |  |  | 	sRegion := cred.scope.region | 
					
						
							|  |  |  | 	// Region is set to be empty, we use whatever was sent by the
 | 
					
						
							|  |  |  | 	// request and proceed further. This is a work-around to address
 | 
					
						
							|  |  |  | 	// an important problem for ListBuckets() getting signed with
 | 
					
						
							|  |  |  | 	// different regions.
 | 
					
						
							|  |  |  | 	if region == "" { | 
					
						
							|  |  |  | 		region = sRegion | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Should validate region, only if region is set.
 | 
					
						
							|  |  |  | 	if !isValidRegion(sRegion, region) { | 
					
						
							|  |  |  | 		return ch, ErrAuthorizationHeaderMalformed | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-28 09:46:55 +08:00
										 |  |  | 	if credElements[2] != string(stype) { | 
					
						
							| 
									
										
										
										
											2020-03-19 08:25:45 +08:00
										 |  |  | 		switch stype { | 
					
						
							|  |  |  | 		case serviceSTS: | 
					
						
							|  |  |  | 			return ch, ErrInvalidServiceSTS | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return ch, ErrInvalidServiceS3 | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-09-12 02:17:23 +08:00
										 |  |  | 	cred.scope.service = credElements[2] | 
					
						
							|  |  |  | 	if credElements[3] != "aws4_request" { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return ch, ErrInvalidRequestVersion | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-09-12 02:17:23 +08:00
										 |  |  | 	cred.scope.request = credElements[3] | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	return cred, ErrNone | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 03:47:16 +08:00
										 |  |  | // Parse signature from signature tag.
 | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | func parseSignature(signElement string) (string, APIErrorCode) { | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	signFields := strings.Split(strings.TrimSpace(signElement), "=") | 
					
						
							|  |  |  | 	if len(signFields) != 2 { | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 		return "", ErrMissingFields | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if signFields[0] != "Signature" { | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 		return "", ErrMissingSignTag | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-07 03:47:16 +08:00
										 |  |  | 	if signFields[1] == "" { | 
					
						
							|  |  |  | 		return "", ErrMissingFields | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	signature := signFields[1] | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	return signature, ErrNone | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 03:47:16 +08:00
										 |  |  | // Parse slice of signed headers from signed headers tag.
 | 
					
						
							|  |  |  | func parseSignedHeader(signedHdrElement string) ([]string, APIErrorCode) { | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	signedHdrFields := strings.Split(strings.TrimSpace(signedHdrElement), "=") | 
					
						
							|  |  |  | 	if len(signedHdrFields) != 2 { | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 		return nil, ErrMissingFields | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if signedHdrFields[0] != "SignedHeaders" { | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 		return nil, ErrMissingSignHeadersTag | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-07 03:47:16 +08:00
										 |  |  | 	if signedHdrFields[1] == "" { | 
					
						
							|  |  |  | 		return nil, ErrMissingFields | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	signedHeaders := strings.Split(signedHdrFields[1], ";") | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	return signedHeaders, ErrNone | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-22 09:57:05 +08:00
										 |  |  | // signValues data type represents structured form of AWS Signature V4 header.
 | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | type signValues struct { | 
					
						
							| 
									
										
										
										
											2016-03-13 08:08:15 +08:00
										 |  |  | 	Credential    credentialHeader | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	SignedHeaders []string | 
					
						
							|  |  |  | 	Signature     string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-22 09:57:05 +08:00
										 |  |  | // preSignValues data type represents structued form of AWS Signature V4 query string.
 | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | type preSignValues struct { | 
					
						
							|  |  |  | 	signValues | 
					
						
							|  |  |  | 	Date    time.Time | 
					
						
							|  |  |  | 	Expires time.Duration | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Parses signature version '4' query string of the following form.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //   querystring = X-Amz-Algorithm=algorithm
 | 
					
						
							| 
									
										
										
										
											2016-03-13 08:08:15 +08:00
										 |  |  | //   querystring += &X-Amz-Credential= urlencode(accessKey + '/' + credential_scope)
 | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | //   querystring += &X-Amz-Date=date
 | 
					
						
							|  |  |  | //   querystring += &X-Amz-Expires=timeout interval
 | 
					
						
							|  |  |  | //   querystring += &X-Amz-SignedHeaders=signed_headers
 | 
					
						
							|  |  |  | //   querystring += &X-Amz-Signature=signature
 | 
					
						
							| 
									
										
										
										
											2016-11-07 03:47:16 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-08-10 00:13:15 +08:00
										 |  |  | // verifies if any of the necessary query params are missing in the presigned request.
 | 
					
						
							|  |  |  | func doesV4PresignParamsExist(query url.Values) APIErrorCode { | 
					
						
							|  |  |  | 	v4PresignQueryParams := []string{"X-Amz-Algorithm", "X-Amz-Credential", "X-Amz-Signature", "X-Amz-Date", "X-Amz-SignedHeaders", "X-Amz-Expires"} | 
					
						
							|  |  |  | 	for _, v4PresignQueryParam := range v4PresignQueryParams { | 
					
						
							|  |  |  | 		if _, ok := query[v4PresignQueryParam]; !ok { | 
					
						
							|  |  |  | 			return ErrInvalidQueryParams | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ErrNone | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 03:47:16 +08:00
										 |  |  | // Parses all the presigned signature values into separate elements.
 | 
					
						
							| 
									
										
										
										
											2019-02-28 09:46:55 +08:00
										 |  |  | func parsePreSignV4(query url.Values, region string, stype serviceType) (psv preSignValues, aec APIErrorCode) { | 
					
						
							| 
									
										
										
										
											2016-08-10 00:13:15 +08:00
										 |  |  | 	// verify whether the required query params exist.
 | 
					
						
							| 
									
										
										
										
											2019-02-13 20:59:36 +08:00
										 |  |  | 	err := doesV4PresignParamsExist(query) | 
					
						
							| 
									
										
										
										
											2016-08-10 00:13:15 +08:00
										 |  |  | 	if err != ErrNone { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return psv, err | 
					
						
							| 
									
										
										
										
											2016-08-10 00:13:15 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	// Verify if the query algorithm is supported or not.
 | 
					
						
							|  |  |  | 	if query.Get("X-Amz-Algorithm") != signV4Algorithm { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return psv, ErrInvalidQuerySignatureAlgo | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize signature version '4' structured header.
 | 
					
						
							|  |  |  | 	preSignV4Values := preSignValues{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-22 09:57:05 +08:00
										 |  |  | 	// Save credential.
 | 
					
						
							| 
									
										
										
										
											2019-02-28 09:46:55 +08:00
										 |  |  | 	preSignV4Values.Credential, err = parseCredentialHeader("Credential="+query.Get("X-Amz-Credential"), region, stype) | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	if err != ErrNone { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return psv, err | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var e error | 
					
						
							|  |  |  | 	// Save date in native time.Time.
 | 
					
						
							|  |  |  | 	preSignV4Values.Date, e = time.Parse(iso8601Format, query.Get("X-Amz-Date")) | 
					
						
							|  |  |  | 	if e != nil { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return psv, ErrMalformedPresignedDate | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Save expires in native time.Duration.
 | 
					
						
							|  |  |  | 	preSignV4Values.Expires, e = time.ParseDuration(query.Get("X-Amz-Expires") + "s") | 
					
						
							|  |  |  | 	if e != nil { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return psv, ErrMalformedExpires | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-10 00:13:15 +08:00
										 |  |  | 	if preSignV4Values.Expires < 0 { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return psv, ErrNegativeExpires | 
					
						
							| 
									
										
										
										
											2016-08-10 00:13:15 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-11-14 04:54:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check if Expiry time is less than 7 days (value in seconds).
 | 
					
						
							|  |  |  | 	if preSignV4Values.Expires.Seconds() > 604800 { | 
					
						
							|  |  |  | 		return psv, ErrMaximumExpires | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-10 10:18:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	// Save signed headers.
 | 
					
						
							| 
									
										
										
										
											2016-11-07 03:47:16 +08:00
										 |  |  | 	preSignV4Values.SignedHeaders, err = parseSignedHeader("SignedHeaders=" + query.Get("X-Amz-SignedHeaders")) | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	if err != ErrNone { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return psv, err | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Save signature.
 | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | 	preSignV4Values.Signature, err = parseSignature("Signature=" + query.Get("X-Amz-Signature")) | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	if err != ErrNone { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return psv, err | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Return structed form of signature query string.
 | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	return preSignV4Values, ErrNone | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Parses signature version '4' header of the following form.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-03-13 08:08:15 +08:00
										 |  |  | //    Authorization: algorithm Credential=accessKeyID/credScope, \
 | 
					
						
							|  |  |  | //            SignedHeaders=signedHeaders, Signature=signature
 | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2019-02-28 09:46:55 +08:00
										 |  |  | func parseSignV4(v4Auth string, region string, stype serviceType) (sv signValues, aec APIErrorCode) { | 
					
						
							| 
									
										
										
										
											2019-10-01 04:55:37 +08:00
										 |  |  | 	// credElement is fetched first to skip replacing the space in access key.
 | 
					
						
							|  |  |  | 	credElement := strings.TrimPrefix(strings.Split(strings.TrimSpace(v4Auth), ",")[0], signV4Algorithm) | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	// Replace all spaced strings, some clients can send spaced
 | 
					
						
							|  |  |  | 	// parameters and some won't. So we pro-actively remove any spaces
 | 
					
						
							|  |  |  | 	// to make parsing easier.
 | 
					
						
							|  |  |  | 	v4Auth = strings.Replace(v4Auth, " ", "", -1) | 
					
						
							|  |  |  | 	if v4Auth == "" { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return sv, ErrAuthHeaderEmpty | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Verify if the header algorithm is supported or not.
 | 
					
						
							|  |  |  | 	if !strings.HasPrefix(v4Auth, signV4Algorithm) { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return sv, ErrSignatureVersionNotSupported | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Strip off the Algorithm prefix.
 | 
					
						
							|  |  |  | 	v4Auth = strings.TrimPrefix(v4Auth, signV4Algorithm) | 
					
						
							|  |  |  | 	authFields := strings.Split(strings.TrimSpace(v4Auth), ",") | 
					
						
							|  |  |  | 	if len(authFields) != 3 { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return sv, ErrMissingFields | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize signature version '4' structured header.
 | 
					
						
							|  |  |  | 	signV4Values := signValues{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	var err APIErrorCode | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	// Save credentail values.
 | 
					
						
							| 
									
										
										
										
											2019-10-01 04:55:37 +08:00
										 |  |  | 	signV4Values.Credential, err = parseCredentialHeader(strings.TrimSpace(credElement), region, stype) | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	if err != ErrNone { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return sv, err | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Save signed headers.
 | 
					
						
							| 
									
										
										
										
											2016-11-07 03:47:16 +08:00
										 |  |  | 	signV4Values.SignedHeaders, err = parseSignedHeader(authFields[1]) | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	if err != ErrNone { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return sv, err | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Save signature.
 | 
					
						
							|  |  |  | 	signV4Values.Signature, err = parseSignature(authFields[2]) | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	if err != ErrNone { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return sv, err | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Return the structure here.
 | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	return signV4Values, ErrNone | 
					
						
							| 
									
										
										
										
											2016-02-16 09:42:39 +08:00
										 |  |  | } |