From 8cb38d225d9b4a091cf58ccae68f6f2f1702ebd0 Mon Sep 17 00:00:00 2001 From: Antonio Alwan Date: Mon, 24 Jun 2024 17:28:22 -0700 Subject: [PATCH] Add tests --- .../MSIDLocalInteractiveController.m | 34 +++++++-- .../tests/MSIDAADWebviewFactoryTests.m | 48 +++++++++++++ .../tests/MSIDWebMSAuthResponseTests.m | 16 +++++ ...SIDInteractiveControllerIntegrationTests.m | 72 +++++++++++++++++++ .../MSIDDefaultInteractiveTokenRequestTests.m | 70 ++++++++++++++++++ 5 files changed, 234 insertions(+), 6 deletions(-) diff --git a/IdentityCore/src/controllers/MSIDLocalInteractiveController.m b/IdentityCore/src/controllers/MSIDLocalInteractiveController.m index d5c6e094f..573d6cadc 100644 --- a/IdentityCore/src/controllers/MSIDLocalInteractiveController.m +++ b/IdentityCore/src/controllers/MSIDLocalInteractiveController.m @@ -35,6 +35,7 @@ #import "MSIDBrokerInteractiveController.h" #endif #import "MSIDWebWPJResponse.h" +#import "MSIDWebUpgradeRegResponse.h" #import "MSIDThrottlingService.h" @interface MSIDLocalInteractiveController() @@ -115,13 +116,34 @@ - (void)handleWebMSAuthResponse:(MSIDWebWPJResponse *)response completion:(MSIDR if (![NSString msidIsStringNilOrBlank:response.upn]) { - MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"Workplace join is required."); - - NSMutableDictionary *additionalInfo = [NSMutableDictionary new]; - additionalInfo[MSIDUserDisplayableIdkey] = response.upn; - additionalInfo[MSIDHomeAccountIdkey] = response.clientInfo.accountIdentifier; + NSError *registrationError; + if ([response isKindOfClass:MSIDWebUpgradeRegResponse.class]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"Workplace join Upgrade registration is required."); + + NSMutableDictionary *additionalInfo = [NSMutableDictionary new]; + additionalInfo[MSIDUserDisplayableIdkey] = response.upn; + additionalInfo[MSIDHomeAccountIdkey] = response.clientInfo.accountIdentifier; + + registrationError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInsufficientDeviceStrength, + @"Workplace join Upgrade registration is required", nil, nil, nil, self.requestParameters.correlationId, additionalInfo, NO); + } + else if ([response isKindOfClass:MSIDWebWPJResponse.class]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"Workplace join is required."); + + NSMutableDictionary *additionalInfo = [NSMutableDictionary new]; + additionalInfo[MSIDUserDisplayableIdkey] = response.upn; + additionalInfo[MSIDHomeAccountIdkey] = response.clientInfo.accountIdentifier; + + registrationError = MSIDCreateError(MSIDErrorDomain, MSIDErrorWorkplaceJoinRequired, @"Workplace join is required", nil, nil, nil, self.requestParameters.correlationId, additionalInfo, NO); + } + else + { + MSID_LOG_WITH_CTX(MSIDLogLevelError, self.requestParameters, @"Invalid WebResponse. This is a critical code bug"); + registrationError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Invalid WebResponse", nil, nil, nil, self.requestParameters.correlationId, nil, NO); + } - NSError *registrationError = MSIDCreateError(MSIDErrorDomain, MSIDErrorWorkplaceJoinRequired, @"Workplace join is required", nil, nil, nil, self.requestParameters.correlationId, additionalInfo, NO); #if !EXCLUDE_FROM_MSALCPP MSIDTelemetryAPIEvent *telemetryEvent = [self telemetryAPIEvent]; [telemetryEvent setLoginHint:response.upn]; diff --git a/IdentityCore/tests/MSIDAADWebviewFactoryTests.m b/IdentityCore/tests/MSIDAADWebviewFactoryTests.m index 194f2f158..b36db1599 100644 --- a/IdentityCore/tests/MSIDAADWebviewFactoryTests.m +++ b/IdentityCore/tests/MSIDAADWebviewFactoryTests.m @@ -31,6 +31,7 @@ #import "MSIDDeviceId.h" #import "NSDictionary+MSIDTestUtil.h" #import "MSIDWebWPJResponse.h" +#import "MSIDWebUpgradeRegResponse.h" #import "MSIDSignoutWebRequestConfiguration.h" #import "MSIDWebOpenBrowserResponse.h" #import "MSIDAadAuthorityCache.h" @@ -178,6 +179,21 @@ - (void)testResponseWithURL_whenURLSchemeMsauthAndHostWPJ_shouldReturnWPJRespons XCTAssertNil(error); } +- (void)testResponseWithURL_whenURLSchemeMsauthAndHostUpgradeReg_shouldReturnUpgradeRegResponse +{ + MSIDAADWebviewFactory *factory = [MSIDAADWebviewFactory new]; + + NSError *error = nil; + __auto_type response = [factory oAuthResponseWithURL:[NSURL URLWithString:@"msauth://upgradeReg?anyParam=1"] + requestState:nil + ignoreInvalidState:NO + context:nil + error:&error]; + + XCTAssertTrue([response isKindOfClass:MSIDWebUpgradeRegResponse.class]); + XCTAssertNil(error); +} + - (void)testResponseWithURL_whenBrokerInstallResponseInSystemBrowser_shouldReturnWPJResponse { MSIDAADWebviewFactory *factory = [MSIDAADWebviewFactory new]; @@ -195,6 +211,22 @@ - (void)testResponseWithURL_whenBrokerInstallResponseInSystemBrowser_shouldRetur XCTAssertEqualObjects(wpjResponse.upn, @"XXX@upn.com"); } +- (void)testResponseWithURL_whenBrokerUpgradeRegResponseInSystemBrowser_shouldReturnUpgradeRegResponse +{ + MSIDAADWebviewFactory *factory = [MSIDAADWebviewFactory new]; + + NSError *error = nil; + + NSURL *url = [NSURL URLWithString:@"msauth.com.microsoft.myapp://auth/msauth/upgradeReg?username=XXX@upn.com"]; + __auto_type response = [factory oAuthResponseWithURL:url requestState:nil ignoreInvalidState:YES context:nil error:&error]; + + XCTAssertTrue([response isKindOfClass:MSIDWebUpgradeRegResponse.class]); + XCTAssertNil(error); + + MSIDWebWPJResponse *wpjResponse = (MSIDWebWPJResponse *)response; + XCTAssertEqualObjects(wpjResponse.upn, @"XXX@upn.com"); +} + - (void)testResponseWithURL_whenBrokerInstallResponseInSystemBrowser_andLocalhostRedirectUri_shouldReturnWPJResponse { MSIDAADWebviewFactory *factory = [MSIDAADWebviewFactory new]; @@ -212,6 +244,22 @@ - (void)testResponseWithURL_whenBrokerInstallResponseInSystemBrowser_andLocalhos XCTAssertEqualObjects(wpjResponse.upn, @"XXX@upn.com"); } +- (void)testResponseWithURL_whenBrokerUpgradeResponseInSystemBrowser_andLocalhostRedirectUri_shouldReturnUpgradeRegResponse +{ + MSIDAADWebviewFactory *factory = [MSIDAADWebviewFactory new]; + + NSError *error = nil; + + NSURL *url = [NSURL URLWithString:@"https://localhost/msauth/upgradeReg?username=XXX@upn.com"]; + __auto_type response = [factory oAuthResponseWithURL:url requestState:nil ignoreInvalidState:YES context:nil error:&error]; + + XCTAssertTrue([response isKindOfClass:MSIDWebUpgradeRegResponse.class]); + XCTAssertNil(error); + + MSIDWebUpgradeRegResponse *wpjResponse = (MSIDWebUpgradeRegResponse *)response; + XCTAssertEqualObjects(wpjResponse.upn, @"XXX@upn.com"); +} + - (void)testResponseWithURL_whenBrokerInstallResponseInSystemBrowser_andRedirectUriEndingInSlash_shouldReturnWPJResponse { MSIDAADWebviewFactory *factory = [MSIDAADWebviewFactory new]; diff --git a/IdentityCore/tests/MSIDWebMSAuthResponseTests.m b/IdentityCore/tests/MSIDWebMSAuthResponseTests.m index 58732685f..0a2781623 100644 --- a/IdentityCore/tests/MSIDWebMSAuthResponseTests.m +++ b/IdentityCore/tests/MSIDWebMSAuthResponseTests.m @@ -23,6 +23,7 @@ #import #import "MSIDWebWPJResponse.h" +#import "MSIDWebUpgradeRegResponse.h" @interface MSIDWebMSAuthResponseTests : XCTestCase @@ -65,4 +66,19 @@ - (void)testInit_whenMSAuthScheme_shouldReturnResponsewithNoError } +- (void)testInit_whenMSAuthScheme_withUpgradeReg_shouldReturnResponsewithNoError +{ + NSError *error = nil; + MSIDWebUpgradeRegResponse *response = [[MSIDWebUpgradeRegResponse alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"msauth://upgradeReg?username=user"]] + context:nil + error:&error]; + + XCTAssertNotNil(response); + XCTAssertNil(error); + + XCTAssertEqualObjects(response.upn, @"user"); + XCTAssertNil(response.appInstallLink); + +} + @end diff --git a/IdentityCore/tests/integration/MSIDInteractiveControllerIntegrationTests.m b/IdentityCore/tests/integration/MSIDInteractiveControllerIntegrationTests.m index 21d81593c..ffd02ef1c 100644 --- a/IdentityCore/tests/integration/MSIDInteractiveControllerIntegrationTests.m +++ b/IdentityCore/tests/integration/MSIDInteractiveControllerIntegrationTests.m @@ -40,6 +40,7 @@ #if TARGET_OS_IPHONE #import "MSIDApplicationTestUtil.h" #import "MSIDWebWPJResponse.h" +#import "MSIDWebUpgradeRegResponse.h" #import "MSIDBrokerInteractiveController.h" #import "MSIDTestBrokerResponseHandler.h" #endif @@ -418,6 +419,77 @@ - (void)testAcquireToken_whenWPJRequest_shouldReturnWorkplaceJoinRequiredError [self waitForExpectationsWithTimeout:1.0 handler:nil]; } +- (void)testAcquireToken_whenUpgradeRegRequest_shouldReturnUpgradeRegistrationRequiredError +{ + // setup telemetry callback + MSIDTelemetryTestDispatcher *dispatcher = [MSIDTelemetryTestDispatcher new]; + + NSMutableArray *receivedEvents = [NSMutableArray array]; + + // the dispatcher will store the telemetry events it receives + [dispatcher setTestCallback:^(id event) + { + [receivedEvents addObject:event]; + }]; + + // register the dispatcher + [[MSIDTelemetry sharedInstance] addDispatcher:dispatcher]; + [MSIDTelemetry sharedInstance].piiEnabled = YES; + + // Setup test request providers + MSIDInteractiveTokenRequestParameters *parameters = [self requestParameters]; + parameters.telemetryApiId = @"api_broker_upgradeReg"; + + NSString *brokerURL = [NSString stringWithFormat:@"msauth://upgradeReg?username=my@test.com"]; + MSIDWebUpgradeRegResponse *msAuthResponse = [[MSIDWebUpgradeRegResponse alloc] initWithURL:[NSURL URLWithString:brokerURL] + context:nil + error:nil]; + + MSIDTestTokenRequestProvider *provider = [[MSIDTestTokenRequestProvider alloc] initWithTestResponse:nil + testError:nil + testWebMSAuthResponse:msAuthResponse + brokerRequestURL:nil + resumeDictionary:nil]; + + NSError *error = nil; + MSIDLocalInteractiveController *interactiveController = [[MSIDLocalInteractiveController alloc] initWithInteractiveRequestParameters:parameters + tokenRequestProvider:provider + error:&error]; + + XCTAssertNotNil(interactiveController); + XCTAssertNil(error); + + XCTestExpectation *expectation = [self expectationWithDescription:@"Acquire token"]; + + [interactiveController acquireToken:^(MSIDTokenResult * _Nullable result, NSError * _Nullable acquireTokenError) { + + XCTAssertNil(result); + XCTAssertNotNil(acquireTokenError); + XCTAssertEqual(acquireTokenError.code, MSIDErrorInsufficientDeviceStrength); + XCTAssertEqualObjects(acquireTokenError.userInfo[MSIDUserDisplayableIdkey], @"my@test.com"); + + // Check Telemetry event + XCTAssertEqual([receivedEvents count], 1); + NSDictionary *telemetryEvent = [receivedEvents[0] propertyMap]; + XCTAssertNotNil(telemetryEvent[@"start_time"]); + XCTAssertNotNil(telemetryEvent[@"stop_time"]); + XCTAssertEqualObjects(telemetryEvent[@"api_id"], @"api_broker_upgradeReg"); + XCTAssertEqualObjects(telemetryEvent[@"event_name"], @"api_event"); + XCTAssertEqualObjects(telemetryEvent[@"extended_expires_on_setting"], @"yes"); + XCTAssertEqualObjects(telemetryEvent[@"is_successfull"], @"no"); + XCTAssertEqualObjects(telemetryEvent[@"request_id"], parameters.telemetryRequestId); + XCTAssertEqualObjects(telemetryEvent[@"status"], @"failed"); + XCTAssertEqualObjects(telemetryEvent[@"login_hint"], @"b3bf42e34c6997b665e8693acf69075072641a1bd44ffe0d2aae21296e32ba02"); + XCTAssertEqualObjects(telemetryEvent[@"client_id"], @"my_client_id"); + XCTAssertEqualObjects(telemetryEvent[@"correlation_id"], parameters.correlationId.UUIDString); + XCTAssertNotNil(telemetryEvent[@"response_time"]); + + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:1.0 handler:nil]; +} + - (void)testAcquireToken_whenInvalidBrokerInstallRequest_shouldReturnError { // setup telemetry callback diff --git a/IdentityCore/tests/integration/ios/MSIDDefaultInteractiveTokenRequestTests.m b/IdentityCore/tests/integration/ios/MSIDDefaultInteractiveTokenRequestTests.m index 751283292..5bc832284 100644 --- a/IdentityCore/tests/integration/ios/MSIDDefaultInteractiveTokenRequestTests.m +++ b/IdentityCore/tests/integration/ios/MSIDDefaultInteractiveTokenRequestTests.m @@ -42,6 +42,7 @@ #import "MSIDRefreshToken.h" #import "MSIDAuthority+Internal.h" #import "MSIDWebWPJResponse.h" +#import "MSIDWebUpgradeRegResponse.h" #import "MSIDTestIdentifiers.h" #if TARGET_OS_IPHONE #import "MSIDApplicationTestUtil.h" @@ -731,6 +732,75 @@ - (void)testInteractiveRequestFlow_whenBrokerInstallResponse_shouldReturnNilResu [self waitForExpectationsWithTimeout:1 handler:nil]; } +- (void)testInteractiveRequestFlow_whenBrokerUpgradeRegResponse_shouldReturnNilResultWithNilErrorAndBrokerResponse +{ + __block NSUUID *correlationId = [NSUUID new]; + + MSIDInteractiveTokenRequestParameters *parameters = [MSIDInteractiveTokenRequestParameters new]; + parameters.target = @"fakescope1 fakescope2"; + parameters.authority = [@"https://login.microsoftonline.com/common" aadAuthority]; + parameters.redirectUri = @"x-msauth-test://com.microsoft.testapp"; + parameters.clientId = @"my_client_id"; + parameters.extraAuthorizeURLQueryParameters = @{ @"eqp1" : @"val1", @"eqp2" : @"val2" }; + parameters.loginHint = @"fakeuser@contoso.com"; + parameters.correlationId = correlationId; + parameters.webviewType = MSIDWebviewTypeWKWebView; + parameters.extraScopesToConsent = @"fakescope3"; + parameters.oidcScope = @"openid profile offline_access"; + parameters.promptType = MSIDPromptTypeConsent; + parameters.authority.openIdConfigurationEndpoint = [NSURL URLWithString:@"https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"]; + parameters.accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:@"user@contoso.com" homeAccountId:@"1.1234-5678-90abcdefg"]; + parameters.enablePkce = YES; + + MSIDInteractiveTokenRequest *request = [[MSIDInteractiveTokenRequest alloc] initWithRequestParameters:parameters + oauthFactory:[MSIDAADV2Oauth2Factory new] + tokenResponseValidator:[MSIDDefaultTokenResponseValidator new] + tokenCache:self.tokenCache + accountMetadataCache:self.metadataCache extendedTokenCache:nil]; + + XCTAssertNotNil(request); + + // Swizzle out the main entry point for WebUI, WebUI is tested in its own component tests + [MSIDTestSwizzle classMethod:@selector(startSessionWithWebView:oauth2Factory:configuration:context:completionHandler:) + class:[MSIDWebviewAuthorization class] + block:(id)^( + __unused id obj, + __unused NSObject *webview, + __unused MSIDOauth2Factory *oauth2Factory, + __unused MSIDBaseWebRequestConfiguration *configuration, + __unused id context, + MSIDWebviewAuthCompletionHandler completionHandler) + { + + NSString *responseString = @"msauth://upgradeReg?username=user"; + + MSIDWebUpgradeRegResponse *msauthResponse = [[MSIDWebUpgradeRegResponse alloc] initWithURL:[NSURL URLWithString:responseString] context:nil error:nil]; + completionHandler(msauthResponse, nil); + }]; + + NSString *authority = @"https://login.microsoftonline.com/common"; + MSIDTestURLResponse *discoveryResponse = [MSIDTestURLResponse discoveryResponseForAuthority:authority]; + [MSIDTestURLSession addResponse:discoveryResponse]; + + MSIDTestURLResponse *oidcResponse = [MSIDTestURLResponse oidcResponseForAuthority:authority]; + [MSIDTestURLSession addResponse:oidcResponse]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"Run request."]; + + [request executeRequestWithCompletion:^(MSIDTokenResult * _Nullable result, NSError * _Nullable error, MSIDWebWPJResponse * _Nullable upgradeRegBrokerResponse) { + + XCTAssertNil(result); + XCTAssertNil(error); + XCTAssertNotNil(upgradeRegBrokerResponse); + XCTAssertEqualObjects(upgradeRegBrokerResponse.upn, @"user"); + + [expectation fulfill]; + + }]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + - (void)testInteractiveRequestFlow_whenNestedAuth_shouldReturnResultWithBrokerParametersAndNoError { __block NSUUID *correlationId = [NSUUID new];