forked from vmware-tanzu/velero
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow to use AWS Signature v1 for creating signed AWS urls
Some aws implementations, for example the quobyte object storage, do not support the v4 signing algorithm, but only v1. This makes it possible to configure the signatureVersion. The algorithm implementation was ported from https://github.com/oNestLab/botocore/blob/d6c1be296e8cfe0706cb0c8bbcad9c095d0f4d09/botocore/auth.py#L860-L862 which is used by the aws CLI client. This fixes vmware-tanzu#811.
- Loading branch information
1 parent
74cb6a2
commit 3308463
Showing
2 changed files
with
145 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
package aws | ||
|
||
import ( | ||
"crypto/hmac" | ||
"crypto/sha1" | ||
"encoding/base64" | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
"net/url" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/aws/credentials" | ||
"github.com/aws/aws-sdk-go/aws/request" | ||
) | ||
|
||
var ( | ||
errInvalidMethod = errors.New("v1 signer only handles HTTP GET") | ||
) | ||
|
||
type signer struct { | ||
// Values that must be populated from the request | ||
Request *http.Request | ||
Time time.Time | ||
Credentials *credentials.Credentials | ||
Debug aws.LogLevelType | ||
Logger aws.Logger | ||
|
||
Query url.Values | ||
stringToSign string | ||
signature string | ||
} | ||
|
||
// SignRequestHandler is a named request handler the SDK will use to sign | ||
// service client request with using the V4 signature. | ||
var V1SignRequestHandler = request.NamedHandler{ | ||
Name: "v1.SignRequestHandler", Fn: SignSDKRequest, | ||
} | ||
|
||
func SignSDKRequest(req *request.Request) { | ||
// If the request does not need to be signed ignore the signing of the | ||
// request if the AnonymousCredentials object is used. | ||
if req.Config.Credentials == credentials.AnonymousCredentials { | ||
return | ||
} | ||
|
||
if req.HTTPRequest.Method != "GET" { | ||
// The V1 signer only supports GET | ||
req.Error = errInvalidMethod | ||
return | ||
} | ||
|
||
v1 := signer{ | ||
Request: req.HTTPRequest, | ||
Time: req.Time, | ||
Credentials: req.Config.Credentials, | ||
Debug: req.Config.LogLevel.Value(), | ||
Logger: req.Config.Logger, | ||
} | ||
|
||
req.Error = v1.Sign() | ||
|
||
if req.Error != nil { | ||
return | ||
} | ||
|
||
req.HTTPRequest.URL.RawQuery = v1.Query.Encode() | ||
} | ||
|
||
func (v1 *signer) Sign() error { | ||
credValue, err := v1.Credentials.Get() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
v1.Query = v1.Request.URL.Query() | ||
|
||
// Set new query parameters | ||
v1.Query.Set("AWSAccessKeyId", credValue.AccessKeyID) | ||
if credValue.SessionToken != "" { | ||
v1.Query.Set("SecurityToken", credValue.SessionToken) | ||
} | ||
|
||
// in case this is a retry, ensure no signature present | ||
v1.Query.Del("Signature") | ||
|
||
method := v1.Request.Method | ||
//host := v1.Request.URL.Host | ||
path := v1.Request.URL.Path | ||
if path == "" { | ||
path = "/" | ||
} | ||
|
||
expires := strconv.FormatInt(v1.Time.Unix()+3600, 10) | ||
|
||
// build the canonical string for the v1 signature | ||
v1.stringToSign = strings.Join([]string{ | ||
method, | ||
"", | ||
"", | ||
expires, | ||
path, | ||
}, "\n") | ||
|
||
hash := hmac.New(sha1.New, []byte(credValue.SecretAccessKey)) | ||
hash.Write([]byte(v1.stringToSign)) | ||
v1.signature = base64.StdEncoding.EncodeToString(hash.Sum(nil)) | ||
v1.Query.Set("Signature", v1.signature) | ||
v1.Query.Set("Expires", expires) | ||
|
||
if v1.Debug.Matches(aws.LogDebugWithSigning) { | ||
v1.logSigningInfo() | ||
} | ||
|
||
return nil | ||
} | ||
|
||
const logSignInfoMsg = `DEBUG: Request Signature: | ||
---[ STRING TO SIGN ]-------------------------------- | ||
%s | ||
---[ SIGNATURE ]------------------------------------- | ||
%s | ||
-----------------------------------------------------` | ||
|
||
func (v1 *signer) logSigningInfo() { | ||
msg := fmt.Sprintf(logSignInfoMsg, v1.stringToSign, v1.Query.Get("Signature")) | ||
v1.Logger.Log(msg) | ||
} |