Skip to content

Commit

Permalink
Merge pull request #10 from makeen-project/main
Browse files Browse the repository at this point in the history
[Extended team WIP] ALMS-208 [iOS] Add support for custom credential providers in Auth SDK
  • Loading branch information
imraymondlee authored Jul 8, 2024
2 parents ab89a0b + e7baaad commit 59356a7
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 21 deletions.
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "e97a6fcb1ab07462881ac165fdbb37f067e205d5",
"version" : "1.5.4"
"revision" : "9cb486020ebf03bfa5b5df985387a14a98744537",
"version" : "1.6.1"
}
}
],
Expand Down
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Amazon Location Service Mobile Authentication SDK for iOS

These utilities help you authenticate when when making [Amazon Location Service](https://aws.amazon.com/location/) API calls from their iOS applications. This specifically helps when using [Amazon Cognito](https://docs.aws.amazon.com/location/latest/developerguide/authenticating-using-cognito.html) or [API keys](https://docs.aws.amazon.com/location/latest/developerguide/using-apikeys.html) as the authentication method.
These utilities help you authenticate when when making [Amazon Location Service](https://aws.amazon.com/location/) API calls from their iOS applications. This specifically helps when using [Amazon Cognito](https://docs.aws.amazon.com/location/latest/developerguide/authenticating-using-cognito.html) as the authentication method.

## Installation

Expand All @@ -21,19 +21,20 @@ import AWSLocationXCF
You can create an AuthHelper and use it with the AWS SDK:

``` swift
// Create an authentication helper instance using an Amazon Location API Key
func exampleAPIKeyLogin() {
// Create an authentication helper using credentials from Cognito
func exampleCognitoLogin() {
let authHelper = AuthHelper()
let locationCredentialsProvider = authHelper.authenticateWithAPIKey(apiKey: "My-Amazon-Location-API-Key", region: "us-east-1")
let locationCredentialsProvider = authHelper.authenticateWithCognitoIdentityPool(identityPoolId: "My-Cognito-Identity-Pool-Id", region: "us-east-1")
let locationClient = authHelper.getLocationClient()
}
```

``` swift
// Create an authentication helper using credentials from Cognito
// Create an authentication helper using credentials from any AWS-Swift-SDK [Credentials Provider](https://github.com/awslabs/aws-crt-swift/blob/main/Source/AwsCommonRuntimeKit/auth/credentials/CredentialsProvider.swift)
func exampleCognitoLogin() {
let authHelper = AuthHelper()
let locationCredentialsProvider = authHelper.authenticateWithCognitoUserPool(identityPoolId: "My-Cognito-Identity-Pool-Id", region: "us-east-1")
let credentialProvider = try CredentialsProvider(source: .static(accessKey: "My-AWS-AccessKey", secret: "My-AWS-Secret", sessionToken: "My-AWS-SessionToken", shutdownCallback: {/*Perform post shutdown operation here*/}))
let locationCredentialsProvider = authHelper.authenticateWithCredentialsProvider(credentialsProvider: credentialProvider)
let locationClient = authHelper.getLocationClient()
}
```
Expand Down
7 changes: 7 additions & 0 deletions Sources/AmazonLocationiOSAuthSDK/Auth/AuthHelper.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import AwsCommonRuntimeKit

@objc public class AuthHelper: NSObject {

Expand Down Expand Up @@ -33,6 +34,12 @@ import Foundation
return credentialProvider
}

public func authenticateWithCredentialsProvider(credentialsProvider: CredentialsProvider, region: String) async throws -> LocationCredentialsProvider? {
let credentialProvider = LocationCredentialsProvider(credentialsProvider: credentialsProvider)
credentialProvider.setRegion(region: region)
return credentialProvider
}

@objc public func getLocationClient() -> AmazonLocationClient?
{
guard let locationCredentialsProvider = self.locationCredentialsProvider else {
Expand Down
21 changes: 18 additions & 3 deletions Sources/AmazonLocationiOSAuthSDK/Client/AmazonLocationClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,26 @@ public struct HTTPHeaders {

@objc public func initialiseLocationClient() async throws {
if let credentials = locationProvider.getCognitoProvider()?.getCognitoCredentials() {
let resolver: StaticAWSCredentialIdentityResolver? = try StaticAWSCredentialIdentityResolver(AWSCredentialIdentity(accessKey: credentials.accessKeyId, secret: credentials.secretKey, expiration: credentials.expiration, sessionToken: credentials.sessionToken))

let clientConfig = try await LocationClient.LocationClientConfiguration(awsCredentialIdentityResolver: resolver, region: locationProvider.getRegion(), signingRegion: locationProvider.getRegion())
self.locationClient = LocationClient(config: clientConfig)
try await setLocationClient(accessKey: credentials.accessKeyId, secret: credentials.secretKey, expiration: credentials.expiration, sessionToken: credentials.sessionToken)
}
else if let credentialsProvider = locationProvider.getCustomCredentialsProvider() {

let credentials = try await credentialsProvider.getCredentials()

if let accessKey = credentials.getAccessKey(), let secret = credentials.getSecret() {
try await setLocationClient(accessKey: accessKey, secret: secret, expiration: credentials.getExpiration(), sessionToken: credentials.getSessionToken())
}
}
}

private func setLocationClient(accessKey: String, secret: String, expiration: Date?, sessionToken: String?) async throws {

let resolver: StaticAWSCredentialIdentityResolver? = try StaticAWSCredentialIdentityResolver(AWSCredentialIdentity(accessKey: accessKey, secret: secret, expiration: expiration, sessionToken: sessionToken))

let clientConfig = try await LocationClient.LocationClientConfiguration(awsCredentialIdentityResolver: resolver, region: locationProvider.getRegion(), signingRegion: locationProvider.getRegion())

self.locationClient = LocationClient(config: clientConfig)
}

public func sendAPIRequest<T: Decodable, E: AmazonBaseErrorResponse & Error>(
Expand Down
12 changes: 4 additions & 8 deletions Sources/AmazonLocationiOSAuthSDK/Cognito/AWSSignerV4.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public struct TimeAmount: Hashable {
/// Amazon request V4 Signer (This signer is for external aws signing such as Maps cognito signing)
public struct AWSSignerV4 {
/// Security credentials for accessing AWS services
public let credentials: CognitoCredentials
public let credentials: AmazonStaticCredentials
/// Service signing name. In general this is the same as the service name
public let serviceName: String
/// AWS region you are working in
Expand All @@ -123,14 +123,15 @@ public struct AWSSignerV4 {
private static let timeStampDateFormatter: DateFormatter = createTimeStampDateFormatter()

/// Initialise the Signer class with AWS credentials
public init(credentials: CognitoCredentials, serviceName: String, region: String) {
public init(credentials: AmazonStaticCredentials, serviceName: String, region: String) {
self.credentials = credentials
self.serviceName = serviceName
self.region = region
}

public init(amazonLocationCognitoCredentialsProvider: AmazonLocationCognitoCredentialsProvider, serviceName: String) {
self.credentials = amazonLocationCognitoCredentialsProvider.getCognitoCredentials()!
let cognitoCredentials = amazonLocationCognitoCredentialsProvider.getCognitoCredentials()!
self.credentials = AmazonStaticCredentials(accessKeyId: cognitoCredentials.accessKeyId, secretKey: cognitoCredentials.secretKey, sessionToken: cognitoCredentials.sessionToken, expiration: cognitoCredentials.expiration)
self.serviceName = serviceName
self.region = amazonLocationCognitoCredentialsProvider.region!
}
Expand Down Expand Up @@ -459,11 +460,6 @@ public struct AWSSignerV4 {
hash = SHA256.hash(data: [UInt8](string.utf8)).hexDigest()
case .data(let data):
hash = SHA256.hash(data: data).hexDigest()
// case .byteBuffer(let byteBuffer):
// let byteBufferView = byteBuffer.readableBytesView
// hash = byteBufferView.withContiguousStorageIfAvailable { bytes in
// return SHA256.hash(data: bytes).hexDigest()
// }
case .unsignedPayload:
return "UNSIGNED-PAYLOAD"
case .s3chunked:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

@objc public class AmazonLocationCognitoCredentialsProvider: NSObject {
@objc public class AmazonLocationCognitoCredentialsProvider: NSObject, LocationCredentialsProtocol {
internal var identityPoolId: String?
internal var region: String?
private var cognitoCredentials: CognitoCredentials?
Expand All @@ -10,7 +10,7 @@ import Foundation
self.region = region
}

internal func getCognitoCredentials() -> CognitoCredentials? {
public func getCognitoCredentials() -> CognitoCredentials? {
if self.cognitoCredentials != nil && self.cognitoCredentials!.expiration! > Date() {
return self.cognitoCredentials
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

import Foundation

@objc public class AmazonStaticCredentials: NSObject {
public let accessKeyId: String
public let secretKey: String
public let sessionToken: String?
public let expiration: Date?

public init(accessKeyId: String, secretKey: String, sessionToken: String?, expiration: Date?) {
self.accessKeyId = accessKeyId
self.secretKey = secretKey
self.sessionToken = sessionToken
self.expiration = expiration
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Foundation

@objc public protocol LocationCredentialsProtocol {

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import Foundation
import AwsCommonRuntimeKit

extension CredentialsProvider: LocationCredentialsProtocol {

}

@objc public class LocationCredentialsProvider: NSObject {
private var cognitoProvider: AmazonLocationCognitoCredentialsProvider?
private var apiProvider: AmazonLocationApiCredentialsProvider?
private var customCredentialsProvider: CredentialsProvider?
private var region: String?

@objc public init(region: String, identityPoolId: String){
Expand All @@ -15,14 +21,33 @@ import Foundation
self.apiProvider = AmazonLocationApiCredentialsProvider(apiKey: apiKey, region: region)
}

public init(credentialsProvider: CredentialsProvider){
self.customCredentialsProvider = credentialsProvider
}

@objc public func getCognitoProvider() -> AmazonLocationCognitoCredentialsProvider? {
return cognitoProvider
}


@objc public func getApiProvider() -> AmazonLocationApiCredentialsProvider? {
return apiProvider
}

public func getCustomCredentialsProvider() -> CredentialsProvider? {
return customCredentialsProvider
}

@objc public func getCredentialsProvider() -> LocationCredentialsProtocol? {
if let cognitoProvider = self.cognitoProvider {
return cognitoProvider
} else if let customCredentialsProvider = self.customCredentialsProvider {
return customCredentialsProvider
} else {
return nil
}
}

@objc public func getIdentityPoolId() -> String? {
return self.cognitoProvider?.identityPoolId
}
Expand Down
18 changes: 18 additions & 0 deletions Tests/AmazonLocationiOSAuthSDKTests/AuthHelperTests.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import XCTest
import Foundation
@testable import AmazonLocationiOSAuthSDK
import AwsCommonRuntimeKit

final class AuthHelperTests: XCTestCase {

Expand Down Expand Up @@ -50,6 +51,23 @@ final class AuthHelperTests: XCTestCase {
XCTAssertNotNil(authProvider.getApiProvider())
}

func testAuthWithCustomeCredentials() async throws {
let config = readTestConfig()

let identityPoolID = config["identityPoolID"]!
let region = config["region"]!
let authHelper = AuthHelper()
let authCognitoProvider = try? await authHelper.authenticateWithCognitoIdentityPool(identityPoolId: identityPoolID, region: region)
let credentials = authCognitoProvider?.getCognitoProvider()?.getCognitoCredentials()

if let accessKey = credentials?.accessKeyId, let secret = credentials?.secretKey, let sessionToken = credentials?.sessionToken {
let credentialProvider = try CredentialsProvider(source: .static(accessKey: accessKey, secret: secret, sessionToken: sessionToken, shutdownCallback: {}))
let authProvider = try? await authHelper.authenticateWithCredentialsProvider(credentialsProvider: credentialProvider, region: region)
let customAccessKey = try await authProvider!.getCustomCredentialsProvider()?.getCredentials().getAccessKey()
XCTAssertEqual(customAccessKey, accessKey)
}
}

func testAWSSigner() async throws {
let config = readTestConfig()

Expand Down

0 comments on commit 59356a7

Please sign in to comment.