Skip to content

Commit

Permalink
Merge branch 'dev' into jarias/use-single-frt
Browse files Browse the repository at this point in the history
  • Loading branch information
juan-arias committed Feb 10, 2025
2 parents 2e732d1 + 4b5b16e commit 0e2175f
Show file tree
Hide file tree
Showing 24 changed files with 436 additions and 9 deletions.
2 changes: 2 additions & 0 deletions IdentityCore/src/MSIDBrokerConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,5 @@ extern NSString * _Nonnull const MSID_CREATE_NEW_URL_SESSION;
extern NSString * _Nonnull const MSID_HTTP_CONNECTION_VALUE;
extern NSString * _Nonnull const MSID_FORCE_REFRESH_KEY;

extern BOOL MSID_SUPPRESS_CAMERA_CONSENT_PROMPT_IN_WEBVIEW;

3 changes: 3 additions & 0 deletions IdentityCore/src/MSIDBrokerConstants.m
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,6 @@
// Http header
NSString *const MSID_HTTP_CONNECTION = @"Connection";
NSString *const MSID_HTTP_CONNECTION_VALUE = @"close";

// Non-constant
BOOL MSID_SUPPRESS_CAMERA_CONSENT_PROMPT_IN_WEBVIEW = NO;
20 changes: 20 additions & 0 deletions IdentityCore/src/MSIDError.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ typedef NS_ENUM(NSInteger, MSIDErrorCode)
*/

MSIDErrorServerUnhandledResponse = -51500,
// http status Code 403 or 404
MSIDErrorUnexpectedHttpResponse = -51501,

/*!
=========================================================
Expand Down Expand Up @@ -334,6 +336,24 @@ typedef NS_ENUM(NSInteger, MSIDErrorCode)

// JIT - Error Handling config invalid or not found
MSIDErrorJITErrorHandlingConfigNotFound = -51839,

// Error is thrown when PSSO biometric policy flag mismatches with the config value
MSIDErrorPSSOBiometricPolicyMismatch = -51840,

// Error is thrown when non ENtra passkey extension tries to access the passkey
MSIDErrorPSSOInvalidPasskeyExtension = -51841,

// Error thrown when psso save login config operation fails
MSIDErrorPSSOSaveLoginConfigFailure = -51842,

// Error is thrown when passkey accessed without biometric when h/w biometric policy configured
MSIDErrorPSSOPasskeyLAError = -51843,

// Error is thrown when PSSO user registration attempted with no biometrics configured and sekey biometric policy is configured
MSIDErrorPSSOBiometricsNotEnrolled = -51844,

// Error is thrown when PSSO user registration attempted with no biometrics available and sekey biometric policy is configured
MSIDErrorPSSOBiometricsNotAvailable = -51845,

// Throttling errors
MSIDErrorThrottleCacheNoRecord = -51900,
Expand Down
23 changes: 22 additions & 1 deletion IdentityCore/src/MSIDError.m
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,12 @@ MSIDErrorCode MSIDErrorCodeForOAuthErrorWithSubErrorCode(NSString *oauthError, M
@(MSIDErrorDeviceNotPSSORegistered),
@(MSIDErrorPSSOKeyIdMismatch),
@(MSIDErrorJITErrorHandlingConfigNotFound),
@(MSIDErrorPSSOBiometricPolicyMismatch),
@(MSIDErrorPSSOInvalidPasskeyExtension),
@(MSIDErrorPSSOSaveLoginConfigFailure),
@(MSIDErrorPSSOPasskeyLAError),
@(MSIDErrorPSSOBiometricsNotEnrolled),
@(MSIDErrorPSSOBiometricsNotAvailable),
],
MSIDOAuthErrorDomain : @[// Server Errors
@(MSIDErrorServerOauth),
Expand All @@ -224,7 +230,8 @@ MSIDErrorCode MSIDErrorCodeForOAuthErrorWithSubErrorCode(NSString *oauthError, M
@(MSIDErrorServerError),
],
MSIDHttpErrorCodeDomain : @[
@(MSIDErrorServerUnhandledResponse)
@(MSIDErrorServerUnhandledResponse),
@(MSIDErrorUnexpectedHttpResponse)
]

// TODO: add new codes here
Expand Down Expand Up @@ -301,6 +308,8 @@ void MSIDFillAndLogError(NSError **error, MSIDErrorCode errorCode, NSString *err
// HTTP errors
case MSIDErrorServerUnhandledResponse:
return @"MSIDErrorServerUnhandledResponse";
case MSIDErrorUnexpectedHttpResponse:
return @"MSIDErrorUnexpectedHttpResponse";
// Authority validation errors
case MSIDErrorAuthorityValidation:
return @"MSIDErrorAuthorityValidation";
Expand Down Expand Up @@ -415,6 +424,18 @@ void MSIDFillAndLogError(NSError **error, MSIDErrorCode errorCode, NSString *err
return @"MSIDErrorDeviceNotPSSORegistered";
case MSIDErrorPSSOKeyIdMismatch:
return @"MSIDErrorPSSOKeyIdMismatch";
case MSIDErrorPSSOBiometricPolicyMismatch:
return @"MSIDErrorPSSOBiometricPolicyMismatch";
case MSIDErrorPSSOInvalidPasskeyExtension:
return @"MSIDErrorPSSOInvalidPasskeyExtension";
case MSIDErrorPSSOSaveLoginConfigFailure:
return @"MSIDErrorPSSOSaveLoginConfigFailure";
case MSIDErrorPSSOPasskeyLAError:
return @"MSIDErrorPSSOPasskeyLAError";
case MSIDErrorPSSOBiometricsNotEnrolled:
return @"MSIDErrorPSSOBiometricsNotEnrolled";
case MSIDErrorPSSOBiometricsNotAvailable:
return @"MSIDErrorPSSOBiometricsNotAvailable";
// Throttling errors
case MSIDErrorThrottleCacheNoRecord:
return @"MSIDErrorThrottleCacheNoRecord";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ typedef NS_ENUM(NSInteger, MSIDPlatformSSOStatus)
MSIDPlatformSSONotEnabled = 0, //Platform SSO Not enabled in SSO Config
MSIDPlatformSSOEnabledNotRegistered = 1, //Platform SSO Enabled in sso config , but not Registered
MSIDPlatformSSOEnabledAndRegistered = 2, //Platform SSO Enabled in sso config and registered
MSIDPlatformSSORegistrationNeedsRepair = 3, //Platform registration needs to be repaired
};

typedef NS_ENUM(NSInteger, MSIDPreferredAuthMethod)
Expand Down
3 changes: 3 additions & 0 deletions IdentityCore/src/broker_operation/response/MSIDDeviceInfo.m
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ - (NSString *)platformSSOStatusStringFromEnum:(MSIDPlatformSSOStatus)platformSSO
return @"platformSSOEnabledNotRegistered";
case MSIDPlatformSSOEnabledAndRegistered:
return @"platformSSOEnabledAndRegistered";
case MSIDPlatformSSORegistrationNeedsRepair:
return @"platformSSORegistrationNeedsRepair";

default:
return nil;
Expand All @@ -187,6 +189,7 @@ - (MSIDPlatformSSOStatus)platformSSOStatusEnumFromString:(NSString *)platformSSO
if ([platformSSOStatusString isEqualToString:@"platformSSONotEnabled"]) return MSIDPlatformSSONotEnabled;
if ([platformSSOStatusString isEqualToString:@"platformSSOEnabledNotRegistered"]) return MSIDPlatformSSOEnabledNotRegistered;
if ([platformSSOStatusString isEqualToString:@"platformSSOEnabledAndRegistered"]) return MSIDPlatformSSOEnabledAndRegistered;
if ([platformSSOStatusString isEqualToString:@"platformSSORegistrationNeedsRepair"]) return MSIDPlatformSSORegistrationNeedsRepair;

return MSIDPlatformSSONotEnabled;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1411,7 +1411,10 @@ - (BOOL)saveAccount:(MSIDAccount *)account
}
else
{
[noReturnAccountsSet addObject:accountCacheItem.username];
if (accountCacheItem.username)
{
[noReturnAccountsSet addObject:accountCacheItem.username];
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,13 @@ - (void)handleError:(NSError *)error
}
}

NSError *httpError = MSIDCreateError(MSIDHttpErrorCodeDomain, MSIDErrorServerUnhandledResponse, errorDescription, nil, nil, nil, context.correlationId, additionalInfo, YES);
NSError *httpUnderlyingError = nil;
if (httpResponse.statusCode == 403 || httpResponse.statusCode == 404)
{
httpUnderlyingError = MSIDCreateError(MSIDHttpErrorCodeDomain, MSIDErrorUnexpectedHttpResponse, errorDescription, nil, nil, nil, context.correlationId, nil, YES);
}

NSError *httpError = MSIDCreateError(MSIDHttpErrorCodeDomain, MSIDErrorServerUnhandledResponse, errorDescription, nil, nil, httpUnderlyingError, context.correlationId, additionalInfo, YES);

if (completionBlock) completionBlock(nil, httpError);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
typedef void (^MSIDNavigationResponseBlock)(NSHTTPURLResponse *response);

@interface MSIDOAuth2EmbeddedWebviewController :
MSIDWebviewUIController <MSIDWebviewInteracting, WKNavigationDelegate>
MSIDWebviewUIController <MSIDWebviewInteracting, WKNavigationDelegate, WKUIDelegate>

typedef NSURLRequest *(^MSIDExternalDecidePolicyForBrowserActionBlock)(MSIDOAuth2EmbeddedWebviewController *webView, NSURL *url);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ -(void)dealloc
{
[self.webView setNavigationDelegate:nil];
}
if ([self.webView.UIDelegate isEqual:self])
{
[self.webView setUIDelegate:nil];
}

self.webView = nil;
}
Expand Down Expand Up @@ -175,6 +179,7 @@ - (BOOL)loadView:(NSError *__autoreleasing*)error
BOOL result = [super loadView:error];

self.webView.navigationDelegate = self;
self.webView.UIDelegate = self;

#if !EXCLUDE_FROM_MSALCPP
#if DEBUG
Expand Down Expand Up @@ -479,6 +484,22 @@ - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavig
}
}

- (void) webView:(WKWebView *)webView
requestMediaCapturePermissionForOrigin:(WKSecurityOrigin *)origin
initiatedByFrame:(WKFrameInfo *)frame
type:(WKMediaCaptureType)type
decisionHandler:(void (^)(WKPermissionDecision decision))decisionHandler API_AVAILABLE(ios(15.0), macos(12.0))
{
if (MSID_SUPPRESS_CAMERA_CONSENT_PROMPT_IN_WEBVIEW && type == WKMediaCaptureTypeCamera)
{
decisionHandler(WKPermissionDecisionGrant);
}
else
{
decisionHandler(WKPermissionDecisionPrompt);
}
}

#pragma mark - Loading Indicator

- (void)onStartLoadingIndicator:(__unused id)sender
Expand Down
4 changes: 4 additions & 0 deletions IdentityCore/tests/MSIDAADRequestErrorHandlerTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ - (void)testHandleError_whenItIsNotServerError_shouldReturnStatusCodeAndHeaders

XCTAssertEqualObjects(returnError.domain, MSIDHttpErrorCodeDomain);
XCTAssertEqual(returnError.code, MSIDErrorServerUnhandledResponse);
NSError *underlyingError = returnError.userInfo[NSUnderlyingErrorKey];
XCTAssertEqual(underlyingError.code, MSIDErrorUnexpectedHttpResponse);
XCTAssertEqualObjects(returnError.userInfo[MSIDHTTPHeadersKey], @{@"headerKey":@"headerValue"});

XCTAssertNil(errorResponse);
Expand Down Expand Up @@ -275,6 +277,8 @@ - (void)testHandleError_whenItIsServerError_shouldReturnResponseCodeInError

XCTAssertEqualObjects(returnError.domain, MSIDHttpErrorCodeDomain);
XCTAssertEqual(returnError.code, MSIDErrorServerUnhandledResponse);
NSError *underlyingError = returnError.userInfo[NSUnderlyingErrorKey];
XCTAssertEqual(underlyingError.code, MSIDErrorUnexpectedHttpResponse);
XCTAssertEqualObjects(returnError.userInfo[MSIDHTTPResponseCodeKey], @"404");
}

Expand Down
8 changes: 7 additions & 1 deletion IdentityCore/tests/MSIDTokenResponseTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,13 @@ - (void)testJsonDictionary_whenAllPropertiesSetForSuccessResponse_shouldReturnJs
XCTAssertEqualObjects(json[@"client_app_version"], @"1.0");
XCTAssertEqualObjects(json[@"expires_in"], @"300");
XCTAssertEqualObjects(json[@"expires_on"], @"1575635662");
XCTAssertEqualObjects(json[@"id_token"], @"eyJhbGciOiJSUzI1NiIsImtpZCI6Il9raWRfdmFsdWUiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJpc3N1ZXIiLCJuYW1lIjoiVGVzdCBuYW1lIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidXNlckBjb250b3NvLmNvbSIsInN1YiI6InN1YiJ9.eyJhbGciOiJSUzI1NiIsImtpZCI6Il9raWRfdmFsdWUiLCJ0eXAiOiJKV1QifQ");

NSArray *idTokenComponents = [json[@"id_token"] componentsSeparatedByString:@"."];
XCTAssertEqual(idTokenComponents.count, 3);
XCTAssertEqualObjects(idTokenComponents[0], @"eyJhbGciOiJSUzI1NiIsImtpZCI6Il9raWRfdmFsdWUiLCJ0eXAiOiJKV1QifQ");
XCTAssertEqualObjects(idTokenComponents[1], @"eyJpc3MiOiJpc3N1ZXIiLCJuYW1lIjoiVGVzdCBuYW1lIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidXNlckBjb250b3NvLmNvbSIsInN1YiI6InN1YiJ9");
XCTAssertEqualObjects(idTokenComponents[2], @"eyJhbGciOiJSUzI1NiIsImtpZCI6Il9raWRfdmFsdWUiLCJ0eXAiOiJKV1QifQ");

XCTAssertEqualObjects(json[@"provider_type"], @"provider_aad_v2");
XCTAssertEqualObjects(json[@"scope"], @"scope 1");
XCTAssertEqualObjects(json[@"token_type"], @"Bearer");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ typedef NS_ENUM(NSUInteger, MSIDAutomationWPJRegistrationAPIMode)
MSIDAutomationWPJRegistrationAPIModeCompanyPortal = 2 //Company Portal
};

typedef NS_ENUM(NSInteger, MSIDAutomationWPJSSOExtensionSecureStorage)
{
MSIDAutomationWPJSSOExtensionNoValueFound = 0,
MSIDAutomationWPJSSOExtensionValueNo = 1,
MSIDAutomationWPJSSOExtensionValueYes = 2
};

@interface MSIDAutomationTestRequest : NSObject <MSIDJsonSerializable>

@property (nonatomic, strong) NSString *clientId;
Expand Down Expand Up @@ -86,6 +93,8 @@ typedef NS_ENUM(NSUInteger, MSIDAutomationWPJRegistrationAPIMode)
@property (nonatomic) NSString *wpjRegistrationUpn;
@property (nonatomic) BOOL operateOnPrimaryWPJ;
@property (nonatomic) BOOL useMostSecureStorageForWpj;
@property (nonatomic) BOOL isSecureEnclaveSupportedForWpj;
@property (nonatomic) MSIDAutomationWPJSSOExtensionSecureStorage ssoExtensionSecureStorageEnabled;
@property (nonatomic) BOOL shouldExpirePRT;
@property (nonatomic) BOOL isSsoSeedingCompleted;
@property (nonatomic) BOOL shouldOnlyDeleteSeedingPrt;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ - (instancetype)initWithJSONDictionary:(NSDictionary *)json
_wpjRegistrationUpn = json[@"wpj_registration_upn"];
_operateOnPrimaryWPJ = [json[@"wpj_operate_on_primary_reg"] boolValue];
_useMostSecureStorageForWpj = [json[@"use_most_secure_storage"] boolValue];
_isSecureEnclaveSupportedForWpj = [json[@"wpj_secure_enclave_supported"] boolValue];
_ssoExtensionSecureStorageEnabled = (MSIDAutomationWPJSSOExtensionSecureStorage)[json[@"wpj_sso_extension_secure_storage_enabled"] integerValue];
_shouldExpirePRT = [json[@"should_expire_prt"] boolValue];
_isSsoSeedingCompleted = [json[@"is_sso_seeding_completed"] boolValue];
_shouldOnlyDeleteSeedingPrt = [json[@"should_only_delete_seeding_prt"] boolValue];
Expand Down Expand Up @@ -184,6 +186,8 @@ - (NSDictionary *)jsonDictionary
json[@"wpj_registration_upn"] = _wpjRegistrationUpn;
json[@"wpj_operate_on_primary_reg"] = @(_operateOnPrimaryWPJ);
json[@"use_most_secure_storage"] = @(_useMostSecureStorageForWpj);
json[@"wpj_secure_enclave_supported"] = @(_isSecureEnclaveSupportedForWpj);
json[@"wpj_sso_extension_secure_storage_enabled"] = @(_ssoExtensionSecureStorageEnabled);
json[@"should_expire_prt"] = @(_shouldExpirePRT);
json[@"is_sso_seeding_completed"] = @(_isSsoSeedingCompleted);
json[@"should_only_delete_seeding_prt"] = @(_shouldOnlyDeleteSeedingPrt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ extern MSIDTestAccountProtectionPolicyType MSIDTestAccountProtectionPolicyTypeMA
extern MSIDTestAccountProtectionPolicyType MSIDTestAccountProtectionPolicyTypeMAMCASPO;
extern MSIDTestAccountProtectionPolicyType MSIDTestAccountProtectionPolicyTypeTrueMAMCA;
extern MSIDTestAccountProtectionPolicyType MSIDTestAccountProtectionPolicyTypeMDMCA;
extern MSIDTestAccountProtectionPolicyType MSIDTestAccountProtectionPolicyTypeTB;

typedef NSString *MSIDTestAccountB2CProviderType;
extern MSIDTestAccountB2CProviderType MSIDTestAccountB2CProviderTypeNone;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
MSIDTestAccountProtectionPolicyType MSIDTestAccountProtectionPolicyTypeMAMCASPO = @"mamspo";
MSIDTestAccountProtectionPolicyType MSIDTestAccountProtectionPolicyTypeTrueMAMCA = @"truemamca";
MSIDTestAccountProtectionPolicyType MSIDTestAccountProtectionPolicyTypeMDMCA = @"mdmca";
MSIDTestAccountProtectionPolicyType MSIDTestAccountProtectionPolicyTypeTB = @"tokenbinding";

#pragma mark - MSIDTestAccountB2CProviderType;
MSIDTestAccountB2CProviderType MSIDTestAccountB2CProviderTypeNone = @"none";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1788,6 +1788,55 @@ - (void)testAccountsWithAuthority_whenReturnSignedInAccountTrue_shouldFilterOutS
XCTAssertFalse([accountUPNs containsObject:@"upn2@test.com"]);
}

- (void)testAccountsWithAuthority_whenReturnSignedInAccountTrue_AndUserNameNil_shouldNotCrash
{
// setup default cache
[self saveResponseWithUPN:@"upn@test.com"
clientId:@"test_client_id"
authority:@"https://login.windows.net/common"
responseScopes:@"user.read user.write"
inputScopes:@"user.read user.write"
uid:@"uid"
utid:@"utid"
accessToken:@"access token"
refreshToken:@"refresh token"
familyId:@"3"
accessor:_nonSSOAccessor];

[self saveResponseWithUPN:nil
clientId:@"test_client_id2"
authority:@"https://login.windows.net/common"
responseScopes:@"user.read user.write"
inputScopes:@"user.read user.write"
uid:@"uid2"
utid:@"utid2"
accessToken:@"access token"
refreshToken:@"refresh token 2"
familyId:nil
accessor:_nonSSOAccessor];

// sign out the second account
NSError *error;
XCTAssertTrue([_accountMetadataCache updateSignInStateForHomeAccountId:@"uid2.utid2" clientId:@"test_client_id2" state:MSIDAccountMetadataStateSignedOut context:nil error:&error]);
XCTAssertNil(error);

// setup legacy cache
[self saveResponseWithUPN:@"upn3@test.com"
clientId:@"test_client_id3"
authority:@"https://login.windows.net/common"
responseScopes:@"user.read user.write"
inputScopes:@"user.read user.write"
uid:@"uid3"
utid:@"utid3"
accessToken:@"access token"
refreshToken:@"refresh token 2"
familyId:@"3"
accessor:_otherAccessor];

NSArray *accounts = [_defaultAccessor accountsWithAuthority:nil clientId:@"test_client_id2" familyId:@"3" accountIdentifier:nil accountMetadataCache:_accountMetadataCache signedInAccountsOnly:YES context:nil error:&error];
XCTAssertEqual([accounts count], 2);
}

- (void)testAccountsWithAuthority_whenReturnSignedInAccountTrue_shouldFilterOutSignedOutAccountInBothDefaultAndLegacyCache
{
// setup default cache
Expand Down Expand Up @@ -3117,7 +3166,15 @@ - (void)saveResponseWithUPN:(NSString *)upn
appIdentifier:(NSString *)appIdentifier
accessor:(id<MSIDCacheAccessor>)accessor
{
NSString *idToken = [MSIDTestIdTokenUtil idTokenWithPreferredUsername:upn subject:@"subject" givenName:@"Hello" familyName:@"World" name:@"Hello World" version:@"2.0" tid:tenantId];
NSString *idToken = nil;
if (!upn)
{
idToken = [MSIDTestIdTokenUtil idTokenWithGivenName:@"Hello" familyName:@"World" name:@"Hello World" version:@"2.0" tid:tenantId];
}
else
{
idToken = [MSIDTestIdTokenUtil idTokenWithPreferredUsername:upn subject:@"subject" givenName:@"Hello" familyName:@"World" name:@"Hello World" version:@"2.0" tid:tenantId];
}

MSIDTokenResponse *response = [MSIDTestTokenResponse v2TokenResponseWithAT:accessToken
RT:refreshToken
Expand Down
Loading

0 comments on commit 0e2175f

Please sign in to comment.