Skip to content

Commit

Permalink
Add no presenting vc auth flow support to mac catalyst external user …
Browse files Browse the repository at this point in the history
…agent

Also updates the presentExternUserAgentRequest test to work for both iOS and catalyst
  • Loading branch information
mdmathias committed Jan 13, 2023
1 parent 598b5f3 commit 2af25fd
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 11 deletions.
21 changes: 15 additions & 6 deletions Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,27 @@ NS_ASSUME_NONNULL_BEGIN
API_AVAILABLE(macCatalyst(13)) API_UNAVAILABLE(ios)
@interface OIDExternalUserAgentCatalyst : NSObject<OIDExternalUserAgent>

/*! @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.
Expand Down
47 changes: 46 additions & 1 deletion Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.m
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -71,6 +84,38 @@ - (BOOL)presentExternalUserAgentRequest:(id<OIDExternalUserAgentRequest>)request
return NO;
}

if (!_presentingViewController) {
// Find presentingViewController
if (@available(iOS 13.0, *)) {
NSSet<UIWindowScene *> *scenes =
(NSSet<UIWindowScene *> *)[UIApplication sharedApplication].connectedScenes;

NSMutableArray<UIWindow *> *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<UIWindow *> *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;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*! @file OIDExternalUserAgentIOSTests.m
/*! @file OIDExternalUserAgentTests.m
@brief AppAuth iOS SDK
@copyright
Copyright 2023 The AppAuth Authors. All Rights Reserved.
Expand All @@ -16,25 +16,35 @@
limitations under the License.
*/

#import <TargetConditionals.h>

#import <XCTest/XCTest.h>

#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<OIDExternalUserAgent> 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
Expand Down

0 comments on commit 2af25fd

Please sign in to comment.