aboutsummaryrefslogtreecommitdiff
path: root/weed/s3api/auth_signature_v4.go
diff options
context:
space:
mode:
Diffstat (limited to 'weed/s3api/auth_signature_v4.go')
-rw-r--r--weed/s3api/auth_signature_v4.go135
1 files changed, 68 insertions, 67 deletions
diff --git a/weed/s3api/auth_signature_v4.go b/weed/s3api/auth_signature_v4.go
index cdfd8be1d..121c793d8 100644
--- a/weed/s3api/auth_signature_v4.go
+++ b/weed/s3api/auth_signature_v4.go
@@ -23,6 +23,7 @@ import (
"crypto/sha256"
"crypto/subtle"
"encoding/hex"
+ "github.com/chrislusf/seaweedfs/weed/s3api/s3err"
"net/http"
"net/url"
"regexp"
@@ -33,7 +34,7 @@ import (
"unicode/utf8"
)
-func (iam *IdentityAccessManagement) reqSignatureV4Verify(r *http.Request) (*Identity, ErrorCode) {
+func (iam *IdentityAccessManagement) reqSignatureV4Verify(r *http.Request) (*Identity, s3err.ErrorCode) {
sha256sum := getContentSha256Cksum(r)
switch {
case isRequestSignatureV4(r):
@@ -41,7 +42,7 @@ func (iam *IdentityAccessManagement) reqSignatureV4Verify(r *http.Request) (*Ide
case isRequestPresignedSignatureV4(r):
return iam.doesPresignedSignatureMatch(sha256sum, r)
}
- return nil, ErrAccessDenied
+ return nil, s3err.ErrAccessDenied
}
// Streaming AWS Signature Version '4' constants.
@@ -89,7 +90,7 @@ func getContentSha256Cksum(r *http.Request) string {
}
// Verify authorization header - http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
-func (iam *IdentityAccessManagement) doesSignatureMatch(hashedPayload string, r *http.Request) (*Identity, ErrorCode) {
+func (iam *IdentityAccessManagement) doesSignatureMatch(hashedPayload string, r *http.Request) (*Identity, s3err.ErrorCode) {
// Copy request.
req := *r
@@ -99,33 +100,33 @@ func (iam *IdentityAccessManagement) doesSignatureMatch(hashedPayload string, r
// Parse signature version '4' header.
signV4Values, err := parseSignV4(v4Auth)
- if err != ErrNone {
+ if err != s3err.ErrNone {
return nil, err
}
// Extract all the signed headers along with its values.
extractedSignedHeaders, errCode := extractSignedHeaders(signV4Values.SignedHeaders, r)
- if errCode != ErrNone {
+ if errCode != s3err.ErrNone {
return nil, errCode
}
// Verify if the access key id matches.
identity, cred, found := iam.lookupByAccessKey(signV4Values.Credential.accessKey)
if !found {
- return nil, ErrInvalidAccessKeyID
+ return nil, s3err.ErrInvalidAccessKeyID
}
// Extract date, if not present throw error.
var date string
if date = req.Header.Get(http.CanonicalHeaderKey("X-Amz-Date")); date == "" {
if date = r.Header.Get("Date"); date == "" {
- return nil, ErrMissingDateHeader
+ return nil, s3err.ErrMissingDateHeader
}
}
// Parse date header.
t, e := time.Parse(iso8601Format, date)
if e != nil {
- return nil, ErrMalformedDate
+ return nil, s3err.ErrMalformedDate
}
// Query string.
@@ -145,11 +146,11 @@ func (iam *IdentityAccessManagement) doesSignatureMatch(hashedPayload string, r
// Verify if signature match.
if !compareSignatureV4(newSignature, signV4Values.Signature) {
- return nil, ErrSignatureDoesNotMatch
+ return nil, s3err.ErrSignatureDoesNotMatch
}
// Return error none.
- return identity, ErrNone
+ return identity, s3err.ErrNone
}
// credentialHeader data type represents structured form of Credential
@@ -184,65 +185,65 @@ func (c credentialHeader) getScope() string {
// Authorization: algorithm Credential=accessKeyID/credScope, \
// SignedHeaders=signedHeaders, Signature=signature
//
-func parseSignV4(v4Auth string) (sv signValues, aec ErrorCode) {
+func parseSignV4(v4Auth string) (sv signValues, aec s3err.ErrorCode) {
// 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 == "" {
- return sv, ErrAuthHeaderEmpty
+ return sv, s3err.ErrAuthHeaderEmpty
}
// Verify if the header algorithm is supported or not.
if !strings.HasPrefix(v4Auth, signV4Algorithm) {
- return sv, ErrSignatureVersionNotSupported
+ return sv, s3err.ErrSignatureVersionNotSupported
}
// Strip off the Algorithm prefix.
v4Auth = strings.TrimPrefix(v4Auth, signV4Algorithm)
authFields := strings.Split(strings.TrimSpace(v4Auth), ",")
if len(authFields) != 3 {
- return sv, ErrMissingFields
+ return sv, s3err.ErrMissingFields
}
// Initialize signature version '4' structured header.
signV4Values := signValues{}
- var err ErrorCode
+ var err s3err.ErrorCode
// Save credentail values.
signV4Values.Credential, err = parseCredentialHeader(authFields[0])
- if err != ErrNone {
+ if err != s3err.ErrNone {
return sv, err
}
// Save signed headers.
signV4Values.SignedHeaders, err = parseSignedHeader(authFields[1])
- if err != ErrNone {
+ if err != s3err.ErrNone {
return sv, err
}
// Save signature.
signV4Values.Signature, err = parseSignature(authFields[2])
- if err != ErrNone {
+ if err != s3err.ErrNone {
return sv, err
}
// Return the structure here.
- return signV4Values, ErrNone
+ return signV4Values, s3err.ErrNone
}
// parse credentialHeader string into its structured form.
-func parseCredentialHeader(credElement string) (ch credentialHeader, aec ErrorCode) {
+func parseCredentialHeader(credElement string) (ch credentialHeader, aec s3err.ErrorCode) {
creds := strings.Split(strings.TrimSpace(credElement), "=")
if len(creds) != 2 {
- return ch, ErrMissingFields
+ return ch, s3err.ErrMissingFields
}
if creds[0] != "Credential" {
- return ch, ErrMissingCredTag
+ return ch, s3err.ErrMissingCredTag
}
credElements := strings.Split(strings.TrimSpace(creds[1]), "/")
if len(credElements) != 5 {
- return ch, ErrCredMalformed
+ return ch, s3err.ErrCredMalformed
}
// Save access key id.
cred := credentialHeader{
@@ -251,69 +252,69 @@ func parseCredentialHeader(credElement string) (ch credentialHeader, aec ErrorCo
var e error
cred.scope.date, e = time.Parse(yyyymmdd, credElements[1])
if e != nil {
- return ch, ErrMalformedCredentialDate
+ return ch, s3err.ErrMalformedCredentialDate
}
cred.scope.region = credElements[2]
cred.scope.service = credElements[3] // "s3"
cred.scope.request = credElements[4] // "aws4_request"
- return cred, ErrNone
+ return cred, s3err.ErrNone
}
// Parse slice of signed headers from signed headers tag.
-func parseSignedHeader(signedHdrElement string) ([]string, ErrorCode) {
+func parseSignedHeader(signedHdrElement string) ([]string, s3err.ErrorCode) {
signedHdrFields := strings.Split(strings.TrimSpace(signedHdrElement), "=")
if len(signedHdrFields) != 2 {
- return nil, ErrMissingFields
+ return nil, s3err.ErrMissingFields
}
if signedHdrFields[0] != "SignedHeaders" {
- return nil, ErrMissingSignHeadersTag
+ return nil, s3err.ErrMissingSignHeadersTag
}
if signedHdrFields[1] == "" {
- return nil, ErrMissingFields
+ return nil, s3err.ErrMissingFields
}
signedHeaders := strings.Split(signedHdrFields[1], ";")
- return signedHeaders, ErrNone
+ return signedHeaders, s3err.ErrNone
}
// Parse signature from signature tag.
-func parseSignature(signElement string) (string, ErrorCode) {
+func parseSignature(signElement string) (string, s3err.ErrorCode) {
signFields := strings.Split(strings.TrimSpace(signElement), "=")
if len(signFields) != 2 {
- return "", ErrMissingFields
+ return "", s3err.ErrMissingFields
}
if signFields[0] != "Signature" {
- return "", ErrMissingSignTag
+ return "", s3err.ErrMissingSignTag
}
if signFields[1] == "" {
- return "", ErrMissingFields
+ return "", s3err.ErrMissingFields
}
signature := signFields[1]
- return signature, ErrNone
+ return signature, s3err.ErrNone
}
// check query headers with presigned signature
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
-func (iam *IdentityAccessManagement) doesPresignedSignatureMatch(hashedPayload string, r *http.Request) (*Identity, ErrorCode) {
+func (iam *IdentityAccessManagement) doesPresignedSignatureMatch(hashedPayload string, r *http.Request) (*Identity, s3err.ErrorCode) {
// Copy request
req := *r
// Parse request query string.
pSignValues, err := parsePreSignV4(req.URL.Query())
- if err != ErrNone {
+ if err != s3err.ErrNone {
return nil, err
}
// Verify if the access key id matches.
identity, cred, found := iam.lookupByAccessKey(pSignValues.Credential.accessKey)
if !found {
- return nil, ErrInvalidAccessKeyID
+ return nil, s3err.ErrInvalidAccessKeyID
}
// Extract all the signed headers along with its values.
extractedSignedHeaders, errCode := extractSignedHeaders(pSignValues.SignedHeaders, r)
- if errCode != ErrNone {
+ if errCode != s3err.ErrNone {
return nil, errCode
}
// Construct new query.
@@ -329,11 +330,11 @@ func (iam *IdentityAccessManagement) doesPresignedSignatureMatch(hashedPayload s
// If the host which signed the request is slightly ahead in time (by less than globalMaxSkewTime) the
// request should still be allowed.
if pSignValues.Date.After(now.Add(15 * time.Minute)) {
- return nil, ErrRequestNotReadyYet
+ return nil, s3err.ErrRequestNotReadyYet
}
if now.Sub(pSignValues.Date) > pSignValues.Expires {
- return nil, ErrExpiredPresignRequest
+ return nil, s3err.ErrExpiredPresignRequest
}
// Save the date and expires.
@@ -365,24 +366,24 @@ func (iam *IdentityAccessManagement) doesPresignedSignatureMatch(hashedPayload s
// Verify if date query is same.
if req.URL.Query().Get("X-Amz-Date") != query.Get("X-Amz-Date") {
- return nil, ErrSignatureDoesNotMatch
+ return nil, s3err.ErrSignatureDoesNotMatch
}
// Verify if expires query is same.
if req.URL.Query().Get("X-Amz-Expires") != query.Get("X-Amz-Expires") {
- return nil, ErrSignatureDoesNotMatch
+ return nil, s3err.ErrSignatureDoesNotMatch
}
// Verify if signed headers query is same.
if req.URL.Query().Get("X-Amz-SignedHeaders") != query.Get("X-Amz-SignedHeaders") {
- return nil, ErrSignatureDoesNotMatch
+ return nil, s3err.ErrSignatureDoesNotMatch
}
// Verify if credential query is same.
if req.URL.Query().Get("X-Amz-Credential") != query.Get("X-Amz-Credential") {
- return nil, ErrSignatureDoesNotMatch
+ return nil, s3err.ErrSignatureDoesNotMatch
}
// Verify if sha256 payload query is same.
if req.URL.Query().Get("X-Amz-Content-Sha256") != "" {
if req.URL.Query().Get("X-Amz-Content-Sha256") != query.Get("X-Amz-Content-Sha256") {
- return nil, ErrContentSHA256Mismatch
+ return nil, s3err.ErrContentSHA256Mismatch
}
}
@@ -402,9 +403,9 @@ func (iam *IdentityAccessManagement) doesPresignedSignatureMatch(hashedPayload s
// Verify signature.
if !compareSignatureV4(req.URL.Query().Get("X-Amz-Signature"), newSignature) {
- return nil, ErrSignatureDoesNotMatch
+ return nil, s3err.ErrSignatureDoesNotMatch
}
- return identity, ErrNone
+ return identity, s3err.ErrNone
}
func contains(list []string, elem string) bool {
@@ -433,28 +434,28 @@ type preSignValues struct {
// querystring += &X-Amz-Signature=signature
//
// verifies if any of the necessary query params are missing in the presigned request.
-func doesV4PresignParamsExist(query url.Values) ErrorCode {
+func doesV4PresignParamsExist(query url.Values) s3err.ErrorCode {
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 s3err.ErrInvalidQueryParams
}
}
- return ErrNone
+ return s3err.ErrNone
}
// Parses all the presigned signature values into separate elements.
-func parsePreSignV4(query url.Values) (psv preSignValues, aec ErrorCode) {
- var err ErrorCode
+func parsePreSignV4(query url.Values) (psv preSignValues, aec s3err.ErrorCode) {
+ var err s3err.ErrorCode
// verify whether the required query params exist.
err = doesV4PresignParamsExist(query)
- if err != ErrNone {
+ if err != s3err.ErrNone {
return psv, err
}
// Verify if the query algorithm is supported or not.
if query.Get("X-Amz-Algorithm") != signV4Algorithm {
- return psv, ErrInvalidQuerySignatureAlgo
+ return psv, s3err.ErrInvalidQuerySignatureAlgo
}
// Initialize signature version '4' structured header.
@@ -462,7 +463,7 @@ func parsePreSignV4(query url.Values) (psv preSignValues, aec ErrorCode) {
// Save credential.
preSignV4Values.Credential, err = parseCredentialHeader("Credential=" + query.Get("X-Amz-Credential"))
- if err != ErrNone {
+ if err != s3err.ErrNone {
return psv, err
}
@@ -470,47 +471,47 @@ func parsePreSignV4(query url.Values) (psv preSignValues, aec ErrorCode) {
// Save date in native time.Time.
preSignV4Values.Date, e = time.Parse(iso8601Format, query.Get("X-Amz-Date"))
if e != nil {
- return psv, ErrMalformedPresignedDate
+ return psv, s3err.ErrMalformedPresignedDate
}
// Save expires in native time.Duration.
preSignV4Values.Expires, e = time.ParseDuration(query.Get("X-Amz-Expires") + "s")
if e != nil {
- return psv, ErrMalformedExpires
+ return psv, s3err.ErrMalformedExpires
}
if preSignV4Values.Expires < 0 {
- return psv, ErrNegativeExpires
+ return psv, s3err.ErrNegativeExpires
}
// Check if Expiry time is less than 7 days (value in seconds).
if preSignV4Values.Expires.Seconds() > 604800 {
- return psv, ErrMaximumExpires
+ return psv, s3err.ErrMaximumExpires
}
// Save signed headers.
preSignV4Values.SignedHeaders, err = parseSignedHeader("SignedHeaders=" + query.Get("X-Amz-SignedHeaders"))
- if err != ErrNone {
+ if err != s3err.ErrNone {
return psv, err
}
// Save signature.
preSignV4Values.Signature, err = parseSignature("Signature=" + query.Get("X-Amz-Signature"))
- if err != ErrNone {
+ if err != s3err.ErrNone {
return psv, err
}
// Return structed form of signature query string.
- return preSignV4Values, ErrNone
+ return preSignV4Values, s3err.ErrNone
}
// extractSignedHeaders extract signed headers from Authorization header
-func extractSignedHeaders(signedHeaders []string, r *http.Request) (http.Header, ErrorCode) {
+func extractSignedHeaders(signedHeaders []string, r *http.Request) (http.Header, s3err.ErrorCode) {
reqHeaders := r.Header
// find whether "host" is part of list of signed headers.
// if not return ErrUnsignedHeaders. "host" is mandatory.
if !contains(signedHeaders, "host") {
- return nil, ErrUnsignedHeaders
+ return nil, s3err.ErrUnsignedHeaders
}
extractedSignedHeaders := make(http.Header)
for _, header := range signedHeaders {
@@ -555,10 +556,10 @@ func extractSignedHeaders(signedHeaders []string, r *http.Request) (http.Header,
// calculation to be compatible with such clients.
extractedSignedHeaders.Set(header, strconv.FormatInt(r.ContentLength, 10))
default:
- return nil, ErrUnsignedHeaders
+ return nil, s3err.ErrUnsignedHeaders
}
}
- return extractedSignedHeaders, ErrNone
+ return extractedSignedHeaders, s3err.ErrNone
}
// getSignedHeaders generate a string i.e alphabetically sorted, semicolon-separated list of lowercase request header names