-
Notifications
You must be signed in to change notification settings - Fork 81
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Expose sigv4 signer for SdkHttpRequestBuilder (#414)
- Loading branch information
Showing
2 changed files
with
123 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import ClientRuntime | ||
import AwsCommonRuntimeKit | ||
|
||
public class AWSSigV4Signer { | ||
static let logger: SwiftLogger = SwiftLogger(label: "AWSSigV4Signer") | ||
|
||
public static func sigV4SignedURL(requestBuilder: SdkHttpRequestBuilder, | ||
credentialsProvider: CredentialsProvider, | ||
signingName: Swift.String, | ||
signingRegion: Swift.String, | ||
date: ClientRuntime.Date, | ||
expiration: Int64) -> ClientRuntime.URL? { | ||
do { | ||
let credentials = try credentialsProvider.getCredentials() | ||
|
||
let flags = SigningFlags(useDoubleURIEncode: true, | ||
shouldNormalizeURIPath: true, | ||
omitSessionToken: false) | ||
let signedBodyHeader: AWSSignedBodyHeader = .none | ||
let signedBodyValue: AWSSignedBodyValue = .empty | ||
let signingConfig = AWSSigningConfig(credentials: credentials, | ||
expiration: expiration, | ||
signedBodyHeader: signedBodyHeader, | ||
signedBodyValue: signedBodyValue, | ||
flags: flags, | ||
date: date, | ||
service: signingName, | ||
region: signingRegion, | ||
signatureType: .requestQueryParams) | ||
let builtRequest = sigV4SignedRequest(requestBuilder: requestBuilder, signingConfig: signingConfig) | ||
guard let presignedURL = builtRequest?.endpoint.url else { | ||
logger.error("Failed to generate presigend url") | ||
return nil | ||
} | ||
return presignedURL | ||
} catch let err { | ||
logger.error("Failed to generate presigned url: \(err)") | ||
return nil | ||
} | ||
} | ||
|
||
public static func sigV4SignedRequest(requestBuilder: SdkHttpRequestBuilder, | ||
signingConfig: AWSSigningConfig) -> SdkHttpRequest? { | ||
let originalRequest = requestBuilder.build() | ||
let crtUnsignedRequest = originalRequest.toHttpRequest() | ||
let signer = SigV4HttpRequestSigner() | ||
do { | ||
let result = try signer.signRequest(request: crtUnsignedRequest, | ||
config: signingConfig.toCRTType()) | ||
let crtSignedRequest = try result.get() | ||
let sdkSignedRequest = requestBuilder.update(from: crtSignedRequest, originalRequest: originalRequest) | ||
return sdkSignedRequest.build() | ||
} catch CRTError.crtError(let crtError) { | ||
logger.error("Failed to sign request (CRT): \(crtError)") | ||
return nil | ||
} catch let err { | ||
logger.error("Failed to sign request: \(err)") | ||
return nil | ||
} | ||
} | ||
} |
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,55 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import AwsCommonRuntimeKit | ||
import ClientRuntime | ||
import XCTest | ||
|
||
@testable import AWSClientRuntime | ||
|
||
class Sigv4SigningTests: XCTestCase { | ||
override func setUp() { | ||
AwsCommonRuntimeKit.initialize() | ||
} | ||
|
||
struct MyCustomCredentialsProvider: CredentialsProvider { | ||
func getCredentials() throws -> AWSCredentials { | ||
return AWSCredentials(accessKey: "AKIDEXAMPLE", secret: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", expirationTimeout: 30) | ||
} | ||
} | ||
|
||
func testPresigner() throws { | ||
let dateString = "2015-08-30T12:36:00Z" | ||
let dateFormatter = DateFormatter.iso8601DateFormatterWithoutFractionalSeconds | ||
guard let date = dateFormatter.date(from: dateString) else { | ||
XCTFail("Unable to parse date") | ||
return | ||
} | ||
|
||
|
||
let requestBuilder = SdkHttpRequestBuilder() | ||
.withHost("example.amazonaws.com") | ||
.withPath("") | ||
.withMethod(.get) | ||
.withPort(443) | ||
.withProtocol(.http) | ||
.withHeader(name: "host", value: "example.amazonaws.com") | ||
.withQueryItem(URLQueryItem(name: "%E1%88%B4", value: "bar")) | ||
|
||
guard let url = AWSSigV4Signer.sigV4SignedURL(requestBuilder: requestBuilder, | ||
credentialsProvider: MyCustomCredentialsProvider(), | ||
signingName: "service", | ||
signingRegion: "us-east-1", | ||
date: date, | ||
expiration: 86400) else { | ||
XCTFail("Unable to generate URL") | ||
return | ||
} | ||
XCTAssertEqual("http://example.amazonaws.com:443?%E1%88%B4=bar&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request&X-Amz-Date=20150830T123600Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86400&X-Amz-Signature=32dea9080047b41e56ee852fe3eba49dae1911b9c5e5728cc1691704f168c70f", url.absoluteString) | ||
} | ||
} | ||
|