From 889ad1996115339eb91ed0693e01ae5d4969ec3a Mon Sep 17 00:00:00 2001 From: Matthew Mathias Date: Wed, 11 Jan 2023 14:04:14 -0800 Subject: [PATCH 1/7] Add methods to not pass a presenting vc or window for auth flow --- .../contents.xcworkspacedata | 7 + Package.swift | 9 +- .../AppAuth/iOS/OIDAuthorizationService+IOS.h | 26 ++++ .../AppAuth/iOS/OIDAuthorizationService+IOS.m | 23 +++ Source/AppAuth/iOS/OIDExternalUserAgentIOS.h | 31 +++-- Source/AppAuth/iOS/OIDExternalUserAgentIOS.m | 53 +++++-- .../AppAuth/OIDExternUserAgentIOSTests.m | 131 ++++++++++++++++++ .../OIDAppAuthTests-Bridging-Header.h | 0 .../{ => AppAuthCore}/OIDAuthStateTests.h | 0 .../{ => AppAuthCore}/OIDAuthStateTests.m | 0 .../OIDAuthorizationRequestTests.h | 0 .../OIDAuthorizationRequestTests.m | 0 .../OIDAuthorizationResponseTests.h | 0 .../OIDAuthorizationResponseTests.m | 0 .../OIDEndSessionRequestTests.h | 0 .../OIDEndSessionRequestTests.m | 0 .../{ => AppAuthCore}/OIDGrantTypesTests.m | 0 .../{ => AppAuthCore}/OIDRPProfileCode.h | 0 .../{ => AppAuthCore}/OIDRPProfileCode.m | 0 .../OIDRegistrationRequestTests.h | 0 .../OIDRegistrationRequestTests.m | 0 .../OIDRegistrationResponseTests.h | 0 .../OIDRegistrationResponseTests.m | 0 .../{ => AppAuthCore}/OIDResponseTypesTests.m | 0 UnitTests/{ => AppAuthCore}/OIDScopesTests.m | 0 .../OIDServiceConfigurationTests.h | 0 .../OIDServiceConfigurationTests.m | 0 .../OIDServiceDiscoveryTests.h | 0 .../OIDServiceDiscoveryTests.m | 0 .../{ => AppAuthCore}/OIDSwiftTests.swift | 0 .../{ => AppAuthCore}/OIDTokenRequestTests.h | 0 .../{ => AppAuthCore}/OIDTokenRequestTests.m | 0 .../{ => AppAuthCore}/OIDTokenResponseTests.h | 0 .../{ => AppAuthCore}/OIDTokenResponseTests.m | 0 .../OIDTokenUtilitiesTests.m | 0 .../OIDURLQueryComponentTests.h | 0 .../OIDURLQueryComponentTests.m | 0 .../OIDURLQueryComponentTestsIOS7.m | 0 .../OIDURLSessionProviderTests.m | 0 39 files changed, 259 insertions(+), 21 deletions(-) create mode 100644 .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata create mode 100644 UnitTests/AppAuth/OIDExternUserAgentIOSTests.m rename UnitTests/{ => AppAuthCore}/OIDAppAuthTests-Bridging-Header.h (100%) rename UnitTests/{ => AppAuthCore}/OIDAuthStateTests.h (100%) rename UnitTests/{ => AppAuthCore}/OIDAuthStateTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDAuthorizationRequestTests.h (100%) rename UnitTests/{ => AppAuthCore}/OIDAuthorizationRequestTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDAuthorizationResponseTests.h (100%) rename UnitTests/{ => AppAuthCore}/OIDAuthorizationResponseTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDEndSessionRequestTests.h (100%) rename UnitTests/{ => AppAuthCore}/OIDEndSessionRequestTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDGrantTypesTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDRPProfileCode.h (100%) rename UnitTests/{ => AppAuthCore}/OIDRPProfileCode.m (100%) rename UnitTests/{ => AppAuthCore}/OIDRegistrationRequestTests.h (100%) rename UnitTests/{ => AppAuthCore}/OIDRegistrationRequestTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDRegistrationResponseTests.h (100%) rename UnitTests/{ => AppAuthCore}/OIDRegistrationResponseTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDResponseTypesTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDScopesTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDServiceConfigurationTests.h (100%) rename UnitTests/{ => AppAuthCore}/OIDServiceConfigurationTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDServiceDiscoveryTests.h (100%) rename UnitTests/{ => AppAuthCore}/OIDServiceDiscoveryTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDSwiftTests.swift (100%) rename UnitTests/{ => AppAuthCore}/OIDTokenRequestTests.h (100%) rename UnitTests/{ => AppAuthCore}/OIDTokenRequestTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDTokenResponseTests.h (100%) rename UnitTests/{ => AppAuthCore}/OIDTokenResponseTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDTokenUtilitiesTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDURLQueryComponentTests.h (100%) rename UnitTests/{ => AppAuthCore}/OIDURLQueryComponentTests.m (100%) rename UnitTests/{ => AppAuthCore}/OIDURLQueryComponentTestsIOS7.m (100%) rename UnitTests/{ => AppAuthCore}/OIDURLSessionProviderTests.m (100%) diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Package.swift b/Package.swift index b031680df..2ae8a710e 100644 --- a/Package.swift +++ b/Package.swift @@ -67,13 +67,18 @@ let package = Package( .testTarget( name: "AppAuthCoreTests", dependencies: ["AppAuthCore"], - path: "UnitTests", + path: "UnitTests/AppAuthCore", exclude: ["OIDSwiftTests.swift", "AppAuthTV"] ), + .testTarget( + name: "AppAuthTests", + dependencies: ["AppAuth", "AppAuthCore"], + path: "UnitTests/AppAuth" + ), .testTarget( name: "AppAuthCoreSwiftTests", dependencies: ["AppAuthCore"], - path: "UnitTests", + path: "UnitTests/AppAuthCore", sources: ["OIDSwiftTests.swift"] ), .testTarget( diff --git a/Source/AppAuth/iOS/OIDAuthorizationService+IOS.h b/Source/AppAuth/iOS/OIDAuthorizationService+IOS.h index c7c685d28..2437c7ac8 100644 --- a/Source/AppAuth/iOS/OIDAuthorizationService+IOS.h +++ b/Source/AppAuth/iOS/OIDAuthorizationService+IOS.h @@ -60,6 +60,32 @@ NS_ASSUME_NONNULL_BEGIN prefersEphemeralSession:(BOOL)prefersEphemeralSession callback:(OIDAuthorizationCallback)callback API_AVAILABLE(ios(13)); +/*! @brief Perform an authorization flow using the @c ASWebAuthenticationSession optionally using an + emphemeral browser session that shares no cookies or data with the normal browser session. + @param request The authorization request. + @param callback The method called when the request has completed or failed. + @return A @c OIDExternalUserAgentSession instance which will terminate when it + receives a @c OIDExternalUserAgentSession.cancel message, or after processing a + @c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message. + */ ++ (id)presentAuthorizationRequest:(OIDAuthorizationRequest *)request + callback:(OIDAuthorizationCallback)callback; + +/*! @brief Perform an authorization flow using the @c ASWebAuthenticationSession optionally using an + emphemeral browser session that shares no cookies or data with the normal browser session. + @param request The authorization request. + @param prefersEphemeralSession Whether the caller prefers to use a private authentication + session. See @c ASWebAuthenticationSession.prefersEphemeralWebBrowserSession for more. + @param callback The method called when the request has completed or failed. + @return A @c OIDExternalUserAgentSession instance which will terminate when it + receives a @c OIDExternalUserAgentSession.cancel message, or after processing a + @c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message. + */ ++ (id)presentAuthorizationRequest:(OIDAuthorizationRequest *)request + prefersEphemeralSession:(BOOL)prefersEphemeralSession + callback:(OIDAuthorizationCallback)callback + API_AVAILABLE(ios(13)); + @end NS_ASSUME_NONNULL_END diff --git a/Source/AppAuth/iOS/OIDAuthorizationService+IOS.m b/Source/AppAuth/iOS/OIDAuthorizationService+IOS.m index 4ca07c55e..a7a09ad6b 100644 --- a/Source/AppAuth/iOS/OIDAuthorizationService+IOS.m +++ b/Source/AppAuth/iOS/OIDAuthorizationService+IOS.m @@ -57,6 +57,29 @@ @implementation OIDAuthorizationService (IOS) return [self presentAuthorizationRequest:request externalUserAgent:externalUserAgent callback:callback]; } ++ (id)presentAuthorizationRequest:(OIDAuthorizationRequest *)request + callback:(OIDAuthorizationCallback)callback { + return [self presentAuthorizationRequest:request + prefersEphemeralSession:NO + callback:callback]; +} + ++ (id)presentAuthorizationRequest:(OIDAuthorizationRequest *)request + prefersEphemeralSession:(BOOL)prefersEphemeralSession + callback:(OIDAuthorizationCallback)callback { + id externalUserAgent; +#if TARGET_OS_MACCATALYST + externalUserAgent = [[OIDExternalUserAgentCatalyst alloc] + initWithPrefersEphemeralSession:prefersEphemeralSession]; +#else // TARGET_OS_MACCATALYST + externalUserAgent = [[OIDExternalUserAgentIOS alloc] + initWithPrefersEphemeralSession:prefersEphemeralSession]; +#endif // TARGET_OS_MACCATALYST + return [self presentAuthorizationRequest:request + externalUserAgent:externalUserAgent + callback:callback]; +} + @end NS_ASSUME_NONNULL_END diff --git a/Source/AppAuth/iOS/OIDExternalUserAgentIOS.h b/Source/AppAuth/iOS/OIDExternalUserAgentIOS.h index ae0773c69..b9a54f620 100644 --- a/Source/AppAuth/iOS/OIDExternalUserAgentIOS.h +++ b/Source/AppAuth/iOS/OIDExternalUserAgentIOS.h @@ -34,21 +34,25 @@ NS_ASSUME_NONNULL_BEGIN API_UNAVAILABLE(macCatalyst) @interface OIDExternalUserAgentIOS : NSObject -- (nullable instancetype)init API_AVAILABLE(ios(11)) - __deprecated_msg("This method will not work on iOS 13, use " - "initWithPresentingViewController:presentingViewController"); +/*! @brief Create an external user-agent. + @discussion The specific authentication UI used depends on the iOS version and accessibility + options. iOS 8 uses the system browser, iOS 9-10 use @c SFSafariViewController, iOS 11 uses + @c SFAuthenticationSession (unless Guided Access is on which does not work) or uses + @c SFSafariViewController, and iOS 12+ uses @c ASWebAuthenticationSession (unless Guided + Access is on). + */ +- (nullable instancetype)init API_AVAILABLE(ios(11)); -/*! @brief The designated initializer. +/*! @brief Create an external user-agent with the presenting view controller. @param presentingViewController The view controller from which to present the authentication UI. @discussion The specific authentication UI used depends on the iOS version and accessibility options. iOS 8 uses the system browser, iOS 9-10 use @c SFSafariViewController, iOS 11 uses - @c SFAuthenticationSession - (unless Guided Access is on which does not work) or uses @c SFSafariViewController, and iOS - 12+ uses @c ASWebAuthenticationSession (unless Guided Access is on). + @c SFAuthenticationSession (unless Guided Access is on which does not work) or uses + @c SFSafariViewController, and iOS 12+ uses @c ASWebAuthenticationSession (unless Guided + Access is on). */ - (nullable instancetype)initWithPresentingViewController: - (UIViewController *)presentingViewController - NS_DESIGNATED_INITIALIZER; + (UIViewController *)presentingViewController; /*! @brief Create an external user-agent which optionally uses a private authentication session. @param presentingViewController The view controller from which to present the browser. @@ -62,6 +66,15 @@ API_UNAVAILABLE(macCatalyst) prefersEphemeralSession:(BOOL)prefersEphemeralSession API_AVAILABLE(ios(13)); +/*! @brief Create an external user-agent which optionally uses a private authentication session. + @param prefersEphemeralSession Whether the caller prefers to use a private authentication + session. See @c ASWebAuthenticationSession.prefersEphemeralWebBrowserSession for more. + @discussion Authentication is performed with @c ASWebAuthenticationSession (unless Guided Access + is on), setting the ephemerality based on the argument. + */ +- (nullable instancetype)initWithPrefersEphemeralSession:(BOOL)prefersEphemeralSession + API_AVAILABLE(ios(13)); + @end NS_ASSUME_NONNULL_END diff --git a/Source/AppAuth/iOS/OIDExternalUserAgentIOS.m b/Source/AppAuth/iOS/OIDExternalUserAgentIOS.m index eab7aa3cb..1ee577abf 100644 --- a/Source/AppAuth/iOS/OIDExternalUserAgentIOS.m +++ b/Source/AppAuth/iOS/OIDExternalUserAgentIOS.m @@ -56,21 +56,22 @@ @implementation OIDExternalUserAgentIOS { } - (nullable instancetype)init { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnonnull" - return [self initWithPresentingViewController:nil]; -#pragma clang diagnostic pop + self = [super init]; + return self; +} + +- (nullable instancetype)initWithPrefersEphemeralSession:(BOOL)prefersEphemeralSession { + self = [self init]; + if (self) { + _prefersEphemeralSession = prefersEphemeralSession; + } + return self; } - (nullable instancetype)initWithPresentingViewController: (UIViewController *)presentingViewController { - self = [super init]; + self = [self init]; if (self) { -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 - NSAssert(presentingViewController != nil, - @"presentingViewController cannot be nil on iOS 13"); -#endif // __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 - _presentingViewController = presentingViewController; } return self; @@ -93,6 +94,38 @@ - (BOOL)presentExternalUserAgentRequest:(id)request return NO; } + if (!_presentingViewController) { + // Find presentingViewController + if (@available(iOS 13.0, *)) { + NSSet *scenes = + (NSSet *)[UIApplication sharedApplication].connectedScenes; + + NSMutableArray *windows = [NSMutableArray array]; + + for (UIWindowScene *scene in scenes) { + [windows addObjectsFromArray:scene.windows]; + } + + for (UIWindow *window in windows) { + if (window.isKeyWindow) { // False if calling before window appears + UIWindow *keyWindow = window; + _presentingViewController = keyWindow.rootViewController; + break; + } + } + } else { + // ≤ iOS 12.X + NSArray *windows = UIApplication.sharedApplication.windows; + NSPredicate *keyWindowPredicate = [NSPredicate predicateWithFormat:@"keyWindow == YES"]; + UIWindow *keyWindow = [windows filteredArrayUsingPredicate:keyWindowPredicate].firstObject; + _presentingViewController = keyWindow.rootViewController; + } + if (!_presentingViewController) { + // Unable to find a presentingViewController; perhaps because no window is key and visible + return NO; + } + } + _externalUserAgentFlowInProgress = YES; _session = session; BOOL openedUserAgent = NO; diff --git a/UnitTests/AppAuth/OIDExternUserAgentIOSTests.m b/UnitTests/AppAuth/OIDExternUserAgentIOSTests.m new file mode 100644 index 000000000..b9f273cae --- /dev/null +++ b/UnitTests/AppAuth/OIDExternUserAgentIOSTests.m @@ -0,0 +1,131 @@ +// +// OIDExternalUserAgentIOSTests.m +// +// +// Created by Matt Mathias on 1/11/23. +// + +#import + +#if SWIFT_PACKAGE +@import AppAuth; +@import AppAuthCore; +#else +#import "Source/AppAuth/iOS/OIDExternalUserAgentIOS.h" +#import "Source/AppAuthCore/OIDAuthorizationRequest.h" +#import "Source/AppAuthCore/OIDAuthorizationService.h" +#endif + +/*! @brief Test value for the @c clientID property. + */ +static NSString *const kTestClientID = @"ClientID"; + +/*! @brief Test value for the @c clientID property. + */ +static NSString *const kTestClientSecret = @"ClientSecret"; + +/*! @brief Test key for the @c additionalParameters property. + */ +static NSString *const kTestAdditionalParameterKey = @"A"; + +/*! @brief Test value for the @c additionalParameters property. + */ +static NSString *const kTestAdditionalParameterValue = @"1"; + +/*! @brief Test value for the @c scope property. + */ +static NSString *const kTestScope = @"Scope"; + +/*! @brief Test value for the @c scope property. + */ +static NSString *const kTestScopeA = @"ScopeA"; + +/*! @brief Test value for the @c redirectURL property. + */ +static NSString *const kTestRedirectURL = @"http://www.google.com/"; + +/*! @brief Test value for the @c state property. + */ +static NSString *const kTestState = @"State"; + +/*! @brief Test value for the @c responseType property. + */ +static NSString *const kTestResponseType = @"code"; + +/*! @brief Test value for the @c nonce property. + */ +static NSString *const kTestNonce = @"Nonce"; + +/*! @brief Test value for the @c codeVerifier property. + */ +static NSString *const kTestCodeVerifier = @"code verifier"; + +/*! @brief Test value for the @c authorizationEndpoint property. + */ +static NSString *const kInitializerTestAuthEndpoint = @"https://www.example.com/auth"; + +/*! @brief Test value for the @c tokenEndpoint property. + */ +static NSString *const kInitializerTestTokenEndpoint = @"https://www.example.com/token"; + +/*! @brief Test value for the @c tokenEndpoint property. + */ +static NSString *const kInitializerTestRegistrationEndpoint = + @"https://www.example.com/registration"; + +@interface OIDExternalUserAgentIOSTests : XCTestCase + +@end + +@implementation OIDExternalUserAgentIOSTests + +- (void)testThatPresentExternalUserAgentRequestReturnsNoWhenMissingPresentingViewController { + OIDExternalUserAgentIOS *userAgent = [[OIDExternalUserAgentIOS alloc] init]; + OIDAuthorizationRequest *authRequest = [[self class] authorizationRequestTestInstance]; + [OIDAuthorizationService presentAuthorizationRequest:authRequest externalUserAgent:userAgent callback:^(OIDAuthorizationResponse * _Nullable authorizationResponse, NSError * _Nullable error) { + XCTAssertNotNil(error); + XCTAssertEqual(error.code, OIDErrorCodeSafariOpenError); + XCTAssertEqualObjects(error.localizedDescription, @"Unable to open Safari."); + }]; +} + ++ (OIDAuthorizationRequest *)authorizationRequestTestInstance { + NSDictionary *additionalParameters = + @{ kTestAdditionalParameterKey : kTestAdditionalParameterValue }; + OIDServiceConfiguration *configuration = [[self class] serviceConfigurationTestInstance]; + OIDAuthorizationRequest *request = + [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration + clientId:kTestClientID + clientSecret:kTestClientSecret + scope:[OIDScopeUtilities scopesWithArray:@[ kTestScope, kTestScopeA ]] + redirectURL:[NSURL URLWithString:kTestRedirectURL] + responseType:kTestResponseType + state:kTestState + nonce:kTestNonce + codeVerifier:kTestCodeVerifier + codeChallenge:[[self class] codeChallenge] + codeChallengeMethod:[[self class] codeChallengeMethod] + additionalParameters:additionalParameters]; + return request; +} + ++ (OIDServiceConfiguration *)serviceConfigurationTestInstance { + NSURL *authEndpoint = [NSURL URLWithString:kInitializerTestAuthEndpoint]; + NSURL *tokenEndpoint = [NSURL URLWithString:kInitializerTestTokenEndpoint]; + NSURL *registrationEndpoint = [NSURL URLWithString:kInitializerTestRegistrationEndpoint]; + OIDServiceConfiguration *configuration = + [[OIDServiceConfiguration alloc] initWithAuthorizationEndpoint:authEndpoint + tokenEndpoint:tokenEndpoint + registrationEndpoint:registrationEndpoint]; + return configuration; +} + ++ (NSString *)codeChallenge { + return [OIDAuthorizationRequest codeChallengeS256ForVerifier:kTestCodeVerifier]; +} + ++ (NSString *)codeChallengeMethod { + return OIDOAuthorizationRequestCodeChallengeMethodS256; +} + +@end diff --git a/UnitTests/OIDAppAuthTests-Bridging-Header.h b/UnitTests/AppAuthCore/OIDAppAuthTests-Bridging-Header.h similarity index 100% rename from UnitTests/OIDAppAuthTests-Bridging-Header.h rename to UnitTests/AppAuthCore/OIDAppAuthTests-Bridging-Header.h diff --git a/UnitTests/OIDAuthStateTests.h b/UnitTests/AppAuthCore/OIDAuthStateTests.h similarity index 100% rename from UnitTests/OIDAuthStateTests.h rename to UnitTests/AppAuthCore/OIDAuthStateTests.h diff --git a/UnitTests/OIDAuthStateTests.m b/UnitTests/AppAuthCore/OIDAuthStateTests.m similarity index 100% rename from UnitTests/OIDAuthStateTests.m rename to UnitTests/AppAuthCore/OIDAuthStateTests.m diff --git a/UnitTests/OIDAuthorizationRequestTests.h b/UnitTests/AppAuthCore/OIDAuthorizationRequestTests.h similarity index 100% rename from UnitTests/OIDAuthorizationRequestTests.h rename to UnitTests/AppAuthCore/OIDAuthorizationRequestTests.h diff --git a/UnitTests/OIDAuthorizationRequestTests.m b/UnitTests/AppAuthCore/OIDAuthorizationRequestTests.m similarity index 100% rename from UnitTests/OIDAuthorizationRequestTests.m rename to UnitTests/AppAuthCore/OIDAuthorizationRequestTests.m diff --git a/UnitTests/OIDAuthorizationResponseTests.h b/UnitTests/AppAuthCore/OIDAuthorizationResponseTests.h similarity index 100% rename from UnitTests/OIDAuthorizationResponseTests.h rename to UnitTests/AppAuthCore/OIDAuthorizationResponseTests.h diff --git a/UnitTests/OIDAuthorizationResponseTests.m b/UnitTests/AppAuthCore/OIDAuthorizationResponseTests.m similarity index 100% rename from UnitTests/OIDAuthorizationResponseTests.m rename to UnitTests/AppAuthCore/OIDAuthorizationResponseTests.m diff --git a/UnitTests/OIDEndSessionRequestTests.h b/UnitTests/AppAuthCore/OIDEndSessionRequestTests.h similarity index 100% rename from UnitTests/OIDEndSessionRequestTests.h rename to UnitTests/AppAuthCore/OIDEndSessionRequestTests.h diff --git a/UnitTests/OIDEndSessionRequestTests.m b/UnitTests/AppAuthCore/OIDEndSessionRequestTests.m similarity index 100% rename from UnitTests/OIDEndSessionRequestTests.m rename to UnitTests/AppAuthCore/OIDEndSessionRequestTests.m diff --git a/UnitTests/OIDGrantTypesTests.m b/UnitTests/AppAuthCore/OIDGrantTypesTests.m similarity index 100% rename from UnitTests/OIDGrantTypesTests.m rename to UnitTests/AppAuthCore/OIDGrantTypesTests.m diff --git a/UnitTests/OIDRPProfileCode.h b/UnitTests/AppAuthCore/OIDRPProfileCode.h similarity index 100% rename from UnitTests/OIDRPProfileCode.h rename to UnitTests/AppAuthCore/OIDRPProfileCode.h diff --git a/UnitTests/OIDRPProfileCode.m b/UnitTests/AppAuthCore/OIDRPProfileCode.m similarity index 100% rename from UnitTests/OIDRPProfileCode.m rename to UnitTests/AppAuthCore/OIDRPProfileCode.m diff --git a/UnitTests/OIDRegistrationRequestTests.h b/UnitTests/AppAuthCore/OIDRegistrationRequestTests.h similarity index 100% rename from UnitTests/OIDRegistrationRequestTests.h rename to UnitTests/AppAuthCore/OIDRegistrationRequestTests.h diff --git a/UnitTests/OIDRegistrationRequestTests.m b/UnitTests/AppAuthCore/OIDRegistrationRequestTests.m similarity index 100% rename from UnitTests/OIDRegistrationRequestTests.m rename to UnitTests/AppAuthCore/OIDRegistrationRequestTests.m diff --git a/UnitTests/OIDRegistrationResponseTests.h b/UnitTests/AppAuthCore/OIDRegistrationResponseTests.h similarity index 100% rename from UnitTests/OIDRegistrationResponseTests.h rename to UnitTests/AppAuthCore/OIDRegistrationResponseTests.h diff --git a/UnitTests/OIDRegistrationResponseTests.m b/UnitTests/AppAuthCore/OIDRegistrationResponseTests.m similarity index 100% rename from UnitTests/OIDRegistrationResponseTests.m rename to UnitTests/AppAuthCore/OIDRegistrationResponseTests.m diff --git a/UnitTests/OIDResponseTypesTests.m b/UnitTests/AppAuthCore/OIDResponseTypesTests.m similarity index 100% rename from UnitTests/OIDResponseTypesTests.m rename to UnitTests/AppAuthCore/OIDResponseTypesTests.m diff --git a/UnitTests/OIDScopesTests.m b/UnitTests/AppAuthCore/OIDScopesTests.m similarity index 100% rename from UnitTests/OIDScopesTests.m rename to UnitTests/AppAuthCore/OIDScopesTests.m diff --git a/UnitTests/OIDServiceConfigurationTests.h b/UnitTests/AppAuthCore/OIDServiceConfigurationTests.h similarity index 100% rename from UnitTests/OIDServiceConfigurationTests.h rename to UnitTests/AppAuthCore/OIDServiceConfigurationTests.h diff --git a/UnitTests/OIDServiceConfigurationTests.m b/UnitTests/AppAuthCore/OIDServiceConfigurationTests.m similarity index 100% rename from UnitTests/OIDServiceConfigurationTests.m rename to UnitTests/AppAuthCore/OIDServiceConfigurationTests.m diff --git a/UnitTests/OIDServiceDiscoveryTests.h b/UnitTests/AppAuthCore/OIDServiceDiscoveryTests.h similarity index 100% rename from UnitTests/OIDServiceDiscoveryTests.h rename to UnitTests/AppAuthCore/OIDServiceDiscoveryTests.h diff --git a/UnitTests/OIDServiceDiscoveryTests.m b/UnitTests/AppAuthCore/OIDServiceDiscoveryTests.m similarity index 100% rename from UnitTests/OIDServiceDiscoveryTests.m rename to UnitTests/AppAuthCore/OIDServiceDiscoveryTests.m diff --git a/UnitTests/OIDSwiftTests.swift b/UnitTests/AppAuthCore/OIDSwiftTests.swift similarity index 100% rename from UnitTests/OIDSwiftTests.swift rename to UnitTests/AppAuthCore/OIDSwiftTests.swift diff --git a/UnitTests/OIDTokenRequestTests.h b/UnitTests/AppAuthCore/OIDTokenRequestTests.h similarity index 100% rename from UnitTests/OIDTokenRequestTests.h rename to UnitTests/AppAuthCore/OIDTokenRequestTests.h diff --git a/UnitTests/OIDTokenRequestTests.m b/UnitTests/AppAuthCore/OIDTokenRequestTests.m similarity index 100% rename from UnitTests/OIDTokenRequestTests.m rename to UnitTests/AppAuthCore/OIDTokenRequestTests.m diff --git a/UnitTests/OIDTokenResponseTests.h b/UnitTests/AppAuthCore/OIDTokenResponseTests.h similarity index 100% rename from UnitTests/OIDTokenResponseTests.h rename to UnitTests/AppAuthCore/OIDTokenResponseTests.h diff --git a/UnitTests/OIDTokenResponseTests.m b/UnitTests/AppAuthCore/OIDTokenResponseTests.m similarity index 100% rename from UnitTests/OIDTokenResponseTests.m rename to UnitTests/AppAuthCore/OIDTokenResponseTests.m diff --git a/UnitTests/OIDTokenUtilitiesTests.m b/UnitTests/AppAuthCore/OIDTokenUtilitiesTests.m similarity index 100% rename from UnitTests/OIDTokenUtilitiesTests.m rename to UnitTests/AppAuthCore/OIDTokenUtilitiesTests.m diff --git a/UnitTests/OIDURLQueryComponentTests.h b/UnitTests/AppAuthCore/OIDURLQueryComponentTests.h similarity index 100% rename from UnitTests/OIDURLQueryComponentTests.h rename to UnitTests/AppAuthCore/OIDURLQueryComponentTests.h diff --git a/UnitTests/OIDURLQueryComponentTests.m b/UnitTests/AppAuthCore/OIDURLQueryComponentTests.m similarity index 100% rename from UnitTests/OIDURLQueryComponentTests.m rename to UnitTests/AppAuthCore/OIDURLQueryComponentTests.m diff --git a/UnitTests/OIDURLQueryComponentTestsIOS7.m b/UnitTests/AppAuthCore/OIDURLQueryComponentTestsIOS7.m similarity index 100% rename from UnitTests/OIDURLQueryComponentTestsIOS7.m rename to UnitTests/AppAuthCore/OIDURLQueryComponentTestsIOS7.m diff --git a/UnitTests/OIDURLSessionProviderTests.m b/UnitTests/AppAuthCore/OIDURLSessionProviderTests.m similarity index 100% rename from UnitTests/OIDURLSessionProviderTests.m rename to UnitTests/AppAuthCore/OIDURLSessionProviderTests.m From 68405555a53543eaa9c21f66db6552768d8be9df Mon Sep 17 00:00:00 2001 From: Matthew Mathias Date: Wed, 11 Jan 2023 17:29:37 -0800 Subject: [PATCH 2/7] Share test helper code --- Package.swift | 14 +- .../AppAuth/OIDExternUserAgentIOSTests.m | 132 ++++-------------- .../OIDAuthorizationRequestTests.h | 4 - .../OIDAuthorizationRequestTests.m | 88 ++---------- .../OIDAuthorizationResponseTests.m | 20 +-- .../AppAuthCore/OIDRegistrationRequestTests.m | 16 +-- .../OIDServiceConfigurationTests.h | 35 ----- .../OIDServiceConfigurationTests.m | 24 +--- UnitTests/AppAuthCore/OIDTokenRequestTests.m | 2 - .../OIDAuthorizationRequest+TestHelper.h | 73 ++++++++++ .../OIDAuthorizationRequest+TestHelper.m | 65 +++++++++ .../OIDServiceConfiguration+TestHelper.h | 29 ++++ .../OIDServiceConfiguration+TestHelper.m | 47 +++++++ 13 files changed, 275 insertions(+), 274 deletions(-) delete mode 100644 UnitTests/AppAuthCore/OIDServiceConfigurationTests.h create mode 100644 UnitTests/Helpers/OIDAuthorizationRequest+TestHelper.h create mode 100644 UnitTests/Helpers/OIDAuthorizationRequest+TestHelper.m create mode 100644 UnitTests/Helpers/OIDServiceConfiguration+TestHelper.h create mode 100644 UnitTests/Helpers/OIDServiceConfiguration+TestHelper.m diff --git a/Package.swift b/Package.swift index 2ae8a710e..4fc0a2fa0 100644 --- a/Package.swift +++ b/Package.swift @@ -64,15 +64,21 @@ let package = Package( path: "Source/AppAuthTV", publicHeadersPath: "" ), + .target( + name: "TestHelpers", + dependencies: ["AppAuthCore"], + path: "UnitTests/Helpers", + publicHeadersPath: "" + ), .testTarget( name: "AppAuthCoreTests", - dependencies: ["AppAuthCore"], + dependencies: ["AppAuthCore", "TestHelpers"], path: "UnitTests/AppAuthCore", - exclude: ["OIDSwiftTests.swift", "AppAuthTV"] + exclude: ["OIDSwiftTests.swift"] ), .testTarget( name: "AppAuthTests", - dependencies: ["AppAuth", "AppAuthCore"], + dependencies: ["AppAuth", "TestHelpers"], path: "UnitTests/AppAuth" ), .testTarget( @@ -85,6 +91,6 @@ let package = Package( name: "AppAuthTVTests", dependencies: ["AppAuthTV"], path: "UnitTests/AppAuthTV" - ), + ) ] ) diff --git a/UnitTests/AppAuth/OIDExternUserAgentIOSTests.m b/UnitTests/AppAuth/OIDExternUserAgentIOSTests.m index b9f273cae..a2b049f71 100644 --- a/UnitTests/AppAuth/OIDExternUserAgentIOSTests.m +++ b/UnitTests/AppAuth/OIDExternUserAgentIOSTests.m @@ -1,78 +1,31 @@ -// -// OIDExternalUserAgentIOSTests.m -// -// -// Created by Matt Mathias on 1/11/23. -// +/*! @file OIDExternalUserAgentIOSTests.m + @brief AppAuth iOS SDK + @copyright + Copyright 2023 The AppAuth Authors. All Rights Reserved. + @copydetails + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ #import #if SWIFT_PACKAGE @import AppAuth; -@import AppAuthCore; +@import TestHelpers; #else #import "Source/AppAuth/iOS/OIDExternalUserAgentIOS.h" -#import "Source/AppAuthCore/OIDAuthorizationRequest.h" -#import "Source/AppAuthCore/OIDAuthorizationService.h" +#import "UnitTests/TestHelpers/OIDAuthorizationRequest+TestHelper.h" #endif -/*! @brief Test value for the @c clientID property. - */ -static NSString *const kTestClientID = @"ClientID"; - -/*! @brief Test value for the @c clientID property. - */ -static NSString *const kTestClientSecret = @"ClientSecret"; - -/*! @brief Test key for the @c additionalParameters property. - */ -static NSString *const kTestAdditionalParameterKey = @"A"; - -/*! @brief Test value for the @c additionalParameters property. - */ -static NSString *const kTestAdditionalParameterValue = @"1"; - -/*! @brief Test value for the @c scope property. - */ -static NSString *const kTestScope = @"Scope"; - -/*! @brief Test value for the @c scope property. - */ -static NSString *const kTestScopeA = @"ScopeA"; - -/*! @brief Test value for the @c redirectURL property. - */ -static NSString *const kTestRedirectURL = @"http://www.google.com/"; - -/*! @brief Test value for the @c state property. - */ -static NSString *const kTestState = @"State"; - -/*! @brief Test value for the @c responseType property. - */ -static NSString *const kTestResponseType = @"code"; - -/*! @brief Test value for the @c nonce property. - */ -static NSString *const kTestNonce = @"Nonce"; - -/*! @brief Test value for the @c codeVerifier property. - */ -static NSString *const kTestCodeVerifier = @"code verifier"; - -/*! @brief Test value for the @c authorizationEndpoint property. - */ -static NSString *const kInitializerTestAuthEndpoint = @"https://www.example.com/auth"; - -/*! @brief Test value for the @c tokenEndpoint property. - */ -static NSString *const kInitializerTestTokenEndpoint = @"https://www.example.com/token"; - -/*! @brief Test value for the @c tokenEndpoint property. - */ -static NSString *const kInitializerTestRegistrationEndpoint = - @"https://www.example.com/registration"; - @interface OIDExternalUserAgentIOSTests : XCTestCase @end @@ -81,51 +34,16 @@ @implementation OIDExternalUserAgentIOSTests - (void)testThatPresentExternalUserAgentRequestReturnsNoWhenMissingPresentingViewController { OIDExternalUserAgentIOS *userAgent = [[OIDExternalUserAgentIOS alloc] init]; - OIDAuthorizationRequest *authRequest = [[self class] authorizationRequestTestInstance]; - [OIDAuthorizationService presentAuthorizationRequest:authRequest externalUserAgent:userAgent callback:^(OIDAuthorizationResponse * _Nullable authorizationResponse, NSError * _Nullable error) { + OIDAuthorizationRequest *authRequest = [OIDAuthorizationRequest testInstance]; + [OIDAuthorizationService + presentAuthorizationRequest:authRequest + externalUserAgent:userAgent + callback:^(OIDAuthorizationResponse * _Nullable authorizationResponse, + NSError * _Nullable error) { XCTAssertNotNil(error); XCTAssertEqual(error.code, OIDErrorCodeSafariOpenError); XCTAssertEqualObjects(error.localizedDescription, @"Unable to open Safari."); }]; } -+ (OIDAuthorizationRequest *)authorizationRequestTestInstance { - NSDictionary *additionalParameters = - @{ kTestAdditionalParameterKey : kTestAdditionalParameterValue }; - OIDServiceConfiguration *configuration = [[self class] serviceConfigurationTestInstance]; - OIDAuthorizationRequest *request = - [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration - clientId:kTestClientID - clientSecret:kTestClientSecret - scope:[OIDScopeUtilities scopesWithArray:@[ kTestScope, kTestScopeA ]] - redirectURL:[NSURL URLWithString:kTestRedirectURL] - responseType:kTestResponseType - state:kTestState - nonce:kTestNonce - codeVerifier:kTestCodeVerifier - codeChallenge:[[self class] codeChallenge] - codeChallengeMethod:[[self class] codeChallengeMethod] - additionalParameters:additionalParameters]; - return request; -} - -+ (OIDServiceConfiguration *)serviceConfigurationTestInstance { - NSURL *authEndpoint = [NSURL URLWithString:kInitializerTestAuthEndpoint]; - NSURL *tokenEndpoint = [NSURL URLWithString:kInitializerTestTokenEndpoint]; - NSURL *registrationEndpoint = [NSURL URLWithString:kInitializerTestRegistrationEndpoint]; - OIDServiceConfiguration *configuration = - [[OIDServiceConfiguration alloc] initWithAuthorizationEndpoint:authEndpoint - tokenEndpoint:tokenEndpoint - registrationEndpoint:registrationEndpoint]; - return configuration; -} - -+ (NSString *)codeChallenge { - return [OIDAuthorizationRequest codeChallengeS256ForVerifier:kTestCodeVerifier]; -} - -+ (NSString *)codeChallengeMethod { - return OIDOAuthorizationRequestCodeChallengeMethodS256; -} - @end diff --git a/UnitTests/AppAuthCore/OIDAuthorizationRequestTests.h b/UnitTests/AppAuthCore/OIDAuthorizationRequestTests.h index db387d5b6..46b9a919c 100644 --- a/UnitTests/AppAuthCore/OIDAuthorizationRequestTests.h +++ b/UnitTests/AppAuthCore/OIDAuthorizationRequestTests.h @@ -26,10 +26,6 @@ NS_ASSUME_NONNULL_BEGIN */ @interface OIDAuthorizationRequestTests : XCTestCase -/*! @brief Creates a new @c OIDAuthorizationRequest for testing. - */ -+ (OIDAuthorizationRequest *)testInstance; - /*! @brief Creates a new @c OIDAuthorizationRequest testing a code flow request. */ + (OIDAuthorizationRequest *)testInstanceCodeFlow; diff --git a/UnitTests/AppAuthCore/OIDAuthorizationRequestTests.m b/UnitTests/AppAuthCore/OIDAuthorizationRequestTests.m index 06bfc6c13..c694008e9 100644 --- a/UnitTests/AppAuthCore/OIDAuthorizationRequestTests.m +++ b/UnitTests/AppAuthCore/OIDAuthorizationRequestTests.m @@ -18,14 +18,14 @@ #import "OIDAuthorizationRequestTests.h" -#import "OIDServiceConfigurationTests.h" - #if SWIFT_PACKAGE @import AppAuthCore; +@import TestHelpers; #else #import "Source/AppAuthCore/OIDAuthorizationRequest.h" #import "Source/AppAuthCore/OIDScopeUtilities.h" -#import "Source/AppAuthCore/OIDServiceConfiguration.h" +#import "UnitTests/TestHelpers/OIDServiceConfiguration+TestHelper.h" +#import "UnitTests/TestHelpers/OIDAuthorizationRequest+TestHelper.h" #endif // Ignore warnings about "Use of GNU statement expression extension" which is raised by our use of @@ -33,54 +33,10 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wgnu" -/*! @brief Test value for the @c responseType property. - */ -static NSString *const kTestResponseType = @"code"; - -/*! @brief Test value for the @c clientID property. - */ -static NSString *const kTestClientID = @"ClientID"; - -/*! @brief Test value for the @c clientID property. - */ -static NSString *const kTestClientSecret = @"ClientSecret"; - -/*! @brief Test value for the @c scope property. - */ -static NSString *const kTestScope = @"Scope"; - -/*! @brief Test value for the @c scope property. - */ -static NSString *const kTestScopeA = @"ScopeA"; - /*! @brief Test value for the @c scope property. */ static NSString *const kTestScopesMerged = @"Scope ScopeA"; -/*! @brief Test value for the @c redirectURL property. - */ -static NSString *const kTestRedirectURL = @"http://www.google.com/"; - -/*! @brief Test key for the @c additionalParameters property. - */ -static NSString *const kTestAdditionalParameterKey = @"A"; - -/*! @brief Test value for the @c additionalParameters property. - */ -static NSString *const kTestAdditionalParameterValue = @"1"; - -/*! @brief Test value for the @c state property. - */ -static NSString *const kTestState = @"State"; - -/*! @brief Test value for the @c nonce property. - */ -static NSString *const kTestNonce = @"Nonce"; - -/*! @brief Test value for the @c codeVerifier property. - */ -static NSString *const kTestCodeVerifier = @"code verifier"; - /*! @brief This test scope contains a character which is one character below the allowed character range. */ @@ -144,28 +100,8 @@ + (NSString *)codeChallengeMethod { return OIDOAuthorizationRequestCodeChallengeMethodS256; } -+ (OIDAuthorizationRequest *)testInstance { - NSDictionary *additionalParameters = - @{ kTestAdditionalParameterKey : kTestAdditionalParameterValue }; - OIDServiceConfiguration *configuration = [OIDServiceConfigurationTests testInstance]; - OIDAuthorizationRequest *request = - [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration - clientId:kTestClientID - clientSecret:kTestClientSecret - scope:[OIDScopeUtilities scopesWithArray:@[ kTestScope, kTestScopeA ]] - redirectURL:[NSURL URLWithString:kTestRedirectURL] - responseType:kTestResponseType - state:kTestState - nonce:kTestNonce - codeVerifier:kTestCodeVerifier - codeChallenge:[[self class] codeChallenge] - codeChallengeMethod:[[self class] codeChallengeMethod] - additionalParameters:additionalParameters]; - return request; -} - + (OIDAuthorizationRequest *)testInstanceCodeFlow { - OIDServiceConfiguration *configuration = [OIDServiceConfigurationTests testInstance]; + OIDServiceConfiguration *configuration = [OIDServiceConfiguration testInstance]; OIDAuthorizationRequest *request = [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration clientId:kTestClientID @@ -183,7 +119,7 @@ + (OIDAuthorizationRequest *)testInstanceCodeFlow { } + (OIDAuthorizationRequest *)testInstanceCodeFlowClientAuth { - OIDServiceConfiguration *configuration = [OIDServiceConfigurationTests testInstance]; + OIDServiceConfiguration *configuration = [OIDServiceConfiguration testInstance]; OIDAuthorizationRequest *request = [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration clientId:kTestClientID @@ -205,7 +141,7 @@ + (OIDAuthorizationRequest *)testInstanceCodeFlowClientAuth { - (void)testScopeInitializerWithManyScopesAndNoClientSecret { NSDictionary *additionalParameters = @{ kTestAdditionalParameterKey : kTestAdditionalParameterValue }; - OIDServiceConfiguration *configuration = [OIDServiceConfigurationTests testInstance]; + OIDServiceConfiguration *configuration = [OIDServiceConfiguration testInstance]; OIDAuthorizationRequest *request = [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration clientId:kTestClientID @@ -226,7 +162,7 @@ - (void)testScopeInitializerWithManyScopesAndNoClientSecret { - (void)testScopeInitializerWithManyScopesAndClientSecret { NSDictionary *additionalParameters = @{ kTestAdditionalParameterKey : kTestAdditionalParameterValue }; - OIDServiceConfiguration *configuration = [OIDServiceConfigurationTests testInstance]; + OIDServiceConfiguration *configuration = [OIDServiceConfiguration testInstance]; OIDAuthorizationRequest *request = [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration clientId:kTestClientID @@ -249,7 +185,7 @@ - (void)testScopeInitializerWithManyScopesAndClientSecret { process and checking to make sure the source and destination instances are equivalent. */ - (void)testCopying { - OIDAuthorizationRequest *request = [[self class] testInstance]; + OIDAuthorizationRequest *request = [OIDAuthorizationRequest testInstance]; XCTAssertEqualObjects(request.responseType, kTestResponseType, @""); XCTAssertEqualObjects(request.scope, kTestScopesMerged, @""); @@ -285,7 +221,7 @@ - (void)testCopying { checking to make sure the source and destination instances are equivalent. */ - (void)testSecureCoding { - OIDAuthorizationRequest *request = [[self class] testInstance]; + OIDAuthorizationRequest *request = [OIDAuthorizationRequest testInstance]; XCTAssertEqualObjects(request.responseType, kTestResponseType, @""); XCTAssertEqualObjects(request.scope, kTestScopesMerged, @""); @@ -327,7 +263,7 @@ - (void)testSecureCoding { */ - (void)testDisallowedCharactersInScopes { NSURL *redirectURL = [NSURL URLWithString:kTestRedirectURL]; - OIDServiceConfiguration *configuration = [OIDServiceConfigurationTests testInstance]; + OIDServiceConfiguration *configuration = [OIDServiceConfiguration testInstance]; XCTAssertThrows( [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration clientId:kTestClientID @@ -441,7 +377,7 @@ - (void)testPKCEVerifierRecommendations { - (void)testSupportedResponseTypes { NSDictionary *additionalParameters = @{ kTestAdditionalParameterKey : kTestAdditionalParameterValue }; - OIDServiceConfiguration *configuration = [OIDServiceConfigurationTests testInstance]; + OIDServiceConfiguration *configuration = [OIDServiceConfiguration testInstance]; NSString *scope = [OIDScopeUtilities scopesWithArray:@[ kTestScope, kTestScopeA ]]; @@ -524,7 +460,7 @@ - (void)testSupportedResponseTypes { } - (void)testExternalUserAgentMethods { - OIDAuthorizationRequest *request = [[self class] testInstance]; + OIDAuthorizationRequest *request = [OIDAuthorizationRequest testInstance]; XCTAssertEqualObjects([request externalUserAgentRequestURL], [request authorizationRequestURL]); XCTAssert([[request redirectScheme] isEqualToString:request.redirectURL.scheme]); } diff --git a/UnitTests/AppAuthCore/OIDAuthorizationResponseTests.m b/UnitTests/AppAuthCore/OIDAuthorizationResponseTests.m index 10e48eaa8..c43e3f44f 100644 --- a/UnitTests/AppAuthCore/OIDAuthorizationResponseTests.m +++ b/UnitTests/AppAuthCore/OIDAuthorizationResponseTests.m @@ -22,10 +22,12 @@ #if SWIFT_PACKAGE @import AppAuthCore; +@import TestHelpers; #else #import "Source/AppAuthCore/OIDAuthorizationRequest.h" #import "Source/AppAuthCore/OIDAuthorizationResponse.h" #import "Source/AppAuthCore/OIDGrantTypes.h" +#import "UnitTests/TestHelpers/OIDAuthorizationRequest+TestHelper.h" #endif // Ignore warnings about "Use of GNU statement expression extension" which is raised by our use of @@ -41,18 +43,6 @@ */ static NSString *const kTestAuthorizationCodeVerifier = @"Verifier"; -/*! @brief Test key for the @c additionalParameters property. - */ -static NSString *const kTestAdditionalParameterKey = @"A"; - -/*! @brief Test value for the @c additionalParameters property. - */ -static NSString *const kTestAdditionalParameterValue = @"1"; - -/*! @brief Test value for the @c state property. - */ -static NSString *const kTestState = @"State"; - /*! @brief Test value for the @c accessToken property. */ static NSString *const kTestAccessToken = @"Access Token"; @@ -69,14 +59,10 @@ */ static NSString *const kTestTokenType = @"Token Type"; -/*! @brief Test value for the @c scopes property. - */ -static NSString *const kTestScope = @"Scope"; - @implementation OIDAuthorizationResponseTests + (OIDAuthorizationResponse *)testInstance { - OIDAuthorizationRequest *request = [OIDAuthorizationRequestTests testInstance]; + OIDAuthorizationRequest *request = [OIDAuthorizationRequest testInstance]; OIDAuthorizationResponse *response = [[OIDAuthorizationResponse alloc] initWithRequest:request parameters:@{ @"code" : kTestAuthorizationCode, diff --git a/UnitTests/AppAuthCore/OIDRegistrationRequestTests.m b/UnitTests/AppAuthCore/OIDRegistrationRequestTests.m index 5fbbd585e..d4a5853c9 100644 --- a/UnitTests/AppAuthCore/OIDRegistrationRequestTests.m +++ b/UnitTests/AppAuthCore/OIDRegistrationRequestTests.m @@ -18,24 +18,16 @@ #import "OIDRegistrationRequestTests.h" -#import "OIDServiceConfigurationTests.h" - #if SWIFT_PACKAGE @import AppAuthCore; +@import TestHelpers; #else #import "Source/AppAuthCore/OIDClientMetadataParameters.h" #import "Source/AppAuthCore/OIDRegistrationRequest.h" -#import "Source/AppAuthCore/OIDServiceConfiguration.h" +#import "UnitTests/Helpers/OIDAuthorizationRequest+TestHelper.h" +#import "UnitTests/Helpers/OIDServiceConfiguration+TestHelper.h" #endif -/*! @brief Test key for the @c additionalParameters property. - */ -static NSString *const kTestAdditionalParameterKey = @"A"; - -/*! @brief Test value for the @c additionalParameters property. - */ -static NSString *const kTestAdditionalParameterValue = @"1"; - /*! @brief Test value for the @c initialAccessToken property. */ static NSString *const kInitialAccessTokenTestValue = @"test"; @@ -67,7 +59,7 @@ + (OIDRegistrationRequest *)testInstance { kTestAdditionalParameterKey : kTestAdditionalParameterValue }; - OIDServiceConfiguration *config = [OIDServiceConfigurationTests testInstance]; + OIDServiceConfiguration *config = [OIDServiceConfiguration testInstance]; OIDRegistrationRequest *request = [[OIDRegistrationRequest alloc] initWithConfiguration:config redirectURIs:@[ [NSURL URLWithString:kRedirectURLTestValue] ] diff --git a/UnitTests/AppAuthCore/OIDServiceConfigurationTests.h b/UnitTests/AppAuthCore/OIDServiceConfigurationTests.h deleted file mode 100644 index 982db2b5b..000000000 --- a/UnitTests/AppAuthCore/OIDServiceConfigurationTests.h +++ /dev/null @@ -1,35 +0,0 @@ -/*! @file OIDServiceConfigurationTests.h - @brief AppAuth iOS SDK - @copyright - Copyright 2015 Google Inc. All Rights Reserved. - @copydetails - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#import - -@class OIDServiceConfiguration; - -NS_ASSUME_NONNULL_BEGIN - -/*! @brief Unit tests for @c OIDServiceConfiguration. - */ -@interface OIDServiceConfigurationTests : XCTestCase - -/*! @brief Creates a new @c OIDServiceConfiguration for testing. - */ -+ (OIDServiceConfiguration *)testInstance; - -@end - -NS_ASSUME_NONNULL_END diff --git a/UnitTests/AppAuthCore/OIDServiceConfigurationTests.m b/UnitTests/AppAuthCore/OIDServiceConfigurationTests.m index 3be785e60..53cef0639 100644 --- a/UnitTests/AppAuthCore/OIDServiceConfigurationTests.m +++ b/UnitTests/AppAuthCore/OIDServiceConfigurationTests.m @@ -16,19 +16,18 @@ limitations under the License. */ -#import "OIDServiceConfigurationTests.h" - #import #import "OIDServiceDiscoveryTests.h" #if SWIFT_PACKAGE @import AppAuthCore; +@import TestHelpers; #else #import "Source/AppAuthCore/OIDAuthorizationService.h" #import "Source/AppAuthCore/OIDError.h" -#import "Source/AppAuthCore/OIDServiceConfiguration.h" #import "Source/AppAuthCore/OIDServiceDiscovery.h" +#import "UnitTests/Helpers/OIDServiceConfiguration+TestHelper.h" #endif // Ignore warnings about "Use of GNU statement expression extension" which is raised by our use of @@ -85,6 +84,8 @@ typedef void(^DataTaskWithURLCompletionHandler)(NSData *_Nullable data, static NSString *const kIssuerTestExpectedFullDiscoveryURL = @"https://accounts.google.com/.well-known/openid-configuration"; +@interface OIDServiceConfigurationTests : XCTestCase +@end @implementation OIDServiceConfigurationTests { /*! @brief A list of tasks to perform during tearDown. @@ -92,17 +93,6 @@ @implementation OIDServiceConfigurationTests { NSMutableArray *_teardownTasks; } -+ (OIDServiceConfiguration *)testInstance { - NSURL *authEndpoint = [NSURL URLWithString:kInitializerTestAuthEndpoint]; - NSURL *tokenEndpoint = [NSURL URLWithString:kInitializerTestTokenEndpoint]; - NSURL *registrationEndpoint = [NSURL URLWithString:kInitializerTestRegistrationEndpoint]; - OIDServiceConfiguration *configuration = - [[OIDServiceConfiguration alloc] initWithAuthorizationEndpoint:authEndpoint - tokenEndpoint:tokenEndpoint - registrationEndpoint:registrationEndpoint]; - return configuration; -} - - (void)setUp { _teardownTasks = [NSMutableArray array]; } @@ -155,7 +145,7 @@ - (void)replaceClassMethodForClass:(Class)class selector:(SEL)selector withBlock /*! @brief Tests the designated initializer. */ - (void)testInitializer { - OIDServiceConfiguration *configuration = [[self class] testInstance]; + OIDServiceConfiguration *configuration = [OIDServiceConfiguration testInstance]; XCTAssertEqualObjects(configuration.authorizationEndpoint.absoluteString, kInitializerTestAuthEndpoint, @""); XCTAssertEqualObjects(configuration.tokenEndpoint.absoluteString, @@ -362,7 +352,7 @@ - (void)testFetcherWithBadJSON { checking to make sure the source and destination instances have equivalent dictionaries. */ - (void)testSecureCoding { - OIDServiceConfiguration *configuration = [[self class] testInstance]; + OIDServiceConfiguration *configuration = [OIDServiceConfiguration testInstance]; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:configuration]; OIDServiceConfiguration *unarchived = [NSKeyedUnarchiver unarchiveObjectWithData:data]; @@ -376,7 +366,7 @@ - (void)testSecureCoding { dictionaries. */ - (void)testCopying { - OIDServiceConfiguration *configuration = [[self class] testInstance]; + OIDServiceConfiguration *configuration = [OIDServiceConfiguration testInstance]; OIDServiceConfiguration *unarchived = [configuration copy]; XCTAssertEqualObjects(configuration.authorizationEndpoint, unarchived.authorizationEndpoint, @""); diff --git a/UnitTests/AppAuthCore/OIDTokenRequestTests.m b/UnitTests/AppAuthCore/OIDTokenRequestTests.m index 4211ef70a..0e65c4bb7 100644 --- a/UnitTests/AppAuthCore/OIDTokenRequestTests.m +++ b/UnitTests/AppAuthCore/OIDTokenRequestTests.m @@ -19,7 +19,6 @@ #import "OIDTokenRequestTests.h" #import "OIDAuthorizationResponseTests.h" -#import "OIDServiceConfigurationTests.h" #if SWIFT_PACKAGE @import AppAuthCore; @@ -27,7 +26,6 @@ #import "Source/AppAuthCore/OIDAuthorizationRequest.h" #import "Source/AppAuthCore/OIDAuthorizationResponse.h" #import "Source/AppAuthCore/OIDScopeUtilities.h" -#import "Source/AppAuthCore/OIDServiceConfiguration.h" #import "Source/AppAuthCore/OIDTokenRequest.h" #endif diff --git a/UnitTests/Helpers/OIDAuthorizationRequest+TestHelper.h b/UnitTests/Helpers/OIDAuthorizationRequest+TestHelper.h new file mode 100644 index 000000000..df4cc0f10 --- /dev/null +++ b/UnitTests/Helpers/OIDAuthorizationRequest+TestHelper.h @@ -0,0 +1,73 @@ +/*! @file OIDAuthorizationRequestion+TestHelper.h + @brief AppAuth iOS SDK + @copyright + Copyright 2023 The AppAuth Authors. All Rights Reserved. + @copydetails + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#import "OIDAuthorizationRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/*! @brief Test value for the @c clientID property. + */ +extern NSString *const kTestClientID; + +/*! @brief Test value for the @c clientID property. + */ +extern NSString *const kTestClientSecret; + +/*! @brief Test key for the @c additionalParameters property. + */ +extern NSString *const kTestAdditionalParameterKey; + +/*! @brief Test value for the @c additionalParameters property. + */ +extern NSString *const kTestAdditionalParameterValue; + +/*! @brief Test value for the @c scope property. + */ +extern NSString *const kTestScope; + +/*! @brief Test value for the @c scope property. + */ +extern NSString *const kTestScopeA; + +/*! @brief Test value for the @c redirectURL property. + */ +extern NSString *const kTestRedirectURL; + +/*! @brief Test value for the @c state property. + */ +extern NSString *const kTestState; + +/*! @brief Test value for the @c responseType property. + */ +extern NSString *const kTestResponseType; + +/*! @brief Test value for the @c nonce property. + */ +extern NSString *const kTestNonce; + +/*! @brief Test value for the @c codeVerifier property. + */ +extern NSString *const kTestCodeVerifier; + +@interface OIDAuthorizationRequest (TestHelper) + ++ (OIDAuthorizationRequest *)testInstance; + +@end + +NS_ASSUME_NONNULL_END diff --git a/UnitTests/Helpers/OIDAuthorizationRequest+TestHelper.m b/UnitTests/Helpers/OIDAuthorizationRequest+TestHelper.m new file mode 100644 index 000000000..d55b2fad1 --- /dev/null +++ b/UnitTests/Helpers/OIDAuthorizationRequest+TestHelper.m @@ -0,0 +1,65 @@ +/*! @file OIDAuthorizationRequestion+TestHelper.m + @brief AppAuth iOS SDK + @copyright + Copyright 2023 The AppAuth Authors. All Rights Reserved. + @copydetails + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#import "OIDAuthorizationRequest+TestHelper.h" +#import "OIDServiceConfiguration+TestHelper.h" + +NSString *const kTestClientID = @"ClientID"; +NSString *const kTestClientSecret = @"ClientSecret"; +NSString *const kTestAdditionalParameterKey = @"A"; +NSString *const kTestAdditionalParameterValue = @"1"; +NSString *const kTestScope = @"Scope"; +NSString *const kTestScopeA = @"ScopeA"; +NSString *const kTestRedirectURL = @"http://www.google.com/"; +NSString *const kTestState = @"State"; +NSString *const kTestResponseType = @"code"; +NSString *const kTestNonce = @"Nonce"; +NSString *const kTestCodeVerifier = @"code verifier"; + +@implementation OIDAuthorizationRequest (TestHelper) + ++ (OIDAuthorizationRequest *)testInstance { + NSDictionary *additionalParameters = + @{ kTestAdditionalParameterKey : kTestAdditionalParameterValue }; + OIDServiceConfiguration *configuration = [OIDServiceConfiguration testInstance]; + OIDAuthorizationRequest *request = + [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration + clientId:kTestClientID + clientSecret:kTestClientSecret + scope:[OIDScopeUtilities scopesWithArray: + @[ kTestScope, kTestScopeA ]] + redirectURL:[NSURL URLWithString:kTestRedirectURL] + responseType:kTestResponseType + state:kTestState + nonce:kTestNonce + codeVerifier:kTestCodeVerifier + codeChallenge:[[self class] codeChallenge] + codeChallengeMethod:[[self class] codeChallengeMethod] + additionalParameters:additionalParameters]; + return request; +} + ++ (NSString *)codeChallenge { + return [OIDAuthorizationRequest codeChallengeS256ForVerifier:kTestCodeVerifier]; +} + ++ (NSString *)codeChallengeMethod { + return OIDOAuthorizationRequestCodeChallengeMethodS256; +} + +@end diff --git a/UnitTests/Helpers/OIDServiceConfiguration+TestHelper.h b/UnitTests/Helpers/OIDServiceConfiguration+TestHelper.h new file mode 100644 index 000000000..6def600ea --- /dev/null +++ b/UnitTests/Helpers/OIDServiceConfiguration+TestHelper.h @@ -0,0 +1,29 @@ +/*! @file OIDServiceConfiguration+TestHelper.h + @brief AppAuth iOS SDK + @copyright + Copyright 2023 The AppAuth Authors. All Rights Reserved. + @copydetails + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#import "OIDServiceConfiguration.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface OIDServiceConfiguration (TestHelper) + ++ (OIDServiceConfiguration *)testInstance; + +@end + +NS_ASSUME_NONNULL_END diff --git a/UnitTests/Helpers/OIDServiceConfiguration+TestHelper.m b/UnitTests/Helpers/OIDServiceConfiguration+TestHelper.m new file mode 100644 index 000000000..e0cee78ee --- /dev/null +++ b/UnitTests/Helpers/OIDServiceConfiguration+TestHelper.m @@ -0,0 +1,47 @@ +/*! @file OIDServiceConfiguration+TestHelper.m + @brief AppAuth iOS SDK + @copyright + Copyright 2023 The AppAuth Authors. All Rights Reserved. + @copydetails + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#import "OIDServiceConfiguration+TestHelper.h" + +/*! @brief Test value for the @c authorizationEndpoint property. + */ +static NSString *const kInitializerTestAuthEndpoint = @"https://www.example.com/auth"; + +/*! @brief Test value for the @c tokenEndpoint property. + */ +static NSString *const kInitializerTestTokenEndpoint = @"https://www.example.com/token"; + +/*! @brief Test value for the @c tokenEndpoint property. + */ +static NSString *const kInitializerTestRegistrationEndpoint = + @"https://www.example.com/registration"; + +@implementation OIDServiceConfiguration (TestHelper) + ++ (OIDServiceConfiguration *)testInstance { + NSURL *authEndpoint = [NSURL URLWithString:kInitializerTestAuthEndpoint]; + NSURL *tokenEndpoint = [NSURL URLWithString:kInitializerTestTokenEndpoint]; + NSURL *registrationEndpoint = [NSURL URLWithString:kInitializerTestRegistrationEndpoint]; + OIDServiceConfiguration *configuration = + [[OIDServiceConfiguration alloc] initWithAuthorizationEndpoint:authEndpoint + tokenEndpoint:tokenEndpoint + registrationEndpoint:registrationEndpoint]; + return configuration; +} + +@end From c0a0f1c291efa6dc444404be4f2bdda20a4059e0 Mon Sep 17 00:00:00 2001 From: Matthew Mathias Date: Wed, 11 Jan 2023 18:00:36 -0800 Subject: [PATCH 3/7] Consolidate prefersEphemeralSession availability check --- .../AppAuth/iOS/OIDAuthorizationService+IOS.m | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Source/AppAuth/iOS/OIDAuthorizationService+IOS.m b/Source/AppAuth/iOS/OIDAuthorizationService+IOS.m index a7a09ad6b..3e1b504d5 100644 --- a/Source/AppAuth/iOS/OIDAuthorizationService+IOS.m +++ b/Source/AppAuth/iOS/OIDAuthorizationService+IOS.m @@ -60,21 +60,38 @@ @implementation OIDAuthorizationService (IOS) + (id)presentAuthorizationRequest:(OIDAuthorizationRequest *)request callback:(OIDAuthorizationCallback)callback { return [self presentAuthorizationRequest:request - prefersEphemeralSession:NO + prefersEphemeralSessionIfAvailable:NO callback:callback]; } + (id)presentAuthorizationRequest:(OIDAuthorizationRequest *)request prefersEphemeralSession:(BOOL)prefersEphemeralSession callback:(OIDAuthorizationCallback)callback { + return [self presentAuthorizationRequest:request + prefersEphemeralSessionIfAvailable:prefersEphemeralSession + callback:callback]; +} + ++ (id)presentAuthorizationRequest:(OIDAuthorizationRequest *)request + prefersEphemeralSessionIfAvailable:(BOOL)prefersEphemeralSession + callback:(OIDAuthorizationCallback)callback { id externalUserAgent; + + if (@available(iOS 13, *)) { #if TARGET_OS_MACCATALYST - externalUserAgent = [[OIDExternalUserAgentCatalyst alloc] - initWithPrefersEphemeralSession:prefersEphemeralSession]; + externalUserAgent = [[OIDExternalUserAgentCatalyst alloc] + initWithPrefersEphemeralSession:prefersEphemeralSession]; +#else // TARGET_OS_MACCATALYST + externalUserAgent = [[OIDExternalUserAgentIOS alloc] + initWithPrefersEphemeralSession:prefersEphemeralSession]; +#endif // TARGET_OS_MACCATALYST + } else { +#if TARGET_OS_MACCATALYST + externalUserAgent = [[OIDExternalUserAgentCatalyst alloc] init]; #else // TARGET_OS_MACCATALYST - externalUserAgent = [[OIDExternalUserAgentIOS alloc] - initWithPrefersEphemeralSession:prefersEphemeralSession]; + externalUserAgent = [[OIDExternalUserAgentIOS alloc] init]; #endif // TARGET_OS_MACCATALYST + } return [self presentAuthorizationRequest:request externalUserAgent:externalUserAgent callback:callback]; From 81598e8c7d7b3fe9cab0e1f1f78867e1cb911987 Mon Sep 17 00:00:00 2001 From: Matthew Mathias Date: Wed, 11 Jan 2023 18:11:19 -0800 Subject: [PATCH 4/7] Remove untracked swiftpm file --- .../xcode/package.xcworkspace/contents.xcworkspacedata | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - From 598b5f3f60a9bf69b6112e8a9a70a539ca0def03 Mon Sep 17 00:00:00 2001 From: Matthew Mathias Date: Wed, 11 Jan 2023 18:14:47 -0800 Subject: [PATCH 5/7] Import OIDError in test case --- UnitTests/AppAuth/OIDExternUserAgentIOSTests.m | 1 + 1 file changed, 1 insertion(+) diff --git a/UnitTests/AppAuth/OIDExternUserAgentIOSTests.m b/UnitTests/AppAuth/OIDExternUserAgentIOSTests.m index a2b049f71..572778787 100644 --- a/UnitTests/AppAuth/OIDExternUserAgentIOSTests.m +++ b/UnitTests/AppAuth/OIDExternUserAgentIOSTests.m @@ -23,6 +23,7 @@ @import TestHelpers; #else #import "Source/AppAuth/iOS/OIDExternalUserAgentIOS.h" +#import "Source/AppAuthCore/OIDError.h" #import "UnitTests/TestHelpers/OIDAuthorizationRequest+TestHelper.h" #endif From 2af25fd461650c564854f1eb09d630cc5decbc7f Mon Sep 17 00:00:00 2001 From: Matthew Mathias Date: Wed, 11 Jan 2023 18:35:26 -0800 Subject: [PATCH 6/7] Add no presenting vc auth flow support to mac catalyst external user agent Also updates the presentExternUserAgentRequest test to work for both iOS and catalyst --- .../iOS/OIDExternalUserAgentCatalyst.h | 21 ++++++--- .../iOS/OIDExternalUserAgentCatalyst.m | 47 ++++++++++++++++++- ...ntIOSTests.m => OIDExternUserAgentTests.m} | 18 +++++-- 3 files changed, 75 insertions(+), 11 deletions(-) rename UnitTests/AppAuth/{OIDExternUserAgentIOSTests.m => OIDExternUserAgentTests.m} (78%) diff --git a/Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.h b/Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.h index 910d0bb86..57ddcf472 100644 --- a/Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.h +++ b/Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.h @@ -32,18 +32,27 @@ NS_ASSUME_NONNULL_BEGIN API_AVAILABLE(macCatalyst(13)) API_UNAVAILABLE(ios) @interface OIDExternalUserAgentCatalyst : NSObject -/*! @internal - @brief Unavailable. Please use @c initWithPresentingViewController: +/*! @brief Create an external user-agent. + @discussion The specific authentication UI used depends on the iOS version and accessibility + options. iOS 8 uses the system browser, iOS 9-10 use @c SFSafariViewController, iOS 11 uses + @c SFAuthenticationSession (unless Guided Access is on which does not work) or uses + @c SFSafariViewController, and iOS 12+ uses @c ASWebAuthenticationSession (unless Guided + Access is on). */ -- (nonnull instancetype)init NS_UNAVAILABLE; +- (nonnull instancetype)init; -/*! @brief The designated initializer. +/*! @brief Create an external user-agent which optionally uses a private authentication session. + @param prefersEphemeralSession Whether the caller prefers to use a private authentication + session. See @c ASWebAuthenticationSession.prefersEphemeralWebBrowserSession for more. + */ +- (nullable instancetype)initWithPrefersEphemeralSession:(BOOL)prefersEphemeralSession; + +/*! @brief Create an external user-agent with a presenting view controller. @param presentingViewController The view controller from which to present the \SFSafariViewController. */ - (nullable instancetype)initWithPresentingViewController: - (UIViewController *)presentingViewController - NS_DESIGNATED_INITIALIZER; + (UIViewController *)presentingViewController; /*! @brief Create an external user-agent which optionally uses a private authentication session. @param presentingViewController The view controller from which to present the browser. diff --git a/Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.m b/Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.m index d6771b3e9..6d3bd2bcd 100644 --- a/Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.m +++ b/Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.m @@ -45,9 +45,22 @@ @implementation OIDExternalUserAgentCatalyst { ASWebAuthenticationSession *_webAuthenticationVC; } +- (nonnull instancetype)init { + self = [super init]; + return self; +} + +- (nullable instancetype)initWithPrefersEphemeralSession:(BOOL)prefersEphemeralSession { + self = [self init]; + if (self) { + _prefersEphemeralSession = prefersEphemeralSession; + } + return self; +} + - (nullable instancetype)initWithPresentingViewController: (UIViewController *)presentingViewController { - self = [super init]; + self = [self init]; if (self) { _presentingViewController = presentingViewController; } @@ -71,6 +84,38 @@ - (BOOL)presentExternalUserAgentRequest:(id)request return NO; } + if (!_presentingViewController) { + // Find presentingViewController + if (@available(iOS 13.0, *)) { + NSSet *scenes = + (NSSet *)[UIApplication sharedApplication].connectedScenes; + + NSMutableArray *windows = [NSMutableArray array]; + + for (UIWindowScene *scene in scenes) { + [windows addObjectsFromArray:scene.windows]; + } + + for (UIWindow *window in windows) { + if (window.isKeyWindow) { // False if calling before window appears + UIWindow *keyWindow = window; + _presentingViewController = keyWindow.rootViewController; + break; + } + } + } else { + // ≤ iOS 12.X + NSArray *windows = UIApplication.sharedApplication.windows; + NSPredicate *keyWindowPredicate = [NSPredicate predicateWithFormat:@"keyWindow == YES"]; + UIWindow *keyWindow = [windows filteredArrayUsingPredicate:keyWindowPredicate].firstObject; + _presentingViewController = keyWindow.rootViewController; + } + if (!_presentingViewController) { + // Unable to find a presentingViewController; perhaps because no window is key and visible + return NO; + } + } + _externalUserAgentFlowInProgress = YES; _session = session; BOOL openedUserAgent = NO; diff --git a/UnitTests/AppAuth/OIDExternUserAgentIOSTests.m b/UnitTests/AppAuth/OIDExternUserAgentTests.m similarity index 78% rename from UnitTests/AppAuth/OIDExternUserAgentIOSTests.m rename to UnitTests/AppAuth/OIDExternUserAgentTests.m index 572778787..696309f1d 100644 --- a/UnitTests/AppAuth/OIDExternUserAgentIOSTests.m +++ b/UnitTests/AppAuth/OIDExternUserAgentTests.m @@ -1,4 +1,4 @@ -/*! @file OIDExternalUserAgentIOSTests.m +/*! @file OIDExternalUserAgentTests.m @brief AppAuth iOS SDK @copyright Copyright 2023 The AppAuth Authors. All Rights Reserved. @@ -16,25 +16,35 @@ limitations under the License. */ +#import + #import #if SWIFT_PACKAGE @import AppAuth; @import TestHelpers; #else +#import "Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.h" #import "Source/AppAuth/iOS/OIDExternalUserAgentIOS.h" #import "Source/AppAuthCore/OIDError.h" #import "UnitTests/TestHelpers/OIDAuthorizationRequest+TestHelper.h" #endif -@interface OIDExternalUserAgentIOSTests : XCTestCase +@interface OIDExternalUserAgentTests : XCTestCase @end -@implementation OIDExternalUserAgentIOSTests +@implementation OIDExternalUserAgentTests - (void)testThatPresentExternalUserAgentRequestReturnsNoWhenMissingPresentingViewController { - OIDExternalUserAgentIOS *userAgent = [[OIDExternalUserAgentIOS alloc] init]; + id userAgent; + +#if TARGET_OS_MACCATALYST + userAgent = [[OIDExternalUserAgentCatalyst alloc] init]; +#elif TARGET_OS_IOS + userAgent = [[OIDExternalUserAgentIOS alloc] init]; +#endif + OIDAuthorizationRequest *authRequest = [OIDAuthorizationRequest testInstance]; [OIDAuthorizationService presentAuthorizationRequest:authRequest From c711eae1077a2fae9a2725c66998306f08a92012 Mon Sep 17 00:00:00 2001 From: Matthew Mathias Date: Thu, 12 Jan 2023 18:42:05 -0800 Subject: [PATCH 7/7] Remove iOS 11 API availability from -[OIDExternUserAgentIOS init] --- Source/AppAuth/iOS/OIDExternalUserAgentIOS.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/AppAuth/iOS/OIDExternalUserAgentIOS.h b/Source/AppAuth/iOS/OIDExternalUserAgentIOS.h index b9a54f620..a418988e8 100644 --- a/Source/AppAuth/iOS/OIDExternalUserAgentIOS.h +++ b/Source/AppAuth/iOS/OIDExternalUserAgentIOS.h @@ -41,7 +41,7 @@ API_UNAVAILABLE(macCatalyst) @c SFSafariViewController, and iOS 12+ uses @c ASWebAuthenticationSession (unless Guided Access is on). */ -- (nullable instancetype)init API_AVAILABLE(ios(11)); +- (nullable instancetype)init; /*! @brief Create an external user-agent with the presenting view controller. @param presentingViewController The view controller from which to present the authentication UI.