Skip to content

Commit b2869af

Browse files
authored
Merge pull request #1508 from AzureAD/kasong/2914053-common-interface-interactive
[Ready for Review] Add XPC interactive Logic
2 parents da051f1 + 7cde715 commit b2869af

24 files changed

+1007
-139
lines changed

IdentityCore/IdentityCore.xcodeproj/project.pbxproj

Lines changed: 34 additions & 8 deletions
Large diffs are not rendered by default.

IdentityCore/src/MSIDError.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,9 @@ typedef NS_ENUM(NSInteger, MSIDErrorCode)
364364
// App state while failed to open broker error
365365
MSIDErrorBrokerAppIsInactive = -51902,
366366
MSIDErrorBrokerAppIsInBackground = -51903,
367+
368+
// Broker Xpc internal error
369+
MSIDErrorBrokerXpcUnexpectedError = -52001,
367370

368371
};
369372

IdentityCore/src/MSIDError.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,9 @@ void MSIDFillAndLogError(NSError **error, MSIDErrorCode errorCode, NSString *err
447447
return @"MSIDErrorBrokerAppIsInactive";
448448
case MSIDErrorBrokerAppIsInBackground:
449449
return @"MSIDErrorBrokerAppIsInBackground";
450+
// Broker Xpc internal error
451+
case MSIDErrorBrokerXpcUnexpectedError:
452+
return @"MSIDErrorBrokerXpcUnexpectedError";
450453
}
451454

452455
return [NSString stringWithFormat:@"Unknown: %@", @(errorCode)];

IdentityCore/src/controllers/MSIDRequestControllerFactory.m

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#import "MSIDSignoutController.h"
3838
#if TARGET_OS_OSX
3939
#import "MSIDXpcSilentTokenRequestController.h"
40+
#import "MSIDXpcInteractiveTokenRequestController.h"
4041
#endif
4142

4243
@implementation MSIDRequestControllerFactory
@@ -328,15 +329,47 @@ @implementation MSIDRequestControllerFactory
328329
return nil;
329330
}
330331
#else
332+
331333
+ (nullable id<MSIDRequestControlling>)brokerController:(nonnull MSIDInteractiveTokenRequestParameters *)parameters
332334
tokenRequestProvider:(nonnull id<MSIDTokenRequestProviding>)tokenRequestProvider
333335
fallbackController:(nullable id<MSIDRequestControlling>)fallbackController
334336
error:(NSError * _Nullable __autoreleasing * _Nullable)error
335337
{
336-
return [self ssoExtensionInteractiveController:parameters
337-
tokenRequestProvider:tokenRequestProvider
338-
fallbackController:fallbackController
339-
error:error];
338+
id<MSIDRequestControlling> xpcController = nil;
339+
340+
// By default the xpc flow is disable, and should fallback to previous flow in else condition
341+
if (parameters.xpcMode != MSIDXpcModeDisable)
342+
{
343+
xpcController = [self xpcInteractiveController:parameters
344+
tokenRequestProvider:tokenRequestProvider
345+
fallbackController:fallbackController
346+
error:error];
347+
if (parameters.xpcMode == MSIDXpcModeBackup || parameters.xpcMode == MSIDXpcModeFull)
348+
{
349+
id<MSIDRequestControlling> ssoExtensionController = [self ssoExtensionInteractiveController:parameters
350+
tokenRequestProvider:tokenRequestProvider
351+
fallbackController:xpcController?:fallbackController
352+
error:error];
353+
if (parameters.xpcMode == MSIDXpcModeFull && !ssoExtensionController)
354+
{
355+
return xpcController;
356+
}
357+
358+
return ssoExtensionController;
359+
}
360+
else
361+
{
362+
// Development only: MSIDXpcModeOverride
363+
return xpcController;
364+
}
365+
}
366+
else
367+
{
368+
return [self ssoExtensionInteractiveController:parameters
369+
tokenRequestProvider:tokenRequestProvider
370+
fallbackController:fallbackController
371+
error:error];
372+
}
340373
}
341374
#endif
342375

@@ -356,6 +389,23 @@ @implementation MSIDRequestControllerFactory
356389
return nil;
357390
}
358391

392+
#if TARGET_OS_OSX
393+
+ (nullable id<MSIDRequestControlling>)xpcInteractiveController:(nonnull MSIDInteractiveTokenRequestParameters *)parameters
394+
tokenRequestProvider:(nonnull id<MSIDTokenRequestProviding>)tokenRequestProvider
395+
fallbackController:(nullable id<MSIDRequestControlling>)fallbackController
396+
error:(NSError * _Nullable __autoreleasing * _Nullable)error
397+
{
398+
if ([MSIDXpcInteractiveTokenRequestController canPerformRequest])
399+
{
400+
return [[MSIDXpcInteractiveTokenRequestController alloc] initWithInteractiveRequestParameters:parameters
401+
tokenRequestProvider:tokenRequestProvider
402+
fallbackController:fallbackController
403+
error:error];
404+
}
405+
406+
return nil;
407+
}
408+
#endif
359409

360410
+ (nullable id<MSIDRequestControlling>)localInteractiveController:(nonnull MSIDInteractiveTokenRequestParameters *)parameters
361411
tokenRequestProvider:(nonnull id<MSIDTokenRequestProviding>)tokenRequestProvider

IdentityCore/src/controllers/MSIDSilentController.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ - (void)acquireTokenWithRequest:(MSIDSilentTokenRequest *)request
143143
self.currentRequest = nil;
144144
MSIDRequestCompletionBlock completionBlockWrapper = ^(MSIDTokenResult *fallResult, NSError *fallError)
145145
{
146-
// We don't have any meaningful information from fallback controller (edge case of SSO error) so we use the local controller result earlier
147-
if (!fallResult && (fallError.code == MSIDErrorSSOExtensionUnexpectedError))
146+
// We don't have any meaningful information from fallback controller (edge case of SSO/Xpc error) so we use the local controller result earlier
147+
if (!fallResult && (fallError.code == MSIDErrorSSOExtensionUnexpectedError || fallError.code == MSIDErrorBrokerXpcUnexpectedError))
148148
{
149149
completionBlock(result, error);
150150
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//
2+
// Copyright (c) Microsoft Corporation.
3+
// All rights reserved.
4+
//
5+
// This code is licensed under the MIT License.
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy
8+
// of this software and associated documentation files(the "Software"), to deal
9+
// in the Software without restriction, including without limitation the rights
10+
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
11+
// copies of the Software, and to permit persons to whom the Software is
12+
// furnished to do so, subject to the following conditions :
13+
//
14+
// The above copyright notice and this permission notice shall be included in
15+
// all copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
// THE SOFTWARE.
24+
25+
26+
#import "MSIDLocalInteractiveController.h"
27+
28+
NS_ASSUME_NONNULL_BEGIN
29+
30+
@interface MSIDXpcInteractiveTokenRequestController : MSIDLocalInteractiveController
31+
32+
- (nullable instancetype)initWithInteractiveRequestParameters:(nonnull MSIDInteractiveTokenRequestParameters *)parameters
33+
tokenRequestProvider:(nonnull id<MSIDTokenRequestProviding>)tokenRequestProvider
34+
fallbackController:(nullable id<MSIDRequestControlling>)fallbackController
35+
error:(NSError * _Nullable __autoreleasing * _Nullable)error NS_DESIGNATED_INITIALIZER;
36+
37+
+ (BOOL)canPerformRequest;
38+
39+
@end
40+
41+
NS_ASSUME_NONNULL_END
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
//
2+
// Copyright (c) Microsoft Corporation.
3+
// All rights reserved.
4+
//
5+
// This code is licensed under the MIT License.
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy
8+
// of this software and associated documentation files(the "Software"), to deal
9+
// in the Software without restriction, including without limitation the rights
10+
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
11+
// copies of the Software, and to permit persons to whom the Software is
12+
// furnished to do so, subject to the following conditions :
13+
//
14+
// The above copyright notice and this permission notice shall be included in
15+
// all copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
// THE SOFTWARE.
24+
25+
26+
#import "MSIDXpcInteractiveTokenRequestController.h"
27+
#import "MSIDLocalInteractiveController+Internal.h"
28+
#import "MSIDXpcSingleSignOnProvider.h"
29+
#import "MSIDLogger+Internal.h"
30+
#import "MSIDThrottlingService.h"
31+
#import "MSIDInteractiveTokenRequest+Internal.h"
32+
#import "MSIDInteractiveTokenRequestParameters.h"
33+
#import "MSIDXpcProviderCache.h"
34+
35+
@implementation MSIDXpcInteractiveTokenRequestController
36+
37+
- (instancetype)initWithInteractiveRequestParameters:(MSIDInteractiveTokenRequestParameters *)parameters
38+
tokenRequestProvider:(id<MSIDTokenRequestProviding>)tokenRequestProvider
39+
fallbackController:(id<MSIDRequestControlling>)fallbackController
40+
error:(NSError *__autoreleasing*)error
41+
{
42+
self = [super initWithInteractiveRequestParameters:parameters
43+
tokenRequestProvider:tokenRequestProvider
44+
error:error];
45+
if (self)
46+
{
47+
_fallbackController = fallbackController;
48+
}
49+
50+
return self;
51+
}
52+
53+
#pragma mark - MSIDRequestControlling
54+
55+
- (void)acquireToken:(MSIDRequestCompletionBlock)completionBlock
56+
{
57+
MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"Beginning interactive broker Xpc service flow.");
58+
MSIDInteractiveTokenRequest *request = [self.tokenRequestProvider interactiveXpcTokenRequestWithParameters:self.interactiveRequestParamaters];
59+
60+
MSIDRequestCompletionBlock completionBlockWrapper = ^(MSIDTokenResult *result, NSError *error)
61+
{
62+
MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"Interactive Broker Xpc flow finished. Result %@, error: %ld error domain: %@", _PII_NULLIFY(result), (long)error.code, error.domain);
63+
if (!error)
64+
{
65+
/**
66+
Throttling service: when an interactive token succeed, we update the last refresh time of the throttling service
67+
*/
68+
[MSIDThrottlingService updateLastRefreshTimeDatasource:request.extendedTokenCache context:self.interactiveRequestParamaters error:nil];
69+
70+
}
71+
else if ([self shouldFallback:error])
72+
{
73+
MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"Falling back to local controller.");
74+
75+
[self.fallbackController acquireToken:completionBlock];
76+
return;
77+
}
78+
79+
completionBlock(result, error);
80+
};
81+
82+
[self acquireTokenWithRequest:request completionBlock:completionBlockWrapper];
83+
}
84+
85+
+ (BOOL)canPerformRequest
86+
{
87+
if (@available(macOS 13, *)) {
88+
return [MSIDXpcSingleSignOnProvider canPerformRequest:MSIDXpcProviderCache.sharedInstance];
89+
} else {
90+
return NO;
91+
}
92+
}
93+
94+
#pragma mark - Private
95+
96+
- (BOOL)shouldFallback:(NSError *)error
97+
{
98+
MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"Looking if we should fallback to fallback controller, error: %ld error domain: %@.", (long)error.code, error.domain);
99+
100+
if (!self.fallbackController)
101+
{
102+
MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"fallback controller is nil, Xpc service controller should fallback: NO");
103+
return NO;
104+
}
105+
106+
// If it is MSIDErrorDomain and Broker Xpc returns unexpected error, we should fall back to local controler and unblock user
107+
if (![error.domain isEqualToString:ASAuthorizationErrorDomain] && ![error.domain isEqualToString:MSIDErrorDomain]) return NO;
108+
109+
BOOL shouldFallback = NO;
110+
switch (error.code)
111+
{
112+
// TODO: 3236668 define XPC error code that should fallback
113+
case ASAuthorizationErrorNotHandled:
114+
case ASAuthorizationErrorUnknown:
115+
case ASAuthorizationErrorFailed:
116+
case MSIDErrorBrokerXpcUnexpectedError:
117+
shouldFallback = YES;
118+
}
119+
120+
MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"SSO extension controller should fallback: %@", shouldFallback ? @"YES" : @"NO");
121+
122+
return shouldFallback;
123+
}
124+
125+
@end

IdentityCore/src/controllers/broker/mac/MSIDXpcSilentTokenRequestController.m

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ - (void)acquireToken:(MSIDRequestCompletionBlock)completionBlock
4646

4747
+ (BOOL)canPerformRequest
4848
{
49-
if (@available(macOS 13, *)) {
49+
if (@available(macOS 13, *))
50+
{
5051
return [MSIDXpcSingleSignOnProvider canPerformRequest:MSIDXpcProviderCache.sharedInstance];
5152
}
5253
else

IdentityCore/src/requests/broker/MSIDSSOExtensionInteractiveTokenRequest.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@
2121
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2222
// THE SOFTWARE.
2323

24-
#import "MSIDInteractiveTokenRequest.h"
24+
#import "MSIDSSORemoteInteractiveTokenRequest.h"
2525
#import "MSIDProviderType.h"
2626

2727
NS_ASSUME_NONNULL_BEGIN
2828

29-
@interface MSIDSSOExtensionInteractiveTokenRequest : MSIDInteractiveTokenRequest
29+
@interface MSIDSSOExtensionInteractiveTokenRequest : MSIDSSORemoteInteractiveTokenRequest
3030

3131
@end
3232

0 commit comments

Comments
 (0)