mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-05-07 22:20:24 +00:00
118 lines
3.3 KiB
Go
118 lines
3.3 KiB
Go
package awsauth
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"net/http"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
func hashedCanonicalRequestV4(request *http.Request, meta *metadata) string {
|
|
// TASK 1. http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
|
|
|
payload := readAndReplaceBody(request)
|
|
payloadHash := hashSHA256(payload)
|
|
request.Header.Set("X-Amz-Content-Sha256", payloadHash)
|
|
|
|
// Set this in header values to make it appear in the range of headers to sign
|
|
request.Header.Set("Host", request.Host)
|
|
|
|
var sortedHeaderKeys []string
|
|
for key, _ := range request.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(request.Header.Get(key))
|
|
if key == "host" {
|
|
//AWS does not include port in signing request.
|
|
if strings.Contains(value, ":") {
|
|
split := strings.Split(value, ":")
|
|
port := split[1]
|
|
if port == "80" || port == "443" {
|
|
value = split[0]
|
|
}
|
|
}
|
|
}
|
|
headersToSign += key + ":" + value + "\n"
|
|
}
|
|
meta.signedHeaders = concat(";", sortedHeaderKeys...)
|
|
canonicalRequest := concat("\n", request.Method, normuri(request.URL.Path), normquery(request.URL.Query()), headersToSign, meta.signedHeaders, payloadHash)
|
|
|
|
return hashSHA256([]byte(canonicalRequest))
|
|
}
|
|
|
|
func stringToSignV4(request *http.Request, hashedCanonReq string, meta *metadata) string {
|
|
// TASK 2. http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
|
|
|
|
requestTs := request.Header.Get("X-Amz-Date")
|
|
|
|
meta.algorithm = "AWS4-HMAC-SHA256"
|
|
meta.service, meta.region = serviceAndRegion(request.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(request *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 request.Header.Get(header) == "" {
|
|
request.Header.Set(header, value)
|
|
}
|
|
}
|
|
|
|
if request.URL.Path == "" {
|
|
request.URL.Path += "/"
|
|
}
|
|
|
|
return request
|
|
}
|
|
|
|
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"
|