Skip to content

Commit

Permalink
Merge pull request #11 from makeen-project/ALS-186_API_Authentication
Browse files Browse the repository at this point in the history
[Enhancement] [ALS-1861] [iOS] Update Auth SDK's AutHelper to support API key
  • Loading branch information
mbalfour-amzn authored Sep 19, 2024
2 parents 59356a7 + 379c599 commit e3bb153
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 34 deletions.
12 changes: 6 additions & 6 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/awslabs/aws-crt-swift",
"state" : {
"revision" : "b6380f683b31072d77b601c88674461c11bcad5a",
"version" : "0.30.0"
"revision" : "7b42e0343f28b3451aab20840dc670abd12790bd",
"version" : "0.36.0"
}
},
{
"identity" : "aws-sdk-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/awslabs/aws-sdk-swift",
"state" : {
"branch" : "0.46.0",
"revision" : "3c20e0be8c8246de8b8e04372404ef1f90be71b6"
"revision" : "a41d3b3e01b9803a4a2e0c2273c2de4b3fd787a4",
"version" : "0.77.1"
}
},
{
Expand All @@ -32,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/smithy-lang/smithy-swift",
"state" : {
"revision" : "b2322a067f85c230f17c80be8a67dd543454b081",
"version" : "0.51.0"
"revision" : "0ed3440f8c41e27a0937364d5035d2d4fefb8aa3",
"version" : "0.71.0"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ let package = Package(
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/evgenyneu/keychain-swift.git", from: "20.0.0"),
.package(url: "https://github.com/awslabs/aws-sdk-swift", branch: "0.46.0")
.package(url: "https://github.com/awslabs/aws-sdk-swift", from: "0.76.1")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
Expand Down
27 changes: 18 additions & 9 deletions Sources/AmazonLocationiOSAuthSDK/Auth/AuthHelper.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import Foundation
import AWSLocation
import AwsCommonRuntimeKit

@objc public class AuthHelper: NSObject {

private var locationCredentialsProvider: LocationCredentialsProvider?

private var amazonLocationClient: AmazonLocationClient?

@objc public override init() {
}

Expand All @@ -22,29 +24,36 @@ import AwsCommonRuntimeKit
private func authenticateWithCognitoIdentityPoolAndRegion(identityPoolId: String, region: String) async throws -> LocationCredentialsProvider? {
let credentialProvider = LocationCredentialsProvider(region: region, identityPoolId: identityPoolId)
credentialProvider.setRegion(region: region)
try await credentialProvider.getCognitoProvider()?.refreshCognitoCredentialsIfExpired()
amazonLocationClient = AmazonLocationClient(locationCredentialsProvider: credentialProvider)
try await amazonLocationClient?.initialiseLocationClient()
return credentialProvider
}

@objc public func authenticateWithApiKey(apiKey: String, region: String) -> LocationCredentialsProvider {
@objc public func authenticateWithApiKey(apiKey: String, region: String) async throws -> LocationCredentialsProvider? {
let credentialProvider = LocationCredentialsProvider(region: region, apiKey: apiKey)
credentialProvider.setAPIKey(apiKey: apiKey)
credentialProvider.setRegion(region: region)
locationCredentialsProvider = credentialProvider
locationCredentialsProvider = credentialProvider
if let credentialsProvider = locationCredentialsProvider {
amazonLocationClient = AmazonLocationClient(locationCredentialsProvider: credentialsProvider)
try await amazonLocationClient?.initialiseLocationClient()
}
return credentialProvider
}

public func authenticateWithCredentialsProvider(credentialsProvider: CredentialsProvider, region: String) async throws -> LocationCredentialsProvider? {
let credentialProvider = LocationCredentialsProvider(credentialsProvider: credentialsProvider)
credentialProvider.setRegion(region: region)
locationCredentialsProvider = credentialProvider
if let credentialsProvider = locationCredentialsProvider {
amazonLocationClient = AmazonLocationClient(locationCredentialsProvider: credentialsProvider)
try await amazonLocationClient?.initialiseLocationClient()
}
return credentialProvider
}

@objc public func getLocationClient() -> AmazonLocationClient?
{
guard let locationCredentialsProvider = self.locationCredentialsProvider else {
return nil
}
return AmazonLocationClient(locationCredentialsProvider: locationCredentialsProvider)
return amazonLocationClient
}
}
31 changes: 23 additions & 8 deletions Sources/AmazonLocationiOSAuthSDK/Client/AmazonLocationClient.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation
import AWSLocation
import SmithyIdentity
import SmithyIdentityAPI
import SmithyHTTPAuthAPI

public enum HTTPMethod: String {
case GET
Expand Down Expand Up @@ -43,9 +43,11 @@ public struct HTTPHeaders {
}

@objc public func initialiseLocationClient() async throws {
if let credentials = locationProvider.getCognitoProvider()?.getCognitoCredentials() {

try await setLocationClient(accessKey: credentials.accessKeyId, secret: credentials.secretKey, expiration: credentials.expiration, sessionToken: credentials.sessionToken)
if let cognitoProvider = locationProvider.getCognitoProvider() {
try await cognitoProvider.refreshCognitoCredentialsIfExpired()
if let credentials = cognitoProvider.getCognitoCredentials() {
try await setLocationClient(accessKey: credentials.accessKeyId, secret: credentials.secretKey, expiration: credentials.expiration, sessionToken: credentials.sessionToken)
}
}
else if let credentialsProvider = locationProvider.getCustomCredentialsProvider() {

Expand All @@ -55,13 +57,26 @@ public struct HTTPHeaders {
try await setLocationClient(accessKey: accessKey, secret: secret, expiration: credentials.getExpiration(), sessionToken: credentials.getSessionToken())
}
}
else if let apiProvider = locationProvider.getApiProvider(),
let apiKey = apiProvider.apiKey {
try await setLocationClient(apiKey: apiKey)
}
}

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))

private func setLocationClient(accessKey: String, secret: String, expiration: Date? = nil, sessionToken: String? = nil) async throws {
let credentialsIdentity = AWSCredentialIdentity(accessKey: accessKey, secret: secret, expiration: expiration, sessionToken: sessionToken)
let resolver: StaticAWSCredentialIdentityResolver? = try StaticAWSCredentialIdentityResolver(credentialsIdentity)
let clientConfig = try await LocationClient.LocationClientConfiguration(awsCredentialIdentityResolver: resolver, region: locationProvider.getRegion(), signingRegion: locationProvider.getRegion())
self.locationClient = LocationClient(config: clientConfig)
}

private func setLocationClient(apiKey: String) async throws {
let resolver: AuthSchemeResolver = ApiKeyAuthSchemeResolver()
let signer = ApiKeySigner()
let authScheme: AuthScheme = ApiKeyAuthScheme(signer: signer)
let authSchemes: [AuthScheme] = [authScheme]
let region = locationProvider.getRegion()
let clientConfig = try await LocationClient.LocationClientConfiguration(region: region, authSchemes: authSchemes, authSchemeResolver: resolver)

self.locationClient = LocationClient(config: clientConfig)
}
Expand Down
52 changes: 52 additions & 0 deletions Sources/AmazonLocationiOSAuthSDK/Client/ApiKeyAuthScheme.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import SmithyHTTPAuthAPI
import Smithy
import SmithyHTTPAPI

public let apiKeyAuthSchemeID: String = "smithy.api#noAuth"

public struct ApiKeyAuthScheme: AuthScheme {
public var schemeID: String = apiKeyAuthSchemeID
public var signer: any SmithyHTTPAuthAPI.Signer

public func customizeSigningProperties(
signingProperties: Smithy.Attributes,
context: Smithy.Context
) throws -> Smithy.Attributes {
return signingProperties
}
}

public class ApiKeySigner: Signer {
public init() {}

public func signRequest<IdentityT>(
requestBuilder: SmithyHTTPAPI.HTTPRequestBuilder,
identity: IdentityT,
signingProperties: Smithy.Attributes
) async throws -> SmithyHTTPAPI.HTTPRequestBuilder {
return requestBuilder
}
}

public class ApiKeyAuthSchemeResolverParameters: AuthSchemeResolverParameters {
public var operation: String
public init(operation: String) {
self.operation = operation
}
}

public class ApiKeyAuthSchemeResolver: AuthSchemeResolver {
public func resolveAuthScheme(params: AuthSchemeResolverParameters) throws -> [AuthOption] {
var validAuthOptions = Array<AuthOption>()
validAuthOptions.append(AuthOption(schemeID: apiKeyAuthSchemeID))
return validAuthOptions
}

public func constructParameters(context: Context) throws -> AuthSchemeResolverParameters {
guard let opName = context.getOperation() else {
throw ClientError.dataNotFound(
"Operation name not configured in middleware context for auth scheme resolver params construction.")
}
return ApiKeyAuthSchemeResolverParameters(operation: opName)
}
}
73 changes: 63 additions & 10 deletions Tests/AmazonLocationiOSAuthSDKTests/AuthHelperTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import XCTest
import Foundation
@testable import AmazonLocationiOSAuthSDK
import AwsCommonRuntimeKit
import CoreLocation
import AWSLocation

final class AuthHelperTests: XCTestCase {

Expand All @@ -25,9 +27,25 @@ final class AuthHelperTests: XCTestCase {
let config = readTestConfig()

let identityPoolID = config["identityPoolID"]!
let searchPlaceIndex = config["placeIndex"]!

let authHelper = AuthHelper()
let authProvider = try? await authHelper.authenticateWithCognitoIdentityPool(identityPoolId: identityPoolID)
XCTAssertEqual(authProvider!.getIdentityPoolId(), identityPoolID)
XCTAssertNotNil(authProvider?.getCognitoProvider())

let biasPosition = CLLocationCoordinate2D(latitude: 47.654502614244194, longitude: -122.35862564621954)
let locationClient = authHelper.getLocationClient()?.locationClient
let searchPlaceIndexForSuggestionsInput = SearchPlaceIndexForSuggestionsInput(biasPosition: [biasPosition.longitude, biasPosition.latitude], indexName: searchPlaceIndex, maxResults: 15, text: "Schools")
let response = try await locationClient?.searchPlaceIndexForSuggestions(input: searchPlaceIndexForSuggestionsInput)

var searchResults: [String] = []
if let results = response?.results {
for item in results {
searchResults.append((item.text)!)
}
}
XCTAssertNotEqual(searchResults.count, 0, "Search has results")
}

func testAuthWithIdentityPoolIDAndRegion() async throws {
Expand All @@ -40,31 +58,66 @@ final class AuthHelperTests: XCTestCase {
XCTAssertEqual(authProvider!.getIdentityPoolId(), identityPoolID)
}

func testAuthWithAPIKey() throws {
let config = readTestConfig()

let apiKey = config["apiKey"]!
let region = config["region"]!

let authHelper = AuthHelper()
let authProvider = authHelper.authenticateWithApiKey(apiKey: apiKey, region: region)
XCTAssertNotNil(authProvider.getApiProvider())
func testAuthWithAPIKey() async throws {
do {
let config = readTestConfig()
let apiKey = config["apiKey"]!
let region = config["region"]!
let searchPlaceIndex = config["placeIndex"]!

let authHelper = AuthHelper()
let authProvider = try await authHelper.authenticateWithApiKey(apiKey: apiKey, region: region)

XCTAssertNotNil(authProvider?.getApiProvider())

let biasPosition = CLLocationCoordinate2D(latitude: 47.654502614244194, longitude: -122.35862564621954)
let locationClient = authHelper.getLocationClient()?.locationClient
let searchPlaceIndexForSuggestionsInput = SearchPlaceIndexForSuggestionsInput(biasPosition: [biasPosition.longitude, biasPosition.latitude], indexName: searchPlaceIndex, key: apiKey, maxResults: 15, text: "Schools")
let response = try await locationClient?.searchPlaceIndexForSuggestions(input: searchPlaceIndexForSuggestionsInput)

var searchResults: [String] = []
if let results = response?.results {
for item in results {
searchResults.append((item.text)!)
}
}
XCTAssertNotEqual(searchResults.count, 0, "Search has results")
}
catch {
XCTFail(error.localizedDescription)
throw error
}
}

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

let identityPoolID = config["identityPoolID"]!
let region = config["region"]!
let searchPlaceIndex = config["placeIndex"]!

let authHelper = AuthHelper()
let authCognitoProvider = try? await authHelper.authenticateWithCognitoIdentityPool(identityPoolId: identityPoolID, region: region)
let authCognitoProvider = try? await authHelper.authenticateWithCognitoIdentityPool(identityPoolId: identityPoolID)
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)

let biasPosition = CLLocationCoordinate2D(latitude: 47.654502614244194, longitude: -122.35862564621954)
let locationClient = authHelper.getLocationClient()?.locationClient
let searchPlaceIndexForSuggestionsInput = SearchPlaceIndexForSuggestionsInput(biasPosition: [biasPosition.longitude, biasPosition.latitude], indexName: searchPlaceIndex, maxResults: 15, text: "Schools")
let response = try await locationClient?.searchPlaceIndexForSuggestions(input: searchPlaceIndexForSuggestionsInput)

var searchResults: [String] = []
if let results = response?.results {
for item in results {
searchResults.append((item.text)!)
}
}
XCTAssertNotEqual(searchResults.count, 0, "Search has results")
}
}

Expand Down

0 comments on commit e3bb153

Please sign in to comment.