Skip to content

Commit

Permalink
Don't add 80/443 to host on http/https URLs when signing (#421)
Browse files Browse the repository at this point in the history
* Don't add 80/443 to host on http/https URLs when signing
* Tidy up
  • Loading branch information
adam-fowler authored Feb 2, 2021
1 parent b987f84 commit 4231c30
Showing 1 changed file with 20 additions and 8 deletions.
28 changes: 20 additions & 8 deletions Sources/SotoSignerV4/signer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ public struct AWSSigner {
let dateString = AWSSigner.timestamp(date)
var headers = headers
// add date, host, sha256 and if available security token headers
headers.add(name: "X-Amz-Date", value: dateString)
headers.add(name: "host", value: "\(url.host ?? "")\(url.port.map { ":\($0)" } ?? "")")
headers.add(name: "x-amz-content-sha256", value: bodyHash)
headers.replaceOrAdd(name: "X-Amz-Date", value: dateString)
headers.replaceOrAdd(name: "host", value: Self.hostname(from: url))
headers.replaceOrAdd(name: "x-amz-content-sha256", value: bodyHash)
if let sessionToken = credentials.sessionToken {
headers.add(name: "x-amz-security-token", value: sessionToken)
headers.replaceOrAdd(name: "x-amz-security-token", value: sessionToken)
}

// construct signing data. Do this after adding the headers as it uses data from the headers
Expand All @@ -97,15 +97,15 @@ public struct AWSSigner {
"Signature=\(signature(signingData: signingData))"

// add Authorization header
headers.add(name: "Authorization", value: authorization)
headers.replaceOrAdd(name: "Authorization", value: authorization)

return headers
}

/// Generate a signed URL, for a HTTP request
public func signURL(url: URL, method: HTTPMethod = .GET, headers: HTTPHeaders = HTTPHeaders(), body: BodyData? = nil, expires: TimeAmount, date: Date = Date()) -> URL {
var headers = headers
headers.replaceOrAdd(name: "host", value: url.host ?? "")
headers.replaceOrAdd(name: "host", value: Self.hostname(from: url))
// Create signing data
var signingData = AWSSigner.SigningData(url: url, method: method, headers: headers, body: body, date: AWSSigner.timestamp(date), signer: self)
// Construct query string. Start with original query strings and append all the signing info.
Expand Down Expand Up @@ -157,14 +157,14 @@ public struct AWSSigner {
var headers = headers
// add date, host, sha256 and if available security token headers
headers.add(name: "X-Amz-Date", value: dateString)
headers.add(name: "host", value: url.host ?? "")
headers.add(name: "host", value: Self.hostname(from: url))
headers.add(name: "x-amz-content-sha256", value: bodyHash)
if let sessionToken = credentials.sessionToken {
headers.add(name: "x-amz-security-token", value: sessionToken)
}
// remove content-length header
headers.remove(name: "content-length")

// construct signing data. Do this after adding the headers as it uses data from the headers
let signingData = AWSSigner.SigningData(url: url, method: method, headers: headers, bodyHash: bodyHash, date: dateString, signer: self)
let signingKey = self.signingKey(date: signingData.date)
Expand Down Expand Up @@ -337,6 +337,18 @@ public struct AWSSigner {
static func timestamp(_ date: Date) -> String {
return timeStampDateFormatter.string(from: date)
}

/// returns port from URL. If port is set to 80 on an http url or 443 on an https url nil is returned
private static func port(from url: URL) -> Int? {
guard let port = url.port else { return nil }
guard url.scheme != "http" || port != 80 else { return nil }
guard url.scheme != "https" || port != 443 else { return nil }
return port
}

private static func hostname(from url: URL) -> String {
"\(url.host ?? "")\(port(from: url).map { ":\($0)" } ?? "")"
}
}

extension String {
Expand Down

0 comments on commit 4231c30

Please sign in to comment.