From e71439794a64e7c3ee107766a5bc33bde3fff941 Mon Sep 17 00:00:00 2001 From: Mohammad Fathi Date: Fri, 24 May 2024 16:07:39 -0700 Subject: [PATCH] Add scope support, fix TokenRequest --- .../AuthorizationCodeAuthProvider.swift | 62 ++++++++++++------- .../UberAuth/Authorize/AuthorizeRequest.swift | 8 ++- Sources/UberAuth/Token/TokenRequest.swift | 2 +- .../AuthorizationCodeAuthProviderTests.swift | 30 ++++++--- 4 files changed, 69 insertions(+), 33 deletions(-) diff --git a/Sources/UberAuth/Authorize/AuthorizationCodeAuthProvider.swift b/Sources/UberAuth/Authorize/AuthorizationCodeAuthProvider.swift index edc2436..e84dc9b 100644 --- a/Sources/UberAuth/Authorize/AuthorizationCodeAuthProvider.swift +++ b/Sources/UberAuth/Authorize/AuthorizationCodeAuthProvider.swift @@ -15,19 +15,25 @@ public final class AuthorizationCodeAuthProvider: AuthProviding { public let redirectURI: String public typealias Completion = (Result) -> Void - + public static let defaultScopes = ["profile"] + // MARK: Internal Properties + + var currentSession: AuthenticationSessioning? + + typealias AuthenticationSessionBuilder = (ASPresentationAnchor, String, URL, AuthCompletion) -> (AuthenticationSessioning) + // MARK: Private Properties private let applicationLauncher: ApplicationLaunching + private let authenticationSessionBuilder: AuthenticationSessionBuilder? + private var completion: Completion? private let configurationProvider: ConfigurationProviding - var currentSession: AuthenticationSessioning? - private let pkce = PKCE() private let presentationAnchor: ASPresentationAnchor @@ -40,6 +46,8 @@ public final class AuthorizationCodeAuthProvider: AuthProviding { private let tokenManager: TokenManaging + private let scopes: [String] + // MARK: Initializers public init(presentationAnchor: ASPresentationAnchor = .init(), @@ -56,6 +64,7 @@ public final class AuthorizationCodeAuthProvider: AuthProviding { } self.applicationLauncher = UIApplication.shared + self.authenticationSessionBuilder = nil self.clientID = clientID self.presentationAnchor = presentationAnchor self.redirectURI = redirectURI @@ -63,9 +72,11 @@ public final class AuthorizationCodeAuthProvider: AuthProviding { self.shouldExchangeAuthCode = shouldExchangeAuthCode self.networkProvider = NetworkProvider(baseUrl: Constants.baseUrl) self.tokenManager = TokenManager() + self.scopes = scopes } init(presentationAnchor: ASPresentationAnchor = .init(), + authenticationSessionBuilder: AuthenticationSessionBuilder? = nil, scopes: [String] = AuthorizationCodeAuthProvider.defaultScopes, shouldExchangeAuthCode: Bool = false, configurationProvider: ConfigurationProviding = DefaultConfigurationProvider(), @@ -83,6 +94,7 @@ public final class AuthorizationCodeAuthProvider: AuthProviding { } self.applicationLauncher = applicationLauncher + self.authenticationSessionBuilder = authenticationSessionBuilder self.clientID = clientID self.configurationProvider = configurationProvider self.presentationAnchor = presentationAnchor @@ -91,6 +103,7 @@ public final class AuthorizationCodeAuthProvider: AuthProviding { self.shouldExchangeAuthCode = shouldExchangeAuthCode self.networkProvider = networkProvider self.tokenManager = tokenManager + self.scopes = scopes } // MARK: AuthProviding @@ -183,7 +196,8 @@ public final class AuthorizationCodeAuthProvider: AuthProviding { clientID: clientID, codeChallenge: pkce.codeChallenge, redirectURI: redirectURI, - requestURI: requestURI + requestURI: requestURI, + scopes: scopes ) guard let url = request.url(baseUrl: Constants.baseUrl) else { @@ -197,16 +211,17 @@ public final class AuthorizationCodeAuthProvider: AuthProviding { return } - currentSession = AuthenticationSession( - anchor: presentationAnchor, - callbackURLScheme: callbackURLScheme, - url: url, - completion: { [weak self] result in - guard let self else { return } - completion(result) - currentSession = nil - } - ) + currentSession = authenticationSessionBuilder?(ASPresentationAnchor(), callbackURLScheme, url, completion) ?? + AuthenticationSession( + anchor: presentationAnchor, + callbackURLScheme: callbackURLScheme, + url: url, + completion: { [weak self] result in + guard let self else { return } + completion(result) + currentSession = nil + } + ) currentSession?.start() } @@ -284,7 +299,8 @@ public final class AuthorizationCodeAuthProvider: AuthProviding { clientID: clientID, codeChallenge: pkce.codeChallenge, redirectURI: redirectURI, - requestURI: requestURI + requestURI: requestURI, + scopes: scopes ) guard let url = request.url(baseUrl: Constants.baseUrl) else { @@ -292,13 +308,15 @@ public final class AuthorizationCodeAuthProvider: AuthProviding { return } - applicationLauncher.open( - url, - options: [:], - completionHandler: { opened in - completion?(opened) - } - ) + DispatchQueue.main.async { + self.applicationLauncher.open( + url, + options: [:], + completionHandler: { opened in + completion?(opened) + } + ) + } } private func executePar(prefill: Prefill?, diff --git a/Sources/UberAuth/Authorize/AuthorizeRequest.swift b/Sources/UberAuth/Authorize/AuthorizeRequest.swift index 4c95688..94f8a65 100644 --- a/Sources/UberAuth/Authorize/AuthorizeRequest.swift +++ b/Sources/UberAuth/Authorize/AuthorizeRequest.swift @@ -19,6 +19,7 @@ struct AuthorizeRequest: NetworkRequest { private let clientID: String private let redirectURI: String private let requestURI: String? + private let scopes: [String] // MARK: Initializers @@ -26,12 +27,14 @@ struct AuthorizeRequest: NetworkRequest { clientID: String, codeChallenge: String, redirectURI: String, - requestURI: String?) { + requestURI: String?, + scopes: [String] = []) { self.app = app self.clientID = clientID self.codeChallenge = codeChallenge self.redirectURI = redirectURI self.requestURI = requestURI + self.scopes = scopes } // MARK: Request @@ -45,7 +48,8 @@ struct AuthorizeRequest: NetworkRequest { "code_challenge": codeChallenge, "code_challenge_method": "S256", "redirect_uri": redirectURI, - "request_uri": requestURI + "request_uri": requestURI, + "scope": scopes.joined(separator: " ") ] .compactMapValues { $0 } } diff --git a/Sources/UberAuth/Token/TokenRequest.swift b/Sources/UberAuth/Token/TokenRequest.swift index 0c2df61..fd9cd2a 100644 --- a/Sources/UberAuth/Token/TokenRequest.swift +++ b/Sources/UberAuth/Token/TokenRequest.swift @@ -42,7 +42,7 @@ struct TokenRequest: NetworkRequest { typealias Response = AccessToken - var parameters: [String : String]? { + var body: [String : String]? { [ "code": authorizationCode, "client_id": clientID, diff --git a/examples/UberSDK/UberSDKTests/UberAuth/AuthorizationCodeAuthProviderTests.swift b/examples/UberSDK/UberSDKTests/UberAuth/AuthorizationCodeAuthProviderTests.swift index fc848bd..0ca2a80 100644 --- a/examples/UberSDK/UberSDKTests/UberAuth/AuthorizationCodeAuthProviderTests.swift +++ b/examples/UberSDK/UberSDKTests/UberAuth/AuthorizationCodeAuthProviderTests.swift @@ -167,9 +167,14 @@ final class AuthorizationCodeAuthProviderTests: XCTestCase { } func test_executeNativeLogin_triggersApplicationLauncher() { - + + let expectation = XCTestExpectation() + let applicationLauncher = ApplicationLaunchingMock() - applicationLauncher.openHandler = { _, _, _ in } + applicationLauncher.openHandler = { _, _, completion in + expectation.fulfill() + completion?(true) + } configurationProvider.isInstalledHandler = { _, _ in true @@ -180,15 +185,13 @@ final class AuthorizationCodeAuthProviderTests: XCTestCase { applicationLauncher: applicationLauncher ) - XCTAssertEqual(applicationLauncher.openCallCount, 0) - provider.execute( authDestination: .native(appPriority: UberApp.allCases), prefill: nil, completion: { _ in } ) - XCTAssertEqual(applicationLauncher.openCallCount, 1) + wait(for: [expectation], timeout: 0.2) } func test_executeNativeLogin_noDestinations_triggersInAppLogin() { @@ -226,13 +229,22 @@ final class AuthorizationCodeAuthProviderTests: XCTestCase { configurationProvider.isInstalledHandler = { _, _ in true } + + let expectation = XCTestExpectation() + + let authenticationSession = AuthenticationSessioningMock() + let authenticationSessionBuilder: AuthorizationCodeAuthProvider.AuthenticationSessionBuilder = { _, _, _, _ in + expectation.fulfill() + return authenticationSession + } let provider = AuthorizationCodeAuthProvider( + authenticationSessionBuilder: authenticationSessionBuilder, configurationProvider: configurationProvider, applicationLauncher: applicationLauncher ) - - XCTAssertNil(provider.currentSession) + + XCTAssertEqual(authenticationSession.startCallCount, 0) provider.execute( authDestination: .native(appPriority: UberApp.allCases), @@ -240,7 +252,9 @@ final class AuthorizationCodeAuthProviderTests: XCTestCase { completion: { _ in } ) - XCTAssertNotNil(provider.currentSession) + wait(for: [expectation], timeout: 0.2) + + XCTAssertEqual(authenticationSession.startCallCount, 1) } func test_handleResponse_true_callsResponseParser() {