@ -20,8 +20,6 @@ import (
"net/url"
"strings"
"time"
"github.com/minio/minio/pkg/probe"
)
// credentialHeader data type represents structured form of Credential
@ -37,20 +35,20 @@ type credentialHeader struct {
}
// parse credentialHeader string into its structured form.
func parseCredentialHeader ( credElement string ) ( credentialHeader , * probe . Error ) {
func parseCredentialHeader ( credElement string ) ( credentialHeader , APIErrorCode ) {
creds := strings . Split ( strings . TrimSpace ( credElement ) , "=" )
if len ( creds ) != 2 {
return credentialHeader { } , ErrMissingFields ( "Credential tag has missing fields." , credElement ) . Trace ( credElement )
return credentialHeader { } , ErrMissingFields
}
if creds [ 0 ] != "Credential" {
return credentialHeader { } , ErrMissingCredTag ( "Missing credentials tag." , credElement ) . Trace ( credElement )
return credentialHeader { } , ErrMissingCredTag
}
credElements := strings . Split ( strings . TrimSpace ( creds [ 1 ] ) , "/" )
if len ( credElements ) != 5 {
return credentialHeader { } , ErrCredMalformed ( "Credential values malformed." , credElement ) . Trace ( credElement )
return credentialHeader { } , ErrCredMalformed
}
if ! isValidAccessKey . MatchString ( credElements [ 0 ] ) {
return credentialHeader { } , ErrInvalidAccessKey ( "Invalid access key id." , credElement ) . Trace ( credElement )
return credentialHeader { } , ErrInvalidAccessKeyID
}
// Save access key id.
cred := credentialHeader {
@ -59,47 +57,47 @@ func parseCredentialHeader(credElement string) (credentialHeader, *probe.Error)
var e error
cred . scope . date , e = time . Parse ( yyyymmdd , credElements [ 1 ] )
if e != nil {
return credentialHeader { } , ErrInvalidDateFormat ( "Invalid date format." , credElement ) . Trace ( credElement )
return credentialHeader { } , ErrMalformedDate
}
if credElements [ 2 ] == "" {
return credentialHeader { } , ErrRegionISEmpty ( "Region is empty." , credElement ) . Trace ( credElement )
return credentialHeader { } , ErrInvalidRegion
}
cred . scope . region = credElements [ 2 ]
if credElements [ 3 ] != "s3" {
return credentialHeader { } , ErrInvalidService ( "Invalid service detected." , credElement ) . Trace ( credElement )
return credentialHeader { } , ErrInvalidService
}
cred . scope . service = credElements [ 3 ]
if credElements [ 4 ] != "aws4_request" {
return credentialHeader { } , ErrInvalidRequestVersion ( "Invalid request version detected." , credElement ) . Trace ( credElement )
return credentialHeader { } , ErrInvalidRequestVersion
}
cred . scope . request = credElements [ 4 ]
return cred , nil
return cred , ErrNone
}
// Parse signature string.
func parseSignature ( signElement string ) ( string , * probe . Error ) {
func parseSignature ( signElement string ) ( string , APIErrorCode ) {
signFields := strings . Split ( strings . TrimSpace ( signElement ) , "=" )
if len ( signFields ) != 2 {
return "" , ErrMissingFields ( "Signature tag has missing fields." , signElement ) . Trace ( signElement )
return "" , ErrMissingFields
}
if signFields [ 0 ] != "Signature" {
return "" , ErrMissingSignTag ( "Signature tag is missing" , signElement ) . Trace ( signElement )
return "" , ErrMissingSignTag
}
signature := signFields [ 1 ]
return signature , nil
return signature , ErrNone
}
// Parse signed headers string.
func parseSignedHeaders ( signedHdrElement string ) ( [ ] string , * probe . Error ) {
func parseSignedHeaders ( signedHdrElement string ) ( [ ] string , APIErrorCode ) {
signedHdrFields := strings . Split ( strings . TrimSpace ( signedHdrElement ) , "=" )
if len ( signedHdrFields ) != 2 {
return nil , ErrMissingFields ( "Signed headers tag has missing fields." , signedHdrElement ) . Trace ( signedHdrElement )
return nil , ErrMissingFields
}
if signedHdrFields [ 0 ] != "SignedHeaders" {
return nil , ErrMissingSignHeadersTag ( "Signed headers tag is missing." , signedHdrElement ) . Trace ( signedHdrElement )
return nil , ErrMissingSignHeadersTag
}
signedHeaders := strings . Split ( signedHdrFields [ 1 ] , ";" )
return signedHeaders , nil
return signedHeaders , ErrNone
}
// signValues data type represents structured form of AWS Signature V4 header.
@ -125,49 +123,49 @@ type preSignValues struct {
// querystring += &X-Amz-SignedHeaders=signed_headers
// querystring += &X-Amz-Signature=signature
//
func parsePreSignV4 ( query url . Values ) ( preSignValues , * probe . Error ) {
func parsePreSignV4 ( query url . Values ) ( preSignValues , APIErrorCode ) {
// Verify if the query algorithm is supported or not.
if query . Get ( "X-Amz-Algorithm" ) != signV4Algorithm {
return preSignValues { } , ErrUnsuppSignAlgo ( "Unsupported algorithm in query string." , query . Get ( "X-Amz-Algorithm" ) )
return preSignValues { } , ErrInvalidQuerySignatureAlgo
}
// Initialize signature version '4' structured header.
preSignV4Values := preSignValues { }
var err * probe . Error
var err APIErrorCode
// Save credential.
preSignV4Values . Credential , err = parseCredentialHeader ( "Credential=" + query . Get ( "X-Amz-Credential" ) )
if err != nil {
return preSignValues { } , err . Trace ( query . Get ( "X-Amz-Credential" ) )
if err != ErrNone {
return preSignValues { } , err
}
var e error
// Save date in native time.Time.
preSignV4Values . Date , e = time . Parse ( iso8601Format , query . Get ( "X-Amz-Date" ) )
if e != nil {
return preSignValues { } , ErrMalformedDate ( "Malformed date string." , query . Get ( "X-Amz-Date" ) ) . Trace ( query . Get ( "X-Amz-Date" ) )
return preSignValues { } , ErrMalformedDate
}
// Save expires in native time.Duration.
preSignV4Values . Expires , e = time . ParseDuration ( query . Get ( "X-Amz-Expires" ) + "s" )
if e != nil {
return preSignValues { } , ErrMalformedExpires ( "Malformed expires string." , query . Get ( "X-Amz-Expires" ) ) . Trace ( query . Get ( "X-Amz-Expires" ) )
return preSignValues { } , ErrMalformedExpires
}
// Save signed headers.
preSignV4Values . SignedHeaders , err = parseSignedHeaders ( "SignedHeaders=" + query . Get ( "X-Amz-SignedHeaders" ) )
if err != nil {
return preSignValues { } , err . Trace ( query . Get ( "X-Amz-SignedHeaders" ) )
if err != ErrNone {
return preSignValues { } , err
}
// Save signature.
preSignV4Values . Signature , err = parseSignature ( "Signature=" + query . Get ( "X-Amz-Signature" ) )
if err != nil {
return preSignValues { } , err . Trace ( query . Get ( "X-Amz-Signature" ) )
if err != ErrNone {
return preSignValues { } , err
}
// Return structed form of signature query string.
return preSignV4Values , nil
return preSignV4Values , ErrNone
}
// Parses signature version '4' header of the following form.
@ -175,49 +173,49 @@ func parsePreSignV4(query url.Values) (preSignValues, *probe.Error) {
// Authorization: algorithm Credential=accessKeyID/credScope, \
// SignedHeaders=signedHeaders, Signature=signature
//
func parseSignV4 ( v4Auth string ) ( signValues , * probe . Error ) {
func parseSignV4 ( v4Auth string ) ( signValues , APIErrorCode ) {
// 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 signValues { } , ErrAuthHeaderEmpty ( "Auth header empty." ) . Trace ( v4Auth )
return signValues { } , ErrAuthHeaderEmpty
}
// Verify if the header algorithm is supported or not.
if ! strings . HasPrefix ( v4Auth , signV4Algorithm ) {
return signValues { } , ErrUnsuppSignAlgo ( "Unsupported algorithm in authorization header." , v4Auth ) . Trace ( v4Auth )
return signValues { } , ErrSignatureVersionNotSupported
}
// Strip off the Algorithm prefix.
v4Auth = strings . TrimPrefix ( v4Auth , signV4Algorithm )
authFields := strings . Split ( strings . TrimSpace ( v4Auth ) , "," )
if len ( authFields ) != 3 {
return signValues { } , ErrMissingFields ( "Missing fields in authorization header." , v4Auth ) . Trace ( v4Auth )
return signValues { } , ErrMissingFields
}
// Initialize signature version '4' structured header.
signV4Values := signValues { }
var err * probe . Error
var err APIErrorCode
// Save credentail values.
signV4Values . Credential , err = parseCredentialHeader ( authFields [ 0 ] )
if err != nil {
return signValues { } , err . Trace ( v4Auth )
if err != ErrNone {
return signValues { } , err
}
// Save signed headers.
signV4Values . SignedHeaders , err = parseSignedHeaders ( authFields [ 1 ] )
if err != nil {
return signValues { } , err . Trace ( v4Auth )
if err != ErrNone {
return signValues { } , err
}
// Save signature.
signV4Values . Signature , err = parseSignature ( authFields [ 2 ] )
if err != nil {
return signValues { } , err . Trace ( v4Auth )
if err != ErrNone {
return signValues { } , err
}
// Return the structure here.
return signV4Values , nil
return signV4Values , ErrNone
}