mirror of https://github.com/docker/docs.git
108 lines
3.0 KiB
Go
108 lines
3.0 KiB
Go
package awsauth
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"net/http"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
func hashedCanonicalRequestV4(req *http.Request, meta *metadata) string {
|
|
// TASK 1. http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
|
|
|
payload := readAndReplaceBody(req)
|
|
payloadHash := hashSHA256(payload)
|
|
req.Header.Set("X-Amz-Content-Sha256", payloadHash)
|
|
|
|
// Set this in header values to make it appear in the range of headers to sign
|
|
req.Header.Set("Host", req.Host)
|
|
|
|
var sortedHeaderKeys []string
|
|
for key, _ := range req.Header {
|
|
switch key {
|
|
case "Content-Type", "Content-Md5", "Host":
|
|
default:
|
|
if !strings.HasPrefix(key, "X-Amz-") {
|
|
continue
|
|
}
|
|
}
|
|
sortedHeaderKeys = append(sortedHeaderKeys, strings.ToLower(key))
|
|
}
|
|
sort.Strings(sortedHeaderKeys)
|
|
|
|
var headersToSign string
|
|
for _, key := range sortedHeaderKeys {
|
|
value := strings.TrimSpace(req.Header.Get(key))
|
|
headersToSign += key + ":" + value + "\n"
|
|
}
|
|
meta.signedHeaders = concat(";", sortedHeaderKeys...)
|
|
canonicalRequest := concat("\n", req.Method, normuri(req.URL.Path), normquery(req.URL.Query()), headersToSign, meta.signedHeaders, payloadHash)
|
|
|
|
return hashSHA256([]byte(canonicalRequest))
|
|
}
|
|
|
|
func stringToSignV4(req *http.Request, hashedCanonReq string, meta *metadata) string {
|
|
// TASK 2. http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
|
|
|
|
requestTs := req.Header.Get("X-Amz-Date")
|
|
|
|
meta.algorithm = "AWS4-HMAC-SHA256"
|
|
meta.service, meta.region = serviceAndRegion(req.Host)
|
|
meta.date = tsDateV4(requestTs)
|
|
meta.credentialScope = concat("/", meta.date, meta.region, meta.service, "aws4_request")
|
|
|
|
return concat("\n", meta.algorithm, requestTs, meta.credentialScope, hashedCanonReq)
|
|
}
|
|
|
|
func signatureV4(signingKey []byte, stringToSign string) string {
|
|
// TASK 3. http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
|
|
|
|
return hex.EncodeToString(hmacSHA256(signingKey, stringToSign))
|
|
}
|
|
|
|
func prepareRequestV4(req *http.Request) *http.Request {
|
|
necessaryDefaults := map[string]string{
|
|
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
|
"X-Amz-Date": timestampV4(),
|
|
}
|
|
|
|
for header, value := range necessaryDefaults {
|
|
if req.Header.Get(header) == "" {
|
|
req.Header.Set(header, value)
|
|
}
|
|
}
|
|
|
|
if req.URL.Path == "" {
|
|
req.URL.Path += "/"
|
|
}
|
|
|
|
return req
|
|
}
|
|
|
|
func signingKeyV4(secretKey, date, region, service string) []byte {
|
|
kDate := hmacSHA256([]byte("AWS4"+secretKey), date)
|
|
kRegion := hmacSHA256(kDate, region)
|
|
kService := hmacSHA256(kRegion, service)
|
|
kSigning := hmacSHA256(kService, "aws4_request")
|
|
return kSigning
|
|
}
|
|
|
|
func buildAuthHeaderV4(signature string, meta *metadata, keys Credentials) string {
|
|
credential := keys.AccessKeyID + "/" + meta.credentialScope
|
|
|
|
return meta.algorithm +
|
|
" Credential=" + credential +
|
|
", SignedHeaders=" + meta.signedHeaders +
|
|
", Signature=" + signature
|
|
}
|
|
|
|
func timestampV4() string {
|
|
return now().Format(timeFormatV4)
|
|
}
|
|
|
|
func tsDateV4(timestamp string) string {
|
|
return timestamp[:8]
|
|
}
|
|
|
|
const timeFormatV4 = "20060102T150405Z"
|