From 1136ba34caba3fac63e76c1d2de3654c1e48beef Mon Sep 17 00:00:00 2001 From: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Date: Tue, 17 Oct 2023 22:59:34 -0700 Subject: [PATCH 01/84] Update submodule --- MSAL/IdentityCore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 17675cbadf..3cb7708a6c 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 17675cbadf8b97be991c52c2214ebb6b6c8a7d81 +Subproject commit 3cb7708a6cc586ac44b5d7aada5e53e5a26b3027 From d64ee1aa21400af77d9464fcb3bac8655b24b15c Mon Sep 17 00:00:00 2001 From: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Date: Wed, 1 Nov 2023 17:14:24 -0700 Subject: [PATCH 02/84] Update submodule --- MSAL/IdentityCore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 3cb7708a6c..4226074780 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 3cb7708a6cc586ac44b5d7aada5e53e5a26b3027 +Subproject commit 42260747803709af57fadfa9332771588e4d544e From cc5162dbe96ce348317a11d71659a5a63c207bae Mon Sep 17 00:00:00 2001 From: Sergei Demchenko Date: Fri, 3 Nov 2023 17:14:05 -0700 Subject: [PATCH 03/84] Get token operation for BrowserCore (#1862) * Update core. * Update msal. * Update core. * update core. * Update core. * Update core. * Update core. * Update core. * Update core. * Update core. --- MSAL/IdentityCore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 17675cbadf..1ff73718ab 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 17675cbadf8b97be991c52c2214ebb6b6c8a7d81 +Subproject commit 1ff73718abab499d35e3248b55fb8a1e6b215cbf From f7de2a791f07ba551d832e034d42e030f528d065 Mon Sep 17 00:00:00 2001 From: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Date: Mon, 6 Nov 2023 09:22:24 -0800 Subject: [PATCH 04/84] Update submodule --- MSAL/IdentityCore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index ad9fcccb56..64ecb78fde 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit ad9fcccb56801c20578cb463acded84524317cfe +Subproject commit 64ecb78fde1d6440f30ed93930b20bf7c5324afe From 28fefe3bbe81f4528c38b18ec211ad8773b7769e Mon Sep 17 00:00:00 2001 From: Veena Soman Date: Mon, 6 Nov 2023 14:35:56 -0800 Subject: [PATCH 05/84] Updated submodule --- MSAL/IdentityCore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 17675cbadf..a15d39de0c 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 17675cbadf8b97be991c52c2214ebb6b6c8a7d81 +Subproject commit a15d39de0cf151f6fb99ddccc6cee83d9e7a7329 From 673bac0f2737ebb3bffd3ef301756a52270d08fb Mon Sep 17 00:00:00 2001 From: Veena Soman Date: Mon, 6 Nov 2023 14:50:42 -0800 Subject: [PATCH 06/84] Updated submodule --- MSAL/IdentityCore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index a15d39de0c..56776ef6c7 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit a15d39de0cf151f6fb99ddccc6cee83d9e7a7329 +Subproject commit 56776ef6c7ce042bea35e86f9d293dc00025d81a From bae31f55ebdda66e295c5071c1f8a9a424f9b000 Mon Sep 17 00:00:00 2001 From: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Date: Mon, 6 Nov 2023 18:14:27 -0800 Subject: [PATCH 07/84] Update submodule --- MSAL/IdentityCore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 64ecb78fde..bec0f22892 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 64ecb78fde1d6440f30ed93930b20bf7c5324afe +Subproject commit bec0f228929623c06e4144c03488275f11103fa3 From 342918b49ccaae72b21506511b441fac70158f9c Mon Sep 17 00:00:00 2001 From: Veena Soman Date: Sun, 19 Nov 2023 18:24:21 -0800 Subject: [PATCH 08/84] update submodule for current key change --- MSAL/IdentityCore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 14c81411d3..ae2fbc82e7 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 14c81411d3fdabac5ceb96625629e448bacf0745 +Subproject commit ae2fbc82e7b8e8fd31aab13a075571aed5278fa8 From 3165335e3095b8b2220f79b584394319657cce87 Mon Sep 17 00:00:00 2001 From: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Date: Thu, 30 Nov 2023 16:06:26 -0800 Subject: [PATCH 09/84] New error message when device is not PSSO registered. --- MSAL/IdentityCore | 2 +- MSAL/src/MSALErrorConverter.m | 3 ++- MSAL/src/public/MSALError.h | 5 +++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 667d842423..f38c7d1ab4 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 667d8424230fd8dd3bd726c27a8fcf4f081ef635 +Subproject commit f38c7d1ab4351af76d0e9a631aa5ff7453f8f3bd diff --git a/MSAL/src/MSALErrorConverter.m b/MSAL/src/MSALErrorConverter.m index 2fe85ce2c0..8c7a5c6228 100644 --- a/MSAL/src/MSALErrorConverter.m +++ b/MSAL/src/MSALErrorConverter.m @@ -110,7 +110,8 @@ + (void)initialize @(MSIDErrorJITTroubleshootingCreateController) : @(MSALErrorJITTroubleshootingCreateController), @(MSIDErrorJITTroubleshootingResultUnknown) : @(MSALErrorJITTroubleshootingResultUnknown), @(MSIDErrorJITTroubleshootingAcquireToken) : @(MSALErrorJITTroubleshootingAcquireToken), - + @(MSIDErrorDeviceNotPSSORegistered) : @(MSALErrorDeviceNotPSSORegistered), + // Oauth2 errors @(MSIDErrorServerOauth) : @(MSALInternalErrorAuthorizationFailed), @(MSIDErrorServerInvalidResponse) : @(MSALInternalErrorInvalidResponse), diff --git a/MSAL/src/public/MSALError.h b/MSAL/src/public/MSALError.h index 1d46a44423..053e4213c8 100644 --- a/MSAL/src/public/MSALError.h +++ b/MSAL/src/public/MSALError.h @@ -490,4 +490,9 @@ typedef NS_ENUM(NSInteger, MSALInternalError) */ MSALErrorJITTroubleshootingResultUnknown = -42735, + /** + Device is not PSSO registered + */ + MSALErrorDeviceNotPSSORegistered = -42736, + }; From 92df4c0a3f57aa0b614ceb2415efac3d1dcac3a5 Mon Sep 17 00:00:00 2001 From: mipetriu Date: Thu, 30 Nov 2023 16:32:32 -0800 Subject: [PATCH 10/84] Added QRPIN changes for MSAL --- MSAL/src/MSALDeviceInformation.m | 14 ++++++++++- MSAL/src/MSALPublicClientApplication.m | 5 ++++ MSAL/src/public/MSALDefinitions.h | 23 +++++++++++++++++++ MSAL/src/public/MSALDeviceInformation.h | 5 ++++ .../public/MSALInteractiveTokenParameters.h | 2 ++ 5 files changed, 48 insertions(+), 1 deletion(-) diff --git a/MSAL/src/MSALDeviceInformation.m b/MSAL/src/MSALDeviceInformation.m index 63fb14de27..b8a6b48cdc 100644 --- a/MSAL/src/MSALDeviceInformation.m +++ b/MSAL/src/MSALDeviceInformation.m @@ -87,7 +87,8 @@ - (instancetype)initWithMSIDDeviceInfo:(MSIDDeviceInfo *)deviceInfo #if TARGET_OS_OSX _platformSSOStatus = [self msalPlatformSSOStatusFromMSIDPlatformSSOStatus:deviceInfo.platformSSOStatus]; #endif - + _qrpinAvailable = [self msalQRPinAvailabilityFromMSIDQRPinAvailability:deviceInfo.qrPinAvailability]; + _extraDeviceInformation = [NSMutableDictionary new]; [self initExtraDeviceInformation:deviceInfo]; } @@ -135,6 +136,17 @@ - (MSALPlatformSSOStatus)msalPlatformSSOStatusFromMSIDPlatformSSOStatus:(MSIDPla } } +- (MSALQRPinAvailability)msalQRPinAvailabilityFromMSIDQRPinAvailability:(MSIDQRPinAvailability)msidQRPinAvailability +{ + switch (msidQRPinAvailability) { + case MSIDQRPinAvailable: + return MSALQRPinAvailable; + + default: + return MSALQRPinNotAvailable; + } +} + // For readability, both keys and values in the output dictionary are NSString - (void) initExtraDeviceInformation:(MSIDDeviceInfo *)deviceInfo { diff --git a/MSAL/src/MSALPublicClientApplication.m b/MSAL/src/MSALPublicClientApplication.m index d2908688f8..8459f7ce3d 100644 --- a/MSAL/src/MSALPublicClientApplication.m +++ b/MSAL/src/MSALPublicClientApplication.m @@ -1206,6 +1206,11 @@ - (void)acquireTokenWithParameters:(MSALInteractiveTokenParameters *)parameters msidParams.currentRequestTelemetry.apiId = [msidParams.telemetryApiId integerValue]; msidParams.currentRequestTelemetry.tokenCacheRefreshType = TokenCacheRefreshTypeNoCacheLookupInvolved; + if (parameters.preferredAuthMethod == MSALPreferredAuthMethodQRPIN) + { + msidParams.preferredAuthMethod = MSIDPreferredAuthMethodQRPIN; + } + MSIDAccountMetadataState signInState = [self accountStateForParameters:msidParams error:nil]; if (signInState == MSIDAccountMetadataStateSignedOut && msidParams.promptType != MSIDPromptTypeConsent) diff --git a/MSAL/src/public/MSALDefinitions.h b/MSAL/src/public/MSALDefinitions.h index 7539d1eedc..c413a6ec9a 100644 --- a/MSAL/src/public/MSALDefinitions.h +++ b/MSAL/src/public/MSALDefinitions.h @@ -178,6 +178,29 @@ typedef NS_ENUM(NSUInteger, MSALPlatformSSOStatus) MSALPlatformSSOEnabledAndRegistered }; +/** + Device mode configured by the administrator + */ +typedef NS_ENUM(NSUInteger, MSALQRPinAvailability) +{ + /* + Administrator hasn't configured QR+PIN as an authentication method for this device. + */ + MSALQRPinNotAvailable, + + /* + Administrator has configured QR+PIN as an authentication method for this device. + */ + MSALQRPinAvailable +}; + +typedef NS_ENUM(NSUInteger, MSALPreferredAuthMethod) +{ + MSALPreferredAuthMethodNone, + + MSALPreferredAuthMethodQRPIN +}; + /** The block that gets invoked after MSAL has finished getting a token silently or interactively. @param result Represents information returned to the application after a successful interactive or silent token acquisition. See `MSALResult` for more information. diff --git a/MSAL/src/public/MSALDeviceInformation.h b/MSAL/src/public/MSALDeviceInformation.h index 04e07e54e3..90dc94aaf7 100644 --- a/MSAL/src/public/MSALDeviceInformation.h +++ b/MSAL/src/public/MSALDeviceInformation.h @@ -69,6 +69,11 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, readonly) MSALDeviceMode deviceMode; +/** + Availability of QR+PIN as an authentication method as configured by the admin +*/ +@property (nonatomic, readonly) MSALQRPinAvailability qrpinAvailable; + /** Specifies whether AAD SSO extension was detected on the device. */ diff --git a/MSAL/src/public/MSALInteractiveTokenParameters.h b/MSAL/src/public/MSALInteractiveTokenParameters.h index 32aef6f000..01f8013453 100644 --- a/MSAL/src/public/MSALInteractiveTokenParameters.h +++ b/MSAL/src/public/MSALInteractiveTokenParameters.h @@ -95,6 +95,8 @@ Modal presentation style for displaying authentication web content. */ @property (nonatomic, nullable) WKWebView *customWebview DEPRECATED_MSG_ATTRIBUTE("Create MSALWebviewParameters and provide it to -initWithScopes:webviewParameters: instead"); +@property (nonatomic) MSALPreferredAuthMethod preferredAuthMethod; + #pragma mark - Constructing MSALInteractiveTokenParameters #if TARGET_OS_IPHONE From 20a5642d8f1925d49224b5795ff31b3a432768bd Mon Sep 17 00:00:00 2001 From: mipetriu Date: Wed, 6 Dec 2023 17:22:57 -0800 Subject: [PATCH 11/84] Added submodule changes --- MSAL/IdentityCore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 17675cbadf..6ce851f7fe 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 17675cbadf8b97be991c52c2214ebb6b6c8a7d81 +Subproject commit 6ce851f7fe9a6cf83f482752aded1e8f1a72a7c7 From 616c7b411b3cea909ad2c7095813104460b01e33 Mon Sep 17 00:00:00 2001 From: Kai Date: Fri, 8 Dec 2023 16:52:54 -0800 Subject: [PATCH 12/84] Merge release 1220 into dev (#1934) * Release MSAL 1.2.20 (#1930) * Update submodule * Update submodule * Get token operation for BrowserCore (#1862) * Update core. * Update msal. * Update core. * update core. * Update core. * Update core. * Update core. * Update core. * Update core. * Update core. * Update submodule * Updated submodule * Updated submodule * Update submodule * update submodule for current key change * New error message when device is not PSSO registered. * Release MSAL 1.2.20 * Align with latest main (#1933) --------- Co-authored-by: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Co-authored-by: Sergei Demchenko Co-authored-by: Swasti Gupta Co-authored-by: Swasti Gupta Co-authored-by: Juan Arias Co-authored-by: Kai * Updating MSAL framework checksum & url for 1.2.20 [skip ci] * Update CommonCore to latest dev --------- Co-authored-by: Veena Soman Co-authored-by: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Co-authored-by: Sergei Demchenko Co-authored-by: Swasti Gupta Co-authored-by: Swasti Gupta Co-authored-by: Juan Arias --- CHANGELOG.md | 3 +++ MSAL.podspec | 2 +- MSAL/IdentityCore | 2 +- MSAL/resources/ios/Info.plist | 2 +- MSAL/resources/mac/Info.plist | 2 +- MSAL/src/MSAL_Internal.h | 2 +- Package.swift | 2 +- 7 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd8c65a8f0..464c808614 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [1.2.20] +* Updated common core submodule with changes for platform sso and mapping broker version in token result + ## [1.2.19] * Introduce a way to inject external WKWebviewConfiguration for MSIDWebviewUIController - needed for MSAL C++ (#1308) diff --git a/MSAL.podspec b/MSAL.podspec index 94aa6649ab..942c6028c9 100644 --- a/MSAL.podspec +++ b/MSAL.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "MSAL" - s.version = "1.2.19" + s.version = "1.2.20" s.summary = "Microsoft Authentication Library (MSAL) for iOS" s.description = <<-DESC The MSAL library for iOS gives your app the ability to begin using the Microsoft Cloud by supporting Microsoft Azure Active Directory and Microsoft Accounts in a converged experience using industry standard OAuth2 and OpenID Connect. The library also supports Microsoft Azure B2C for those using our hosted identity management service. diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index d012ccd1b3..e23cb10d35 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit d012ccd1b37df91ebb6dc11084677cbb3f6eed2c +Subproject commit e23cb10d35ec3a8ce0c94f7e5a3a0a622e9d2873 diff --git a/MSAL/resources/ios/Info.plist b/MSAL/resources/ios/Info.plist index bbe748cae8..3757227635 100644 --- a/MSAL/resources/ios/Info.plist +++ b/MSAL/resources/ios/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.2.19 + 1.2.20 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass diff --git a/MSAL/resources/mac/Info.plist b/MSAL/resources/mac/Info.plist index 3b3dca33d8..27e64571d9 100644 --- a/MSAL/resources/mac/Info.plist +++ b/MSAL/resources/mac/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.2.19 + 1.2.20 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright diff --git a/MSAL/src/MSAL_Internal.h b/MSAL/src/MSAL_Internal.h index 19e96ccdce..511441672c 100644 --- a/MSAL/src/MSAL_Internal.h +++ b/MSAL/src/MSAL_Internal.h @@ -27,7 +27,7 @@ #define MSAL_VER_HIGH 1 #define MSAL_VER_LOW 2 -#define MSAL_VER_PATCH 19 +#define MSAL_VER_PATCH 20 #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) diff --git a/Package.swift b/Package.swift index 6ff4b7af73..1f1e784fff 100644 --- a/Package.swift +++ b/Package.swift @@ -13,6 +13,6 @@ let package = Package( targets: ["MSAL"]), ], targets: [ - .binaryTarget(name: "MSAL", url: "https://github.com/AzureAD/microsoft-authentication-library-for-objc/releases/download/1.2.19/MSAL.zip", checksum: "a90f11aac4f1a76bd93938f7bbe9f3ad375bd0e3f838dc65edff91111793701f") + .binaryTarget(name: "MSAL", url: "https://github.com/AzureAD/microsoft-authentication-library-for-objc/releases/download/1.2.20/MSAL.zip", checksum: "af2143bd263b384ba4f9d825a4baac18c5511de23a5abf147d0ff1972cd897a9") ] ) From 7166bf34552ffec8d14b6d217fa96d0cb70e7b9e Mon Sep 17 00:00:00 2001 From: Marcos Borges <116104275+borgesmb@users.noreply.github.com> Date: Mon, 11 Dec 2023 21:33:10 +0000 Subject: [PATCH 13/84] Native Auth features (#1911) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * check that codeLength is not nil * Initial depth first doc comments for Sign In public interface * Quick fixes to sign in docs * Initial sign up doc comments * Two small fixes * Typos * Just adding some fullstops * Doc comments for getCurrentAccount and result * Added SSPR doc comments * Fixed doc comment for sign up * Updated top level documentation * Add doc comments for init methdos * Merged PR 9103: Fix sign out e2e tests for mock API, skip for test tenant ## Proposed changes Small PR to fix sign out e2e tests for mock API, skip for test tenant. Now that we no longer go straight to the token endpoint when signing in with a password, we need to provide queue up the mock responses for the /initiate and /challenge endpoints too. Also, as this flow isn't supported in the test tenant at the moment we need to skip running this if it is not a Mock API test configuration. ## Type of change - [ ] Feature work - [ ] Bug fix - [ ] Documentation - [ ] Engineering change - [X] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [X] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information Fix sign out e2e tests for mock API, skip for test tenant * Initial depth first doc comments for Sign In public interface * Quick fixes to sign in docs * Initial sign up doc comments * Two small fixes * Typos * Just adding some fullstops * Doc comments for getCurrentAccount and result * Added SSPR doc comments * Fixed doc comment for sign up * Updated top level documentation * Add doc comments for init methdos * PR Comments * PR Comments * PR Comments * Removed not needed configuration parameter * Added Notes about optional delegate parameters * Used consistent parameter groups for documentation when more than 1 parameter * Added note and corrected error * Changed description of `newState` parameter in docc comments * Removed mention of text message from docc comments * Doc comment updates * Added some missing doc comments * Added optional label to optional parameters in doc comments * Updated comment * Updated initial text in markdown about Native Auth * PR comment * PR comment * Updated PCA initialiser to take clientId, tenantName and challengeTypes as parameters * Fixed bad commit * - Added a slice config property to MSALNativeAuthConfiguration - Changed MSALNativeAuthRequestable default implementation to inject the slice information in an url query - All controllers that want to point to a specific test slice need to first set the sliceConfig property (in MSALNativeAuthClientApplicationConfig) before constructing an instance of MSALNativeAuthPublicClientApplication * Fixed capitalisation * Fixed reference to password error delegate in code comment * Fixed typos in doc comments * Updated error description in doc comments * Updated delegate description in doc comments * Updated doc comment for account result * Added missing doc comments for some error types * Merged PR 9102: Add default error descriptions for all MSALNativeAuthError subclasses ## Proposed changes This PR adds default error descriptions for all `MSALNativeAuthError` subclasses. If an error already has a non-nil `errorDescription` then that is returned, otherwise we return a string based on the `type`. ## Type of change - [X] Feature work - [ ] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [X] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information Before: ![CleanShot 2023-07-14 at 07.11.10@2x.png](https://identitydivision.visualstudio.com/fac9d424-53d2-45c0-91b5-ef6ba7a6bf26/_apis/git/repositories/616da9d3-8336-4562-811a-581d9a5cbe9c/pullRequests/9102/attachments/CleanShot%202023-07-14%20at%2007.11.10%402x.png) After: ![CleanShot 2023-07-14 at 07.10.36@2x.png](https://identitydivision.visualstudio.com/fac9d424-53d2-45c0-91b5-ef6ba7a6bf26/_apis/git/repositories/616da9d3-8336-4562-811a-581d9a5cbe9c/pullRequests/9102/attachments/CleanShot%202023-07-14%20at%2007.10.36%402x.png) * - Added unit test for MSALNativeAuthRequestable default implementation * - Using url components to construct endpoints * Updated PCA initialiser to take clientId, tenantName and challengeTypes as parameters * Fixed bad commit * Removed debug code * Fixed doc comment for new initialiser * - Removed changes done in view controllers, since Sample App is going to use a different initialiser * Added back redirectUri parameter * - Fixing url component to resolve against base url * - Added new unit test for when test slice is not used * - Fixing merge issues * - Fixing more merge issues * Changing parameter from NULL to nil when constructing MSALNativeAuthPublicClientApplication in objc view controller * make account accessible from external dev, update unit tests * remove accountClaims and fix swift lint warnings * update signUp integration tests * make account a constant and remove private(set) * call SDK signOut method when pressing signOut button * submodule update * Update readme * Merged PR 9199: Update MSAL podspec to enable installation of Native Auth with Cocoapods ## Proposed changes - Added updates to MSAL.podspec needed to compile the Swift files that were added to the project: -- Disabled MACos build as it's outside the private preview scope -- Added the 'HEADER_SEARCH_PATHS' => __dir__ to the pod_target_xcconfig to allow for the Pod Project to compile the modulemap -- Added the Swift extension to the list of source files for both iOS and MacOS (app.source_files / ext.source_files) -- Added the new MSAL Native Auth public headers to both subspecs and both platforms - "MSAL/src/native_auth/public/*.h" - The swift files removed were still present in the folders even though they were not use inside the xcodeproj, but because Cocoapods was picking them up as Swift files, they needed to be removed. ## Type of change - [x] Feature work - [ ] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [x] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information To test: - Create a new App - Install Cocoapods - Go to the folder of the app in terminal and execute "pod init" - Edit the Podfile and set your pulled branch as the local path to the folder: `pod 'MSAL' , :path => '/Users//Desktop/Projects/MSAL'` (or wherever your project is) - Go to the folder of the app in terminal and execute "pod install" - Import MSAL, make sure you can access the MSALNativeAuthPublicClientApplication class - To build be sure to be on the iOS framework, not the MACos one Related work items: #2621133 * Merged PR 9342: Fix Build for Azure Pipelines ## Proposed changes Fix project so pipeline builds successfully Following fixes were applied: -Because of this [issue](https://github.com/actions/runner-images/issues/8023) where the latest MacOS 13 image uses XCode 15 with the iOS 17 beta simulator, the "latest" iPhone 14 simulator is now 17. Due to this, the build is very slow which makes multiple tests fail due to timeouts -The iOS simulator that is now launched is the iOS 16.4 one instead of the 17 one -The GUID used for code coverage is the one of the iOS 16.4 simulator to allow the code coverage to work properly -Swiftlint appears to be running on all the code now, so fixed swiftlint issues on the Native Auth Sample app ## Type of change - [ ] Feature work - [ ] Bug fix - [ ] Documentation - [x] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [X] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information Related work items: #2655681 * Merged PR 9259: ResetPassword-start. Not all invalidRequest are related to "UserDoesNotHaveAPassword" error ## Proposed changes Highlights: - Created new custom validated error enum for resetPassword start - update unit tests ## Type of change - [ ] Feature work - [X] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information We don't need to log the unexpected error codes Related work items: #2640267 * Merged PR 9426: Include errorDescription, when available, on log message ## Proposed changes - Whenever an error gets logged it's errorDescription should be logged rather than the description of the Object. `error.errorDescription` vs 'error.description' - The change to the `MSALNativeAuthPublicClientApplication.swift` is due to an Swiftlint issue that doesn't get picked up by the git difference. - The cases where an errorType or error as part of a do/try was logged didn't need change. ## Type of change - [ ] Feature work - [ ] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [x] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information This can be tested by replacing this function in AppDelegate.swift on the NativeAuthSampleApp and then calling an API ``` func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. MSALGlobalConfig.loggerConfig.setLogCallback { (level: MSALLogLevel, message: String?, containsPII: Bool) in // If PiiLoggingEnabled is set YES, this block will potentially contain sensitive information (Personally Identifiable Information), but not all messages will contain it. // containsPII == YES indicates if a particular message contains PII. // You might want to capture PII only in debug builds, or only if you take necessary actions to handle PII properly according to legal requirements of the region if let displayableMessage = message { if (!containsPII) { #if DEBUG // NB! This sample uses print just for testing purposes // You should only ever log to NSLog in debug mode to prevent leaking potentially sensitive information print(displayableMessage) #endif } } } return true } ``` Related work items: #2641240 * points to latests commit on IdentityCore/ciam-master * increase timeout cause the mac agent uses beta version simulator * - Added two new delegates to sign up, to be triggered instead of returning errors: `onSignUpAttributesRequired` and `onSignUpAttributesInvalid` - Parsing error responses from sign up /start and /continue endpoints - Adjusted spies and tests accordingly * add new otp error codes, parse error code for invalid request, add new unit tests * Merged PR 9568: - Fix re-encoding of attributes in MSALNativeAuthSignUpRequestProvider ## Proposed changes Describe what this PR is trying to do. ## Type of change - [ ] Feature work - [X] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [X] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information - Fix re-encoding of attributes in MSALNativeAuthSignUpRequestProvider Related work items: #2670284 * Merged PR 9542: iOS - Use error description from API when available ## Proposed changes Whenever API sends error descriptions, they should be returned to the developer integrating the SDK to better debug the issues they are facing -Changed how errors are returned -Changed unit tests to use the new functionality -Added unit tests for the Enums and new functions ## Type of change - [x] Feature work - [ ] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [x] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information Related work items: #2610913 * - Removed unnecessary statement in MSALNativeAuthErrorRequiredAttributes string description * - Fixed unit testes for MSALNativeAuthErrorRequiredAttributes * - Removed public access tp MSALNativeAuthErrorRequiredAttributes initialiser * i Improved methods description in SignUpAttributesRequiredDelegate * - Methods description fix * - Removed error assertion * - Made property "regex" of RequiredAttributeOptions access public as well * - Moved MSALNativeAuthErrorBasicAttributes and RequiredAttributeOptions to separate files * - Fixed file headers - Fixed SwiftLint warnings - Changed MSALNativeAuthSignUpContinueResponseError to use MSALNativeAuthErrorBasicAttributes instead of dictionary in unverifiedAttributes * handle new otp error codes for signIn token endpoint result * handle invalid request for otp error codes in signUp * send invalid user input result instead of generic error * - Created RequiredAttributesError to separate MSALNativeAuthErrorRequiredAttributes from the SDK's external interface * test all error cases for invalid grant * add new tests for invalid request-otp error codes in signUp validator class * return invalidRequest instead of general error when invalidRequest is received * - Added list of attributes required to SignUpVerifyCodeDelegate and SignUpPasswordRequiredDelegate * no message * Rename file * Fixed white space * Fixed attributeValidationFailed case on submitCode and submitPassword * Grouped cases together * Merged PR 9618: Provide username for signin with slt via SignUpController ## Proposed changes Now we keep the username in memory between calls. I'm carrying over every call in order to avoid having state in the Controller. I've added an integration test at the end of `MSALNativeAuthSignUpControllerTests` because although we have the E2E test for signUp, the mock api is not updated and I'm not sure if the parameter is mandatory at the moment. Apart from the test in code, I've retested the following tests of the [Native Auth Private Preview test cases](https://microsofteur.sharepoint.com/:x:/t/DevExDublin/ESLT-SpZO7dEpuN4aLIiB9MBMPeJ94oJWIy8vFEa4Jsimg?e=enJcyV) sheet: - Test 1 (also tried re-sending the oob code and continuing from there) - Test 3 - Test 13 - Test 17 ## Type of change - [ ] Feature work - [x] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information Related work items: #2670401 * remove swiftlint warinings, copy all error fields, add new unit tests related to the changes * Add new eSTS error for sign-up flow. However, this will need to be refactored since we shouldn't be creating API Models on our own (IMO). API Models should reflect API. I'm making this change now to avoid creating another "middle" model for the sign-up errors, which would lead to a few changes in tests. Options to solve this problem in the future would be: 1) Create a new validated error enum in the SignUpValidator 2) Perform some conversion logic from the eSTS error to our error inside the error API models via a method or computed property. * Fix test * Add integration test to mock api * remove invalid and required attributes error * update and add unit tests * remove newState from attributesRequiredError callback. update unit and integration tests * Add new case to handle invalidUsername error in MSALNativeAuthSignUpStartValidatedResponse * remove invalid attributes for signUpStart error enums, use optional delegate methods * update sample app * remove swiftlint warnings * update unit tests * add new unit tests * update log message for invalid attributes * Merged PR 9669: Change API error invalid_client to unauthorized_client ## Proposed changes -For SignUp Start/Challenge/Continue and SignIn Initiate/Challenge the error code for invalid_client should be changed to unauthorized_client -For Token unauthorized_client should be added to the possible list of error codes ## Type of change - [ ] Feature work - [ ] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [x] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information -Integration tests don't work anymore as the Mock API is not updated so they were disabled Related work items: #2654063 * Update submodules * Merged PR 9687: Change auth_not_supported to unsupported_auth_method ## Proposed changes Changed auth_not_supported to unsupported_auth_method ## Type of change - [ ] Feature work - [ ] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information Related work items: #2673106 * update configuration file * do not show cached user username. log accountId instead of username * use sample placeholders as specified in the document * rename tenantName to tenantSubdomain * remove client id * add default value for redirectUri and bypass redirect URI validation when needed * Merged PR 9738: Update IdentityCore submodule ## Proposed changes Update submodules in the project to include our [latest changes](https://identitydivision.visualstudio.com/Engineering/_git/devexdub-microsoft-authentication-library-common-for-objc/pullrequest/9737) from IdentityCore. ## Type of change - [ ] Feature work - [ ] Bug fix - [ ] Documentation - [x] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information Update submodules Related work items: #2643139 * add new unit test, remove unwanted characters * Remove old sample app and rename proper sample app folder * remove raw tenant from MSIDCIAMAuthotiry initialisation * remove doc folder * remove old sample app from build script and rename folder * update build script, remove simple word from * remove blank lines to make swiftlint happy * Merged PR 9759: Treat InvalidClientId correctly ## Proposed changes Because both invalid client id and invalid username API errors generate a invalidRequest error with an error code of 90100, we have to check the error_description to see why it happens -Invalid username is now mapped to public error invalidUsername -Invalid client id is now mapped to public error generalError but we log the client id error ## Type of change - [ ] Feature work - [x] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information Related work items: #2685134 * set correct name for attributes required method name * remove optional methods from sample app * Merged PR 9768: Update MSALNativeAuthServerTelemetry to include optional errors ## Proposed changes We need to merge !9767 before merging this one. ## Type of change - [ ] Feature work - [ ] Bug fix - [ ] Documentation - [x] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information Update MSALNativeAuthServerTelemetry to include optional errors Related work items: #2643139 * remove empty implementation of optional methods * update readme doc * update readme file, add new images * address comments * modifications to let xcode 13.4.1 works * update SDK version for private preview * skip test for private preview versioning * Merged PR 9361: Refactor controllers to enable new public interfaces ## Proposed changes - Refactor the controllers to return a response to the public interface (and the public interface will return to the developer). This makes the task of creating public interfaces (such as async/await, combine, etc.) easier because the controller is not tightly coupled to the interface. - Unit tests updated. ## Type of change - [x] Feature work - [ ] Bug fix - [ ] Documentation - [x] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [x] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) Related work items: #2635763 * Merged PR 9843: Changes to NativeAuthSampleApp for Xcode 13.4 compatibility ## Proposed changes Changes that remove Swift features specific to Xcode 14 to allow building NativeAuthSampleApp on Xcode 13.4. The 2 Swift changes needed to build on Xcode 13.4 are 1. Providing initializers in if/guard statements when unwrapping optionals 2. Explicit use of "self" The project format has been changed to "Xcode 13.0-compatible" ## Type of change - [ ] Feature work - [ ] Bug fix - [ ] Documentation - [x] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information * Fix for account claims * Made the initialiser easier to use * Merged PR 9900: Fix Cocoapods to work with Git installations ## Proposed changes - Fixed Cocoapods so that when users use `pod 'MSAL', :git => "https://github.com/AzureAD/msal-objc-native-auth-preview"` in their pod file it works as intended - This change means the local install with path doesn't work as both relative and absolute paths can't work at the same time (there could be a configuration that we are unaware of which might make both work but the git one is more important) -To test from ADO set `pod 'MSAL', :git => "https://identitydivision.visualstudio.com/DefaultCollection/Engineering/_git/devexdub-microsoft-authentication-library-for-objc", :branch => "spetrescu/cocoapods-git-fix", :submodules => true ` ## Type of change - [ ] Feature work - [ ] Bug fix - [ ] Documentation - [x] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [x] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information - Changed modulemap to use Relative Path instead of Absolute - Added modulemap file to source files so it gets downloaded as we use a private module map rather than a normal one (where all files are public) - Split modulemap file into two modules for files that are not added to the target - Modified unit tests to load needed modules based on requirements Related work items: #2697240 * - Added Native Auth base classes that interact with MSAL * - Added Native Auth network classes that interact with MSAL * - Added unit tests * - Added unit tests * -Fixed unit tests -PR Comments * - Added Native Auth Sign Up files * - Added Native Auth Sign In * - Added Native Auth Password Reset files * Merged PR 9949: [iOS SDK] Make the SDK build for Release and Profiling ## Proposed changes Fix the build error around the `performTokenRequest` function in `MSALNativeAuthTokenController` The linker, when optimizing for speed or size, doesn't process the function `private func performTokenRequest(_ request: MSIDHttpRequest, context: MSIDRequestContext) async -> Result {` properly. The only workaround found so far was to move all private functions into an extension in the same file ## Type of change - [ ] Feature work - [x] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information Created extension to circumvent undefined symbol error Related work items: #2694846 * - Clearing cache in setup and teardown methods only (MSALNativeAuthCacheAccessorTests) - Added full SLT naming * Merged PR 10009: Fix imports for new MSAL private module in integration tests ## Proposed changes Quick fix to two places in the integration tests that required the MSAL_Unit_Test_Private instead of MSAL_Private ## Type of change - [ ] Feature work - [ ] Bug fix - [ ] Documentation - [ ] Engineering change - [X] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [X] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information Fix imports for new MSAL private module in integration tests * Merged PR 9998: [iOS SDK] Make changes to project and Cocoapods to allow building the MAC Framework ## Proposed changes -There were no changes needed to the project as they were already done previously and MacOS MSAL framework builds properly -The Podspec file has been changed to build properly ## Type of change - [x] Feature work - [ ] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information To test properly, create a XCode Project with a Mac target which uses Cocoapods Set the Podfile as follows: ``` target 'TestAppMac' do pod 'MSAL', :git => "https://identitydivision.visualstudio.com/Engineering/_git/devexdub-microsoft-authentication-library-for-objc", :branch => "spetrescu/msal-mac-cocoapods", :submodules => true end ``` Related work items: #2652866 * Merged PR 10087: [iOS SDK] Fix Sample App pipeline build ## Proposed changes Swiftlint added a rule to check if functions that `override` only call the super, which in the end indeed does nothing. For example: ``` override func viewDidLoad() { super.viewDidLoad() } ``` Because the sample app had 3 such functions the PR validation failed Furthermore our PR validation script runs Swiftlint on the Native Sample App but we didn't have that so the script was added ## Type of change - [ ] Feature work - [x] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information -Added swiftlint to Sample App -Disabled warnings for Sample App * Merged PR 10086: [IOS SDK] Remove unused getAccount function from Cache Interface ## Proposed changes Because the function getAccount was unused as we don't have multiple accounts yet we need to remove it from the Accessor, Protocol and unit tests ## Type of change - [x] Feature work - [ ] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information Related work items: #2644201 * Merged PR 10133: Update position of "delegate" parameter in public interfaces for consistency ## Proposed changes This pull request is about changing the position of the `delegate` parameter in public interface method calls, for consistency. Modified interfaces: - MSALNativeAuthUserAccountResult - SignUpStates - SignInStates - ResetPasswordStates ## Type of change - [ ] Feature work - [ ] Bug fix - [ ] Documentation - [X] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [X] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information - Changed public interface to be consistent and always have the delegate as the last parameter of method calls - Changed sample app to reflect the changes Related work items: #2690285 * Merged PR 10194: Fix inline documentation in public delegates ## Proposed changes Add missing inline documentation for parameters in ResetPasswordDelegates, SignInDelegates and SignUpDelegates that were found while working [this ticket](https://identitydivision.visualstudio.com/Engineering/_workitems/edit/2711520/). ## Type of change - [ ] Feature work - [ ] Bug fix - [x] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ---- #### AI-Generated Description This pull request modifies three files related to the native authentication state machine delegates in MSAL. The main changes are: - Adding parameters to some delegate methods to provide more information about the new state of the flow and the required attributes. - Changing the error parameter type in some delegate methods to include the new state of the flow as an optional value. - Adding some optional methods to some delegate protocols to handle different scenarios that may require a code or a password from the user. Related work items: #2711520 * - Refactor of MSALNativeAuthResponseErrorHandler to remove duplicated code with IdetityCore * - Added MSIDAADRequestErrorHandler to module map * - Changed method name from "handleAPIError" to "handleCustomError" to be more concise with IdentityCore implementation. * - Added NativeAuthCustomErrorSerializer to deal with Native Auth custom errors serialization - Refactor of MSALNativeAuthResponseErrorHandler * - Removed unused property * - Changed class name to add "MSAL" prefix * - Added a comment explaining the "throw" command in MSALNativeAuthCustomErrorSerializer method * Merged PR 10303: Ciam Master updated to MSAL 1.2.18 ## Proposed changes Update with MSAL 1.2.18 from GitHub ## Type of change - [ ] Feature work - [ ] Bug fix - [ ] Documentation - [X] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [X] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information ---- #### AI-Generated Description This pull request updates the MSAL library for iOS and Mac to version 1.2.18. The main changes are: - Fixed duplicate values for error JIT codes (#1893) - Added ccs request id header (#1844) - Added separate error code for OneAuth telemetry purpose (common core #1292) - Exposed APIs for manually setting time_Interval for request and session resource (#1288) - Updated the iOS simulator device and OS version for testing - Updated the Package.swift and MSAL.podspec files with the new version number - Fixed some linting and code coverage issues Related work items: #2726861 * Merged PR 10343: [iOS SDK] SignUp error API responses are parsed to general SDK error ## Proposed changes Problem: MSALNativeAuthResponseErrorHandler was changed during merging to use the responseSerializer passed into the handleError function resulting in the incorrect serializer parsing API response errors. Solution: Always use MSALNativeAuthCustomErrorSerializer as the responseSerializer to ensure API errors are parsed as expected. ## Type of change - [ ] Feature work - [x] Bug fix - [ ] Documentation - [ ] Engineering change - [ ] Test - [ ] Logging/Telemetry ## Risk - [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes) - [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features) - [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes) ## Additional information ---- #### AI-Generated Description This pull request adds a new unit test case for the MSALNativeAuthResponseErrorHandler class, which handles errors from native auth requests. The test case checks that the error handler uses the correct response serializer when the status code is 400 and the error is verification_required. The pull request also modifies the error handler to always use the MSALNativeAuthCustomErrorSerializer instead of the response serializer passed as an argument. Related work items: #2727783 * PR comments * Files changed/removed during private preview Removed documentation for NativeAuth Removed NativeAuthSampleApp * - Restored changes based on code review * - Removed extra space * - Restored original README.md * Spacing on Pr-Validation.yml * Changed Mock API url * Switched to Environment variable * - Created cgmanifest.json file to add SwiftLint to component governance verification * - Updated CODEOWNERS file to give AppleCIAMTeam onwnership over Native Auth code. * - Updated description * - Changed CIAM team * - Fixed text description * Removed MSALNativeAuthInternalChallengeType.swift from being added twice to the Project --------- Co-authored-by: Danilo Raspa Co-authored-by: Silviu Petrescu Co-authored-by: Rodhan Hickey Co-authored-by: Swasti Gupta Co-authored-by: Swasti Gupta Co-authored-by: Ameya <> Co-authored-by: Ameya Patil Co-authored-by: Diego Jerez Barroso Co-authored-by: Dualtagh Murray Co-authored-by: Danilo Raspa <105228698+nilo-ms@users.noreply.github.com> --- CODEOWNERS | 5 + MSAL.podspec | 24 +- MSAL/.swiftlint.yml | 15 + MSAL/IdentityCore | 2 +- MSAL/MSAL.xcodeproj/project.pbxproj | 2504 ++++++++++++++++- .../xcschemes/unit-test-host-mac.xcscheme | 77 + .../xcschemes/unit-test-host.xcscheme | 95 + MSAL/NativeAuthEndToEndTestPlan.xctestplan | 77 + MSAL/module.modulemap | 100 + MSAL/src/MSALAccount+Internal.h | 3 + MSAL/src/MSALAccount.m | 9 + .../MSALNativeAuthInternalError.swift | 39 + .../cache/MSALNativeAuthCacheAccessor.swift | 170 ++ .../cache/MSALNativeAuthCacheInterface.swift | 52 + .../cache/MSALNativeAuthTokens.swift | 37 + .../MSALNativeAuthConfiguration.swift | 49 + .../MSALNativeAuthBaseController.swift | 143 + ...NativeAuthControllerTelemetryWrapper.swift | 38 + .../MSALNativeAuthTokenController.swift | 231 ++ .../MSALNativeAuthCredentialsController.swift | 192 ++ ...MSALNativeAuthCredentialsControlling.swift | 30 + .../MSALNativeAuthControllerFactory.swift | 54 + .../MSALNativeAuthResultFactory.swift | 97 + ...SALNativeAuthResetPasswordController.swift | 537 ++++ ...ALNativeAuthResetPasswordControlling.swift | 40 + .../responses/CodeRequiredGenericResult.swift | 39 + .../responses/ResetPasswordResults.swift | 61 + .../controllers/responses/SignInResults.swift | 82 + .../controllers/responses/SignUpResults.swift | 113 + .../MSALNativeAuthSignInController.swift | 592 ++++ .../MSALNativeAuthSignInControlling.swift | 53 + ...ALNativeAuthSignInWithCodeParameters.swift | 40 + ...tiveAuthSignInWithPasswordParameters.swift | 41 + .../MSALNativeAuthSignUpController.swift | 664 +++++ .../MSALNativeAuthSignUpControlling.swift | 55 + .../extension/Array+joinScopes.swift | 31 + .../MSALNativeAuthInputValidator.swift | 35 + MSAL/src/native_auth/logger/MSALLogMask.h | 55 + MSAL/src/native_auth/logger/MSALLogMask.m | 45 + .../logger/MSALNativeAuthLogging.swift | 150 + .../MSALNativeAuthCustomErrorSerializer.swift | 35 + .../network/MSALNativeAuthEndpoint.swift | 38 + .../network/MSALNativeAuthGrantType.swift | 32 + .../MSALNativeAuthInternalChallengeType.swift | 30 + .../MSALNativeAuthInternalChannelType.swift | 37 + .../MSALNativeAuthRequestConfigurator.swift | 271 ++ .../MSALNativeAuthRequestParametersKey.swift | 48 + .../MSALNativeAuthResponseErrorHandler.swift | 51 + .../MSALNativeAuthResponseSerializer.swift | 39 + .../MSALNativeAuthUrlRequestSerializer.swift | 94 + .../MSALNativeAuthESTSApiErrorCodes.swift | 35 + ...ALNativeAuthESTSApiErrorDescriptions.swift | 31 + .../errors/MSALNativeAuthErrorMessage.swift | 42 + .../errors/MSALNativeAuthInnerError.swift | 34 + .../errors/MSALNativeAuthResponseError.swift | 35 + ...esetPasswordChallengeOauth2ErrorCode.swift | 32 + ...hResetPasswordChallengeResponseError.swift | 67 + ...ResetPasswordContinueOauth2ErrorCode.swift | 34 + ...thResetPasswordContinueResponseError.swift | 62 + ...asswordPollCompletionOauth2ErrorCode.swift | 37 + ...tPasswordPollCompletionResponseError.swift | 63 + ...uthResetPasswordStartOauth2ErrorCode.swift | 32 + ...eAuthResetPasswordStartResponseError.swift | 44 + ...thResetPasswordSubmitOauth2ErrorCode.swift | 36 + ...AuthResetPasswordSubmitResponseError.swift | 62 + ...veAuthSignInChallengeOauth2ErrorCode.swift | 33 + ...tiveAuthSignInChallengeResponseError.swift | 42 + ...iveAuthSignInInitiateOauth2ErrorCode.swift | 32 + ...ativeAuthSignInInitiateResponseError.swift | 42 + .../MSALNativeAuthErrorBasicAttributes.swift | 33 + ...ALNativeAuthRequiredAttributeOptions.swift | 29 + ...NativeAuthRequiredAttributesInternal.swift | 47 + ...veAuthSignUpChallengeOauth2ErrorCode.swift | 32 + ...tiveAuthSignUpChallengeResponseError.swift | 84 + ...iveAuthSignUpContinueOauth2ErrorCode.swift | 43 + ...ativeAuthSignUpContinueResponseError.swift | 100 + ...NativeAuthSignUpStartOauth2ErrorCode.swift | 41 + ...ALNativeAuthSignUpStartResponseError.swift | 92 + .../MSALNativeAuthTokenOauth2ErrorCode.swift | 38 + .../MSALNativeAuthTokenResponseError.swift | 44 + .../MSALNativeAuthRequestContext.swift | 62 + .../MSALNativeAuthRequestable.swift | 51 + ...etPasswordChallengeRequestParameters.swift | 41 + ...setPasswordContinueRequestParameters.swift | 44 + ...swordPollCompletionRequestParameters.swift | 40 + ...hResetPasswordStartRequestParameters.swift | 42 + ...ResetPasswordSubmitRequestParameters.swift | 42 + ...AuthSignInChallengeRequestParameters.swift | 41 + ...eAuthSignInInitiateRequestParameters.swift | 41 + ...AuthSignUpChallengeRequestParameters.swift | 41 + ...eAuthSignUpContinueRequestParameters.swift | 48 + ...tiveAuthSignUpStartRequestParameters.swift | 45 + ...MSALNativeAuthTokenRequestParameters.swift | 62 + ...tiveAuthResetPasswordRequestProvider.swift | 137 + ...sswordStartRequestProviderParameters.swift | 30 + ...LNativeAuthResendCodeRequestResponse.swift | 35 + ...veAuthResetPasswordChallengeResponse.swift | 36 + ...iveAuthResetPasswordContinueResponse.swift | 32 + ...hResetPasswordPollCompletionResponse.swift | 33 + ...uthResetPasswordPollCompletionStatus.swift | 32 + ...NativeAuthResetPasswordStartResponse.swift | 42 + ...ativeAuthResetPasswordSubmitResponse.swift | 32 + ...SALNativeAuthSignInChallengeResponse.swift | 37 + ...MSALNativeAuthSignInInitiateResponse.swift | 37 + ...SALNativeAuthSignUpChallengeResponse.swift | 41 + ...MSALNativeAuthSignUpContinueResponse.swift | 37 + .../MSALNativeAuthSignUpStartResponse.swift | 30 + ...veAuthResetPasswordResponseValidator.swift | 273 ++ ...eAuthResetPasswordValidatedResponses.swift | 79 + ...SALNativeAuthSignInResponseValidator.swift | 160 ++ ...AuthSignInChallengeValidatedResponse.swift | 76 + ...eAuthSignInInitiateValidatedResponse.swift | 69 + ...SALNativeAuthSignUpResponseValidator.swift | 274 ++ ...ALNativeAuthSignUpValidatedResponses.swift | 53 + ...MSALNativeAuthTokenResponseValidator.swift | 222 ++ ...MSALNativeAuthTokenValidatedResponse.swift | 128 + .../MSALNativeAuthSignInRequestProvider.swift | 83 + ...hSignUpContinueRequestProviderParams.swift | 50 + .../MSALNativeAuthSignUpRequestProvider.swift | 99 + ...SignUpStartRequestProviderParameters.swift | 30 + .../MSALNativeAuthTokenRequestProvider.swift | 80 + .../public/MSALNativeAuthChallengeTypes.h | 38 + .../public/MSALNativeAuthChannelType.swift | 31 + ...AuthPublicClientApplication+Internal.swift | 152 + ...SALNativeAuthPublicClientApplication.swift | 312 ++ ...NativeAuthUserAccountResult+Internal.swift | 45 + .../MSALNativeAuthUserAccountResult.swift | 100 + .../parameters/MSALNativeAuthParameters.swift | 38 + .../MSALNativeAuthResendCodeParameters.swift | 37 + .../MSALNativeAuthSignInOTPParameters.swift | 38 + .../MSALNativeAuthSignInParameters.swift | 43 + .../MSALNativeAuthVerifyCodeParameters.swift | 40 + .../MSALNativeAuthRequiredAttributes.swift | 41 + .../delegate/CredentialsDelegates.swift | 36 + .../delegate/ResetPasswordDelegates.swift | 92 + .../delegate/SignInAfterSignUpDelegate.swift | 36 + .../delegate/SignInDelegates.swift | 115 + .../delegate/SignUpDelegates.swift | 159 ++ .../error/AttributesRequiredError.swift | 36 + .../error/MSALNativeAuthError.swift | 38 + .../error/PasswordRequiredError.swift | 70 + .../state_machine/error/ResendCodeError.swift | 36 + .../error/ResetPasswordStartError.swift | 64 + .../error/RetrieveAccessTokenError.swift | 61 + .../error/SignInAfterSignUpError.swift | 36 + .../error/SignInPasswordStartError.swift | 64 + .../error/SignInStartError.swift | 61 + .../error/SignUpPasswordStartError.swift | 65 + .../error/SignUpStartError.swift | 61 + .../state_machine/error/VerifyCodeError.swift | 58 + .../state/MSALNativeAuthBaseState.swift | 34 + .../state/ResetPasswordStates+Internal.swift | 58 + .../state/ResetPasswordStates.swift | 105 + .../SignInAfterSignUpState+Internal.swift | 33 + .../state/SignInAfterSignUpState.swift | 61 + .../state/SignInStates+Internal.swift | 64 + .../state_machine/state/SignInStates.swift | 130 + .../state/SignUpStates+Internal.swift | 69 + .../state_machine/state/SignUpStates.swift | 165 ++ ...SALNativeAuthCurrentRequestTelemetry.swift | 59 + .../MSALNativeAuthOperationTypes.swift | 78 + .../MSALNativeAuthServerTelemetry.swift | 67 + .../MSALNativeAuthTelemetryApiId.swift | 57 + .../MSALNativeAuthTelemetryProvider.swift | 108 + .../MSALNativeAuthAuthorityProvider.swift | 42 + MSAL/src/public/MSAL.h | 1 + .../native_auth/MockAPIHandlerTest.swift | 45 + .../MSALNativeAuthIntegrationBaseTests.swift | 127 + .../native_auth/common/MockAPIHandler.swift | 80 + .../native_auth/common/Model.swift | 103 + .../MSALNativeAuthEndToEndBaseTestCase.swift | 77 + ...NativeAuthResetPasswordEndToEndTests.swift | 82 + .../ResetPasswordDelegateSpies.swift | 119 + ...gnInUserNameAndPasswordEndToEndTests.swift | 97 + ...ativeAuthSignInUsernameEndToEndTests.swift | 248 ++ .../sign_in/SignInDelegateSpies.swift | 152 + .../MSALNativeAuthSignOutEndToEndTests.swift | 194 ++ ...gnUpUsernameAndPasswordEndToEndTests.swift | 445 +++ ...ativeAuthSignUpUsernameEndToEndTests.swift | 313 +++ .../sign_up/SignUpDelegateSpies.swift | 267 ++ ...setPasswordChallengeIntegrationTests.swift | 119 + ...esetPasswordContinueIntegrationTests.swift | 131 + ...sswordPollCompletionIntegrationTests.swift | 195 ++ ...thResetPasswordStartIntegrationTests.swift | 113 + ...hResetPasswordSubmitIntegrationTests.swift | 137 + ...eAuthSignInChallengeIntegrationTests.swift | 120 + ...veAuthSignInInitiateIntegrationTests.swift | 92 + ...eAuthSignUpChallengeIntegrationTests.swift | 112 + ...veAuthSignUpContinueIntegrationTests.swift | 241 ++ ...ativeAuthSignUpStartIntegrationTests.swift | 188 ++ .../MSALNativeAuthTokenIntegrationTests.swift | 181 ++ MSAL/test/unit/MSALAccountTests.m | 68 + MSAL/test/unit/MSALDeviceInfoProviderTests.m | 2 +- .../unit/MSALPublicClientApplicationTests.m | 1 + MSAL/test/unit/ios/unit-test-host/Info.plist | 14 + .../native_auth/MSALNativeAuthTestCase.swift | 56 + .../MSALNativeAuthCacheAccessorTest.swift | 286 ++ .../MSALNativeAuthBaseControllerTests.swift | 270 ++ ...NativeAuthCredentialsControllerTests.swift | 215 ++ ...tiveAuthResetPasswordControllerTests.swift | 923 ++++++ .../MSALNativeAuthSignInControllerTests.swift | 1083 +++++++ .../MSALNativeAuthSignUpControllerTests.swift | 1949 +++++++++++++ .../MSALNativeAuthResultFactoryTests.swift | 119 + .../MSALNativeAuthInputValidatorTest.swift | 42 + .../native_auth/logger/MSALLogMaskTests.m | 167 ++ .../logger/MSALNativeLoggingTests.swift | 342 +++ .../mock/CredentialsDelegateSpies.swift | 78 + .../mock/MSALNativeAuthCacheMocks.swift | 68 + .../mock/MSALNativeAuthConfigStubs.swift | 57 + ...LNativeAuthCredentialsControllerMock.swift | 41 + .../mock/MSALNativeAuthFactoriesMocks.swift | 93 + .../mock/MSALNativeAuthNetworkMocks.swift | 305 ++ ...ativeAuthResetPasswordControllerMock.swift | 51 + .../MSALNativeAuthSignInControllerMock.swift | 68 + .../MSALNativeAuthSignUpControllerMock.swift | 61 + .../MSALNativeAuthSignUpControllerSpy.swift | 107 + ...LNativeAuthSignUpRequestProviderMock.swift | 117 + ...ativeAuthSignUpResponseValidatorMock.swift | 69 + .../MSALNativeAuthUserAccountResultStub.swift | 62 + .../mock/ResetPasswordDelegateSpies.swift | 161 ++ .../ResetPasswordTestValidatorHelpers.swift | 114 + .../mock/SignInDelegatesSpies.swift | 311 ++ .../mock/SignInTestsValidatorHelpers.swift | 134 + .../mock/SignUpDelegateSpies.swift | 370 +++ .../mock/SignUpTestsValidatorHelpers.swift | 272 ++ ...NativeAuthResetPasswordControllerSpy.swift | 76 + ...AuthResetPasswordRequestProviderMock.swift | 182 ++ ...thResetPasswordResponseValidatorMock.swift | 110 + .../network/MSALNativeAuthEndpointTests.swift | 79 + ...ALNativeAuthRequestConfiguratorTests.swift | 452 +++ ...ALNativeAuthRequestErrorHandlerTests.swift | 359 +++ .../MSALNativeAuthRequestableTests.swift | 79 + ...SALNativeAuthResponseSerializerTests.swift | 80 + ...NativeAuthSignUpRequestProviderTests.swift | 142 + ...LNativeAuthUrlRequestSerializerTests.swift | 196 ++ ...iveAuthESTSApiErrorDescriptionsTests.swift | 43 + ...asswordChallengeOauth2ErrorCodeTests.swift | 51 + ...tPasswordChallengeResponseErrorTests.swift | 88 + ...PasswordContinueOauth2ErrorCodeTests.swift | 59 + ...etPasswordContinueResponseErrorTests.swift | 76 + ...rdPollCompletionOauth2ErrorCodeTests.swift | 71 + ...wordPollCompletionResponseErrorTests.swift | 79 + ...setPasswordStartOauth2ErrorCodeTests.swift | 51 + ...etPasswordSubmitOauth2ErrorCodeTests.swift | 67 + ...esetPasswordSubmitResponseErrorTests.swift | 75 + ...tiveAuthErrorRequiredAttributesTests.swift | 39 + ...hSignUpChallengeOauth2ErrorCodeTests.swift | 51 + ...uthSignUpChallengeResponseErrorTests.swift | 134 + ...thSignUpContinueOauth2ErrorCodeTests.swift | 95 + ...AuthSignUpContinueResponseErrorTests.swift | 240 ++ ...eAuthSignUpStartOauth2ErrorCodeTests.swift | 87 + ...iveAuthSignUpStartResponseErrorTests.swift | 156 + ...sswordChallengeRequestParametersTest.swift | 86 + ...asswordContinueRequestParametersTest.swift | 93 + ...dPollCompletionRequestParametersTest.swift | 67 + ...etPasswordStartRequestParametersTest.swift | 67 + ...tPasswordSubmitRequestParametersTest.swift | 70 + ...SignInChallengeRequestParametersTest.swift | 83 + ...hSignInInitiateRequestParametersTest.swift | 83 + ...SignUpChallengeRequestParametersTest.swift | 67 + ...hSignUpContinueRequestParametersTest.swift | 78 + ...AuthSignUpStartRequestParametersTest.swift | 73 + ...NativeAuthTokenRequestParametersTest.swift | 113 + ...ativeAuthSignInChallengeRequestTests.swift | 137 + ...SALNativeAuthSignInTokenRequestTests.swift | 158 ++ ...hResetPasswordResponseValidatorTests.swift | 662 +++++ ...PasswordStartValidatedErrorTypeTests.swift | 64 + ...ignInInitiateValidatedErrorTypeTests.swift | 110 + ...ativeAuthSignInResponseValidatorTest.swift | 172 ++ ...tiveAuthSignUpResponseValidatorTests.swift | 742 +++++ ...ativeAuthTokenResponseValidatorTests.swift | 256 ++ ...tiveAuthTokenValidatedErrorTypeTests.swift | 119 + ...ativeAuthPublicClientApplicationTest.swift | 367 +++ ...MSALNativeAuthUserAccountResultTests.swift | 85 + .../ResetPasswordCodeSentStateTests.swift | 118 + .../ResetPasswordRequiredStateTests.swift | 56 + .../SignInCodeRequiredStateTests.swift | 115 + .../SignInPasswordRequiredStateTests.swift | 73 + .../SignUpAttributesRequiredStateTests.swift | 109 + .../sign_up/SignUpCodeSentStateTests.swift | 197 ++ .../SignUpPasswordRequiredStateTests.swift | 116 + ...tiveAuthCurrentRequestTelemetryTests.swift | 62 + ...MSALNativeAuthTelemetryProviderTests.swift | 83 + ...SALNativeAuthTelemetryTestDispatcher.swift | 48 + .../project.pbxproj | 56 +- build.py | 24 +- cgmanifest.json | 17 + 287 files changed, 34743 insertions(+), 84 deletions(-) create mode 100644 MSAL/.swiftlint.yml create mode 100644 MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/unit-test-host-mac.xcscheme create mode 100644 MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/unit-test-host.xcscheme create mode 100644 MSAL/NativeAuthEndToEndTestPlan.xctestplan create mode 100644 MSAL/module.modulemap create mode 100644 MSAL/src/native_auth/MSALNativeAuthInternalError.swift create mode 100644 MSAL/src/native_auth/cache/MSALNativeAuthCacheAccessor.swift create mode 100644 MSAL/src/native_auth/cache/MSALNativeAuthCacheInterface.swift create mode 100644 MSAL/src/native_auth/cache/MSALNativeAuthTokens.swift create mode 100644 MSAL/src/native_auth/configuration/MSALNativeAuthConfiguration.swift create mode 100644 MSAL/src/native_auth/controllers/MSALNativeAuthBaseController.swift create mode 100644 MSAL/src/native_auth/controllers/MSALNativeAuthControllerTelemetryWrapper.swift create mode 100644 MSAL/src/native_auth/controllers/MSALNativeAuthTokenController.swift create mode 100644 MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift create mode 100644 MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsControlling.swift create mode 100644 MSAL/src/native_auth/controllers/factories/MSALNativeAuthControllerFactory.swift create mode 100644 MSAL/src/native_auth/controllers/factories/MSALNativeAuthResultFactory.swift create mode 100644 MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift create mode 100644 MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift create mode 100644 MSAL/src/native_auth/controllers/responses/CodeRequiredGenericResult.swift create mode 100644 MSAL/src/native_auth/controllers/responses/ResetPasswordResults.swift create mode 100644 MSAL/src/native_auth/controllers/responses/SignInResults.swift create mode 100644 MSAL/src/native_auth/controllers/responses/SignUpResults.swift create mode 100644 MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift create mode 100644 MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift create mode 100644 MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithCodeParameters.swift create mode 100644 MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithPasswordParameters.swift create mode 100644 MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift create mode 100644 MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift create mode 100644 MSAL/src/native_auth/extension/Array+joinScopes.swift create mode 100644 MSAL/src/native_auth/input_validator/MSALNativeAuthInputValidator.swift create mode 100644 MSAL/src/native_auth/logger/MSALLogMask.h create mode 100644 MSAL/src/native_auth/logger/MSALLogMask.m create mode 100644 MSAL/src/native_auth/logger/MSALNativeAuthLogging.swift create mode 100644 MSAL/src/native_auth/network/MSALNativeAuthCustomErrorSerializer.swift create mode 100644 MSAL/src/native_auth/network/MSALNativeAuthEndpoint.swift create mode 100644 MSAL/src/native_auth/network/MSALNativeAuthGrantType.swift create mode 100644 MSAL/src/native_auth/network/MSALNativeAuthInternalChallengeType.swift create mode 100644 MSAL/src/native_auth/network/MSALNativeAuthInternalChannelType.swift create mode 100644 MSAL/src/native_auth/network/MSALNativeAuthRequestConfigurator.swift create mode 100644 MSAL/src/native_auth/network/MSALNativeAuthRequestParametersKey.swift create mode 100644 MSAL/src/native_auth/network/MSALNativeAuthResponseErrorHandler.swift create mode 100644 MSAL/src/native_auth/network/MSALNativeAuthResponseSerializer.swift create mode 100644 MSAL/src/native_auth/network/MSALNativeAuthUrlRequestSerializer.swift create mode 100644 MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorCodes.swift create mode 100644 MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorDescriptions.swift create mode 100644 MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift create mode 100644 MSAL/src/native_auth/network/errors/MSALNativeAuthInnerError.swift create mode 100644 MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift create mode 100644 MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift create mode 100644 MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift create mode 100644 MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift create mode 100644 MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift create mode 100644 MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift create mode 100644 MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift create mode 100644 MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift create mode 100644 MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift create mode 100644 MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift create mode 100644 MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift create mode 100644 MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeOauth2ErrorCode.swift create mode 100644 MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift create mode 100644 MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateOauth2ErrorCode.swift create mode 100644 MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift create mode 100644 MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthErrorBasicAttributes.swift create mode 100644 MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthRequiredAttributeOptions.swift create mode 100644 MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthRequiredAttributesInternal.swift create mode 100644 MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift create mode 100644 MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift create mode 100644 MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCode.swift create mode 100644 MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift create mode 100644 MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCode.swift create mode 100644 MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift create mode 100644 MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenOauth2ErrorCode.swift create mode 100644 MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift create mode 100644 MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestContext.swift create mode 100644 MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestable.swift create mode 100644 MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParameters.swift create mode 100644 MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParameters.swift create mode 100644 MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift create mode 100644 MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordStartRequestParameters.swift create mode 100644 MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordSubmitRequestParameters.swift create mode 100644 MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParameters.swift create mode 100644 MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInInitiateRequestParameters.swift create mode 100644 MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParameters.swift create mode 100644 MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParameters.swift create mode 100644 MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpStartRequestParameters.swift create mode 100644 MSAL/src/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParameters.swift create mode 100644 MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordRequestProvider.swift create mode 100644 MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordStartRequestProviderParameters.swift create mode 100644 MSAL/src/native_auth/network/responses/MSALNativeAuthResendCodeRequestResponse.swift create mode 100644 MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordChallengeResponse.swift create mode 100644 MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordContinueResponse.swift create mode 100644 MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionResponse.swift create mode 100644 MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionStatus.swift create mode 100644 MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift create mode 100644 MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordSubmitResponse.swift create mode 100644 MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInChallengeResponse.swift create mode 100644 MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInInitiateResponse.swift create mode 100644 MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpChallengeResponse.swift create mode 100644 MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpContinueResponse.swift create mode 100644 MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpStartResponse.swift create mode 100644 MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift create mode 100644 MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift create mode 100644 MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift create mode 100644 MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift create mode 100644 MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift create mode 100644 MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift create mode 100644 MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift create mode 100644 MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift create mode 100644 MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift create mode 100644 MSAL/src/native_auth/network/sign_in/MSALNativeAuthSignInRequestProvider.swift create mode 100644 MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpContinueRequestProviderParams.swift create mode 100644 MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift create mode 100644 MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpStartRequestProviderParameters.swift create mode 100644 MSAL/src/native_auth/network/token/MSALNativeAuthTokenRequestProvider.swift create mode 100644 MSAL/src/native_auth/public/MSALNativeAuthChallengeTypes.h create mode 100644 MSAL/src/native_auth/public/MSALNativeAuthChannelType.swift create mode 100644 MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift create mode 100644 MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift create mode 100644 MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift create mode 100644 MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift create mode 100644 MSAL/src/native_auth/public/parameters/MSALNativeAuthParameters.swift create mode 100644 MSAL/src/native_auth/public/parameters/MSALNativeAuthResendCodeParameters.swift create mode 100644 MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInOTPParameters.swift create mode 100644 MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInParameters.swift create mode 100644 MSAL/src/native_auth/public/parameters/MSALNativeAuthVerifyCodeParameters.swift create mode 100644 MSAL/src/native_auth/public/state_machine/MSALNativeAuthRequiredAttributes.swift create mode 100644 MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift create mode 100644 MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift create mode 100644 MSAL/src/native_auth/public/state_machine/delegate/SignInAfterSignUpDelegate.swift create mode 100644 MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift create mode 100644 MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift create mode 100644 MSAL/src/native_auth/public/state_machine/error/AttributesRequiredError.swift create mode 100644 MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift create mode 100644 MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift create mode 100644 MSAL/src/native_auth/public/state_machine/error/ResendCodeError.swift create mode 100644 MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift create mode 100644 MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift create mode 100644 MSAL/src/native_auth/public/state_machine/error/SignInAfterSignUpError.swift create mode 100644 MSAL/src/native_auth/public/state_machine/error/SignInPasswordStartError.swift create mode 100644 MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift create mode 100644 MSAL/src/native_auth/public/state_machine/error/SignUpPasswordStartError.swift create mode 100644 MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift create mode 100644 MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift create mode 100644 MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift create mode 100644 MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift create mode 100644 MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift create mode 100644 MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift create mode 100644 MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift create mode 100644 MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift create mode 100644 MSAL/src/native_auth/public/state_machine/state/SignInStates.swift create mode 100644 MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift create mode 100644 MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift create mode 100644 MSAL/src/native_auth/telemetry/MSALNativeAuthCurrentRequestTelemetry.swift create mode 100644 MSAL/src/native_auth/telemetry/MSALNativeAuthOperationTypes.swift create mode 100644 MSAL/src/native_auth/telemetry/MSALNativeAuthServerTelemetry.swift create mode 100644 MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryApiId.swift create mode 100644 MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryProvider.swift create mode 100644 MSAL/src/native_auth/validation/MSALNativeAuthAuthorityProvider.swift create mode 100644 MSAL/test/integration/native_auth/MockAPIHandlerTest.swift create mode 100644 MSAL/test/integration/native_auth/common/MSALNativeAuthIntegrationBaseTests.swift create mode 100644 MSAL/test/integration/native_auth/common/MockAPIHandler.swift create mode 100644 MSAL/test/integration/native_auth/common/Model.swift create mode 100644 MSAL/test/integration/native_auth/end_to_end/MSALNativeAuthEndToEndBaseTestCase.swift create mode 100644 MSAL/test/integration/native_auth/end_to_end/reset_password/MSALNativeAuthResetPasswordEndToEndTests.swift create mode 100644 MSAL/test/integration/native_auth/end_to_end/reset_password/ResetPasswordDelegateSpies.swift create mode 100644 MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUserNameAndPasswordEndToEndTests.swift create mode 100644 MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUsernameEndToEndTests.swift create mode 100644 MSAL/test/integration/native_auth/end_to_end/sign_in/SignInDelegateSpies.swift create mode 100644 MSAL/test/integration/native_auth/end_to_end/sign_out/MSALNativeAuthSignOutEndToEndTests.swift create mode 100644 MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift create mode 100644 MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameEndToEndTests.swift create mode 100644 MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift create mode 100644 MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift create mode 100644 MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift create mode 100644 MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift create mode 100644 MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordStartIntegrationTests.swift create mode 100644 MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordSubmitIntegrationTests.swift create mode 100644 MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInChallengeIntegrationTests.swift create mode 100644 MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift create mode 100644 MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift create mode 100644 MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift create mode 100644 MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift create mode 100644 MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift create mode 100644 MSAL/test/unit/native_auth/MSALNativeAuthTestCase.swift create mode 100644 MSAL/test/unit/native_auth/cache/MSALNativeAuthCacheAccessorTest.swift create mode 100644 MSAL/test/unit/native_auth/controllers/MSALNativeAuthBaseControllerTests.swift create mode 100644 MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift create mode 100644 MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift create mode 100644 MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift create mode 100644 MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift create mode 100644 MSAL/test/unit/native_auth/controllers/factories/MSALNativeAuthResultFactoryTests.swift create mode 100644 MSAL/test/unit/native_auth/input_validator/MSALNativeAuthInputValidatorTest.swift create mode 100644 MSAL/test/unit/native_auth/logger/MSALLogMaskTests.m create mode 100644 MSAL/test/unit/native_auth/logger/MSALNativeLoggingTests.swift create mode 100644 MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift create mode 100644 MSAL/test/unit/native_auth/mock/MSALNativeAuthCacheMocks.swift create mode 100644 MSAL/test/unit/native_auth/mock/MSALNativeAuthConfigStubs.swift create mode 100644 MSAL/test/unit/native_auth/mock/MSALNativeAuthCredentialsControllerMock.swift create mode 100644 MSAL/test/unit/native_auth/mock/MSALNativeAuthFactoriesMocks.swift create mode 100644 MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift create mode 100644 MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift create mode 100644 MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift create mode 100644 MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift create mode 100644 MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift create mode 100644 MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift create mode 100644 MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpResponseValidatorMock.swift create mode 100644 MSAL/test/unit/native_auth/mock/MSALNativeAuthUserAccountResultStub.swift create mode 100644 MSAL/test/unit/native_auth/mock/ResetPasswordDelegateSpies.swift create mode 100644 MSAL/test/unit/native_auth/mock/ResetPasswordTestValidatorHelpers.swift create mode 100644 MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift create mode 100644 MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift create mode 100644 MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift create mode 100644 MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift create mode 100644 MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift create mode 100644 MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordRequestProviderMock.swift create mode 100644 MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordResponseValidatorMock.swift create mode 100644 MSAL/test/unit/native_auth/network/MSALNativeAuthEndpointTests.swift create mode 100644 MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift create mode 100644 MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift create mode 100644 MSAL/test/unit/native_auth/network/MSALNativeAuthRequestableTests.swift create mode 100644 MSAL/test/unit/native_auth/network/MSALNativeAuthResponseSerializerTests.swift create mode 100644 MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift create mode 100644 MSAL/test/unit/native_auth/network/MSALNativeAuthUrlRequestSerializerTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/MSALNativeAuthESTSApiErrorDescriptionsTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthErrorRequiredAttributesTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift create mode 100644 MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParametersTest.swift create mode 100644 MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift create mode 100644 MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordStartRequestParametersTest.swift create mode 100644 MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordSubmitRequestParametersTest.swift create mode 100644 MSAL/test/unit/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParametersTest.swift create mode 100644 MSAL/test/unit/native_auth/network/parameters/sign_in/MSALNativeAuthSignInInitiateRequestParametersTest.swift create mode 100644 MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParametersTest.swift create mode 100644 MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParametersTest.swift create mode 100644 MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpStartRequestParametersTest.swift create mode 100644 MSAL/test/unit/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParametersTest.swift create mode 100644 MSAL/test/unit/native_auth/network/requests/sign_in/MSALNativeAuthSignInChallengeRequestTests.swift create mode 100644 MSAL/test/unit/native_auth/network/requests/sign_in/MSALNativeAuthSignInTokenRequestTests.swift create mode 100644 MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift create mode 100644 MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift create mode 100644 MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift create mode 100644 MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift create mode 100644 MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift create mode 100644 MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift create mode 100644 MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift create mode 100644 MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift create mode 100644 MSAL/test/unit/native_auth/public/MSALNativeAuthUserAccountResultTests.swift create mode 100644 MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift create mode 100644 MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift create mode 100644 MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift create mode 100644 MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift create mode 100644 MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift create mode 100644 MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift create mode 100644 MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift create mode 100644 MSAL/test/unit/native_auth/telemetry/MSALNativeAuthCurrentRequestTelemetryTests.swift create mode 100644 MSAL/test/unit/native_auth/telemetry/MSALNativeAuthTelemetryProviderTests.swift create mode 100644 MSAL/test/unit/native_auth/utils/MSALNativeAuthTelemetryTestDispatcher.swift create mode 100644 cgmanifest.json diff --git a/CODEOWNERS b/CODEOWNERS index 16fdfdfca6..0234657fe7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -2,6 +2,11 @@ # Unless a later match takes precedence, these users will be requested # for review whenever someone opens a pull request. * @AzureAD/AppleIdentityTeam +# @AzureAD/MSAL-ObjC-CIAM owns any files in the */native_auth +# directories and any of its subdirectories. +/MSAL/src/native_auth/ @AzureAD/MSAL-ObjC-CIAM +/MSAL/test/unit/native_auth/ @AzureAD/MSAL-ObjC-CIAM +/MSAL/test/integration/native_auth/ @AzureAD/MSAL-ObjC-CIAM # For more details about inheritance patterns, or to assign different # owners for individual file extensions, see: # https://help.github.com/articles/about-codeowners/ diff --git a/MSAL.podspec b/MSAL.podspec index 942c6028c9..4b43fc76dc 100644 --- a/MSAL.podspec +++ b/MSAL.podspec @@ -21,34 +21,32 @@ Pod::Spec.new do |s| :submodules => true } - s.pod_target_xcconfig = { 'CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF' => 'NO' } + s.pod_target_xcconfig = { 'CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF' => 'NO', 'HEADER_SEARCH_PATHS' => "$SRCROOT/MSAL"} s.default_subspecs ='app-lib' s.prefix_header_file = "MSAL/src/MSAL.pch" s.header_dir = "MSAL" s.subspec 'app-lib' do |app| - app.source_files = "MSAL/src/**/*.{h,m}", "MSAL/IdentityCore/IdentityCore/src/**/*.{h,m}" - app.ios.public_header_files = "MSAL/src/public/*.h","MSAL/src/public/ios/**/*.h", "MSAL/src/public/configuration/**/*.h" - app.osx.public_header_files = "MSAL/src/public/mac/*.h","MSAL/src/public/*.h", "MSAL/src/public/configuration/**/*.h" - - app.ios.exclude_files = "MSAL/src/**/mac/*", "MSAL/IdentityCore/IdentityCore/src/**/mac/*" - - app.osx.exclude_files = "MSAL/src/**/ios/*", "MSAL/IdentityCore/IdentityCore/src/**/ios/*" - app.requires_arc = true + app.source_files = "MSAL/src/**/*.{h,m}", "MSAL/src/native_auth/**/*.{h,m,swift}", "MSAL/IdentityCore/IdentityCore/src/**/*.{h,m}", "MSAL/module.modulemap" + app.ios.public_header_files = "MSAL/src/public/*.h","MSAL/src/public/ios/**/*.h", "MSAL/src/public/configuration/**/*.h", "MSAL/src/native_auth/public/*.h" + app.osx.public_header_files = "MSAL/src/public/mac/*.h","MSAL/src/public/*.h", "MSAL/src/public/configuration/**/*.h" + app.ios.exclude_files = "MSAL/src/**/mac/*", "MSAL/IdentityCore/IdentityCore/src/**/mac/*" + app.osx.exclude_files = "MSAL/src/**/ios/*", "MSAL/IdentityCore/IdentityCore/src/**/ios/*", "MSAL/src/native_auth/**/*", "MSAL/module.modulemap" + app.requires_arc = true end # Note, MSAL has limited support for running in app extensions. s.subspec 'extension' do |ext| ext.compiler_flags = '-DADAL_EXTENSION_SAFE=1' - ext.source_files = "MSAL/src/**/*.{h,m}", "MSAL/IdentityCore/IdentityCore/src/**/*.{h,m}" - ext.ios.public_header_files = "MSAL/src/public/*.h","MSAL/src/public/ios/**/*.h", "MSAL/src/public/configuration/**/*.h" - ext.osx.public_header_files = "MSAL/src/public/mac/*.h","MSAL/src/public/*.h", "MSAL/src/public/configuration/**/*.h" + ext.source_files = "MSAL/src/**/*.{h,m}", "MSAL/src/native_auth/**/*.{h,m,swift}", "MSAL/IdentityCore/IdentityCore/src/**/*.{h,m}", "MSAL/module.modulemap" + ext.ios.public_header_files = "MSAL/src/public/*.h","MSAL/src/public/ios/**/*.h", "MSAL/src/public/configuration/**/*.h", "MSAL/src/native_auth/public/*.h" + ext.osx.public_header_files = "MSAL/src/public/mac/*.h","MSAL/src/public/*.h", "MSAL/src/public/configuration/**/*.h" # There is currently a bug in CocoaPods where it doesn't combine the public headers # for both the platform and overall. ext.ios.exclude_files = "MSAL/src/**/mac/*", "MSAL/IdentityCore/IdentityCore/src/**/mac/*" - ext.osx.exclude_files = "MSAL/src/**/ios/*", "MSAL/IdentityCore/IdentityCore/src/**/ios/*" + ext.osx.exclude_files = "MSAL/src/**/ios/*", "MSAL/IdentityCore/IdentityCore/src/**/ios/*", "MSAL/src/native_auth/**/*", "MSAL/module.modulemap" ext.requires_arc = true end diff --git a/MSAL/.swiftlint.yml b/MSAL/.swiftlint.yml new file mode 100644 index 0000000000..d63075c409 --- /dev/null +++ b/MSAL/.swiftlint.yml @@ -0,0 +1,15 @@ +included: + - src/native_auth + + +line_length: + warning: 150 + +type_name: + max_length: 60 + +function_parameter_count: + warning: 7 + +disabled_rules: + - todo diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index e23cb10d35..0cdad2ff99 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit e23cb10d35ec3a8ce0c94f7e5a3a0a622e9d2873 +Subproject commit 0cdad2ff998cd14bfb2c9dc361f17a461ca724b4 diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index cf4b76aa6a..0d6a5bd32a 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -90,7 +90,6 @@ 04D32CD11FD8AFF3000B123E /* MSALErrorConverterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 04D32CCF1FD8AFF3000B123E /* MSALErrorConverterTests.m */; }; 0D96DB3727850E3900DEAF87 /* MSALWipeCacheForAllAccountsConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D96DB3627850E3900DEAF87 /* MSALWipeCacheForAllAccountsConfig.m */; }; 0D96DB3827850E8200DEAF87 /* MSALWipeCacheForAllAccountsConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D96DB3627850E3900DEAF87 /* MSALWipeCacheForAllAccountsConfig.m */; }; - 0D96DB3927850E8400DEAF87 /* MSALWipeCacheForAllAccountsConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D96DB3627850E3900DEAF87 /* MSALWipeCacheForAllAccountsConfig.m */; }; 0D96DB3A27850E8500DEAF87 /* MSALWipeCacheForAllAccountsConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D96DB3627850E3900DEAF87 /* MSALWipeCacheForAllAccountsConfig.m */; }; 0D96DB3B27850F0E00DEAF87 /* MSALWipeCacheForAllAccountsConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D96DB2E27850E1300DEAF87 /* MSALWipeCacheForAllAccountsConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0D96DB3C27850F0F00DEAF87 /* MSALWipeCacheForAllAccountsConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D96DB2E27850E1300DEAF87 /* MSALWipeCacheForAllAccountsConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -107,7 +106,6 @@ 1E4FD39E2121F2910069BCF6 /* MSALTestAppSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D61A64A81E5AABC50086D120 /* MSALTestAppSettingsViewController.m */; }; 1E5319BA24A51DDE007BCF30 /* MSALAuthenticationSchemeBearer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EE776BC246C98D300F7EBFC /* MSALAuthenticationSchemeBearer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E5319BB24A51DDF007BCF30 /* MSALAuthenticationSchemeBearer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EE776BC246C98D300F7EBFC /* MSALAuthenticationSchemeBearer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E5319BC24A51DF5007BCF30 /* MSALAuthenticationSchemeBearer.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EE776BD246C98D300F7EBFC /* MSALAuthenticationSchemeBearer.m */; }; 1E5319BD24A51DF6007BCF30 /* MSALAuthenticationSchemeBearer.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EE776BD246C98D300F7EBFC /* MSALAuthenticationSchemeBearer.m */; }; 1E5319BE24A51DFE007BCF30 /* MSALAuthenticationSchemePop.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EE776C2246C98E700F7EBFC /* MSALAuthenticationSchemePop.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E5319BF24A51DFF007BCF30 /* MSALAuthenticationSchemePop.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EE776C2246C98E700F7EBFC /* MSALAuthenticationSchemePop.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -241,6 +239,86 @@ 23F32F0C1FF4789100B2905E /* MSIDTestURLResponse+MSAL.m in Sources */ = {isa = PBXBuildFile; fileRef = 23F32F061FF4787600B2905E /* MSIDTestURLResponse+MSAL.m */; }; 23F32F0D1FF4789200B2905E /* MSIDTestURLResponse+MSAL.m in Sources */ = {isa = PBXBuildFile; fileRef = 23F32F061FF4787600B2905E /* MSIDTestURLResponse+MSAL.m */; }; 23FB5C1E22542B99002BF1EB /* MSALJsonDeserializable.h in Headers */ = {isa = PBXBuildFile; fileRef = 23FB5C1C22542B99002BF1EB /* MSALJsonDeserializable.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2814B4DA2A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2814B4D92A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift */; }; + 2814B4DB2A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2814B4D92A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift */; }; + 2826932A2A0974750037B93A /* MSALNativeAuthTokenRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282693272A0974740037B93A /* MSALNativeAuthTokenRequestParameters.swift */; }; + 2826932B2A0974750037B93A /* MSALNativeAuthTokenRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282693272A0974740037B93A /* MSALNativeAuthTokenRequestParameters.swift */; }; + 2826933B2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2826933A2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift */; }; + 2826933C2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2826933A2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift */; }; + 285F36082A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 285F36072A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift */; }; + 285F36092A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 285F36072A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift */; }; + 2877081F2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2877081E2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift */; }; + 287708202A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2877081E2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift */; }; + 287708222A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287708212A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift */; }; + 287708232A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287708212A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift */; }; + 287708252A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287708242A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift */; }; + 287708262A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287708242A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift */; }; + 287F64D4297EC29400ED90BD /* MSALNativeAuthTelemetryProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64D2297EC29400ED90BD /* MSALNativeAuthTelemetryProviderTests.swift */; }; + 287F64D5297EC29400ED90BD /* MSALNativeAuthCurrentRequestTelemetryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64D3297EC29400ED90BD /* MSALNativeAuthCurrentRequestTelemetryTests.swift */; }; + 287F64D92981781A00ED90BD /* MSALNativeAuthSignInParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64D82981781A00ED90BD /* MSALNativeAuthSignInParameters.swift */; }; + 287F64DA2981781A00ED90BD /* MSALNativeAuthSignInParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64D82981781A00ED90BD /* MSALNativeAuthSignInParameters.swift */; }; + 287F64E62981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64E52981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift */; }; + 287F64E72981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64E52981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift */; }; + 287F64E92981786A00ED90BD /* MSALNativeAuthVerifyCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64E82981786A00ED90BD /* MSALNativeAuthVerifyCodeParameters.swift */; }; + 287F64F0298186EA00ED90BD /* MSALNativeAuthInputValidatorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64EF298186EA00ED90BD /* MSALNativeAuthInputValidatorTest.swift */; }; + 287F64F32981A00400ED90BD /* MSALNativeAuthPublicClientApplicationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64F22981A00400ED90BD /* MSALNativeAuthPublicClientApplicationTest.swift */; }; + 287F650C2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F650B2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift */; }; + 287F650D2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F650B2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift */; }; + 287F65182983F77D00ED90BD /* MSALNativeAuthRequestParametersKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F65172983F77D00ED90BD /* MSALNativeAuthRequestParametersKey.swift */; }; + 287F65192983F77D00ED90BD /* MSALNativeAuthRequestParametersKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F65172983F77D00ED90BD /* MSALNativeAuthRequestParametersKey.swift */; }; + 287F6524298401AE00ED90BD /* MSALNativeAuthResponseSerializerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F6523298401AE00ED90BD /* MSALNativeAuthResponseSerializerTests.swift */; }; + 2884855C295DAFD400516492 /* MSALNativeAuthTokens.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2884855B295DAFD400516492 /* MSALNativeAuthTokens.swift */; }; + 2884855D295DAFD400516492 /* MSALNativeAuthTokens.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2884855B295DAFD400516492 /* MSALNativeAuthTokens.swift */; }; + 289747AC2979487900838C80 /* MSALNativeAuthUrlRequestSerializerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289747A92979487900838C80 /* MSALNativeAuthUrlRequestSerializerTests.swift */; }; + 289747B129799C6B00838C80 /* MSALNativeAuthInputValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289747AF29799A8700838C80 /* MSALNativeAuthInputValidator.swift */; }; + 289747B42979A3C800838C80 /* MSALNativeAuthParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289747B32979A3C800838C80 /* MSALNativeAuthParameters.swift */; }; + 289747B7297ABEA300838C80 /* MSALNativeAuthInputValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289747AF29799A8700838C80 /* MSALNativeAuthInputValidator.swift */; }; + 289747BA297ABEB400838C80 /* MSALNativeAuthParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289747B32979A3C800838C80 /* MSALNativeAuthParameters.swift */; }; + 289E15592948E601006104D9 /* MSALNativeAuthCacheInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289E15582948E601006104D9 /* MSALNativeAuthCacheInterface.swift */; }; + 289E156D2948EB8A006104D9 /* MSALNativeAuthCacheAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289E156C2948EB8A006104D9 /* MSALNativeAuthCacheAccessor.swift */; }; + 28A472EC2A276C3B003F988B /* MSALNativeAuthTokenValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28A472EB2A276C3B003F988B /* MSALNativeAuthTokenValidatedResponse.swift */; }; + 28B6494D2A0959EB00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B6494A2A0959DC00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTest.swift */; }; + 28CA6F5D29689F34004DB11D /* MSALNativeAuthCacheAccessorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28CA6F5429689F26004DB11D /* MSALNativeAuthCacheAccessorTest.swift */; }; + 28D1D57029BF62E900CE75F4 /* MSAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D65A6F431E3FD30A00C69FBA /* MSAL.framework */; }; + 28D1D58029BF883D00CE75F4 /* MSALNativeAuthIntegrationBaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D1D57F29BF883D00CE75F4 /* MSALNativeAuthIntegrationBaseTests.swift */; }; + 28D1D59229C2231C00CE75F4 /* MockAPIHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D1D59129C2231C00CE75F4 /* MockAPIHandler.swift */; }; + 28D1D59C29C2266500CE75F4 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D1D59B29C2266500CE75F4 /* Model.swift */; }; + 28D1D59E29C2392000CE75F4 /* MockAPIHandlerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D1D59D29C2392000CE75F4 /* MockAPIHandlerTest.swift */; }; + 28D5B05D2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D5B05C2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift */; }; + 28D5B05E2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D5B05C2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift */; }; + 28DCD09229D7166F00C4601E /* SignUpDelegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD09129D7166F00C4601E /* SignUpDelegates.swift */; }; + 28DCD09A29D7192F00C4601E /* MSALNativeAuthError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD09929D7192F00C4601E /* MSALNativeAuthError.swift */; }; + 28DCD09C29D71E7E00C4601E /* SignUpPasswordStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD09B29D71E7E00C4601E /* SignUpPasswordStartError.swift */; }; + 28DCD0A029D7260B00C4601E /* MSALNativeAuthBaseState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD09F29D7260B00C4601E /* MSALNativeAuthBaseState.swift */; }; + 28DCD0A229D7272300C4601E /* SignInDelegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0A129D7272300C4601E /* SignInDelegates.swift */; }; + 28DCD0A429D72C7100C4601E /* SignUpStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0A329D72C7100C4601E /* SignUpStates.swift */; }; + 28DCD0A629D72F6600C4601E /* PasswordRequiredError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0A529D72F6600C4601E /* PasswordRequiredError.swift */; }; + 28DCD0A829D72F9A00C4601E /* AttributesRequiredError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0A729D72F9A00C4601E /* AttributesRequiredError.swift */; }; + 28DCD0AA29D7344000C4601E /* SignInStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0A929D7344000C4601E /* SignInStates.swift */; }; + 28DCD0AC29D736BC00C4601E /* SignInPasswordStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0AB29D736BC00C4601E /* SignInPasswordStartError.swift */; }; + 28DCD0AE29D737E600C4601E /* VerifyCodeError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0AD29D737E600C4601E /* VerifyCodeError.swift */; }; + 28DCD0B029D738DD00C4601E /* ResetPasswordStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0AF29D738DD00C4601E /* ResetPasswordStartError.swift */; }; + 28DCD0B229D7392400C4601E /* ResetPasswordStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0B129D7392400C4601E /* ResetPasswordStates.swift */; }; + 28DCD0B429D73BCE00C4601E /* ResetPasswordDelegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0B329D73BCE00C4601E /* ResetPasswordDelegates.swift */; }; + 28DE3FD02A0921E2003148A4 /* SignInTestsValidatorHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DE3FCF2A0921E2003148A4 /* SignInTestsValidatorHelpers.swift */; }; + 28DE70D629FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DE70D529FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift */; }; + 28DE70D729FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DE70D529FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift */; }; + 28E4D9032A30ABA200280921 /* ResendCodeError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28E4D9022A30ABA200280921 /* ResendCodeError.swift */; }; + 28E4D9042A30ABA200280921 /* ResendCodeError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28E4D9022A30ABA200280921 /* ResendCodeError.swift */; }; + 28EDF93E29E6D43900A99F2A /* SignUpStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28EDF93D29E6D43900A99F2A /* SignUpStartError.swift */; }; + 28EDF94129E6D52E00A99F2A /* SignInStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28EDF94029E6D52E00A99F2A /* SignInStartError.swift */; }; + 28EDF94229E6D52E00A99F2A /* SignInStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28EDF94029E6D52E00A99F2A /* SignInStartError.swift */; }; + 28F19BEB2A2F884D00575581 /* Array+joinScopes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28F19BEA2A2F884D00575581 /* Array+joinScopes.swift */; }; + 28F19BEC2A2F884D00575581 /* Array+joinScopes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28F19BEA2A2F884D00575581 /* Array+joinScopes.swift */; }; + 28F74D54295C90E100B89A78 /* MSALNativeAuthCacheAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289E156C2948EB8A006104D9 /* MSALNativeAuthCacheAccessor.swift */; }; + 28F74D55295C90E100B89A78 /* MSALNativeAuthCacheInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289E15582948E601006104D9 /* MSALNativeAuthCacheInterface.swift */; }; + 28FDC49C2A38BFA900E38BE1 /* SignInAfterSignUpState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDC49B2A38BFA900E38BE1 /* SignInAfterSignUpState.swift */; }; + 28FDC49D2A38BFA900E38BE1 /* SignInAfterSignUpState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDC49B2A38BFA900E38BE1 /* SignInAfterSignUpState.swift */; }; + 28FDC4A62A38C00900E38BE1 /* SignInAfterSignUpDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDC4A52A38C00900E38BE1 /* SignInAfterSignUpDelegate.swift */; }; + 28FDC4A72A38C00900E38BE1 /* SignInAfterSignUpDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDC4A52A38C00900E38BE1 /* SignInAfterSignUpDelegate.swift */; }; + 28FDC4A92A38C0D100E38BE1 /* SignInAfterSignUpError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDC4A82A38C0D000E38BE1 /* SignInAfterSignUpError.swift */; }; + 28FDC4AA2A38C0D100E38BE1 /* SignInAfterSignUpError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDC4A82A38C0D000E38BE1 /* SignInAfterSignUpError.swift */; }; + 28FDC4AE2A38D81100E38BE1 /* MSALNativeAuthSignInControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDC4AB2A38D7D200E38BE1 /* MSALNativeAuthSignInControllerMock.swift */; }; 38880DF423280C5900688C24 /* MSALPublicClientApplicationConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 23B1D35D22EA4797000954AF /* MSALPublicClientApplicationConfig.m */; }; 38880DF523280C5A00688C24 /* MSALPublicClientApplicationConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 23B1D35D22EA4797000954AF /* MSALPublicClientApplicationConfig.m */; }; 583BFD0F24DC8E670035B901 /* MSALRedirectUriVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = B21E07B0210E542C007E3A3C /* MSALRedirectUriVerifier.m */; }; @@ -264,15 +342,15 @@ 886F516529CCA58900F09471 /* MSALCIAMAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 886F516329CCA58900F09471 /* MSALCIAMAuthority.m */; }; 886F516629CCA58900F09471 /* MSALCIAMAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 886F516329CCA58900F09471 /* MSALCIAMAuthority.m */; }; 886F516729CCA58900F09471 /* MSALCIAMAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 886F516329CCA58900F09471 /* MSALCIAMAuthority.m */; }; - 8878C61229DC9AFB002F5F4B /* MSALCIAMOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = 8878C61129DC9AFB002F5F4B /* MSALCIAMOauth2Provider.m */; }; - 8878C61329DC9B07002F5F4B /* MSALCIAMOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = 8878C61129DC9AFB002F5F4B /* MSALCIAMOauth2Provider.m */; }; - 8878C61429DC9B08002F5F4B /* MSALCIAMOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = 8878C61129DC9AFB002F5F4B /* MSALCIAMOauth2Provider.m */; }; - 8878C61529DC9B09002F5F4B /* MSALCIAMOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = 8878C61129DC9AFB002F5F4B /* MSALCIAMOauth2Provider.m */; }; - 8878C61729DC9B2C002F5F4B /* MSALCIAMOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = 8878C61629DC9B1A002F5F4B /* MSALCIAMOauth2Provider.h */; }; - 8878C61829DC9B2D002F5F4B /* MSALCIAMOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = 8878C61629DC9B1A002F5F4B /* MSALCIAMOauth2Provider.h */; }; - 8878C61929DC9B2E002F5F4B /* MSALCIAMOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = 8878C61629DC9B1A002F5F4B /* MSALCIAMOauth2Provider.h */; }; - 8878C61A29DC9B2F002F5F4B /* MSALCIAMOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = 8878C61629DC9B1A002F5F4B /* MSALCIAMOauth2Provider.h */; }; 88A25EE729E7347400066311 /* MSALCIAMAuthorityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25ED229E7185B00066311 /* MSALCIAMAuthorityTests.m */; }; + 8D2733142AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D2733132AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift */; }; + 8D2733152AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D2733132AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift */; }; + 8D35C8E72A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D35C8E62A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift */; }; + 8D35C8E82A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D35C8E62A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift */; }; + 8D35C8F12A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D35C8F02A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift */; }; + 8D35C8F22A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D35C8F02A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift */; }; + 8D61F9A12A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D61F9A02A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift */; }; + 8DDF473F2A98FE1C00126A47 /* MSALNativeAuthRequiredAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DDF473E2A98FE1C00126A47 /* MSALNativeAuthRequiredAttributes.swift */; }; 94E876CE1E492D6000FB96ED /* MSALAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 94E876CB1E492D6000FB96ED /* MSALAuthority.m */; }; 960751BB2183E82C00F2BF2F /* MSALAccountIdTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 960751BA2183E82C00F2BF2F /* MSALAccountIdTests.m */; }; 960751BC2183E82C00F2BF2F /* MSALAccountIdTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 960751BA2183E82C00F2BF2F /* MSALAccountIdTests.m */; }; @@ -353,6 +431,39 @@ 96CFA00B1E6E3460003BFCDC /* MSALTestAppScopesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CFA0091E6E3454003BFCDC /* MSALTestAppScopesViewController.m */; }; 96D9A5451E4AB1DC00674A85 /* MSALTelemetry.h in Headers */ = {isa = PBXBuildFile; fileRef = 96D9A5431E4AB1DC00674A85 /* MSALTelemetry.h */; settings = {ATTRIBUTES = (Public, ); }; }; 96D9A54A1E4AB23100674A85 /* MSALTelemetry.m in Sources */ = {isa = PBXBuildFile; fileRef = 96D9A5471E4AB22900674A85 /* MSALTelemetry.m */; }; + 9B235D9D2A3CC71C00657331 /* NativeAuthEndToEndTestPlan.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = 9B235D952A3CC71C00657331 /* NativeAuthEndToEndTestPlan.xctestplan */; }; + 9B235D9F2A3CFB4300657331 /* MSALNativeAuthEndToEndBaseTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B235D9E2A3CFB4300657331 /* MSALNativeAuthEndToEndBaseTestCase.swift */; }; + 9B235DA12A3CFC4500657331 /* MSALNativeAuthSignInUsernameEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B235DA02A3CFC4500657331 /* MSALNativeAuthSignInUsernameEndToEndTests.swift */; }; + 9B2BBA2F2A3293330075F702 /* MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2BBA2D2A3292400075F702 /* MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift */; }; + 9B2BBA312A3296010075F702 /* MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2BBA302A3296010075F702 /* MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift */; }; + 9B2BBA332A3297EA0075F702 /* MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2BBA322A3297EA0075F702 /* MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift */; }; + 9B2BBA352A3297F80075F702 /* MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2BBA342A3297F80075F702 /* MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift */; }; + 9B2BBA372A3298080075F702 /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2BBA362A3298080075F702 /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift */; }; + 9B2E93452A0D3801008A5DD2 /* MSALNativeAuthResetPasswordControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2E93442A0D3801008A5DD2 /* MSALNativeAuthResetPasswordControlling.swift */; }; + 9B2E93462A0D3813008A5DD2 /* MSALNativeAuthResetPasswordControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2E93442A0D3801008A5DD2 /* MSALNativeAuthResetPasswordControlling.swift */; }; + 9B4EE9D52A1686A900F243C1 /* MSALNativeAuthResetPasswordControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B4EE9CD2A1686A900F243C1 /* MSALNativeAuthResetPasswordControllerTests.swift */; }; + 9B4EE9D82A1687AE00F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B4EE9D62A16874F00F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift */; }; + 9B4EE9DA2A1687B600F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B4EE9D62A16874F00F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift */; }; + 9B5D6D062A3CA0E300521576 /* MSALNativeAuthSignInUsernameAndPasswordEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B5D6D052A3CA0E300521576 /* MSALNativeAuthSignInUsernameAndPasswordEndToEndTests.swift */; }; + 9B5D6D082A3CA55600521576 /* SignInDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B5D6D072A3CA55600521576 /* SignInDelegateSpies.swift */; }; + 9B61C9132A27E51900CE9E3A /* MSALNativeAuthResetPasswordRequestProviderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B61C9122A27E51900CE9E3A /* MSALNativeAuthResetPasswordRequestProviderMock.swift */; }; + 9B61C91C2A27E57C00CE9E3A /* MSALNativeAuthResetPasswordResponseValidatorMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B61C91B2A27E57C00CE9E3A /* MSALNativeAuthResetPasswordResponseValidatorMock.swift */; }; + 9B6EECEF2A3146ED008ABA50 /* MSALNativeAuthResetPasswordResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B6EECEE2A3146ED008ABA50 /* MSALNativeAuthResetPasswordResponseValidatorTests.swift */; }; + 9B839A102A4D7CF600BCC6F6 /* MSAL.docc in Sources */ = {isa = PBXBuildFile; fileRef = 9B839A0F2A4D7CF600BCC6F6 /* MSAL.docc */; }; + 9B839A112A4D7CF600BCC6F6 /* MSAL.docc in Sources */ = {isa = PBXBuildFile; fileRef = 9B839A0F2A4D7CF600BCC6F6 /* MSAL.docc */; }; + 9BB5180B2A2A2B5B00D6276A /* MSALNativeAuthResetPasswordControllerSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BB518032A2A2B5B00D6276A /* MSALNativeAuthResetPasswordControllerSpy.swift */; }; + 9BD2763D2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD2763C2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift */; }; + 9BD2763E2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD2763C2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift */; }; + 9BD2765A2A0E7E6F00FBD033 /* ResetPasswordTestValidatorHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD276582A0E7E6700FBD033 /* ResetPasswordTestValidatorHelpers.swift */; }; + 9BD2765B2A0E7E7D00FBD033 /* ResetPasswordCodeSentStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD276562A0E7DEC00FBD033 /* ResetPasswordCodeSentStateTests.swift */; }; + 9BD2765F2A0E81CE00FBD033 /* ResetPasswordRequiredStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD2765E2A0E81CE00FBD033 /* ResetPasswordRequiredStateTests.swift */; }; + 9BD78D822A126DC400AA7E12 /* MSALNativeAuthChallengeTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BD78D7A2A126A1500AA7E12 /* MSALNativeAuthChallengeTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9BD78D902A127F8000AA7E12 /* MSALNativeAuthChallengeTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BD78D7A2A126A1500AA7E12 /* MSALNativeAuthChallengeTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9BE7E3CB2A1CB70700CC3A62 /* MSALNativeAuthResetPasswordStartRequestProviderParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BE7E3CA2A1CB70700CC3A62 /* MSALNativeAuthResetPasswordStartRequestProviderParameters.swift */; }; + 9BE7E3CC2A1CB70700CC3A62 /* MSALNativeAuthResetPasswordStartRequestProviderParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BE7E3CA2A1CB70700CC3A62 /* MSALNativeAuthResetPasswordStartRequestProviderParameters.swift */; }; + 9BE7E3D52A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BE7E3D42A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift */; }; + 9BE7E3D62A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BE7E3D42A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift */; }; + 9BEF84742A31EF70005CB0B6 /* MSALNativeAuthTokenValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28A472EB2A276C3B003F988B /* MSALNativeAuthTokenValidatedResponse.swift */; }; 9D02FCAF28EF33F8003F791C /* MSALWPJMetaData.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DA6473528EC2FF10014F44F /* MSALWPJMetaData.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D02FCB728EF33FE003F791C /* MSALWPJMetaData.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DA6473528EC2FF10014F44F /* MSALWPJMetaData.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D292B1028F05696007FE93C /* MSALWPJMetaData.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D292B0F28F05696007FE93C /* MSALWPJMetaData.m */; }; @@ -722,7 +833,6 @@ B2D4789B230E3E01005AE186 /* MSALSerializedADALCacheProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = B29A56B8228266B40023F5E6 /* MSALSerializedADALCacheProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; B2D4789C230E3E14005AE186 /* MSALAccount+MultiTenantAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = B27CCDDE229F65D700CAD565 /* MSALAccount+MultiTenantAccount.h */; settings = {ATTRIBUTES = (Public, ); }; }; B2D4789D230E3E14005AE186 /* MSALAccount+MultiTenantAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = B27CCDDE229F65D700CAD565 /* MSALAccount+MultiTenantAccount.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B2D4789E230E3E2C005AE186 /* MSALWebviewParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 2338294D22D7DC9E001B8AD6 /* MSALWebviewParameters.h */; settings = {ATTRIBUTES = (Public, ); }; }; B2D4789F230E3E2D005AE186 /* MSALWebviewParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 2338294D22D7DC9E001B8AD6 /* MSALWebviewParameters.h */; settings = {ATTRIBUTES = (Public, ); }; }; B2D478A0230E3E40005AE186 /* MSALAccountEnumerationParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = B27CCDF0229F9F4700CAD565 /* MSALAccountEnumerationParameters.h */; settings = {ATTRIBUTES = (Public, ); }; }; B2D478A1230E3E40005AE186 /* MSALAccountEnumerationParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = B27CCDF0229F9F4700CAD565 /* MSALAccountEnumerationParameters.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -837,6 +947,273 @@ D6A2063E1FC511EB00755A51 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A206311FC5108000755A51 /* UIKit.framework */; }; D6A2063F1FC512EF00755A51 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A206311FC5108000755A51 /* UIKit.framework */; }; D6A206401FC512F400755A51 /* SafariServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A206331FC5109400755A51 /* SafariServices.framework */; }; + DE03478A2A39ED6A003CB3B6 /* MSALCIAMOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9244D72A31E1D500C0389F /* MSALCIAMOauth2Provider.m */; }; + DE0347A82A41AD08003CB3B6 /* MSALNativeAuthUserAccountResultStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0347A72A41AD08003CB3B6 /* MSALNativeAuthUserAccountResultStub.swift */; }; + DE0347BC2A41B768003CB3B6 /* MSALNativeAuthCredentialsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE92450B2A385ED800C0389F /* MSALNativeAuthCredentialsController.swift */; }; + DE0347BD2A41B76E003CB3B6 /* MSALNativeAuthCredentialsControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE92450D2A38601100C0389F /* MSALNativeAuthCredentialsControlling.swift */; }; + DE0347C12A41B7FC003CB3B6 /* SignUpStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28EDF93D29E6D43900A99F2A /* SignUpStartError.swift */; }; + DE0347C22A41B80C003CB3B6 /* MSALNativeAuthVerifyCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64E82981786A00ED90BD /* MSALNativeAuthVerifyCodeParameters.swift */; }; + DE0347C32A41B819003CB3B6 /* MSALNativeAuthUserAccountResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8BE7DB2A1F6BD2009642A5 /* MSALNativeAuthUserAccountResult.swift */; }; + DE0D656F29BF72F7005798B1 /* MSALNativeAuthSignInInitiateRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D656729BF72F6005798B1 /* MSALNativeAuthSignInInitiateRequestParameters.swift */; }; + DE0D657029BF72F7005798B1 /* MSALNativeAuthSignInInitiateRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D656729BF72F6005798B1 /* MSALNativeAuthSignInInitiateRequestParameters.swift */; }; + DE0D657629BF73CB005798B1 /* MSALNativeAuthSignInChallengeRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D657429BF73CB005798B1 /* MSALNativeAuthSignInChallengeRequestParameters.swift */; }; + DE0D657729BF73CB005798B1 /* MSALNativeAuthSignInChallengeRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D657429BF73CB005798B1 /* MSALNativeAuthSignInChallengeRequestParameters.swift */; }; + DE0D659529C1DCC9005798B1 /* MSALNativeAuthSignInInitiateRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D658E29C1DCA6005798B1 /* MSALNativeAuthSignInInitiateRequestParametersTest.swift */; }; + DE0D659629C1DCCC005798B1 /* MSALNativeAuthSignInChallengeRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D658C29C1DCA6005798B1 /* MSALNativeAuthSignInChallengeRequestParametersTest.swift */; }; + DE0D659729C1DCCF005798B1 /* MSALNativeAuthTokenRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D658D29C1DCA6005798B1 /* MSALNativeAuthTokenRequestParametersTest.swift */; }; + DE0D65AC29CC6A5A005798B1 /* MSALNativeAuthSignInInitiateResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65AB29CC6A59005798B1 /* MSALNativeAuthSignInInitiateResponse.swift */; }; + DE0D65AD29CC6A5A005798B1 /* MSALNativeAuthSignInInitiateResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65AB29CC6A59005798B1 /* MSALNativeAuthSignInInitiateResponse.swift */; }; + DE0D65B629CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65B529CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift */; }; + DE0D65B729CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65B529CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift */; }; + DE0D65B929D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65B829D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift */; }; + DE0D65BA29D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65B829D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift */; }; + DE0D65BF29D30BAE005798B1 /* MSALNativeAuthResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65BE29D30BAE005798B1 /* MSALNativeAuthResponseError.swift */; }; + DE0D65C029D30BAE005798B1 /* MSALNativeAuthResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65BE29D30BAE005798B1 /* MSALNativeAuthResponseError.swift */; }; + DE0D65C229D30C38005798B1 /* MSALNativeAuthSignInInitiateOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65C129D30C38005798B1 /* MSALNativeAuthSignInInitiateOauth2ErrorCode.swift */; }; + DE0D65C629D344F1005798B1 /* MSALNativeAuthSignInInitiateIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65C529D344F1005798B1 /* MSALNativeAuthSignInInitiateIntegrationTests.swift */; }; + DE0D65CD29D5CE56005798B1 /* MSALNativeAuthSignInChallengeIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65CA29D5CD6D005798B1 /* MSALNativeAuthSignInChallengeIntegrationTests.swift */; }; + DE0FECAC2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0FECAA2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift */; }; + DE0FECAD2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0FECAA2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift */; }; + DE0FECC72993ADAF00B139A8 /* MSALNativeAuthResendCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0FECC62993ADAE00B139A8 /* MSALNativeAuthResendCodeParameters.swift */; }; + DE0FECC82993ADAF00B139A8 /* MSALNativeAuthResendCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0FECC62993ADAE00B139A8 /* MSALNativeAuthResendCodeParameters.swift */; }; + DE14096B2A38DE0E008E6F1E /* CredentialsDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE14096A2A38DE0E008E6F1E /* CredentialsDelegateSpies.swift */; }; + DE14096D2A38DF41008E6F1E /* MSALNativeAuthCredentialsControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE14096C2A38DF40008E6F1E /* MSALNativeAuthCredentialsControllerTests.swift */; }; + DE14D75D29897D8000F37BEF /* MSALNativeAuthTelemetryApiId.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D995296EC35A006CB384 /* MSALNativeAuthTelemetryApiId.swift */; }; + DE14D75E29897D9500F37BEF /* MSALNativeAuthUrlRequestSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA49B2953576C00E98964 /* MSALNativeAuthUrlRequestSerializer.swift */; }; + DE14D76129898CF900F37BEF /* MSALNativeAuthTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE14D76029898CF900F37BEF /* MSALNativeAuthTestCase.swift */; }; + DE1D8AA829E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1D8AA729E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift */; }; + DE1D8AA929E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1D8AA729E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift */; }; + DE40A4CA2A8F801200928CEE /* MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE40A4C92A8F801200928CEE /* MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift */; }; + DE40A4D32A8F80C100928CEE /* MSALNativeAuthSignUpContinueResponseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE40A4D22A8F80C100928CEE /* MSALNativeAuthSignUpContinueResponseErrorTests.swift */; }; + DE4F0F3129D6F1AA00D561FD /* MSALNativeAuthTokenIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4F0F2929D6F1AA00D561FD /* MSALNativeAuthTokenIntegrationTests.swift */; }; + DE54B5912A434B9B00460B34 /* MSALNativeAuthTokenController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE54B5902A434B9B00460B34 /* MSALNativeAuthTokenController.swift */; }; + DE54B5922A434B9B00460B34 /* MSALNativeAuthTokenController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE54B5902A434B9B00460B34 /* MSALNativeAuthTokenController.swift */; }; + DE54B5942A43587800460B34 /* MSALNativeAuthTokenRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE54B5932A43587800460B34 /* MSALNativeAuthTokenRequestProvider.swift */; }; + DE54B5952A43587800460B34 /* MSALNativeAuthTokenRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE54B5932A43587800460B34 /* MSALNativeAuthTokenRequestProvider.swift */; }; + DE54B59F2A4452DB00460B34 /* MSALNativeAuthTokenResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE54B59C2A44521E00460B34 /* MSALNativeAuthTokenResponseValidatorTests.swift */; }; + DE54B5AD2A459B0400460B34 /* MSALNativeAuthTokenResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE54B5AC2A459B0400460B34 /* MSALNativeAuthTokenResponseValidator.swift */; }; + DE5738B22A8E71D500D9120D /* MSALNativeAuthResetPasswordContinueResponseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE5738AA2A8E71D500D9120D /* MSALNativeAuthResetPasswordContinueResponseErrorTests.swift */; }; + DE5738B42A8E74DC00D9120D /* MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE5738B32A8E74DC00D9120D /* MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift */; }; + DE5738B62A8E790100D9120D /* MSALNativeAuthTokenValidatedErrorTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE5738B52A8E790100D9120D /* MSALNativeAuthTokenValidatedErrorTypeTests.swift */; }; + DE5738B82A8F76C600D9120D /* MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE5738B72A8F76C600D9120D /* MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift */; }; + DE5738BA2A8F780E00D9120D /* MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE5738B92A8F780E00D9120D /* MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift */; }; + DE5738BC2A8F79A800D9120D /* MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE5738BB2A8F79A800D9120D /* MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift */; }; + DE5738BE2A8F7AC600D9120D /* MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE5738BD2A8F7AC600D9120D /* MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift */; }; + DE5738C02A8F7C2000D9120D /* MSALNativeAuthSignUpStartResponseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE5738BF2A8F7C1F00D9120D /* MSALNativeAuthSignUpStartResponseErrorTests.swift */; }; + DE729ECD2A1793A100A761D9 /* MSALNativeAuthChannelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE729ECC2A1793A100A761D9 /* MSALNativeAuthChannelType.swift */; }; + DE729ECE2A1793A100A761D9 /* MSALNativeAuthChannelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE729ECC2A1793A100A761D9 /* MSALNativeAuthChannelType.swift */; }; + DE87DE6A2A39E80B0032BF9E /* MSALNativeAuthUserAccountResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE87DE692A39E80B0032BF9E /* MSALNativeAuthUserAccountResultTests.swift */; }; + DE8BE7DC2A1F6BD2009642A5 /* MSALNativeAuthUserAccountResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8BE7DB2A1F6BD2009642A5 /* MSALNativeAuthUserAccountResult.swift */; }; + DE8EC8742A026BA0003FA561 /* MSALNativeAuthSignInRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC86C2A026BA0003FA561 /* MSALNativeAuthSignInRequestProvider.swift */; }; + DE8EC8752A026BA0003FA561 /* MSALNativeAuthSignInRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC86C2A026BA0003FA561 /* MSALNativeAuthSignInRequestProvider.swift */; }; + DE8EC8A82A026FE2003FA561 /* MSALNativeAuthResetPasswordChallengeIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC8772A026C2E003FA561 /* MSALNativeAuthResetPasswordChallengeIntegrationTests.swift */; }; + DE8EC8A92A026FE7003FA561 /* MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC8782A026C2E003FA561 /* MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift */; }; + DE8EC8AA2A026FEA003FA561 /* MSALNativeAuthResetPasswordStartIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC8792A026C2E003FA561 /* MSALNativeAuthResetPasswordStartIntegrationTests.swift */; }; + DE8EC8AB2A026FEC003FA561 /* MSALNativeAuthResetPasswordContinueIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC87A2A026C2E003FA561 /* MSALNativeAuthResetPasswordContinueIntegrationTests.swift */; }; + DE8EC8AC2A026FEF003FA561 /* MSALNativeAuthResetPasswordSubmitIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC87B2A026C2E003FA561 /* MSALNativeAuthResetPasswordSubmitIntegrationTests.swift */; }; + DE8EC8B62A053D80003FA561 /* MSALNativeAuthESTSApiErrorCodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC8B52A053D80003FA561 /* MSALNativeAuthESTSApiErrorCodes.swift */; }; + DE8EC8B72A053D80003FA561 /* MSALNativeAuthESTSApiErrorCodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC8B52A053D80003FA561 /* MSALNativeAuthESTSApiErrorCodes.swift */; }; + DE9244D82A31E1D500C0389F /* MSALCIAMOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = DE9244D62A31E1D500C0389F /* MSALCIAMOauth2Provider.h */; }; + DE9244D92A31E1D500C0389F /* MSALCIAMOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = DE9244D62A31E1D500C0389F /* MSALCIAMOauth2Provider.h */; }; + DE9244DA2A31E1D500C0389F /* MSALCIAMOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = DE9244D62A31E1D500C0389F /* MSALCIAMOauth2Provider.h */; }; + DE9244DB2A31E1D500C0389F /* MSALCIAMOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = DE9244D62A31E1D500C0389F /* MSALCIAMOauth2Provider.h */; }; + DE9244DD2A31E1D500C0389F /* MSALCIAMOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9244D72A31E1D500C0389F /* MSALCIAMOauth2Provider.m */; }; + DE9244DE2A31E1D500C0389F /* MSALCIAMOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9244D72A31E1D500C0389F /* MSALCIAMOauth2Provider.m */; }; + DE9244DF2A31E1D500C0389F /* MSALCIAMOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9244D72A31E1D500C0389F /* MSALCIAMOauth2Provider.m */; }; + DE92450C2A385ED800C0389F /* MSALNativeAuthCredentialsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE92450B2A385ED800C0389F /* MSALNativeAuthCredentialsController.swift */; }; + DE92450E2A38601100C0389F /* MSALNativeAuthCredentialsControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE92450D2A38601100C0389F /* MSALNativeAuthCredentialsControlling.swift */; }; + DE9245122A38736600C0389F /* CredentialsDelegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9245112A38736600C0389F /* CredentialsDelegates.swift */; }; + DE9245152A3875D700C0389F /* RetrieveAccessTokenError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9245142A3875D700C0389F /* RetrieveAccessTokenError.swift */; }; + DE94C9E029F198D600C1EC1F /* MSALNativeAuthResetPasswordStartRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94C9DE29F1989600C1EC1F /* MSALNativeAuthResetPasswordStartRequestParametersTest.swift */; }; + DE94C9E229F19AA200C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94C9E129F19AA200C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift */; }; + DE94C9E429F19C4C00C1EC1F /* MSALNativeAuthResetPasswordContinueRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94C9E329F19C4C00C1EC1F /* MSALNativeAuthResetPasswordContinueRequestParametersTest.swift */; }; + DE94C9E629F19D9B00C1EC1F /* MSALNativeAuthResetPasswordSubmitRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94C9E529F19D9A00C1EC1F /* MSALNativeAuthResetPasswordSubmitRequestParametersTest.swift */; }; + DE94C9E829F19E6B00C1EC1F /* MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94C9E729F19E6B00C1EC1F /* MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift */; }; + DE94C9F029F2AF5E00C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94C9EE29F2AF3200C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParameters.swift */; }; + DEC1E425298BE18A00948BED /* MSALNativeAuthServerTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26097C62948FC720060DD7C /* MSALNativeAuthServerTelemetry.swift */; }; + DECC1F9629521E35006D9FB1 /* MSALLogMask.m in Sources */ = {isa = PBXBuildFile; fileRef = DECC1F9229521E34006D9FB1 /* MSALLogMask.m */; }; + DECC1F9729521E35006D9FB1 /* MSALLogMask.m in Sources */ = {isa = PBXBuildFile; fileRef = DECC1F9229521E34006D9FB1 /* MSALLogMask.m */; }; + DECC1F9829521E35006D9FB1 /* MSALLogMask.h in Headers */ = {isa = PBXBuildFile; fileRef = DECC1F9329521E34006D9FB1 /* MSALLogMask.h */; }; + DECC1F9929521E35006D9FB1 /* MSALLogMask.h in Headers */ = {isa = PBXBuildFile; fileRef = DECC1F9329521E34006D9FB1 /* MSALLogMask.h */; }; + DECC1FB329531032006D9FB1 /* MSALLogMaskTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DECC1FB229531032006D9FB1 /* MSALLogMaskTests.m */; }; + DECC1FB5295322A8006D9FB1 /* MSALNativeLoggingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DECC1FB4295322A8006D9FB1 /* MSALNativeLoggingTests.swift */; }; + DEDB298B29D72D62008DA85B /* MSALNativeAuthInnerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDB298A29D72D62008DA85B /* MSALNativeAuthInnerError.swift */; }; + DEDB298C29D72D62008DA85B /* MSALNativeAuthInnerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDB298A29D72D62008DA85B /* MSALNativeAuthInnerError.swift */; }; + DEDB29A529DDA9DC008DA85B /* MSALNativeAuthSignInInitiateResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDB29A429DDA9DC008DA85B /* MSALNativeAuthSignInInitiateResponseError.swift */; }; + DEDB29A829DDAEB3008DA85B /* MSALNativeAuthSignInChallengeOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDB29A629DDAEB3008DA85B /* MSALNativeAuthSignInChallengeOauth2ErrorCode.swift */; }; + DEDB29A929DDAEB3008DA85B /* MSALNativeAuthTokenOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDB29A729DDAEB3008DA85B /* MSALNativeAuthTokenOauth2ErrorCode.swift */; }; + DEDB29AC29DDAF53008DA85B /* MSALNativeAuthSignInChallengeResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDB29AA29DDAF52008DA85B /* MSALNativeAuthSignInChallengeResponseError.swift */; }; + DEDB29AD29DDAF53008DA85B /* MSALNativeAuthTokenResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDB29AB29DDAF53008DA85B /* MSALNativeAuthTokenResponseError.swift */; }; + DEDB29B129DEC770008DA85B /* MSALNativeAuthRequestErrorHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDB29B029DEC770008DA85B /* MSALNativeAuthRequestErrorHandlerTests.swift */; }; + DEDD6F0829E83FD20017989F /* MSALNativeAuthRequestConfiguratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDD6F0729E83FD20017989F /* MSALNativeAuthRequestConfiguratorTests.swift */; }; + DEE34F12D170B71C00BC302A /* MSALNativeAuthResetPasswordStartRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F11D170B71C00BC302A /* MSALNativeAuthResetPasswordStartRequestParameters.swift */; }; + DEE34F48D170B71C00BC302A /* MSALNativeAuthResultFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F43D170B71C00BC302A /* MSALNativeAuthResultFactory.swift */; }; + DEE34F49D170B71C00BC302A /* MSALNativeAuthResultFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F43D170B71C00BC302A /* MSALNativeAuthResultFactory.swift */; }; + DEE34F5CD170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F5BD170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponse.swift */; }; + DEE34F60D170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F5ED170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponseError.swift */; }; + DEE34F61D170B71C00BC302A /* MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F5FD170B71C00BC302A /* MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift */; }; + DEE34F65D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F64D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeResponse.swift */; }; + DEE34F72D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F69D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeResponseError.swift */; }; + DEE34F73D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F71D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift */; }; + DEE34F75D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F74D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueRequestParameters.swift */; }; + DEE34F77D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F76D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueResponse.swift */; }; + DEE34F7AD170B71C00BC302A /* MSALNativeAuthResetPasswordContinueResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F78D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueResponseError.swift */; }; + DEE34F7BD170B71C00BC302A /* MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F79D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift */; }; + DEE34F7DD170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F7CD170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitRequestParameters.swift */; }; + DEE34F7FD170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F7ED170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitResponse.swift */; }; + DEE34F82D170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F80D170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift */; }; + DEE34F83D170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F81D170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitResponseError.swift */; }; + DEE34F85D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F84D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift */; }; + DEE34F87D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F86D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponse.swift */; }; + DEE34F89D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F88D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionStatus.swift */; }; + DEE34F8CD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F8AD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift */; }; + DEE34F8DD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F8BD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponseError.swift */; }; + DEE34F96D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F95D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift */; }; + DEE34F97D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F95D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift */; }; + DEE34FA1D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34FA0D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift */; }; + DEE34FA2D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34FA0D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift */; }; + DEF1DD322AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF1DD312AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift */; }; + DEF1DD332AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF1DD312AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift */; }; + DEF1DD3C2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF1DD3B2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift */; }; + DEF1DD3D2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF1DD3B2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift */; }; + DEF9D989296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D988296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift */; }; + DEF9D98A296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D988296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift */; }; + DEF9D997296EC35A006CB384 /* MSALNativeAuthTelemetryApiId.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D995296EC35A006CB384 /* MSALNativeAuthTelemetryApiId.swift */; }; + DEF9D999296EC848006CB384 /* MSALNativeAuthOperationTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D998296EC848006CB384 /* MSALNativeAuthOperationTypes.swift */; }; + DEF9D99A296EC848006CB384 /* MSALNativeAuthOperationTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D998296EC848006CB384 /* MSALNativeAuthOperationTypes.swift */; }; + DEF9D99F296F08CE006CB384 /* MSALNativeAuthTelemetryProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D99E296F08CE006CB384 /* MSALNativeAuthTelemetryProvider.swift */; }; + DEF9D9A0296F08CE006CB384 /* MSALNativeAuthTelemetryProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D99E296F08CE006CB384 /* MSALNativeAuthTelemetryProvider.swift */; }; + DEFB46ED2A52BA3700DBC006 /* MSALNativeAuthSignOutEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFB46EC2A52BA3700DBC006 /* MSALNativeAuthSignOutEndToEndTests.swift */; }; + DEFB46F22A52C11400DBC006 /* MSALNativeAuthResetPasswordEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFB46F12A52C11400DBC006 /* MSALNativeAuthResetPasswordEndToEndTests.swift */; }; + DEFB46F42A52C28100DBC006 /* ResetPasswordDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFB46F32A52C28100DBC006 /* ResetPasswordDelegateSpies.swift */; }; + E205D62E29B783FF003887BC /* MSALNativeAuthConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = E205D62D29B783FF003887BC /* MSALNativeAuthConfiguration.swift */; }; + E205D62F29B783FF003887BC /* MSALNativeAuthConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = E205D62D29B783FF003887BC /* MSALNativeAuthConfiguration.swift */; }; + E206FC5F296D65DE00AF4400 /* MSALNativeAuthInternalError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E206FC5E296D65DE00AF4400 /* MSALNativeAuthInternalError.swift */; }; + E206FC60296D65DE00AF4400 /* MSALNativeAuthInternalError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E206FC5E296D65DE00AF4400 /* MSALNativeAuthInternalError.swift */; }; + E206FCEF2979BC4600AF4400 /* MSALNativeAuthSignInController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E206FCEE2979BC4600AF4400 /* MSALNativeAuthSignInController.swift */; }; + E206FCF02979BC4600AF4400 /* MSALNativeAuthSignInController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E206FCEE2979BC4600AF4400 /* MSALNativeAuthSignInController.swift */; }; + E20C21752A7A61B600E31598 /* SignUpDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20C21742A7A61B600E31598 /* SignUpDelegateSpies.swift */; }; + E20C217E2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20C217D2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift */; }; + E20C21842A7A6CA400E31598 /* SignInCodeRequiredStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20C21832A7A6CA400E31598 /* SignInCodeRequiredStateTests.swift */; }; + E20C218B2A7A805900E31598 /* SignInPasswordRequiredStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20C218A2A7A805800E31598 /* SignInPasswordRequiredStateTests.swift */; }; + E22952682A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22952672A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift */; }; + E22E20282A7936C50073A6FF /* MSALNativeAuthSignUpControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22E20272A7936C50073A6FF /* MSALNativeAuthSignUpControllerMock.swift */; }; + E235610E29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235610D29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift */; }; + E235610F29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235610D29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift */; }; + E235613129C9CEA8000E01CA /* MSALNativeAuthSignUpStartRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235613029C9CEA8000E01CA /* MSALNativeAuthSignUpStartRequestParameters.swift */; }; + E235613229C9CEA8000E01CA /* MSALNativeAuthSignUpStartRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235613029C9CEA8000E01CA /* MSALNativeAuthSignUpStartRequestParameters.swift */; }; + E235613429C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235613329C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift */; }; + E235613529C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235613329C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift */; }; + E23E955F29D4B9F7001DC59C /* MSALNativeAuthSignUpChallengeIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E23E955E29D4B9F7001DC59C /* MSALNativeAuthSignUpChallengeIntegrationTests.swift */; }; + E23E956929D5BD6B001DC59C /* MSALNativeAuthSignUpRequestProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E23E956829D5BD6B001DC59C /* MSALNativeAuthSignUpRequestProviderTests.swift */; }; + E243F69429D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69329D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift */; }; + E243F69529D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69329D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift */; }; + E243F69A29D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69929D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift */; }; + E243F69B29D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69929D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift */; }; + E243F69D29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69C29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift */; }; + E243F69E29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69C29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift */; }; + E243F6A029D1FF9E00DAC60F /* MSALNativeAuthSignUpContinueRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69F29D1FF9E00DAC60F /* MSALNativeAuthSignUpContinueRequestParameters.swift */; }; + E243F6A129D1FF9E00DAC60F /* MSALNativeAuthSignUpContinueRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69F29D1FF9E00DAC60F /* MSALNativeAuthSignUpContinueRequestParameters.swift */; }; + E243F6A629D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F6A529D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift */; }; + E243F6A729D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F6A529D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift */; }; + E243F6AA29D42FE900DAC60F /* MSALNativeAuthSignUpContinueRequestProviderParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F6A929D42FE900DAC60F /* MSALNativeAuthSignUpContinueRequestProviderParams.swift */; }; + E243F6AB29D42FE900DAC60F /* MSALNativeAuthSignUpContinueRequestProviderParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F6A929D42FE900DAC60F /* MSALNativeAuthSignUpContinueRequestProviderParams.swift */; }; + E243F6AF29D446FC00DAC60F /* MSALNativeAuthSignUpStartIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F6AD29D4427E00DAC60F /* MSALNativeAuthSignUpStartIntegrationTests.swift */; }; + E248917A2A1CFA6B001ECBE2 /* MSALNativeAuthConfigStubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F5BE9429894FCA00C67EC7 /* MSALNativeAuthConfigStubs.swift */; }; + E25BC07A2995423100588549 /* MSALNativeAuthNetworkMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25BC0792995423100588549 /* MSALNativeAuthNetworkMocks.swift */; }; + E25BC0832995429D00588549 /* MSALNativeAuthCacheMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25BC0822995429D00588549 /* MSALNativeAuthCacheMocks.swift */; }; + E25BC0852995430B00588549 /* MSALNativeAuthFactoriesMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25BC0842995430B00588549 /* MSALNativeAuthFactoriesMocks.swift */; }; + E25BC099299555C000588549 /* MSALNativeAuthTelemetryTestDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25BC098299555C000588549 /* MSALNativeAuthTelemetryTestDispatcher.swift */; }; + E25E6E512AA7725F0094461E /* MSALNativeAuthResetPasswordControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25E6E502AA7725F0094461E /* MSALNativeAuthResetPasswordControllerMock.swift */; }; + E25E6E5A2AA7727D0094461E /* MSALNativeAuthCredentialsControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25E6E592AA7727D0094461E /* MSALNativeAuthCredentialsControllerMock.swift */; }; + E25EA4EC2A4C9B75004C8E40 /* MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26E391A2A4C2BE200063C07 /* MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift */; }; + E26097C32948FC4D0060DD7C /* MSALNativeAuthLogging.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26097C22948FC4D0060DD7C /* MSALNativeAuthLogging.swift */; }; + E26097C42948FC4D0060DD7C /* MSALNativeAuthLogging.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26097C22948FC4D0060DD7C /* MSALNativeAuthLogging.swift */; }; + E26097C82948FC720060DD7C /* MSALNativeAuthServerTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26097C62948FC720060DD7C /* MSALNativeAuthServerTelemetry.swift */; }; + E26E39242A4C2D7400063C07 /* SignUpDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26E39232A4C2D7400063C07 /* SignUpDelegateSpies.swift */; }; + E272C4EC2A4447520013B805 /* MSALNativeAuthSignUpUsernameEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E272C4EA2A4447520013B805 /* MSALNativeAuthSignUpUsernameEndToEndTests.swift */; }; + E27332C02A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E27332BF2A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift */; }; + E27332C12A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E27332BF2A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift */; }; + E284F5D929F28B4200DBED7D /* MSALNativeAuthSignUpController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E284F5D829F28B4200DBED7D /* MSALNativeAuthSignUpController.swift */; }; + E284F5DA29F28B4200DBED7D /* MSALNativeAuthSignUpController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E284F5D829F28B4200DBED7D /* MSALNativeAuthSignUpController.swift */; }; + E284F5E429F2F28A00DBED7D /* MSALNativeAuthSignUpControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = E284F5E329F2F28A00DBED7D /* MSALNativeAuthSignUpControlling.swift */; }; + E284F5E529F2F28A00DBED7D /* MSALNativeAuthSignUpControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = E284F5E329F2F28A00DBED7D /* MSALNativeAuthSignUpControlling.swift */; }; + E286E2DD2A1BAEA800666DD0 /* MSALNativeAuthSignUpControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E286E2DC2A1BAEA800666DD0 /* MSALNativeAuthSignUpControllerTests.swift */; }; + E2960A112A1F4D2F000F441B /* MSALNativeAuthSignUpChallengeResponseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2960A102A1F4D2F000F441B /* MSALNativeAuthSignUpChallengeResponseErrorTests.swift */; }; + E2ACA47B29520C2200E98964 /* MSALNativeAuthEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA47A29520C2200E98964 /* MSALNativeAuthEndpoint.swift */; }; + E2ACA47C29520C2200E98964 /* MSALNativeAuthEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA47A29520C2200E98964 /* MSALNativeAuthEndpoint.swift */; }; + E2ACA48B2952302B00E98964 /* MSALNativeAuthRequestContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA48A2952302B00E98964 /* MSALNativeAuthRequestContext.swift */; }; + E2ACA48C2952302B00E98964 /* MSALNativeAuthRequestContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA48A2952302B00E98964 /* MSALNativeAuthRequestContext.swift */; }; + E2ACA4952953415E00E98964 /* MSALNativeAuthGrantType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA4942953415E00E98964 /* MSALNativeAuthGrantType.swift */; }; + E2ACA4962953415E00E98964 /* MSALNativeAuthGrantType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA4942953415E00E98964 /* MSALNativeAuthGrantType.swift */; }; + E2ACA49D2953576C00E98964 /* MSALNativeAuthUrlRequestSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA49B2953576C00E98964 /* MSALNativeAuthUrlRequestSerializer.swift */; }; + E2B8532B2A1531DA007A4776 /* MSALNativeAuthSignUpValidatedResponses.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2B8532A2A1531DA007A4776 /* MSALNativeAuthSignUpValidatedResponses.swift */; }; + E2B8532C2A1531DA007A4776 /* MSALNativeAuthSignUpValidatedResponses.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2B8532A2A1531DA007A4776 /* MSALNativeAuthSignUpValidatedResponses.swift */; }; + E2B8532F2A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2B8532E2A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift */; }; + E2B853302A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2B8532E2A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift */; }; + E2BC027529D6E0C600041DBC /* MSALNativeAuthSignUpContinueIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BC027429D6E0C600041DBC /* MSALNativeAuthSignUpContinueIntegrationTests.swift */; }; + E2BC029829D766A800041DBC /* MSALNativeAuthSignUpChallengeRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BC029729D766A800041DBC /* MSALNativeAuthSignUpChallengeRequestParametersTest.swift */; }; + E2BC029A29D766B200041DBC /* MSALNativeAuthSignUpStartRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BC029929D766B200041DBC /* MSALNativeAuthSignUpStartRequestParametersTest.swift */; }; + E2BC029C29D766CB00041DBC /* MSALNativeAuthSignUpContinueRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BC029B29D766CB00041DBC /* MSALNativeAuthSignUpContinueRequestParametersTest.swift */; }; + E2BDD98B2A28FBDD00E3ED6B /* MSALNativeAuthErrorRequiredAttributesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BDD98A2A28FBDD00E3ED6B /* MSALNativeAuthErrorRequiredAttributesTests.swift */; }; + E2C1D287299BA15D00B26449 /* MSALNativeAuthBaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C1D286299BA15D00B26449 /* MSALNativeAuthBaseController.swift */; }; + E2C1D288299BA15D00B26449 /* MSALNativeAuthBaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C1D286299BA15D00B26449 /* MSALNativeAuthBaseController.swift */; }; + E2C1D2D429A3992100B26449 /* MSALNativeAuthBaseControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C1D2D329A3992100B26449 /* MSALNativeAuthBaseControllerTests.swift */; }; + E2C61FE129DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE029DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift */; }; + E2C61FE229DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE029DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift */; }; + E2C61FE429DED15800F15203 /* MSALNativeAuthSignUpStartResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE329DED15800F15203 /* MSALNativeAuthSignUpStartResponseError.swift */; }; + E2C61FE529DED15800F15203 /* MSALNativeAuthSignUpStartResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE329DED15800F15203 /* MSALNativeAuthSignUpStartResponseError.swift */; }; + E2C61FE729DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE629DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift */; }; + E2C61FE829DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE629DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift */; }; + E2C61FEA29DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE929DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift */; }; + E2C61FEB29DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE929DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift */; }; + E2C61FED29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FEC29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift */; }; + E2C61FEE29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FEC29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift */; }; + E2C61FF029DEDB0200F15203 /* MSALNativeAuthSignUpContinueResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FEF29DEDB0200F15203 /* MSALNativeAuthSignUpContinueResponseError.swift */; }; + E2C61FF129DEDB0200F15203 /* MSALNativeAuthSignUpContinueResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FEF29DEDB0200F15203 /* MSALNativeAuthSignUpContinueResponseError.swift */; }; + E2C872C3294CDEE800C4F580 /* MSALNativeAuthRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C872C2294CDEE800C4F580 /* MSALNativeAuthRequestable.swift */; }; + E2C872C4294CDEE800C4F580 /* MSALNativeAuthRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C872C2294CDEE800C4F580 /* MSALNativeAuthRequestable.swift */; }; + E2CD2E4A29FBEA36009F8FFA /* SignUpCodeSentStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2E4929FBEA36009F8FFA /* SignUpCodeSentStateTests.swift */; }; + E2CD2E4F29FC0451009F8FFA /* SignUpPasswordRequiredStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2E4E29FC0451009F8FFA /* SignUpPasswordRequiredStateTests.swift */; }; + E2CD2E5129FC087A009F8FFA /* SignUpAttributesRequiredStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2E5029FC087A009F8FFA /* SignUpAttributesRequiredStateTests.swift */; }; + E2CD2E8D2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2E8C2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift */; }; + E2CD2E8E2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2E8C2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift */; }; + E2CD2EB32A040012009F8FFA /* SignUpTestsValidatorHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2EB22A040012009F8FFA /* SignUpTestsValidatorHelpers.swift */; }; + E2CD2EB52A0404DA009F8FFA /* MSALNativeAuthSignUpControllerSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2EB42A0404DA009F8FFA /* MSALNativeAuthSignUpControllerSpy.swift */; }; + E2D3BC4F2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D3BC4E2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift */; }; + E2D3BC502A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D3BC4E2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift */; }; + E2DC31BC29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DC31BB29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift */; }; + E2DC31BD29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DC31BB29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift */; }; + E2DC31C829B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DC31C729B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift */; }; + E2DC31C929B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DC31C729B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift */; }; + E2EBD6212A1BB4640049467A /* MSALNativeAuthSignUpRequestProviderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EBD6202A1BB4640049467A /* MSALNativeAuthSignUpRequestProviderMock.swift */; }; + E2EBD62A2A1BB7700049467A /* MSALNativeAuthSignUpResponseValidatorMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EBD6292A1BB7700049467A /* MSALNativeAuthSignUpResponseValidatorMock.swift */; }; + E2EFACFE2A69915100D6C3DE /* SignInResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFACFD2A69915100D6C3DE /* SignInResults.swift */; }; + E2EFACFF2A69915100D6C3DE /* SignInResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFACFD2A69915100D6C3DE /* SignInResults.swift */; }; + E2EFAD092A69A34300D6C3DE /* CodeRequiredGenericResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD082A69A34300D6C3DE /* CodeRequiredGenericResult.swift */; }; + E2EFAD0A2A69A34300D6C3DE /* CodeRequiredGenericResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD082A69A34300D6C3DE /* CodeRequiredGenericResult.swift */; }; + E2EFAD0C2A69B45100D6C3DE /* SignUpResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD0B2A69B45100D6C3DE /* SignUpResults.swift */; }; + E2EFAD0D2A69B45100D6C3DE /* SignUpResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD0B2A69B45100D6C3DE /* SignUpResults.swift */; }; + E2EFAD0F2A69BBB800D6C3DE /* ResetPasswordResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD0E2A69BBB800D6C3DE /* ResetPasswordResults.swift */; }; + E2EFAD102A69BBB800D6C3DE /* ResetPasswordResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD0E2A69BBB800D6C3DE /* ResetPasswordResults.swift */; }; + E2EFAD162A70300B00D6C3DE /* MSALNativeAuthControllerTelemetryWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD152A70300B00D6C3DE /* MSALNativeAuthControllerTelemetryWrapper.swift */; }; + E2EFAD172A70300B00D6C3DE /* MSALNativeAuthControllerTelemetryWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD152A70300B00D6C3DE /* MSALNativeAuthControllerTelemetryWrapper.swift */; }; + E2F4DB242A1F525A009FBCD0 /* MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F4DB232A1F525A009FBCD0 /* MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift */; }; + E2F4DB2D2A1F5714009FBCD0 /* MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F4DB2C2A1F5714009FBCD0 /* MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift */; }; + E2F5BE8E29893A4100C67EC7 /* MSALNativeAuthEndpointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F5BE8D29893A4100C67EC7 /* MSALNativeAuthEndpointTests.swift */; }; + E2F5BE9A29896ADB00C67EC7 /* MSALNativeAuthSignInControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F5BE9929896ADB00C67EC7 /* MSALNativeAuthSignInControllerTests.swift */; }; + E2F5BE9D298A6CEB00C67EC7 /* MSALNativeAuthResultFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F5BE9C298A6CEB00C67EC7 /* MSALNativeAuthResultFactoryTests.swift */; }; + E2F6269D2A780DDE00C4A303 /* MSALNativeAuthPublicClientApplication+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F6269C2A780DDE00C4A303 /* MSALNativeAuthPublicClientApplication+Internal.swift */; }; + E2F6269E2A780DDE00C4A303 /* MSALNativeAuthPublicClientApplication+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F6269C2A780DDE00C4A303 /* MSALNativeAuthPublicClientApplication+Internal.swift */; }; + E2F626A72A780F3D00C4A303 /* SignUpStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626A62A780F3D00C4A303 /* SignUpStates+Internal.swift */; }; + E2F626A82A780F3D00C4A303 /* SignUpStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626A62A780F3D00C4A303 /* SignUpStates+Internal.swift */; }; + E2F626AA2A780F8200C4A303 /* SignInStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626A92A780F8200C4A303 /* SignInStates+Internal.swift */; }; + E2F626AB2A780F8200C4A303 /* SignInStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626A92A780F8200C4A303 /* SignInStates+Internal.swift */; }; + E2F626AD2A78119900C4A303 /* ResetPasswordStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AC2A78119900C4A303 /* ResetPasswordStates+Internal.swift */; }; + E2F626AE2A78119900C4A303 /* ResetPasswordStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AC2A78119900C4A303 /* ResetPasswordStates+Internal.swift */; }; + E2F626B02A78130700C4A303 /* SignInAfterSignUpState+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AF2A78130700C4A303 /* SignInAfterSignUpState+Internal.swift */; }; + E2F626B12A78130700C4A303 /* SignInAfterSignUpState+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AF2A78130700C4A303 /* SignInAfterSignUpState+Internal.swift */; }; + E2F626B32A781CE300C4A303 /* SignInDelegatesSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626B22A781CE300C4A303 /* SignInDelegatesSpies.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -875,6 +1252,20 @@ remoteGlobalIDString = D626FFDF1FBD1F5700EE4487; remoteInfo = "IdentityTest Mac"; }; + 28D1D57129BF62E900CE75F4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D6DFF39A1E2579360012891A /* Project object */; + proxyType = 1; + remoteGlobalIDString = D65A6F421E3FD30A00C69FBA; + remoteInfo = "MSAL (iOS Framework)"; + }; + 28D1D57D29BF633900CE75F4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D6DFF39A1E2579360012891A /* Project object */; + proxyType = 1; + remoteGlobalIDString = D672279E1EBD111900F3422A; + remoteInfo = "unit-test-host"; + }; 58BBA13225C141CA007B3EF6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D6DFF39A1E2579360012891A /* Project object */; @@ -1215,6 +1606,62 @@ 23F32F051FF4787600B2905E /* MSIDTestURLResponse+MSAL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MSIDTestURLResponse+MSAL.h"; sourceTree = ""; }; 23F32F061FF4787600B2905E /* MSIDTestURLResponse+MSAL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MSIDTestURLResponse+MSAL.m"; sourceTree = ""; }; 23FB5C1C22542B99002BF1EB /* MSALJsonDeserializable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALJsonDeserializable.h; sourceTree = ""; }; + 2814B4D92A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInWithPasswordParameters.swift; sourceTree = ""; }; + 282693272A0974740037B93A /* MSALNativeAuthTokenRequestParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenRequestParameters.swift; sourceTree = ""; }; + 2826933A2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInWithCodeParameters.swift; sourceTree = ""; }; + 285F36072A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInControlling.swift; sourceTree = ""; }; + 2877081E2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInChallengeValidatedResponse.swift; sourceTree = ""; }; + 287708212A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthInternalChannelType.swift; sourceTree = ""; }; + 287708242A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInInitiateValidatedResponse.swift; sourceTree = ""; }; + 287F64D2297EC29400ED90BD /* MSALNativeAuthTelemetryProviderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTelemetryProviderTests.swift; sourceTree = ""; }; + 287F64D3297EC29400ED90BD /* MSALNativeAuthCurrentRequestTelemetryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCurrentRequestTelemetryTests.swift; sourceTree = ""; }; + 287F64D82981781A00ED90BD /* MSALNativeAuthSignInParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInParameters.swift; sourceTree = ""; }; + 287F64E52981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInOTPParameters.swift; sourceTree = ""; }; + 287F64E82981786A00ED90BD /* MSALNativeAuthVerifyCodeParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthVerifyCodeParameters.swift; sourceTree = ""; }; + 287F64EF298186EA00ED90BD /* MSALNativeAuthInputValidatorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthInputValidatorTest.swift; sourceTree = ""; }; + 287F64F22981A00400ED90BD /* MSALNativeAuthPublicClientApplicationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthPublicClientApplicationTest.swift; sourceTree = ""; }; + 287F650B2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResponseSerializer.swift; sourceTree = ""; }; + 287F65172983F77D00ED90BD /* MSALNativeAuthRequestParametersKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequestParametersKey.swift; sourceTree = ""; }; + 287F6523298401AE00ED90BD /* MSALNativeAuthResponseSerializerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResponseSerializerTests.swift; sourceTree = ""; }; + 2884855B295DAFD400516492 /* MSALNativeAuthTokens.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokens.swift; sourceTree = ""; }; + 289747A92979487900838C80 /* MSALNativeAuthUrlRequestSerializerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthUrlRequestSerializerTests.swift; sourceTree = ""; }; + 289747AF29799A8700838C80 /* MSALNativeAuthInputValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthInputValidator.swift; sourceTree = ""; }; + 289747B32979A3C800838C80 /* MSALNativeAuthParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthParameters.swift; sourceTree = ""; }; + 289E15582948E601006104D9 /* MSALNativeAuthCacheInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCacheInterface.swift; sourceTree = ""; }; + 289E156C2948EB8A006104D9 /* MSALNativeAuthCacheAccessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCacheAccessor.swift; sourceTree = ""; }; + 28A472EB2A276C3B003F988B /* MSALNativeAuthTokenValidatedResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenValidatedResponse.swift; sourceTree = ""; }; + 28B6494A2A0959DC00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInResponseValidatorTest.swift; sourceTree = ""; }; + 28CA6F5429689F26004DB11D /* MSALNativeAuthCacheAccessorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCacheAccessorTest.swift; sourceTree = ""; }; + 28D1D56C29BF62E900CE75F4 /* MSAL iOS Native Auth Integration Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "MSAL iOS Native Auth Integration Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 28D1D57F29BF883D00CE75F4 /* MSALNativeAuthIntegrationBaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthIntegrationBaseTests.swift; sourceTree = ""; }; + 28D1D59129C2231C00CE75F4 /* MockAPIHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAPIHandler.swift; sourceTree = ""; }; + 28D1D59B29C2266500CE75F4 /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = ""; }; + 28D1D59D29C2392000CE75F4 /* MockAPIHandlerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAPIHandlerTest.swift; sourceTree = ""; }; + 28D5B05C2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthControllerFactory.swift; sourceTree = ""; }; + 28DCD09129D7166F00C4601E /* SignUpDelegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpDelegates.swift; sourceTree = ""; }; + 28DCD09929D7192F00C4601E /* MSALNativeAuthError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthError.swift; sourceTree = ""; }; + 28DCD09B29D71E7E00C4601E /* SignUpPasswordStartError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpPasswordStartError.swift; sourceTree = ""; }; + 28DCD09F29D7260B00C4601E /* MSALNativeAuthBaseState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthBaseState.swift; sourceTree = ""; }; + 28DCD0A129D7272300C4601E /* SignInDelegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInDelegates.swift; sourceTree = ""; }; + 28DCD0A329D72C7100C4601E /* SignUpStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpStates.swift; sourceTree = ""; }; + 28DCD0A529D72F6600C4601E /* PasswordRequiredError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordRequiredError.swift; sourceTree = ""; }; + 28DCD0A729D72F9A00C4601E /* AttributesRequiredError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributesRequiredError.swift; sourceTree = ""; }; + 28DCD0A929D7344000C4601E /* SignInStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInStates.swift; sourceTree = ""; }; + 28DCD0AB29D736BC00C4601E /* SignInPasswordStartError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInPasswordStartError.swift; sourceTree = ""; }; + 28DCD0AD29D737E600C4601E /* VerifyCodeError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifyCodeError.swift; sourceTree = ""; }; + 28DCD0AF29D738DD00C4601E /* ResetPasswordStartError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordStartError.swift; sourceTree = ""; }; + 28DCD0B129D7392400C4601E /* ResetPasswordStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordStates.swift; sourceTree = ""; }; + 28DCD0B329D73BCE00C4601E /* ResetPasswordDelegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordDelegates.swift; sourceTree = ""; }; + 28DE3FCF2A0921E2003148A4 /* SignInTestsValidatorHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInTestsValidatorHelpers.swift; sourceTree = ""; }; + 28DE70D529FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInResponseValidator.swift; sourceTree = ""; }; + 28E4D9022A30ABA200280921 /* ResendCodeError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResendCodeError.swift; sourceTree = ""; }; + 28EDF93D29E6D43900A99F2A /* SignUpStartError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpStartError.swift; sourceTree = ""; }; + 28EDF94029E6D52E00A99F2A /* SignInStartError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInStartError.swift; sourceTree = ""; }; + 28F19BEA2A2F884D00575581 /* Array+joinScopes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+joinScopes.swift"; sourceTree = ""; }; + 28FDC49B2A38BFA900E38BE1 /* SignInAfterSignUpState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAfterSignUpState.swift; sourceTree = ""; }; + 28FDC4A52A38C00900E38BE1 /* SignInAfterSignUpDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAfterSignUpDelegate.swift; sourceTree = ""; }; + 28FDC4A82A38C0D000E38BE1 /* SignInAfterSignUpError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAfterSignUpError.swift; sourceTree = ""; }; + 28FDC4AB2A38D7D200E38BE1 /* MSALNativeAuthSignInControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInControllerMock.swift; sourceTree = ""; }; 583BFD1524DDF9B10035B901 /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; 58B81F6524AC59A000E8799E /* MSALTestCacheTokenResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALTestCacheTokenResponse.h; sourceTree = ""; }; 58B81F6E24AC59C600E8799E /* MSALTestCacheTokenResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALTestCacheTokenResponse.m; sourceTree = ""; }; @@ -1225,9 +1672,12 @@ 60DEF15A1E67756800966664 /* MSAL Test App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = "MSAL Test App.entitlements"; path = "../../../../MSAL Test App.entitlements"; sourceTree = ""; }; 886F515729CCA50300F09471 /* MSALCIAMAuthority.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALCIAMAuthority.h; sourceTree = ""; }; 886F516329CCA58900F09471 /* MSALCIAMAuthority.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALCIAMAuthority.m; sourceTree = ""; }; - 8878C61129DC9AFB002F5F4B /* MSALCIAMOauth2Provider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALCIAMOauth2Provider.m; sourceTree = ""; }; - 8878C61629DC9B1A002F5F4B /* MSALCIAMOauth2Provider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALCIAMOauth2Provider.h; sourceTree = ""; }; 88A25ED229E7185B00066311 /* MSALCIAMAuthorityTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALCIAMAuthorityTests.m; sourceTree = ""; }; + 8D2733132AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCustomErrorSerializer.swift; sourceTree = ""; }; + 8D35C8E62A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthErrorBasicAttributes.swift; sourceTree = ""; }; + 8D35C8F02A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequiredAttributeOptions.swift; sourceTree = ""; }; + 8D61F9A02A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequestableTests.swift; sourceTree = ""; }; + 8DDF473E2A98FE1C00126A47 /* MSALNativeAuthRequiredAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequiredAttributes.swift; sourceTree = ""; }; 94E876B01E4556B400FB96ED /* MSAL.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSAL.pch; sourceTree = ""; }; 94E876CA1E492D6000FB96ED /* MSALAuthority.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSALAuthority.h; sourceTree = ""; }; 94E876CB1E492D6000FB96ED /* MSALAuthority.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALAuthority.m; sourceTree = ""; }; @@ -1278,6 +1728,31 @@ 96CFA0091E6E3454003BFCDC /* MSALTestAppScopesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALTestAppScopesViewController.m; sourceTree = ""; }; 96D9A5431E4AB1DC00674A85 /* MSALTelemetry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSALTelemetry.h; sourceTree = ""; }; 96D9A5471E4AB22900674A85 /* MSALTelemetry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALTelemetry.m; sourceTree = ""; }; + 9B235D952A3CC71C00657331 /* NativeAuthEndToEndTestPlan.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = NativeAuthEndToEndTestPlan.xctestplan; sourceTree = ""; }; + 9B235D9E2A3CFB4300657331 /* MSALNativeAuthEndToEndBaseTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthEndToEndBaseTestCase.swift; sourceTree = ""; }; + 9B235DA02A3CFC4500657331 /* MSALNativeAuthSignInUsernameEndToEndTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInUsernameEndToEndTests.swift; sourceTree = ""; }; + 9B2BBA2D2A3292400075F702 /* MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift; sourceTree = ""; }; + 9B2BBA302A3296010075F702 /* MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift; sourceTree = ""; }; + 9B2BBA322A3297EA0075F702 /* MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift; sourceTree = ""; }; + 9B2BBA342A3297F80075F702 /* MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift; sourceTree = ""; }; + 9B2BBA362A3298080075F702 /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift; sourceTree = ""; }; + 9B2E93442A0D3801008A5DD2 /* MSALNativeAuthResetPasswordControlling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordControlling.swift; sourceTree = ""; }; + 9B4EE9CD2A1686A900F243C1 /* MSALNativeAuthResetPasswordControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordControllerTests.swift; sourceTree = ""; }; + 9B4EE9D62A16874F00F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordResponseValidator.swift; sourceTree = ""; }; + 9B5D6D052A3CA0E300521576 /* MSALNativeAuthSignInUsernameAndPasswordEndToEndTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInUsernameAndPasswordEndToEndTests.swift; sourceTree = ""; }; + 9B5D6D072A3CA55600521576 /* SignInDelegateSpies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInDelegateSpies.swift; sourceTree = ""; }; + 9B61C9122A27E51900CE9E3A /* MSALNativeAuthResetPasswordRequestProviderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordRequestProviderMock.swift; sourceTree = ""; }; + 9B61C91B2A27E57C00CE9E3A /* MSALNativeAuthResetPasswordResponseValidatorMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordResponseValidatorMock.swift; sourceTree = ""; }; + 9B6EECEE2A3146ED008ABA50 /* MSALNativeAuthResetPasswordResponseValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordResponseValidatorTests.swift; sourceTree = ""; }; + 9B839A0F2A4D7CF600BCC6F6 /* MSAL.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = MSAL.docc; sourceTree = ""; }; + 9BB518032A2A2B5B00D6276A /* MSALNativeAuthResetPasswordControllerSpy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordControllerSpy.swift; sourceTree = ""; }; + 9BD2763C2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordController.swift; sourceTree = ""; }; + 9BD276562A0E7DEC00FBD033 /* ResetPasswordCodeSentStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordCodeSentStateTests.swift; sourceTree = ""; }; + 9BD276582A0E7E6700FBD033 /* ResetPasswordTestValidatorHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordTestValidatorHelpers.swift; sourceTree = ""; }; + 9BD2765E2A0E81CE00FBD033 /* ResetPasswordRequiredStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordRequiredStateTests.swift; sourceTree = ""; }; + 9BD78D7A2A126A1500AA7E12 /* MSALNativeAuthChallengeTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALNativeAuthChallengeTypes.h; sourceTree = ""; }; + 9BE7E3CA2A1CB70700CC3A62 /* MSALNativeAuthResetPasswordStartRequestProviderParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordStartRequestProviderParameters.swift; sourceTree = ""; }; + 9BE7E3D42A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordValidatedResponses.swift; sourceTree = ""; }; 9D292B0F28F05696007FE93C /* MSALWPJMetaData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALWPJMetaData.m; sourceTree = ""; }; 9DA6473528EC2FF10014F44F /* MSALWPJMetaData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALWPJMetaData.h; sourceTree = ""; }; A0274CBD24B432B100BD198D /* MSALAuthSchemeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALAuthSchemeTests.m; sourceTree = ""; }; @@ -1531,7 +2006,193 @@ D6A206371FC510B500755A51 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; D6A2063B1FC510FB00755A51 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; D6B58A531EB2C4A8000B3A5F /* MSALAcquireTokenTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALAcquireTokenTests.m; sourceTree = ""; }; + DE0347A72A41AD08003CB3B6 /* MSALNativeAuthUserAccountResultStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthUserAccountResultStub.swift; sourceTree = ""; }; + DE0D656729BF72F6005798B1 /* MSALNativeAuthSignInInitiateRequestParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInInitiateRequestParameters.swift; sourceTree = ""; }; + DE0D657429BF73CB005798B1 /* MSALNativeAuthSignInChallengeRequestParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInChallengeRequestParameters.swift; sourceTree = ""; }; + DE0D658C29C1DCA6005798B1 /* MSALNativeAuthSignInChallengeRequestParametersTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInChallengeRequestParametersTest.swift; sourceTree = ""; }; + DE0D658D29C1DCA6005798B1 /* MSALNativeAuthTokenRequestParametersTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenRequestParametersTest.swift; sourceTree = ""; }; + DE0D658E29C1DCA6005798B1 /* MSALNativeAuthSignInInitiateRequestParametersTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInInitiateRequestParametersTest.swift; sourceTree = ""; }; + DE0D65AB29CC6A59005798B1 /* MSALNativeAuthSignInInitiateResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInInitiateResponse.swift; sourceTree = ""; }; + DE0D65B529CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInChallengeResponse.swift; sourceTree = ""; }; + DE0D65B829D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResponseErrorHandler.swift; sourceTree = ""; }; + DE0D65BE29D30BAE005798B1 /* MSALNativeAuthResponseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResponseError.swift; sourceTree = ""; }; + DE0D65C129D30C38005798B1 /* MSALNativeAuthSignInInitiateOauth2ErrorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInInitiateOauth2ErrorCode.swift; sourceTree = ""; }; + DE0D65C529D344F1005798B1 /* MSALNativeAuthSignInInitiateIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInInitiateIntegrationTests.swift; sourceTree = ""; }; + DE0D65CA29D5CD6D005798B1 /* MSALNativeAuthSignInChallengeIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInChallengeIntegrationTests.swift; sourceTree = ""; }; + DE0FECAA2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResendCodeRequestResponse.swift; sourceTree = ""; }; + DE0FECC62993ADAE00B139A8 /* MSALNativeAuthResendCodeParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResendCodeParameters.swift; sourceTree = ""; }; + DE14096A2A38DE0E008E6F1E /* CredentialsDelegateSpies.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CredentialsDelegateSpies.swift; sourceTree = ""; }; + DE14096C2A38DF40008E6F1E /* MSALNativeAuthCredentialsControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCredentialsControllerTests.swift; sourceTree = ""; }; + DE14D76029898CF900F37BEF /* MSALNativeAuthTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTestCase.swift; sourceTree = ""; }; + DE1D8AA729E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequestConfigurator.swift; sourceTree = ""; }; + DE40A4C92A8F801200928CEE /* MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift; sourceTree = ""; }; + DE40A4D22A8F80C100928CEE /* MSALNativeAuthSignUpContinueResponseErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpContinueResponseErrorTests.swift; sourceTree = ""; }; + DE4F0F2929D6F1AA00D561FD /* MSALNativeAuthTokenIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenIntegrationTests.swift; sourceTree = ""; }; + DE53C7D4293F9F5A00E5B2BB /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; + DE54B5902A434B9B00460B34 /* MSALNativeAuthTokenController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenController.swift; sourceTree = ""; }; + DE54B5932A43587800460B34 /* MSALNativeAuthTokenRequestProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenRequestProvider.swift; sourceTree = ""; }; + DE54B59C2A44521E00460B34 /* MSALNativeAuthTokenResponseValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenResponseValidatorTests.swift; sourceTree = ""; }; + DE54B5AC2A459B0400460B34 /* MSALNativeAuthTokenResponseValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenResponseValidator.swift; sourceTree = ""; }; + DE5738AA2A8E71D500D9120D /* MSALNativeAuthResetPasswordContinueResponseErrorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordContinueResponseErrorTests.swift; sourceTree = ""; }; + DE5738B32A8E74DC00D9120D /* MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift; sourceTree = ""; }; + DE5738B52A8E790100D9120D /* MSALNativeAuthTokenValidatedErrorTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenValidatedErrorTypeTests.swift; sourceTree = ""; }; + DE5738B72A8F76C600D9120D /* MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift; sourceTree = ""; }; + DE5738B92A8F780E00D9120D /* MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift; sourceTree = ""; }; + DE5738BB2A8F79A800D9120D /* MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift; sourceTree = ""; }; + DE5738BD2A8F7AC600D9120D /* MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift; sourceTree = ""; }; + DE5738BF2A8F7C1F00D9120D /* MSALNativeAuthSignUpStartResponseErrorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpStartResponseErrorTests.swift; sourceTree = ""; }; + DE729ECC2A1793A100A761D9 /* MSALNativeAuthChannelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthChannelType.swift; sourceTree = ""; }; + DE87DE692A39E80B0032BF9E /* MSALNativeAuthUserAccountResultTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthUserAccountResultTests.swift; sourceTree = ""; }; + DE8BE7DB2A1F6BD2009642A5 /* MSALNativeAuthUserAccountResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthUserAccountResult.swift; sourceTree = ""; }; + DE8EC86C2A026BA0003FA561 /* MSALNativeAuthSignInRequestProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInRequestProvider.swift; sourceTree = ""; }; + DE8EC8772A026C2E003FA561 /* MSALNativeAuthResetPasswordChallengeIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordChallengeIntegrationTests.swift; sourceTree = ""; }; + DE8EC8782A026C2E003FA561 /* MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift; sourceTree = ""; }; + DE8EC8792A026C2E003FA561 /* MSALNativeAuthResetPasswordStartIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordStartIntegrationTests.swift; sourceTree = ""; }; + DE8EC87A2A026C2E003FA561 /* MSALNativeAuthResetPasswordContinueIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordContinueIntegrationTests.swift; sourceTree = ""; }; + DE8EC87B2A026C2E003FA561 /* MSALNativeAuthResetPasswordSubmitIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordSubmitIntegrationTests.swift; sourceTree = ""; }; + DE8EC8B52A053D80003FA561 /* MSALNativeAuthESTSApiErrorCodes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthESTSApiErrorCodes.swift; sourceTree = ""; }; + DE9244D62A31E1D500C0389F /* MSALCIAMOauth2Provider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSALCIAMOauth2Provider.h; sourceTree = ""; }; + DE9244D72A31E1D500C0389F /* MSALCIAMOauth2Provider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALCIAMOauth2Provider.m; sourceTree = ""; }; + DE92450B2A385ED800C0389F /* MSALNativeAuthCredentialsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCredentialsController.swift; sourceTree = ""; }; + DE92450D2A38601100C0389F /* MSALNativeAuthCredentialsControlling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCredentialsControlling.swift; sourceTree = ""; }; + DE9245112A38736600C0389F /* CredentialsDelegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialsDelegates.swift; sourceTree = ""; }; + DE9245142A3875D700C0389F /* RetrieveAccessTokenError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RetrieveAccessTokenError.swift; sourceTree = ""; }; + DE94C9DE29F1989600C1EC1F /* MSALNativeAuthResetPasswordStartRequestParametersTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordStartRequestParametersTest.swift; sourceTree = ""; }; + DE94C9E129F19AA200C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift; sourceTree = ""; }; + DE94C9E329F19C4C00C1EC1F /* MSALNativeAuthResetPasswordContinueRequestParametersTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordContinueRequestParametersTest.swift; sourceTree = ""; }; + DE94C9E529F19D9A00C1EC1F /* MSALNativeAuthResetPasswordSubmitRequestParametersTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordSubmitRequestParametersTest.swift; sourceTree = ""; }; + DE94C9E729F19E6B00C1EC1F /* MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift; sourceTree = ""; }; + DE94C9EE29F2AF3200C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordChallengeRequestParameters.swift; sourceTree = ""; }; + DECC1F9229521E34006D9FB1 /* MSALLogMask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALLogMask.m; sourceTree = ""; }; + DECC1F9329521E34006D9FB1 /* MSALLogMask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSALLogMask.h; sourceTree = ""; }; + DECC1FB229531032006D9FB1 /* MSALLogMaskTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALLogMaskTests.m; sourceTree = ""; }; + DECC1FB4295322A8006D9FB1 /* MSALNativeLoggingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeLoggingTests.swift; sourceTree = ""; }; + DEDB298A29D72D62008DA85B /* MSALNativeAuthInnerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthInnerError.swift; sourceTree = ""; }; + DEDB29A429DDA9DC008DA85B /* MSALNativeAuthSignInInitiateResponseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInInitiateResponseError.swift; sourceTree = ""; }; + DEDB29A629DDAEB3008DA85B /* MSALNativeAuthSignInChallengeOauth2ErrorCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInChallengeOauth2ErrorCode.swift; sourceTree = ""; }; + DEDB29A729DDAEB3008DA85B /* MSALNativeAuthTokenOauth2ErrorCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenOauth2ErrorCode.swift; sourceTree = ""; }; + DEDB29AA29DDAF52008DA85B /* MSALNativeAuthSignInChallengeResponseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInChallengeResponseError.swift; sourceTree = ""; }; + DEDB29AB29DDAF53008DA85B /* MSALNativeAuthTokenResponseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenResponseError.swift; sourceTree = ""; }; + DEDB29B029DEC770008DA85B /* MSALNativeAuthRequestErrorHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequestErrorHandlerTests.swift; sourceTree = ""; }; + DEDD6F0729E83FD20017989F /* MSALNativeAuthRequestConfiguratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequestConfiguratorTests.swift; sourceTree = ""; }; + DEE34F11D170B71C00BC302A /* MSALNativeAuthResetPasswordStartRequestParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordStartRequestParameters.swift; sourceTree = ""; }; + DEE34F43D170B71C00BC302A /* MSALNativeAuthResultFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResultFactory.swift; sourceTree = ""; }; + DEE34F5BD170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordStartResponse.swift; sourceTree = ""; }; + DEE34F5ED170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordStartResponseError.swift; sourceTree = ""; }; + DEE34F5FD170B71C00BC302A /* MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift; sourceTree = ""; }; + DEE34F64D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordChallengeResponse.swift; sourceTree = ""; }; + DEE34F69D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeResponseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordChallengeResponseError.swift; sourceTree = ""; }; + DEE34F71D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift; sourceTree = ""; }; + DEE34F74D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueRequestParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordContinueRequestParameters.swift; sourceTree = ""; }; + DEE34F76D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordContinueResponse.swift; sourceTree = ""; }; + DEE34F78D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueResponseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordContinueResponseError.swift; sourceTree = ""; }; + DEE34F79D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift; sourceTree = ""; }; + DEE34F7CD170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitRequestParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordSubmitRequestParameters.swift; sourceTree = ""; }; + DEE34F7ED170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordSubmitResponse.swift; sourceTree = ""; }; + DEE34F80D170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift; sourceTree = ""; }; + DEE34F81D170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitResponseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordSubmitResponseError.swift; sourceTree = ""; }; + DEE34F84D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift; sourceTree = ""; }; + DEE34F86D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordPollCompletionResponse.swift; sourceTree = ""; }; + DEE34F88D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordPollCompletionStatus.swift; sourceTree = ""; }; + DEE34F8AD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift; sourceTree = ""; }; + DEE34F8BD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordPollCompletionResponseError.swift; sourceTree = ""; }; + DEE34F95D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequiredAttributesInternal.swift; sourceTree = ""; }; + DEE34FA0D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordRequestProvider.swift; sourceTree = ""; }; + DEF1DD312AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthESTSApiErrorDescriptions.swift; sourceTree = ""; }; + DEF1DD3B2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthESTSApiErrorDescriptionsTests.swift; sourceTree = ""; }; + DEF9D988296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCurrentRequestTelemetry.swift; sourceTree = ""; }; + DEF9D995296EC35A006CB384 /* MSALNativeAuthTelemetryApiId.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTelemetryApiId.swift; sourceTree = ""; }; + DEF9D998296EC848006CB384 /* MSALNativeAuthOperationTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthOperationTypes.swift; sourceTree = ""; }; + DEF9D99E296F08CE006CB384 /* MSALNativeAuthTelemetryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTelemetryProvider.swift; sourceTree = ""; }; + DEFB46EC2A52BA3700DBC006 /* MSALNativeAuthSignOutEndToEndTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignOutEndToEndTests.swift; sourceTree = ""; }; + DEFB46F12A52C11400DBC006 /* MSALNativeAuthResetPasswordEndToEndTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordEndToEndTests.swift; sourceTree = ""; }; + DEFB46F32A52C28100DBC006 /* ResetPasswordDelegateSpies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordDelegateSpies.swift; sourceTree = ""; }; E02396F31E79E2F4004D6278 /* MSALTelemetryApiId.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALTelemetryApiId.h; sourceTree = ""; }; + E205D62D29B783FF003887BC /* MSALNativeAuthConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthConfiguration.swift; sourceTree = ""; }; + E206FC5E296D65DE00AF4400 /* MSALNativeAuthInternalError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthInternalError.swift; sourceTree = ""; }; + E206FCEE2979BC4600AF4400 /* MSALNativeAuthSignInController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInController.swift; sourceTree = ""; }; + E20C21742A7A61B600E31598 /* SignUpDelegateSpies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpDelegateSpies.swift; sourceTree = ""; }; + E20C217D2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordDelegateSpies.swift; sourceTree = ""; }; + E20C21832A7A6CA400E31598 /* SignInCodeRequiredStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInCodeRequiredStateTests.swift; sourceTree = ""; }; + E20C218A2A7A805800E31598 /* SignInPasswordRequiredStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInPasswordRequiredStateTests.swift; sourceTree = ""; }; + E22952672A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpResponseValidatorTests.swift; sourceTree = ""; }; + E22E20272A7936C50073A6FF /* MSALNativeAuthSignUpControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpControllerMock.swift; sourceTree = ""; }; + E235610D29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpRequestProvider.swift; sourceTree = ""; }; + E235613029C9CEA8000E01CA /* MSALNativeAuthSignUpStartRequestParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpStartRequestParameters.swift; sourceTree = ""; }; + E235613329C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthInternalChallengeType.swift; sourceTree = ""; }; + E23E955E29D4B9F7001DC59C /* MSALNativeAuthSignUpChallengeIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpChallengeIntegrationTests.swift; sourceTree = ""; }; + E23E956829D5BD6B001DC59C /* MSALNativeAuthSignUpRequestProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpRequestProviderTests.swift; sourceTree = ""; }; + E243F69329D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpStartResponse.swift; sourceTree = ""; }; + E243F69929D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpChallengeRequestParameters.swift; sourceTree = ""; }; + E243F69C29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpChallengeResponse.swift; sourceTree = ""; }; + E243F69F29D1FF9E00DAC60F /* MSALNativeAuthSignUpContinueRequestParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpContinueRequestParameters.swift; sourceTree = ""; }; + E243F6A529D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpContinueResponse.swift; sourceTree = ""; }; + E243F6A929D42FE900DAC60F /* MSALNativeAuthSignUpContinueRequestProviderParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpContinueRequestProviderParams.swift; sourceTree = ""; }; + E243F6AD29D4427E00DAC60F /* MSALNativeAuthSignUpStartIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpStartIntegrationTests.swift; sourceTree = ""; }; + E25BC0792995423100588549 /* MSALNativeAuthNetworkMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthNetworkMocks.swift; sourceTree = ""; }; + E25BC0822995429D00588549 /* MSALNativeAuthCacheMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCacheMocks.swift; sourceTree = ""; }; + E25BC0842995430B00588549 /* MSALNativeAuthFactoriesMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthFactoriesMocks.swift; sourceTree = ""; }; + E25BC098299555C000588549 /* MSALNativeAuthTelemetryTestDispatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTelemetryTestDispatcher.swift; sourceTree = ""; }; + E25E6E502AA7725F0094461E /* MSALNativeAuthResetPasswordControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordControllerMock.swift; sourceTree = ""; }; + E25E6E592AA7727D0094461E /* MSALNativeAuthCredentialsControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCredentialsControllerMock.swift; sourceTree = ""; }; + E26097C22948FC4D0060DD7C /* MSALNativeAuthLogging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthLogging.swift; sourceTree = ""; }; + E26097C62948FC720060DD7C /* MSALNativeAuthServerTelemetry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthServerTelemetry.swift; sourceTree = ""; }; + E26E391A2A4C2BE200063C07 /* MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift; sourceTree = ""; }; + E26E39232A4C2D7400063C07 /* SignUpDelegateSpies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpDelegateSpies.swift; sourceTree = ""; }; + E272C4EA2A4447520013B805 /* MSALNativeAuthSignUpUsernameEndToEndTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpUsernameEndToEndTests.swift; sourceTree = ""; }; + E27332BF2A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthErrorMessage.swift; sourceTree = ""; }; + E284F5D829F28B4200DBED7D /* MSALNativeAuthSignUpController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpController.swift; sourceTree = ""; }; + E284F5E329F2F28A00DBED7D /* MSALNativeAuthSignUpControlling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpControlling.swift; sourceTree = ""; }; + E286E2DC2A1BAEA800666DD0 /* MSALNativeAuthSignUpControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpControllerTests.swift; sourceTree = ""; }; + E2960A102A1F4D2F000F441B /* MSALNativeAuthSignUpChallengeResponseErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpChallengeResponseErrorTests.swift; sourceTree = ""; }; + E2ACA47A29520C2200E98964 /* MSALNativeAuthEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthEndpoint.swift; sourceTree = ""; }; + E2ACA48A2952302B00E98964 /* MSALNativeAuthRequestContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequestContext.swift; sourceTree = ""; }; + E2ACA4942953415E00E98964 /* MSALNativeAuthGrantType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthGrantType.swift; sourceTree = ""; }; + E2ACA49B2953576C00E98964 /* MSALNativeAuthUrlRequestSerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthUrlRequestSerializer.swift; sourceTree = ""; }; + E2B8532A2A1531DA007A4776 /* MSALNativeAuthSignUpValidatedResponses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpValidatedResponses.swift; sourceTree = ""; }; + E2B8532E2A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpStartRequestProviderParameters.swift; sourceTree = ""; }; + E2BC027429D6E0C600041DBC /* MSALNativeAuthSignUpContinueIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpContinueIntegrationTests.swift; sourceTree = ""; }; + E2BC029729D766A800041DBC /* MSALNativeAuthSignUpChallengeRequestParametersTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpChallengeRequestParametersTest.swift; sourceTree = ""; }; + E2BC029929D766B200041DBC /* MSALNativeAuthSignUpStartRequestParametersTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpStartRequestParametersTest.swift; sourceTree = ""; }; + E2BC029B29D766CB00041DBC /* MSALNativeAuthSignUpContinueRequestParametersTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpContinueRequestParametersTest.swift; sourceTree = ""; }; + E2BDD98A2A28FBDD00E3ED6B /* MSALNativeAuthErrorRequiredAttributesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthErrorRequiredAttributesTests.swift; sourceTree = ""; }; + E2C1D286299BA15D00B26449 /* MSALNativeAuthBaseController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthBaseController.swift; sourceTree = ""; }; + E2C1D2D329A3992100B26449 /* MSALNativeAuthBaseControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthBaseControllerTests.swift; sourceTree = ""; }; + E2C61FE029DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpStartOauth2ErrorCode.swift; sourceTree = ""; }; + E2C61FE329DED15800F15203 /* MSALNativeAuthSignUpStartResponseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpStartResponseError.swift; sourceTree = ""; }; + E2C61FE629DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpChallengeResponseError.swift; sourceTree = ""; }; + E2C61FE929DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift; sourceTree = ""; }; + E2C61FEC29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpContinueOauth2ErrorCode.swift; sourceTree = ""; }; + E2C61FEF29DEDB0200F15203 /* MSALNativeAuthSignUpContinueResponseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpContinueResponseError.swift; sourceTree = ""; }; + E2C872C2294CDEE800C4F580 /* MSALNativeAuthRequestable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequestable.swift; sourceTree = ""; }; + E2CD2E4929FBEA36009F8FFA /* SignUpCodeSentStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpCodeSentStateTests.swift; sourceTree = ""; }; + E2CD2E4E29FC0451009F8FFA /* SignUpPasswordRequiredStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpPasswordRequiredStateTests.swift; sourceTree = ""; }; + E2CD2E5029FC087A009F8FFA /* SignUpAttributesRequiredStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpAttributesRequiredStateTests.swift; sourceTree = ""; }; + E2CD2E8C2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpResponseValidator.swift; sourceTree = ""; }; + E2CD2EB22A040012009F8FFA /* SignUpTestsValidatorHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpTestsValidatorHelpers.swift; sourceTree = ""; }; + E2CD2EB42A0404DA009F8FFA /* MSALNativeAuthSignUpControllerSpy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpControllerSpy.swift; sourceTree = ""; }; + E2D3BC4E2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MSALNativeAuthUserAccountResult+Internal.swift"; sourceTree = ""; }; + E2DC31BB29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthPublicClientApplication.swift; sourceTree = ""; }; + E2DC31C729B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthAuthorityProvider.swift; sourceTree = ""; }; + E2EBD6202A1BB4640049467A /* MSALNativeAuthSignUpRequestProviderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpRequestProviderMock.swift; sourceTree = ""; }; + E2EBD6292A1BB7700049467A /* MSALNativeAuthSignUpResponseValidatorMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpResponseValidatorMock.swift; sourceTree = ""; }; + E2EFACFD2A69915100D6C3DE /* SignInResults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInResults.swift; sourceTree = ""; }; + E2EFAD082A69A34300D6C3DE /* CodeRequiredGenericResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeRequiredGenericResult.swift; sourceTree = ""; }; + E2EFAD0B2A69B45100D6C3DE /* SignUpResults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpResults.swift; sourceTree = ""; }; + E2EFAD0E2A69BBB800D6C3DE /* ResetPasswordResults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordResults.swift; sourceTree = ""; }; + E2EFAD152A70300B00D6C3DE /* MSALNativeAuthControllerTelemetryWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthControllerTelemetryWrapper.swift; sourceTree = ""; }; + E2F4DB232A1F525A009FBCD0 /* MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift; sourceTree = ""; }; + E2F4DB2C2A1F5714009FBCD0 /* MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift; sourceTree = ""; }; + E2F5BE8D29893A4100C67EC7 /* MSALNativeAuthEndpointTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthEndpointTests.swift; sourceTree = ""; }; + E2F5BE9429894FCA00C67EC7 /* MSALNativeAuthConfigStubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthConfigStubs.swift; sourceTree = ""; }; + E2F5BE9929896ADB00C67EC7 /* MSALNativeAuthSignInControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInControllerTests.swift; sourceTree = ""; }; + E2F5BE9C298A6CEB00C67EC7 /* MSALNativeAuthResultFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResultFactoryTests.swift; sourceTree = ""; }; + E2F6269C2A780DDE00C4A303 /* MSALNativeAuthPublicClientApplication+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MSALNativeAuthPublicClientApplication+Internal.swift"; sourceTree = ""; }; + E2F626A62A780F3D00C4A303 /* SignUpStates+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SignUpStates+Internal.swift"; sourceTree = ""; }; + E2F626A92A780F8200C4A303 /* SignInStates+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SignInStates+Internal.swift"; sourceTree = ""; }; + E2F626AC2A78119900C4A303 /* ResetPasswordStates+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ResetPasswordStates+Internal.swift"; sourceTree = ""; }; + E2F626AF2A78130700C4A303 /* SignInAfterSignUpState+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SignInAfterSignUpState+Internal.swift"; sourceTree = ""; }; + E2F626B22A781CE300C4A303 /* SignInDelegatesSpies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInDelegatesSpies.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1562,6 +2223,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 28D1D56929BF62E900CE75F4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 28D1D57029BF62E900CE75F4 /* MSAL.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 962E37B51E720C5D00DE71FE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1681,20 +2350,287 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 238A362622EA390400F08167 /* Recovered References */ = { + 2811CDCF296F16DE007BA21B /* controllers */ = { + isa = PBXGroup; + children = ( + E2EFAD072A69A2C300D6C3DE /* responses */, + E284F5DB29F2F1A200DBED7D /* sign_up */, + 282693392A0B98490037B93A /* sign_in */, + 9B2E933C2A0D379D008A5DD2 /* reset_password */, + DE92450A2A385EAD00C0389F /* credentials */, + DEE34F41D170B71C00BC302A /* factories */, + E2C1D286299BA15D00B26449 /* MSALNativeAuthBaseController.swift */, + DE54B5902A434B9B00460B34 /* MSALNativeAuthTokenController.swift */, + E2EFAD152A70300B00D6C3DE /* MSALNativeAuthControllerTelemetryWrapper.swift */, + ); + path = controllers; + sourceTree = ""; + }; + 282693392A0B98490037B93A /* sign_in */ = { isa = PBXGroup; children = ( + 285F36072A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift */, + E206FCEE2979BC4600AF4400 /* MSALNativeAuthSignInController.swift */, + 2814B4D92A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift */, + 2826933A2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift */, ); - name = "Recovered References"; + path = sign_in; sourceTree = ""; }; - 8878C60929DC9AD4002F5F4B /* ciam */ = { + 287708272A178ED200E371ED /* validated_response */ = { isa = PBXGroup; children = ( - 8878C61129DC9AFB002F5F4B /* MSALCIAMOauth2Provider.m */, - 8878C61629DC9B1A002F5F4B /* MSALCIAMOauth2Provider.h */, + 2877081E2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift */, + 287708242A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift */, ); - path = ciam; + path = validated_response; + sourceTree = ""; + }; + 287F64D1297EC27200ED90BD /* telemetry */ = { + isa = PBXGroup; + children = ( + 287F64D3297EC29400ED90BD /* MSALNativeAuthCurrentRequestTelemetryTests.swift */, + 287F64D2297EC29400ED90BD /* MSALNativeAuthTelemetryProviderTests.swift */, + ); + path = telemetry; + sourceTree = ""; + }; + 287F64EE298186C800ED90BD /* input_validator */ = { + isa = PBXGroup; + children = ( + 287F64EF298186EA00ED90BD /* MSALNativeAuthInputValidatorTest.swift */, + ); + path = input_validator; + sourceTree = ""; + }; + 287F64F129819F6B00ED90BD /* public */ = { + isa = PBXGroup; + children = ( + E2CD2E3F29FBE957009F8FFA /* state_machine */, + 287F64F22981A00400ED90BD /* MSALNativeAuthPublicClientApplicationTest.swift */, + DE87DE692A39E80B0032BF9E /* MSALNativeAuthUserAccountResultTests.swift */, + ); + path = public; + sourceTree = ""; + }; + 287F64F42981A7B800ED90BD /* mock */ = { + isa = PBXGroup; + children = ( + E25BC0822995429D00588549 /* MSALNativeAuthCacheMocks.swift */, + E2F5BE9429894FCA00C67EC7 /* MSALNativeAuthConfigStubs.swift */, + DE0347A72A41AD08003CB3B6 /* MSALNativeAuthUserAccountResultStub.swift */, + E25BC0842995430B00588549 /* MSALNativeAuthFactoriesMocks.swift */, + E22E20272A7936C50073A6FF /* MSALNativeAuthSignUpControllerMock.swift */, + E25E6E592AA7727D0094461E /* MSALNativeAuthCredentialsControllerMock.swift */, + E25E6E502AA7725F0094461E /* MSALNativeAuthResetPasswordControllerMock.swift */, + E25BC0792995423100588549 /* MSALNativeAuthNetworkMocks.swift */, + E2CD2EB22A040012009F8FFA /* SignUpTestsValidatorHelpers.swift */, + E2CD2EB42A0404DA009F8FFA /* MSALNativeAuthSignUpControllerSpy.swift */, + 28DE3FCF2A0921E2003148A4 /* SignInTestsValidatorHelpers.swift */, + 9BD276582A0E7E6700FBD033 /* ResetPasswordTestValidatorHelpers.swift */, + DE14096A2A38DE0E008E6F1E /* CredentialsDelegateSpies.swift */, + E2EBD6202A1BB4640049467A /* MSALNativeAuthSignUpRequestProviderMock.swift */, + E2EBD6292A1BB7700049467A /* MSALNativeAuthSignUpResponseValidatorMock.swift */, + 28FDC4AB2A38D7D200E38BE1 /* MSALNativeAuthSignInControllerMock.swift */, + E20C217D2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift */, + E20C21742A7A61B600E31598 /* SignUpDelegateSpies.swift */, + E2F626B22A781CE300C4A303 /* SignInDelegatesSpies.swift */, + 9B61C91D2A27E5E200CE9E3A /* reset_password */, + ); + path = mock; + sourceTree = ""; + }; + 287F65142983EEAC00ED90BD /* parameters */ = { + isa = PBXGroup; + children = ( + E2BC029629D7668D00041DBC /* sign_up */, + E2C6201F29E0420200F15203 /* sign_in */, + DE94C9D629F1898A00C1EC1F /* reset_password */, + DE54B5A22A4464D400460B34 /* token */, + ); + path = parameters; + sourceTree = ""; + }; + 289747AE29799A6600838C80 /* input_validator */ = { + isa = PBXGroup; + children = ( + 289747AF29799A8700838C80 /* MSALNativeAuthInputValidator.swift */, + ); + path = input_validator; + sourceTree = ""; + }; + 289747B22979A3AD00838C80 /* parameters */ = { + isa = PBXGroup; + children = ( + 289747B32979A3C800838C80 /* MSALNativeAuthParameters.swift */, + 287F64D82981781A00ED90BD /* MSALNativeAuthSignInParameters.swift */, + 287F64E52981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift */, + DE0FECC62993ADAE00B139A8 /* MSALNativeAuthResendCodeParameters.swift */, + 287F64E82981786A00ED90BD /* MSALNativeAuthVerifyCodeParameters.swift */, + ); + path = parameters; + sourceTree = ""; + }; + 28A3147029705B4500573AFF /* network */ = { + isa = PBXGroup; + children = ( + E2960A072A1F4D13000F441B /* errors */, + 28B649412A09596300EF3DB7 /* responses */, + 287F65142983EEAC00ED90BD /* parameters */, + 289747A92979487900838C80 /* MSALNativeAuthUrlRequestSerializerTests.swift */, + 287F6523298401AE00ED90BD /* MSALNativeAuthResponseSerializerTests.swift */, + E2F5BE8D29893A4100C67EC7 /* MSALNativeAuthEndpointTests.swift */, + DEDB29B029DEC770008DA85B /* MSALNativeAuthRequestErrorHandlerTests.swift */, + E23E956829D5BD6B001DC59C /* MSALNativeAuthSignUpRequestProviderTests.swift */, + DEDD6F0729E83FD20017989F /* MSALNativeAuthRequestConfiguratorTests.swift */, + 8D61F9A02A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift */, + ); + path = network; + sourceTree = ""; + }; + 28B649412A09596300EF3DB7 /* responses */ = { + isa = PBXGroup; + children = ( + 28B649492A0959B800EF3DB7 /* validator */, + ); + path = responses; + sourceTree = ""; + }; + 28B649492A0959B800EF3DB7 /* validator */ = { + isa = PBXGroup; + children = ( + DE5738B32A8E74DC00D9120D /* MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift */, + DE5738B52A8E790100D9120D /* MSALNativeAuthTokenValidatedErrorTypeTests.swift */, + 9B2BBA2D2A3292400075F702 /* MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift */, + 28B6494A2A0959DC00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTest.swift */, + E22952672A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift */, + 9B6EECEE2A3146ED008ABA50 /* MSALNativeAuthResetPasswordResponseValidatorTests.swift */, + DE54B59C2A44521E00460B34 /* MSALNativeAuthTokenResponseValidatorTests.swift */, + ); + path = validator; + sourceTree = ""; + }; + 28CA6F5E29689F3E004DB11D /* cache */ = { + isa = PBXGroup; + children = ( + 28CA6F5429689F26004DB11D /* MSALNativeAuthCacheAccessorTest.swift */, + ); + path = cache; + sourceTree = ""; + }; + 28D1D58129BF885500CE75F4 /* integration */ = { + isa = PBXGroup; + children = ( + 28D1D58229BF886000CE75F4 /* native_auth */, + ); + path = integration; + sourceTree = ""; + }; + 28D1D58229BF886000CE75F4 /* native_auth */ = { + isa = PBXGroup; + children = ( + 9B5D6D042A3CA0C600521576 /* end_to_end */, + DE0D65C429D344AC005798B1 /* requests */, + 28D1D59A29C2265400CE75F4 /* common */, + 28D1D59D29C2392000CE75F4 /* MockAPIHandlerTest.swift */, + ); + path = native_auth; + sourceTree = ""; + }; + 28D1D59A29C2265400CE75F4 /* common */ = { + isa = PBXGroup; + children = ( + 28D1D59129C2231C00CE75F4 /* MockAPIHandler.swift */, + 28D1D57F29BF883D00CE75F4 /* MSALNativeAuthIntegrationBaseTests.swift */, + 28D1D59B29C2266500CE75F4 /* Model.swift */, + ); + path = common; + sourceTree = ""; + }; + 28DCD08829D70FA000C4601E /* state_machine */ = { + isa = PBXGroup; + children = ( + 8DDF473E2A98FE1C00126A47 /* MSALNativeAuthRequiredAttributes.swift */, + 28DCD09629D7171600C4601E /* error */, + 28DCD09529D7170F00C4601E /* state */, + 28DCD09029D7165700C4601E /* delegate */, + ); + path = state_machine; + sourceTree = ""; + }; + 28DCD09029D7165700C4601E /* delegate */ = { + isa = PBXGroup; + children = ( + 28DCD09129D7166F00C4601E /* SignUpDelegates.swift */, + 28DCD0A129D7272300C4601E /* SignInDelegates.swift */, + 28DCD0B329D73BCE00C4601E /* ResetPasswordDelegates.swift */, + DE9245112A38736600C0389F /* CredentialsDelegates.swift */, + 28FDC4A52A38C00900E38BE1 /* SignInAfterSignUpDelegate.swift */, + ); + path = delegate; + sourceTree = ""; + }; + 28DCD09529D7170F00C4601E /* state */ = { + isa = PBXGroup; + children = ( + 28DCD09F29D7260B00C4601E /* MSALNativeAuthBaseState.swift */, + 28DCD0A329D72C7100C4601E /* SignUpStates.swift */, + E2F626A62A780F3D00C4A303 /* SignUpStates+Internal.swift */, + 28DCD0A929D7344000C4601E /* SignInStates.swift */, + E2F626A92A780F8200C4A303 /* SignInStates+Internal.swift */, + 28DCD0B129D7392400C4601E /* ResetPasswordStates.swift */, + E2F626AC2A78119900C4A303 /* ResetPasswordStates+Internal.swift */, + 28FDC49B2A38BFA900E38BE1 /* SignInAfterSignUpState.swift */, + E2F626AF2A78130700C4A303 /* SignInAfterSignUpState+Internal.swift */, + ); + path = state; + sourceTree = ""; + }; + 28DCD09629D7171600C4601E /* error */ = { + isa = PBXGroup; + children = ( + 28DCD09929D7192F00C4601E /* MSALNativeAuthError.swift */, + 28DCD09B29D71E7E00C4601E /* SignUpPasswordStartError.swift */, + 28EDF93D29E6D43900A99F2A /* SignUpStartError.swift */, + 28DCD0A529D72F6600C4601E /* PasswordRequiredError.swift */, + 28DCD0A729D72F9A00C4601E /* AttributesRequiredError.swift */, + 28DCD0AB29D736BC00C4601E /* SignInPasswordStartError.swift */, + 28EDF94029E6D52E00A99F2A /* SignInStartError.swift */, + 28DCD0AD29D737E600C4601E /* VerifyCodeError.swift */, + 28DCD0AF29D738DD00C4601E /* ResetPasswordStartError.swift */, + 28E4D9022A30ABA200280921 /* ResendCodeError.swift */, + DE9245142A3875D700C0389F /* RetrieveAccessTokenError.swift */, + 28FDC4A82A38C0D000E38BE1 /* SignInAfterSignUpError.swift */, + ); + path = error; + sourceTree = ""; + }; + 28DE70CD29FAC14500EB75AA /* validator */ = { + isa = PBXGroup; + children = ( + 28F19BE12A2F4A0100575581 /* sign_in */, + E2B8532D2A153287007A4776 /* sign_up */, + 9B6EECE62A31467E008ABA50 /* reset_password */, + DE54B5972A44431C00460B34 /* token */, + ); + path = validator; + sourceTree = ""; + }; + 28F19BE12A2F4A0100575581 /* sign_in */ = { + isa = PBXGroup; + children = ( + 287708272A178ED200E371ED /* validated_response */, + 28DE70D529FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift */, + ); + path = sign_in; + sourceTree = ""; + }; + 28F19BE92A2F881D00575581 /* extension */ = { + isa = PBXGroup; + children = ( + 28F19BEA2A2F884D00575581 /* Array+joinScopes.swift */, + ); + path = extension; sourceTree = ""; }; 94E876C91E492D2800FB96ED /* instance */ = { @@ -1821,6 +2757,81 @@ path = telemetry; sourceTree = ""; }; + 9B235DA22A3D15E400657331 /* sign_in */ = { + isa = PBXGroup; + children = ( + 9B5D6D052A3CA0E300521576 /* MSALNativeAuthSignInUsernameAndPasswordEndToEndTests.swift */, + 9B235DA02A3CFC4500657331 /* MSALNativeAuthSignInUsernameEndToEndTests.swift */, + 9B5D6D072A3CA55600521576 /* SignInDelegateSpies.swift */, + ); + path = sign_in; + sourceTree = ""; + }; + 9B2BBA252A3291DD0075F702 /* reset_password */ = { + isa = PBXGroup; + children = ( + DE5738BD2A8F7AC600D9120D /* MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift */, + DE5738B72A8F76C600D9120D /* MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift */, + 9B2BBA302A3296010075F702 /* MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift */, + 9B2BBA322A3297EA0075F702 /* MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift */, + DE5738AA2A8E71D500D9120D /* MSALNativeAuthResetPasswordContinueResponseErrorTests.swift */, + DE5738B92A8F780E00D9120D /* MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift */, + 9B2BBA342A3297F80075F702 /* MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift */, + 9B2BBA362A3298080075F702 /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift */, + DE5738BB2A8F79A800D9120D /* MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift */, + ); + path = reset_password; + sourceTree = ""; + }; + 9B2E933C2A0D379D008A5DD2 /* reset_password */ = { + isa = PBXGroup; + children = ( + 9B2E93442A0D3801008A5DD2 /* MSALNativeAuthResetPasswordControlling.swift */, + 9BD2763C2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift */, + ); + path = reset_password; + sourceTree = ""; + }; + 9B5D6D042A3CA0C600521576 /* end_to_end */ = { + isa = PBXGroup; + children = ( + E272C4E92A4447520013B805 /* sign_up */, + 9B235DA22A3D15E400657331 /* sign_in */, + DEFB46E12A52B9B800DBC006 /* reset_password */, + DEFB46EB2A52BA1300DBC006 /* sign_out */, + 9B235D9E2A3CFB4300657331 /* MSALNativeAuthEndToEndBaseTestCase.swift */, + ); + path = end_to_end; + sourceTree = ""; + }; + 9B61C91D2A27E5E200CE9E3A /* reset_password */ = { + isa = PBXGroup; + children = ( + 9BB518032A2A2B5B00D6276A /* MSALNativeAuthResetPasswordControllerSpy.swift */, + 9B61C9122A27E51900CE9E3A /* MSALNativeAuthResetPasswordRequestProviderMock.swift */, + 9B61C91B2A27E57C00CE9E3A /* MSALNativeAuthResetPasswordResponseValidatorMock.swift */, + ); + path = reset_password; + sourceTree = ""; + }; + 9B6EECE62A31467E008ABA50 /* reset_password */ = { + isa = PBXGroup; + children = ( + 9B4EE9D62A16874F00F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift */, + 9BE7E3D42A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift */, + ); + path = reset_password; + sourceTree = ""; + }; + 9BD2764E2A0E7DA400FBD033 /* reset_password */ = { + isa = PBXGroup; + children = ( + 9BD276562A0E7DEC00FBD033 /* ResetPasswordCodeSentStateTests.swift */, + 9BD2765E2A0E81CE00FBD033 /* ResetPasswordRequiredStateTests.swift */, + ); + path = reset_password; + sourceTree = ""; + }; B25A439021C35A67000B3DD4 /* actions */ = { isa = PBXGroup; children = ( @@ -1870,7 +2881,7 @@ B26756B822921A30000F01D7 /* oauth2 */ = { isa = PBXGroup; children = ( - 8878C60929DC9AD4002F5F4B /* ciam */, + DE9244D52A31E1D500C0389F /* ciam */, B26756BB22921A60000F01D7 /* adfs */, B26756BA22921A5B000F01D7 /* b2c */, B26756B922921A51000F01D7 /* aad */, @@ -2148,6 +3159,7 @@ D61F5B691E53FCA100912CB8 /* test */ = { isa = PBXGroup; children = ( + 28D1D58129BF885500CE75F4 /* integration */, 962E37BE1E720E1700DE71FE /* automation */, D61A647D1E5AA7C60086D120 /* app */, D65A6FDB1E3FF71000C69FBA /* unit */, @@ -2173,6 +3185,7 @@ D65A6F671E3FF3D900C69FBA /* src */ = { isa = PBXGroup; children = ( + E2AA770B292F972500113F04 /* native_auth */, 94E876C91E492D2800FB96ED /* instance */, D65A6F7E1E3FF3D900C69FBA /* public */, 96D9A5461E4AB21400674A85 /* telemetry */, @@ -2231,6 +3244,7 @@ B2C0E79C23AC7996006C9CAD /* MSALParameters.m */, 23014D4F25672E53005E12F2 /* MSALAuthenticationSchemeBearer+Internal.h */, 23014D4425672DF9005E12F2 /* MSALAuthenticationSchemePop+Internal.h */, + 9B839A0F2A4D7CF600BCC6F6 /* MSAL.docc */, ); path = src; sourceTree = ""; @@ -2334,6 +3348,7 @@ D65A6FDB1E3FF71000C69FBA /* unit */ = { isa = PBXGroup; children = ( + DECC1FB029530FEB006D9FB1 /* native_auth */, A0274CBD24B432B100BD198D /* MSALAuthSchemeTests.m */, B295A15E22D0344B00FFB313 /* mac */, B2725EBD22BF2805009B454A /* mocks */, @@ -2499,15 +3514,16 @@ D6DFF3991E2579360012891A = { isa = PBXGroup; children = ( + DE53C7D4293F9F5A00E5B2BB /* module.modulemap */, 231CE9E01FECBD4600E95D3E /* unit-test-host.entitlements */, - D6A206191FC50A4D00755A51 /* IdentityCore.xcodeproj */, + 9B235D952A3CC71C00657331 /* NativeAuthEndToEndTestPlan.xctestplan */, D65A6F671E3FF3D900C69FBA /* src */, D61F5B691E53FCA100912CB8 /* test */, D65A6FB71E3FF44A00C69FBA /* resources */, D65A6FBC1E3FF46100C69FBA /* xcconfig */, D6DFF3A31E2579360012891A /* Products */, D6A2062E1FC5106F00755A51 /* Frameworks */, - 238A362622EA390400F08167 /* Recovered References */, + D6A206191FC50A4D00755A51 /* IdentityCore.xcodeproj */, ); sourceTree = ""; }; @@ -2527,16 +3543,619 @@ 04A6B57B226921890035C7C2 /* libMSAL (iOS Static Library).a */, 04A6B59C2269286F0035C7C2 /* libMSAL (macOS Static Library).a */, B295A16422D0348400FFB313 /* unit-test-host-mac.app */, + 28D1D56C29BF62E900CE75F4 /* MSAL iOS Native Auth Integration Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + DE0347952A3B20B2003CB3B6 /* token */ = { + isa = PBXGroup; + children = ( + DE54B5932A43587800460B34 /* MSALNativeAuthTokenRequestProvider.swift */, + ); + path = token; + sourceTree = ""; + }; + DE0D65C429D344AC005798B1 /* requests */ = { + isa = PBXGroup; + children = ( + E243F6AC29D4424D00DAC60F /* sign_up */, + DEDB29AE29DDC04A008DA85B /* sign_in */, + DE8EC8762A026C2E003FA561 /* reset_password */, + DE54B5A12A44615A00460B34 /* token */, + ); + path = requests; + sourceTree = ""; + }; + DE0FECA92993AD3700B139A8 /* responses */ = { + isa = PBXGroup; + children = ( + 28DE70CD29FAC14500EB75AA /* validator */, + DEDB29A029DDA18F008DA85B /* sign_in */, + E243F69229D1973900DAC60F /* sign_up */, + DEE34F51D170B71C00BC302A /* reset_password */, + DE0FECAA2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift */, + ); + path = responses; + sourceTree = ""; + }; + DE54B5962A4358A200460B34 /* token */ = { + isa = PBXGroup; + children = ( + 282693272A0974740037B93A /* MSALNativeAuthTokenRequestParameters.swift */, + ); + path = token; + sourceTree = ""; + }; + DE54B5972A44431C00460B34 /* token */ = { + isa = PBXGroup; + children = ( + DE54B5982A44433200460B34 /* validated_response */, + DE54B5AC2A459B0400460B34 /* MSALNativeAuthTokenResponseValidator.swift */, + ); + path = token; + sourceTree = ""; + }; + DE54B5982A44433200460B34 /* validated_response */ = { + isa = PBXGroup; + children = ( + 28A472EB2A276C3B003F988B /* MSALNativeAuthTokenValidatedResponse.swift */, + ); + path = validated_response; + sourceTree = ""; + }; + DE54B5A02A44601500460B34 /* token */ = { + isa = PBXGroup; + children = ( + DEDB29A729DDAEB3008DA85B /* MSALNativeAuthTokenOauth2ErrorCode.swift */, + DEDB29AB29DDAF53008DA85B /* MSALNativeAuthTokenResponseError.swift */, + ); + path = token; + sourceTree = ""; + }; + DE54B5A12A44615A00460B34 /* token */ = { + isa = PBXGroup; + children = ( + DE4F0F2929D6F1AA00D561FD /* MSALNativeAuthTokenIntegrationTests.swift */, + ); + path = token; + sourceTree = ""; + }; + DE54B5A22A4464D400460B34 /* token */ = { + isa = PBXGroup; + children = ( + DE0D658D29C1DCA6005798B1 /* MSALNativeAuthTokenRequestParametersTest.swift */, + ); + path = token; + sourceTree = ""; + }; + DE8EC86B2A026BA0003FA561 /* sign_in */ = { + isa = PBXGroup; + children = ( + DE8EC86C2A026BA0003FA561 /* MSALNativeAuthSignInRequestProvider.swift */, + ); + path = sign_in; + sourceTree = ""; + }; + DE8EC8762A026C2E003FA561 /* reset_password */ = { + isa = PBXGroup; + children = ( + DE8EC8772A026C2E003FA561 /* MSALNativeAuthResetPasswordChallengeIntegrationTests.swift */, + DE8EC8782A026C2E003FA561 /* MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift */, + DE8EC8792A026C2E003FA561 /* MSALNativeAuthResetPasswordStartIntegrationTests.swift */, + DE8EC87A2A026C2E003FA561 /* MSALNativeAuthResetPasswordContinueIntegrationTests.swift */, + DE8EC87B2A026C2E003FA561 /* MSALNativeAuthResetPasswordSubmitIntegrationTests.swift */, + ); + path = reset_password; + sourceTree = ""; + }; + DE9244D52A31E1D500C0389F /* ciam */ = { + isa = PBXGroup; + children = ( + DE9244D62A31E1D500C0389F /* MSALCIAMOauth2Provider.h */, + DE9244D72A31E1D500C0389F /* MSALCIAMOauth2Provider.m */, + ); + path = ciam; + sourceTree = ""; + }; + DE92450A2A385EAD00C0389F /* credentials */ = { + isa = PBXGroup; + children = ( + DE92450D2A38601100C0389F /* MSALNativeAuthCredentialsControlling.swift */, + DE92450B2A385ED800C0389F /* MSALNativeAuthCredentialsController.swift */, + ); + path = credentials; + sourceTree = ""; + }; + DE94C9D629F1898A00C1EC1F /* reset_password */ = { + isa = PBXGroup; + children = ( + DE94C9DE29F1989600C1EC1F /* MSALNativeAuthResetPasswordStartRequestParametersTest.swift */, + DE94C9E129F19AA200C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift */, + DE94C9E329F19C4C00C1EC1F /* MSALNativeAuthResetPasswordContinueRequestParametersTest.swift */, + DE94C9E529F19D9A00C1EC1F /* MSALNativeAuthResetPasswordSubmitRequestParametersTest.swift */, + DE94C9E729F19E6B00C1EC1F /* MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift */, + ); + path = reset_password; + sourceTree = ""; + }; + DECC1FB029530FEB006D9FB1 /* native_auth */ = { + isa = PBXGroup; + children = ( + E25BC0902995559700588549 /* utils */, + DE14D76029898CF900F37BEF /* MSALNativeAuthTestCase.swift */, + E2F5BE9829896AC700C67EC7 /* controllers */, + 287F64F42981A7B800ED90BD /* mock */, + 287F64F129819F6B00ED90BD /* public */, + 287F64EE298186C800ED90BD /* input_validator */, + 287F64D1297EC27200ED90BD /* telemetry */, + 28A3147029705B4500573AFF /* network */, + 28CA6F5E29689F3E004DB11D /* cache */, + DECC1FB129530FF6006D9FB1 /* logger */, + ); + path = native_auth; + sourceTree = ""; + }; + DECC1FB129530FF6006D9FB1 /* logger */ = { + isa = PBXGroup; + children = ( + DECC1FB229531032006D9FB1 /* MSALLogMaskTests.m */, + DECC1FB4295322A8006D9FB1 /* MSALNativeLoggingTests.swift */, + ); + path = logger; + sourceTree = ""; + }; + DEDB29A029DDA18F008DA85B /* sign_in */ = { + isa = PBXGroup; + children = ( + DE0D65AB29CC6A59005798B1 /* MSALNativeAuthSignInInitiateResponse.swift */, + DE0D65B529CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift */, + ); + path = sign_in; + sourceTree = ""; + }; + DEDB29A229DDA992008DA85B /* errors */ = { + isa = PBXGroup; + children = ( + E27332BF2A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift */, + DEDB298A29D72D62008DA85B /* MSALNativeAuthInnerError.swift */, + DE0D65BE29D30BAE005798B1 /* MSALNativeAuthResponseError.swift */, + DE8EC8B52A053D80003FA561 /* MSALNativeAuthESTSApiErrorCodes.swift */, + DEF1DD312AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift */, + E2C61FD829DECE8900F15203 /* sign_up */, + DEDB29A329DDA99C008DA85B /* sign_in */, + DEE34F5DD170B71C00BC302A /* reset_password */, + DE54B5A02A44601500460B34 /* token */, + ); + path = errors; + sourceTree = ""; + }; + DEDB29A329DDA99C008DA85B /* sign_in */ = { + isa = PBXGroup; + children = ( + DE0D65C129D30C38005798B1 /* MSALNativeAuthSignInInitiateOauth2ErrorCode.swift */, + DEDB29A429DDA9DC008DA85B /* MSALNativeAuthSignInInitiateResponseError.swift */, + DEDB29A629DDAEB3008DA85B /* MSALNativeAuthSignInChallengeOauth2ErrorCode.swift */, + DEDB29AA29DDAF52008DA85B /* MSALNativeAuthSignInChallengeResponseError.swift */, + ); + path = sign_in; + sourceTree = ""; + }; + DEDB29AE29DDC04A008DA85B /* sign_in */ = { + isa = PBXGroup; + children = ( + DE0D65C529D344F1005798B1 /* MSALNativeAuthSignInInitiateIntegrationTests.swift */, + DE0D65CA29D5CD6D005798B1 /* MSALNativeAuthSignInChallengeIntegrationTests.swift */, + ); + path = sign_in; + sourceTree = ""; + }; + DEE34F10D170B71C00BC302A /* reset_password */ = { + isa = PBXGroup; + children = ( + DEE34F11D170B71C00BC302A /* MSALNativeAuthResetPasswordStartRequestParameters.swift */, + DE94C9EE29F2AF3200C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParameters.swift */, + DEE34F74D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueRequestParameters.swift */, + DEE34F7CD170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitRequestParameters.swift */, + DEE34F84D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift */, + ); + path = reset_password; + sourceTree = ""; + }; + DEE34F41D170B71C00BC302A /* factories */ = { + isa = PBXGroup; + children = ( + 28D5B05C2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift */, + DEE34F43D170B71C00BC302A /* MSALNativeAuthResultFactory.swift */, + ); + path = factories; + sourceTree = ""; + }; + DEE34F51D170B71C00BC302A /* reset_password */ = { + isa = PBXGroup; + children = ( + DEE34F5BD170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponse.swift */, + DEE34F64D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeResponse.swift */, + DEE34F76D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueResponse.swift */, + DEE34F7ED170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitResponse.swift */, + DEE34F88D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionStatus.swift */, + DEE34F86D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponse.swift */, + ); + path = reset_password; + sourceTree = ""; + }; + DEE34F5DD170B71C00BC302A /* reset_password */ = { + isa = PBXGroup; + children = ( + DEE34F5FD170B71C00BC302A /* MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift */, + DEE34F5ED170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponseError.swift */, + DEE34F71D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift */, + DEE34F69D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeResponseError.swift */, + DEE34F79D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift */, + DEE34F78D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueResponseError.swift */, + DEE34F80D170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift */, + DEE34F81D170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitResponseError.swift */, + DEE34F8AD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift */, + DEE34F8BD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponseError.swift */, + ); + path = reset_password; + sourceTree = ""; + }; + DEE34F9FD170B71C00BC302A /* reset_password */ = { + isa = PBXGroup; + children = ( + DEE34FA0D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift */, + 9BE7E3CA2A1CB70700CC3A62 /* MSALNativeAuthResetPasswordStartRequestProviderParameters.swift */, + ); + path = reset_password; + sourceTree = ""; + }; + DEFB46E12A52B9B800DBC006 /* reset_password */ = { + isa = PBXGroup; + children = ( + DEFB46F12A52C11400DBC006 /* MSALNativeAuthResetPasswordEndToEndTests.swift */, + DEFB46F32A52C28100DBC006 /* ResetPasswordDelegateSpies.swift */, + ); + path = reset_password; + sourceTree = ""; + }; + DEFB46EB2A52BA1300DBC006 /* sign_out */ = { + isa = PBXGroup; + children = ( + DEFB46EC2A52BA3700DBC006 /* MSALNativeAuthSignOutEndToEndTests.swift */, + ); + path = sign_out; + sourceTree = ""; + }; + E02396F51E7AFFF7004D6278 /* telemetry */ = { + isa = PBXGroup; + children = ( + 233E970A226571AB007FCE2A /* MSALTelemetryAggregatedTests.m */, + ); + name = telemetry; + sourceTree = ""; + }; + E205D62C29B783D6003887BC /* configuration */ = { + isa = PBXGroup; + children = ( + E205D62D29B783FF003887BC /* MSALNativeAuthConfiguration.swift */, + ); + path = configuration; + sourceTree = ""; + }; + E206FCFB297B01DF00AF4400 /* validation */ = { + isa = PBXGroup; + children = ( + E2DC31C729B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift */, + ); + path = validation; + sourceTree = ""; + }; + E20C21822A7A6C7300E31598 /* sign_in */ = { + isa = PBXGroup; + children = ( + E20C21832A7A6CA400E31598 /* SignInCodeRequiredStateTests.swift */, + E20C218A2A7A805800E31598 /* SignInPasswordRequiredStateTests.swift */, + ); + path = sign_in; + sourceTree = ""; + }; + E235612F29C9CE81000E01CA /* sign_up */ = { + isa = PBXGroup; + children = ( + E235613029C9CEA8000E01CA /* MSALNativeAuthSignUpStartRequestParameters.swift */, + E243F69929D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift */, + E243F69F29D1FF9E00DAC60F /* MSALNativeAuthSignUpContinueRequestParameters.swift */, + ); + path = sign_up; + sourceTree = ""; + }; + E243F69229D1973900DAC60F /* sign_up */ = { + isa = PBXGroup; + children = ( + E243F69329D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift */, + E243F69C29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift */, + E243F6A529D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift */, + ); + path = sign_up; + sourceTree = ""; + }; + E243F6A829D42F7800DAC60F /* sign_up */ = { + isa = PBXGroup; + children = ( + E235610D29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift */, + E243F6A929D42FE900DAC60F /* MSALNativeAuthSignUpContinueRequestProviderParams.swift */, + E2B8532E2A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift */, + ); + path = sign_up; + sourceTree = ""; + }; + E243F6AC29D4424D00DAC60F /* sign_up */ = { + isa = PBXGroup; + children = ( + E243F6AD29D4427E00DAC60F /* MSALNativeAuthSignUpStartIntegrationTests.swift */, + E23E955E29D4B9F7001DC59C /* MSALNativeAuthSignUpChallengeIntegrationTests.swift */, + E2BC027429D6E0C600041DBC /* MSALNativeAuthSignUpContinueIntegrationTests.swift */, + ); + path = sign_up; + sourceTree = ""; + }; + E25BC0902995559700588549 /* utils */ = { + isa = PBXGroup; + children = ( + E25BC098299555C000588549 /* MSALNativeAuthTelemetryTestDispatcher.swift */, + ); + path = utils; + sourceTree = ""; + }; + E260964129489CA60060DD7C /* public */ = { + isa = PBXGroup; + children = ( + 28DCD08829D70FA000C4601E /* state_machine */, + 289747B22979A3AD00838C80 /* parameters */, + E2DC31BB29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift */, + E2F6269C2A780DDE00C4A303 /* MSALNativeAuthPublicClientApplication+Internal.swift */, + DE729ECC2A1793A100A761D9 /* MSALNativeAuthChannelType.swift */, + 9BD78D7A2A126A1500AA7E12 /* MSALNativeAuthChallengeTypes.h */, + DE8BE7DB2A1F6BD2009642A5 /* MSALNativeAuthUserAccountResult.swift */, + E2D3BC4E2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift */, + ); + path = public; + sourceTree = ""; + }; + E26097942948FB660060DD7C /* cache */ = { + isa = PBXGroup; + children = ( + 289E156C2948EB8A006104D9 /* MSALNativeAuthCacheAccessor.swift */, + 289E15582948E601006104D9 /* MSALNativeAuthCacheInterface.swift */, + 2884855B295DAFD400516492 /* MSALNativeAuthTokens.swift */, + ); + path = cache; + sourceTree = ""; + }; + E26097C12948FC410060DD7C /* logger */ = { + isa = PBXGroup; + children = ( + DECC1F9329521E34006D9FB1 /* MSALLogMask.h */, + DECC1F9229521E34006D9FB1 /* MSALLogMask.m */, + E26097C22948FC4D0060DD7C /* MSALNativeAuthLogging.swift */, + ); + path = logger; + sourceTree = ""; + }; + E26097C52948FC630060DD7C /* telemetry */ = { + isa = PBXGroup; + children = ( + E26097C62948FC720060DD7C /* MSALNativeAuthServerTelemetry.swift */, + DEF9D988296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift */, + DEF9D995296EC35A006CB384 /* MSALNativeAuthTelemetryApiId.swift */, + DEF9D998296EC848006CB384 /* MSALNativeAuthOperationTypes.swift */, + DEF9D99E296F08CE006CB384 /* MSALNativeAuthTelemetryProvider.swift */, + ); + path = telemetry; + sourceTree = ""; + }; + E272C4E92A4447520013B805 /* sign_up */ = { + isa = PBXGroup; + children = ( + E272C4EA2A4447520013B805 /* MSALNativeAuthSignUpUsernameEndToEndTests.swift */, + E26E391A2A4C2BE200063C07 /* MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift */, + E26E39232A4C2D7400063C07 /* SignUpDelegateSpies.swift */, + ); + path = sign_up; + sourceTree = ""; + }; + E284F5DB29F2F1A200DBED7D /* sign_up */ = { + isa = PBXGroup; + children = ( + E284F5E329F2F28A00DBED7D /* MSALNativeAuthSignUpControlling.swift */, + E284F5D829F28B4200DBED7D /* MSALNativeAuthSignUpController.swift */, + ); + path = sign_up; + sourceTree = ""; + }; + E2960A072A1F4D13000F441B /* errors */ = { + isa = PBXGroup; + children = ( + E2960A0F2A1F4D18000F441B /* sign_up */, + 9B2BBA252A3291DD0075F702 /* reset_password */, + DEF1DD3B2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift */, + ); + path = errors; + sourceTree = ""; + }; + E2960A0F2A1F4D18000F441B /* sign_up */ = { + isa = PBXGroup; + children = ( + E2F4DB232A1F525A009FBCD0 /* MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift */, + DE5738BF2A8F7C1F00D9120D /* MSALNativeAuthSignUpStartResponseErrorTests.swift */, + DE40A4C92A8F801200928CEE /* MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift */, + E2960A102A1F4D2F000F441B /* MSALNativeAuthSignUpChallengeResponseErrorTests.swift */, + E2F4DB2C2A1F5714009FBCD0 /* MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift */, + DE40A4D22A8F80C100928CEE /* MSALNativeAuthSignUpContinueResponseErrorTests.swift */, + E2BDD98A2A28FBDD00E3ED6B /* MSALNativeAuthErrorRequiredAttributesTests.swift */, + ); + path = sign_up; + sourceTree = ""; + }; + E2AA770B292F972500113F04 /* native_auth */ = { + isa = PBXGroup; + children = ( + E206FC5E296D65DE00AF4400 /* MSALNativeAuthInternalError.swift */, + E26097942948FB660060DD7C /* cache */, + E205D62C29B783D6003887BC /* configuration */, + 289747AE29799A6600838C80 /* input_validator */, + 2811CDCF296F16DE007BA21B /* controllers */, + E26097C12948FC410060DD7C /* logger */, + E260964129489CA60060DD7C /* public */, + E2C872AD294CC94A00C4F580 /* network */, + E26097C52948FC630060DD7C /* telemetry */, + 28F19BE92A2F881D00575581 /* extension */, + E206FCFB297B01DF00AF4400 /* validation */, + ); + path = native_auth; + sourceTree = ""; + }; + E2B8532D2A153287007A4776 /* sign_up */ = { + isa = PBXGroup; + children = ( + E2CD2E8C2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift */, + E2B8532A2A1531DA007A4776 /* MSALNativeAuthSignUpValidatedResponses.swift */, + ); + path = sign_up; + sourceTree = ""; + }; + E2BC029629D7668D00041DBC /* sign_up */ = { + isa = PBXGroup; + children = ( + E2BC029929D766B200041DBC /* MSALNativeAuthSignUpStartRequestParametersTest.swift */, + E2BC029729D766A800041DBC /* MSALNativeAuthSignUpChallengeRequestParametersTest.swift */, + E2BC029B29D766CB00041DBC /* MSALNativeAuthSignUpContinueRequestParametersTest.swift */, + ); + path = sign_up; + sourceTree = ""; + }; + E2C61FD829DECE8900F15203 /* sign_up */ = { + isa = PBXGroup; + children = ( + DEE34F95D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift */, + 8D35C8E62A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift */, + 8D35C8F02A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift */, + E2C61FE029DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift */, + E2C61FE329DED15800F15203 /* MSALNativeAuthSignUpStartResponseError.swift */, + E2C61FE929DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift */, + E2C61FE629DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift */, + E2C61FEC29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift */, + E2C61FEF29DEDB0200F15203 /* MSALNativeAuthSignUpContinueResponseError.swift */, + ); + path = sign_up; + sourceTree = ""; + }; + E2C6201E29E038DB00F15203 /* sign_in */ = { + isa = PBXGroup; + children = ( + DE0D656729BF72F6005798B1 /* MSALNativeAuthSignInInitiateRequestParameters.swift */, + DE0D657429BF73CB005798B1 /* MSALNativeAuthSignInChallengeRequestParameters.swift */, + ); + path = sign_in; + sourceTree = ""; + }; + E2C6201F29E0420200F15203 /* sign_in */ = { + isa = PBXGroup; + children = ( + DE0D658E29C1DCA6005798B1 /* MSALNativeAuthSignInInitiateRequestParametersTest.swift */, + DE0D658C29C1DCA6005798B1 /* MSALNativeAuthSignInChallengeRequestParametersTest.swift */, + ); + path = sign_in; + sourceTree = ""; + }; + E2C872AD294CC94A00C4F580 /* network */ = { + isa = PBXGroup; + children = ( + E243F6A829D42F7800DAC60F /* sign_up */, + DE8EC86B2A026BA0003FA561 /* sign_in */, + DEE34F9FD170B71C00BC302A /* reset_password */, + DE0347952A3B20B2003CB3B6 /* token */, + E2ACA47A29520C2200E98964 /* MSALNativeAuthEndpoint.swift */, + E2ACA4942953415E00E98964 /* MSALNativeAuthGrantType.swift */, + 287F65172983F77D00ED90BD /* MSALNativeAuthRequestParametersKey.swift */, + 287F650B2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift */, + DE0D65B829D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift */, + 8D2733132AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift */, + E2ACA49B2953576C00E98964 /* MSALNativeAuthUrlRequestSerializer.swift */, + DE1D8AA729E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift */, + E2C872C1294CDEAB00C4F580 /* parameters */, + DE0FECA92993AD3700B139A8 /* responses */, + DEDB29A229DDA992008DA85B /* errors */, + E235613329C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift */, + 287708212A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift */, + ); + path = network; + sourceTree = ""; + }; + E2C872C1294CDEAB00C4F580 /* parameters */ = { + isa = PBXGroup; + children = ( + E235612F29C9CE81000E01CA /* sign_up */, + E2C6201E29E038DB00F15203 /* sign_in */, + DEE34F10D170B71C00BC302A /* reset_password */, + E2C872C2294CDEE800C4F580 /* MSALNativeAuthRequestable.swift */, + E2ACA48A2952302B00E98964 /* MSALNativeAuthRequestContext.swift */, + DE54B5962A4358A200460B34 /* token */, + ); + path = parameters; + sourceTree = ""; + }; + E2CD2E3F29FBE957009F8FFA /* state_machine */ = { + isa = PBXGroup; + children = ( + E20C21822A7A6C7300E31598 /* sign_in */, + E2CD2E4D29FC0435009F8FFA /* sign_up */, + 9BD2764E2A0E7DA400FBD033 /* reset_password */, + ); + path = state_machine; + sourceTree = ""; + }; + E2CD2E4D29FC0435009F8FFA /* sign_up */ = { + isa = PBXGroup; + children = ( + E2CD2E4929FBEA36009F8FFA /* SignUpCodeSentStateTests.swift */, + E2CD2E4E29FC0451009F8FFA /* SignUpPasswordRequiredStateTests.swift */, + E2CD2E5029FC087A009F8FFA /* SignUpAttributesRequiredStateTests.swift */, + ); + path = sign_up; + sourceTree = ""; + }; + E2EFAD072A69A2C300D6C3DE /* responses */ = { + isa = PBXGroup; + children = ( + E2EFAD082A69A34300D6C3DE /* CodeRequiredGenericResult.swift */, + E2EFACFD2A69915100D6C3DE /* SignInResults.swift */, + E2EFAD0B2A69B45100D6C3DE /* SignUpResults.swift */, + E2EFAD0E2A69BBB800D6C3DE /* ResetPasswordResults.swift */, ); - name = Products; + path = responses; sourceTree = ""; }; - E02396F51E7AFFF7004D6278 /* telemetry */ = { + E2F5BE9829896AC700C67EC7 /* controllers */ = { isa = PBXGroup; children = ( - 233E970A226571AB007FCE2A /* MSALTelemetryAggregatedTests.m */, + E2F5BE9B298A6CDB00C67EC7 /* factories */, + E2C1D2D329A3992100B26449 /* MSALNativeAuthBaseControllerTests.swift */, + E2F5BE9929896ADB00C67EC7 /* MSALNativeAuthSignInControllerTests.swift */, + E286E2DC2A1BAEA800666DD0 /* MSALNativeAuthSignUpControllerTests.swift */, + 9B4EE9CD2A1686A900F243C1 /* MSALNativeAuthResetPasswordControllerTests.swift */, + DE14096C2A38DF40008E6F1E /* MSALNativeAuthCredentialsControllerTests.swift */, + ); + path = controllers; + sourceTree = ""; + }; + E2F5BE9B298A6CDB00C67EC7 /* factories */ = { + isa = PBXGroup; + children = ( + E2F5BE9C298A6CEB00C67EC7 /* MSALNativeAuthResultFactoryTests.swift */, ); - name = telemetry; + path = factories; sourceTree = ""; }; /* End PBXGroup section */ @@ -2589,6 +4208,7 @@ B273D0EE226E8606005A7BB4 /* MSALTokenParameters+Internal.h in Headers */, 2343CC2A2576C37C002D405A /* MSALParameters.h in Headers */, B2D47881230E3DBE005AE186 /* MSALADFSOauth2Provider.h in Headers */, + DE9244DB2A31E1D500C0389F /* MSALCIAMOauth2Provider.h in Headers */, B2D478C3230E3EBD005AE186 /* MSALTenantProfile+Internal.h in Headers */, B273D078226E84DD005A7BB4 /* MSALHTTPConfig.h in Headers */, B273D090226E8534005A7BB4 /* MSALJsonDeserializable.h in Headers */, @@ -2621,7 +4241,6 @@ 2328074328BC175C000306A9 /* MSALAccountEnumerationParameters+Private.h in Headers */, B273D0A2226E8574005A7BB4 /* MSALIndividualClaimRequest+Internal.h in Headers */, B2D47885230E3DC6005AE186 /* MSALB2COauth2Provider.h in Headers */, - 8878C61A29DC9B2F002F5F4B /* MSALCIAMOauth2Provider.h in Headers */, B273D08E226E852F005A7BB4 /* MSALJsonSerializable.h in Headers */, B273D08A226E8525005A7BB4 /* MSALIndividualClaimRequest.h in Headers */, 04A6B5FF226938050035C7C2 /* MSALResult.h in Headers */, @@ -2676,8 +4295,10 @@ 1E5319BE24A51DFE007BCF30 /* MSALAuthenticationSchemePop.h in Headers */, 04A6B602226938110035C7C2 /* MSALLogger.h in Headers */, 04A6B5F6226937EA0035C7C2 /* MSALAccountId.h in Headers */, + DE9244DA2A31E1D500C0389F /* MSALCIAMOauth2Provider.h in Headers */, B273D07B226E84E9005A7BB4 /* MSALDefinitions.h in Headers */, B273D0ED226E8606005A7BB4 /* MSALTokenParameters+Internal.h in Headers */, + 9BD78D902A127F8000AA7E12 /* MSALNativeAuthChallengeTypes.h in Headers */, B273D08F226E8534005A7BB4 /* MSALJsonDeserializable.h in Headers */, B273D077226E84DD005A7BB4 /* MSALHTTPConfig.h in Headers */, B273D0CB226E85C7005A7BB4 /* MSALHTTPConfig+Internal.h in Headers */, @@ -2686,12 +4307,12 @@ B273D06F226E84C3005A7BB4 /* MSALGlobalConfig.h in Headers */, 04A6B5E0226937AD0035C7C2 /* MSALAccountsProvider.h in Headers */, B2D478B6230E3E8D005AE186 /* MSALSerializedADALCacheProvider+Internal.h in Headers */, + DECC1F9929521E35006D9FB1 /* MSALLogMask.h in Headers */, B273D085226E851A005A7BB4 /* MSALInteractiveTokenParameters.h in Headers */, 04A6B5F0226937D00035C7C2 /* MSALB2CAuthority.h in Headers */, 04A6B6012269380B0035C7C2 /* MSALPublicClientApplication.h in Headers */, B273D0A1226E8574005A7BB4 /* MSALIndividualClaimRequest+Internal.h in Headers */, B273D083226E8514005A7BB4 /* MSALSilentTokenParameters.h in Headers */, - 8878C61929DC9B2E002F5F4B /* MSALCIAMOauth2Provider.h in Headers */, 1E5319C224A51E4C007BCF30 /* MSALAuthScheme.h in Headers */, B2D47896230E3DF5005AE186 /* MSALCacheConfig.h in Headers */, B273D08D226E852E005A7BB4 /* MSALJsonSerializable.h in Headers */, @@ -2700,7 +4321,6 @@ 04A6B5F3226937DE0035C7C2 /* MSALAuthority.h in Headers */, B273D07F226E8507005A7BB4 /* MSALPublicClientStatusNotifications.h in Headers */, B2D478AC230E3E88005AE186 /* MSALLegacySharedMSAAccount.h in Headers */, - B2D4789E230E3E2C005AE186 /* MSALWebviewParameters.h in Headers */, 0D96DB3D27850F1100DEAF87 /* MSALWipeCacheForAllAccountsConfig.h in Headers */, B2D478AA230E3E82005AE186 /* MSALLegacySharedADALAccount.h in Headers */, B273D0B6226E8596005A7BB4 /* MSALPublicClientApplication+Internal.h in Headers */, @@ -2779,20 +4399,22 @@ B273D0D3226E85D0005A7BB4 /* MSALTelemetryConfig+Internal.h in Headers */, 96CF951E2268FD0400D97374 /* MSALError.h in Headers */, B2C0E79D23AC7996006C9CAD /* MSALParameters.h in Headers */, + DECC1F9829521E35006D9FB1 /* MSALLogMask.h in Headers */, 96CF95302268FD0500D97374 /* MSALIndividualClaimRequestAdditionalInfo.h in Headers */, B221CEEB20C0AF0B002F5E94 /* MSALAccountId+Internal.h in Headers */, + 9BD78D822A126DC400AA7E12 /* MSALNativeAuthChallengeTypes.h in Headers */, 96CF951A2268FD0400D97374 /* MSALHTTPConfig.h in Headers */, B273D0E6226E85F9005A7BB4 /* MSALResult+Internal.h in Headers */, 96CF95152268FD0400D97374 /* MSALPublicClientApplicationConfig.h in Headers */, 1EF395FD246DFAD200647FDB /* MSALAuthScheme.h in Headers */, B2A3C2892145FD0F0082525C /* MSALAccountsProvider.h in Headers */, B273D0B8226E859F005A7BB4 /* MSALPublicClientApplicationConfig+Internal.h in Headers */, + DE9244D82A31E1D500C0389F /* MSALCIAMOauth2Provider.h in Headers */, 96CF95252268FD0500D97374 /* MSALB2CAuthority.h in Headers */, 96CF95272268FD0500D97374 /* MSALLogger.h in Headers */, B26756CA22921C5B000F01D7 /* MSALB2COauth2Provider.h in Headers */, 96CF95172268FD0400D97374 /* MSALSliceConfig.h in Headers */, B227037122A4BA3600030ADC /* MSALLegacySharedAccountsProvider.h in Headers */, - 8878C61729DC9B2C002F5F4B /* MSALCIAMOauth2Provider.h in Headers */, 1EE776C4246C98E700F7EBFC /* MSALAuthenticationSchemePop.h in Headers */, 96CF95192268FD0400D97374 /* MSALTelemetryConfig.h in Headers */, A0274CDB24B54A7000BD198D /* MSALDevicePopManagerUtil.h in Headers */, @@ -2896,8 +4518,8 @@ B273D0D2226E85D0005A7BB4 /* MSALTelemetryConfig+Internal.h in Headers */, B28BBD342211DC7D00F51723 /* MSALPublicClientStatusNotifications.h in Headers */, 232D68DD223DBA0700594BBD /* MSALInteractiveTokenParameters.h in Headers */, + DE9244D92A31E1D500C0389F /* MSALCIAMOauth2Provider.h in Headers */, B26756C522921C42000F01D7 /* MSALAADOauth2Provider.h in Headers */, - 8878C61829DC9B2D002F5F4B /* MSALCIAMOauth2Provider.h in Headers */, B2FBB3DB28F72A5700A3591C /* MSALWPJMetaData+Internal.h in Headers */, B27CCDE1229F65D700CAD565 /* MSALAccount+MultiTenantAccount.h in Headers */, 232D614B2248484C00260C42 /* MSALClaimsRequest.h in Headers */, @@ -3001,6 +4623,25 @@ productReference = 1E614BDA22558D8300EBF62F /* MSAL Test App (Mac).app */; productType = "com.apple.product-type.application"; }; + 28D1D56B29BF62E900CE75F4 /* MSAL iOS Native Auth Integration Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 28D1D57C29BF62E900CE75F4 /* Build configuration list for PBXNativeTarget "MSAL iOS Native Auth Integration Tests" */; + buildPhases = ( + 28D1D56829BF62E900CE75F4 /* Sources */, + 28D1D56929BF62E900CE75F4 /* Frameworks */, + 28D1D56A29BF62E900CE75F4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 28D1D57229BF62E900CE75F4 /* PBXTargetDependency */, + 28D1D57E29BF633900CE75F4 /* PBXTargetDependency */, + ); + name = "MSAL iOS Native Auth Integration Tests"; + productName = "MSAL iOS Native Auth Integration Tests"; + productReference = 28D1D56C29BF62E900CE75F4 /* MSAL iOS Native Auth Integration Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 962E37A61E720C5D00DE71FE /* MSAL Test Automation (iOS) */ = { isa = PBXNativeTarget; buildConfigurationList = 962E37B91E720C5D00DE71FE /* Build configuration list for PBXNativeTarget "MSAL Test Automation (iOS)" */; @@ -3106,10 +4747,11 @@ isa = PBXNativeTarget; buildConfigurationList = D65A6F481E3FD30A00C69FBA /* Build configuration list for PBXNativeTarget "MSAL (iOS Framework)" */; buildPhases = ( + D65A6F401E3FD30A00C69FBA /* Headers */, D65A6F3E1E3FD30A00C69FBA /* Sources */, D65A6F3F1E3FD30A00C69FBA /* Frameworks */, - D65A6F401E3FD30A00C69FBA /* Headers */, D65A6F411E3FD30A00C69FBA /* Resources */, + 9BFFD3092968A0A0009866FC /* ShellScript */, ); buildRules = ( ); @@ -3205,11 +4847,13 @@ D6DFF39A1E2579360012891A /* Project object */ = { isa = PBXProject; attributes = { + LastSwiftUpdateCheck = 1410; LastUpgradeCheck = 0820; ORGANIZATIONNAME = Microsoft; TargetAttributes = { 04A6B57A226921890035C7C2 = { CreatedOnToolsVersion = 10.1; + LastSwiftMigration = 1410; ProvisioningStyle = Automatic; }; 04A6B59B2269286F0035C7C2 = { @@ -3229,6 +4873,10 @@ }; }; }; + 28D1D56B29BF62E900CE75F4 = { + CreatedOnToolsVersion = 14.1; + TestTargetID = D672279E1EBD111900F3422A; + }; 962E37A61E720C5D00DE71FE = { DevelopmentTeam = UBF8T346G9; ProvisioningStyle = Automatic; @@ -3267,14 +4915,17 @@ }; D65A6F421E3FD30A00C69FBA = { CreatedOnToolsVersion = 8.2.1; + LastSwiftMigration = 1410; ProvisioningStyle = Automatic; }; D65A6F4F1E3FD32D00C69FBA = { CreatedOnToolsVersion = 8.2.1; + LastSwiftMigration = 1410; ProvisioningStyle = Automatic; }; D65A6FC01E3FF47D00C69FBA = { CreatedOnToolsVersion = 8.2.1; + LastSwiftMigration = 1410; ProvisioningStyle = Manual; TestTargetID = D672279E1EBD111900F3422A; }; @@ -3327,6 +4978,7 @@ 04A6B57A226921890035C7C2 /* MSAL (iOS Static Library) */, 04A6B59B2269286F0035C7C2 /* MSAL (Mac Static Library) */, B295A16322D0348400FFB313 /* unit-test-host-mac */, + 28D1D56B29BF62E900CE75F4 /* MSAL iOS Native Auth Integration Tests */, ); }; /* End PBXProject section */ @@ -3428,6 +5080,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 28D1D56A29BF62E900CE75F4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9B235D9D2A3CC71C00657331 /* NativeAuthEndToEndTestPlan.xctestplan in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 962E37B71E720C5D00DE71FE /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -3516,6 +5176,24 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 9BFFD3092968A0A0009866FC /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\nif which swiftlint > /dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; + }; B286864824037DCB004E83FC /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -3583,64 +5261,170 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + E26097C82948FC720060DD7C /* MSALNativeAuthServerTelemetry.swift in Sources */, + 287708202A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift in Sources */, + E27332C12A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift in Sources */, + 28EDF94229E6D52E00A99F2A /* SignInStartError.swift in Sources */, + DEE34FA2D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift in Sources */, B2D478A9230E3E80005AE186 /* MSALLegacySharedAccountsProvider.m in Sources */, - 8878C61529DC9B09002F5F4B /* MSALCIAMOauth2Provider.m in Sources */, 1E5319C024A51E07007BCF30 /* MSALAuthenticationSchemePop.m in Sources */, B273D0E0226E85E3005A7BB4 /* MSALExtraQueryParameters.m in Sources */, - 1E5319BC24A51DF5007BCF30 /* MSALAuthenticationSchemeBearer.m in Sources */, - 0D96DB3927850E8400DEAF87 /* MSALWipeCacheForAllAccountsConfig.m in Sources */, + DE0D65BA29D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift in Sources */, + DEF9D997296EC35A006CB384 /* MSALNativeAuthTelemetryApiId.swift in Sources */, + 287F64DA2981781A00ED90BD /* MSALNativeAuthSignInParameters.swift in Sources */, + 287F650D2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift in Sources */, + E284F5E529F2F28A00DBED7D /* MSALNativeAuthSignUpControlling.swift in Sources */, + E2EFAD102A69BBB800D6C3DE /* ResetPasswordResults.swift in Sources */, + DE0347C32A41B819003CB3B6 /* MSALNativeAuthUserAccountResult.swift in Sources */, 2343CBF02576C2D3002D405A /* MSALParameters.m in Sources */, B2D478B4230E3E8B005AE186 /* MSALSerializedADALCacheProvider.m in Sources */, 38880DF423280C5900688C24 /* MSALPublicClientApplicationConfig.m in Sources */, + E243F69E29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift in Sources */, B2D478AF230E3E88005AE186 /* MSALLegacySharedAccount.m in Sources */, + DE0D65B729CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift in Sources */, + DE0FECC82993ADAF00B139A8 /* MSALNativeAuthResendCodeParameters.swift in Sources */, B2D47883230E3DC1005AE186 /* MSALADFSOauth2Provider.m in Sources */, + E2EFAD0D2A69B45100D6C3DE /* SignUpResults.swift in Sources */, + E2EFAD0A2A69A34300D6C3DE /* CodeRequiredGenericResult.swift in Sources */, + E2ACA49D2953576C00E98964 /* MSALNativeAuthUrlRequestSerializer.swift in Sources */, B2D4788A230E3DCF005AE186 /* MSALAADOauth2Provider.m in Sources */, + E2C61FF129DEDB0200F15203 /* MSALNativeAuthSignUpContinueResponseError.swift in Sources */, + DE0D657029BF72F7005798B1 /* MSALNativeAuthSignInInitiateRequestParameters.swift in Sources */, B2D478BF230E3EB0005AE186 /* MSALTenantProfile.m in Sources */, + DE0347BC2A41B768003CB3B6 /* MSALNativeAuthCredentialsController.swift in Sources */, + E2ACA4962953415E00E98964 /* MSALNativeAuthGrantType.swift in Sources */, + E2C1D288299BA15D00B26449 /* MSALNativeAuthBaseController.swift in Sources */, B2D47886230E3DC9005AE186 /* MSALB2COauth2Provider.m in Sources */, + 287F64E72981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift in Sources */, 2396EFCD2582D8A500ADA9EB /* MSALSSOExtensionRequestHandler.m in Sources */, 04A6B5C1226937590035C7C2 /* MSALResult.m in Sources */, + 28D5B05E2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift in Sources */, 04A6B60F226938340035C7C2 /* MSALADFSAuthority.m in Sources */, + DEDB298C29D72D62008DA85B /* MSALNativeAuthInnerError.swift in Sources */, + E2F626AB2A780F8200C4A303 /* SignInStates+Internal.swift in Sources */, 886F516629CCA58900F09471 /* MSALCIAMAuthority.m in Sources */, B273D0F0226E8609005A7BB4 /* MSALTokenParameters.m in Sources */, + DEE34F97D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift in Sources */, B2D478AB230E3E84005AE186 /* MSALLegacySharedADALAccount.m in Sources */, + 8D2733152AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift in Sources */, + E2F626B12A78130700C4A303 /* SignInAfterSignUpState+Internal.swift in Sources */, B273D0F1226E860B005A7BB4 /* MSALInteractiveTokenParameters.m in Sources */, 04A6B5B5226937080035C7C2 /* MSALWebviewType.m in Sources */, + DE8EC8B72A053D80003FA561 /* MSALNativeAuthESTSApiErrorCodes.swift in Sources */, B2D47894230E3DEB005AE186 /* MSALOauth2Authority.m in Sources */, B273D0A3226E8576005A7BB4 /* MSALIndividualClaimRequest.m in Sources */, + E2EFACFF2A69915100D6C3DE /* SignInResults.swift in Sources */, 04A6B5B4226937080035C7C2 /* MSALPromptType.m in Sources */, + DE0D65AD29CC6A5A005798B1 /* MSALNativeAuthSignInInitiateResponse.swift in Sources */, + E2C61FE229DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift in Sources */, + DECC1F9729521E35006D9FB1 /* MSALLogMask.m in Sources */, + DE54B5922A434B9B00460B34 /* MSALNativeAuthTokenController.swift in Sources */, + E2C61FEB29DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift in Sources */, + DE0347BD2A41B76E003CB3B6 /* MSALNativeAuthCredentialsControlling.swift in Sources */, + 9B4EE9DA2A1687B600F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift in Sources */, B2D478A7230E3E5A005AE186 /* MSALTelemetryEventsObservingProxy.m in Sources */, + 9BE7E3CC2A1CB70700CC3A62 /* MSALNativeAuthResetPasswordStartRequestProviderParameters.swift in Sources */, B2D478B3230E3E88005AE186 /* NSString+MSALAccountIdenfiers.m in Sources */, + 289747B7297ABEA300838C80 /* MSALNativeAuthInputValidator.swift in Sources */, + 285F36092A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift in Sources */, + 2814B4DB2A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift in Sources */, 04A6B5BD2269374D0035C7C2 /* MSALAccount.m in Sources */, + E2ACA47C29520C2200E98964 /* MSALNativeAuthEndpoint.swift in Sources */, 04A6B6092269382B0035C7C2 /* MSALAuthority.m in Sources */, 04A6B6162269383F0035C7C2 /* MSALOauth2ProviderFactory.m in Sources */, 1E5319C424A51E51007BCF30 /* MSALAuthScheme.m in Sources */, 04A6B5C92269376A0035C7C2 /* MSALErrorConverter.m in Sources */, + E235610F29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift in Sources */, + DEF9D9A0296F08CE006CB384 /* MSALNativeAuthTelemetryProvider.swift in Sources */, + E235613229C9CEA8000E01CA /* MSALNativeAuthSignUpStartRequestParameters.swift in Sources */, + 28FDC4A72A38C00900E38BE1 /* SignInAfterSignUpDelegate.swift in Sources */, 2396EFE82582DEFC00ADA9EB /* MSALDeviceInformation.m in Sources */, + DEF1DD3D2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift in Sources */, B2D478BB230E3E94005AE186 /* MSALExternalAccountHandler.m in Sources */, + E2B853302A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift in Sources */, + DE0347C12A41B7FC003CB3B6 /* SignUpStartError.swift in Sources */, + 8D35C8F22A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift in Sources */, B273D0DC226E85DD005A7BB4 /* MSALSliceConfig.m in Sources */, 04A6B60B2269382E0035C7C2 /* MSALAADAuthority.m in Sources */, + DEF9D99A296EC848006CB384 /* MSALNativeAuthOperationTypes.swift in Sources */, B2D478C5230E3EC5005AE186 /* MSALAccountEnumerationParameters.m in Sources */, B273D0A7226E857B005A7BB4 /* MSALIndividualClaimRequestAdditionalInfo.m in Sources */, + E2F6269E2A780DDE00C4A303 /* MSALNativeAuthPublicClientApplication+Internal.swift in Sources */, + E243F69B29D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift in Sources */, B2D478BD230E3EA8005AE186 /* MSALWebviewParameters.m in Sources */, 04A6B5AE226936F30035C7C2 /* MSALFramework.m in Sources */, + 9BD2763E2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift in Sources */, + E2C61FEE29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift in Sources */, B273D0C3226E85AA005A7BB4 /* MSALGlobalConfig.m in Sources */, + E2C61FE529DED15800F15203 /* MSALNativeAuthSignUpStartResponseError.swift in Sources */, + E243F6AB29D42FE900DAC60F /* MSALNativeAuthSignUpContinueRequestProviderParams.swift in Sources */, + 9B2E93462A0D3813008A5DD2 /* MSALNativeAuthResetPasswordControlling.swift in Sources */, + E2ACA48C2952302B00E98964 /* MSALNativeAuthRequestContext.swift in Sources */, + E243F69529D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift in Sources */, B273D0DA226E85DB005A7BB4 /* MSALLoggerConfig.m in Sources */, + 9BEF84742A31EF70005CB0B6 /* MSALNativeAuthTokenValidatedResponse.swift in Sources */, B273D0CF226E85CC005A7BB4 /* MSALHTTPConfig.m in Sources */, + 287708262A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift in Sources */, + E2DC31BD29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift in Sources */, + E2B8532C2A1531DA007A4776 /* MSALNativeAuthSignUpValidatedResponses.swift in Sources */, 04A6B5D1226937850035C7C2 /* MSALRedirectUriVerifier.m in Sources */, + 287708232A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift in Sources */, 04A6B5B72269371E0035C7C2 /* MSALAccountId.m in Sources */, + E206FC60296D65DE00AF4400 /* MSALNativeAuthInternalError.swift in Sources */, B273D095226E855B005A7BB4 /* MSALRedirectUri.m in Sources */, + DE8EC8752A026BA0003FA561 /* MSALNativeAuthSignInRequestProvider.swift in Sources */, 04A6B5C7226937660035C7C2 /* MSALLogger.m in Sources */, + E206FCF02979BC4600AF4400 /* MSALNativeAuthSignInController.swift in Sources */, + DEF1DD332AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift in Sources */, + E205D62F29B783FF003887BC /* MSALNativeAuthConfiguration.swift in Sources */, + 28F74D55295C90E100B89A78 /* MSALNativeAuthCacheInterface.swift in Sources */, + E243F6A729D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift in Sources */, 04A6B5B1226936FE0035C7C2 /* MSIDVersion.m in Sources */, + E2EFAD172A70300B00D6C3DE /* MSALNativeAuthControllerTelemetryWrapper.swift in Sources */, + E2F626AE2A78119900C4A303 /* ResetPasswordStates+Internal.swift in Sources */, + DE0FECAD2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift in Sources */, + E2D3BC502A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift in Sources */, + E2DC31C929B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift in Sources */, B273D0A0226E8571005A7BB4 /* MSALClaimsRequest.m in Sources */, + E235613529C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift in Sources */, 04A6B5D6226937940035C7C2 /* MSALTelemetry.m in Sources */, + DE9244DE2A31E1D500C0389F /* MSALCIAMOauth2Provider.m in Sources */, + 28E4D9042A30ABA200280921 /* ResendCodeError.swift in Sources */, + 8D35C8E82A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift in Sources */, + E243F6A129D1FF9E00DAC60F /* MSALNativeAuthSignUpContinueRequestParameters.swift in Sources */, + 28FDC4AA2A38C0D100E38BE1 /* SignInAfterSignUpError.swift in Sources */, B2D478AD230E3E88005AE186 /* MSALLegacySharedMSAAccount.m in Sources */, + DE0D65C029D30BAE005798B1 /* MSALNativeAuthResponseError.swift in Sources */, B273D0EA226E85FF005A7BB4 /* MSALPublicClientStatusNotifications.m in Sources */, + 287F65192983F77D00ED90BD /* MSALNativeAuthRequestParametersKey.swift in Sources */, B273D0D5226E85D3005A7BB4 /* MSALTelemetryConfig.m in Sources */, + DE0D657729BF73CB005798B1 /* MSALNativeAuthSignInChallengeRequestParameters.swift in Sources */, + DE1D8AA929E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift in Sources */, + 289747BA297ABEB400838C80 /* MSALNativeAuthParameters.swift in Sources */, + 28F74D54295C90E100B89A78 /* MSALNativeAuthCacheAccessor.swift in Sources */, + E2CD2E8E2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift in Sources */, 04A6B60C226938300035C7C2 /* MSALB2CAuthority.m in Sources */, + DE0347C22A41B80C003CB3B6 /* MSALNativeAuthVerifyCodeParameters.swift in Sources */, + 2826933C2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift in Sources */, + E2F626A82A780F3D00C4A303 /* SignUpStates+Internal.swift in Sources */, + E26097C42948FC4D0060DD7C /* MSALNativeAuthLogging.swift in Sources */, + E2C872C4294CDEE800C4F580 /* MSALNativeAuthRequestable.swift in Sources */, + 9BE7E3D62A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift in Sources */, + 28DE70D729FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift in Sources */, + E2C61FE829DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift in Sources */, B2D478B1230E3E88005AE186 /* MSALLegacySharedAccountFactory.m in Sources */, + 28F19BEC2A2F884D00575581 /* Array+joinScopes.swift in Sources */, + DE729ECE2A1793A100A761D9 /* MSALNativeAuthChannelType.swift in Sources */, + DEF9D98A296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift in Sources */, 2396EFDE2582D8B000ADA9EB /* MSALDeviceInfoProvider.m in Sources */, + E284F5DA29F28B4200DBED7D /* MSALNativeAuthSignUpController.swift in Sources */, + DEE34F49D170B71C00BC302A /* MSALNativeAuthResultFactory.swift in Sources */, + 28FDC49D2A38BFA900E38BE1 /* SignInAfterSignUpState.swift in Sources */, + DE54B5952A43587800460B34 /* MSALNativeAuthTokenRequestProvider.swift in Sources */, 1E5319C824A51FCE007BCF30 /* MSALHttpMethod.m in Sources */, 04A6B5CB226937700035C7C2 /* MSALError.m in Sources */, + 2826932B2A0974750037B93A /* MSALNativeAuthTokenRequestParameters.swift in Sources */, + 2884855D295DAFD400516492 /* MSALNativeAuthTokens.swift in Sources */, B2D4788E230E3DD6005AE186 /* MSALOauth2Provider.m in Sources */, B273D0F3226E860D005A7BB4 /* MSALSilentTokenParameters.m in Sources */, 04A6B5C5226937620035C7C2 /* MSALPublicClientApplication.m in Sources */, @@ -3708,7 +5492,7 @@ B273D0F4226E860D005A7BB4 /* MSALSilentTokenParameters.m in Sources */, 04A6B5C4226937610035C7C2 /* MSALPublicClientApplication.m in Sources */, 04A6B5DD226937AA0035C7C2 /* MSALAccountsProvider.m in Sources */, - 8878C61429DC9B08002F5F4B /* MSALCIAMOauth2Provider.m in Sources */, + DE9244DF2A31E1D500C0389F /* MSALCIAMOauth2Provider.m in Sources */, B273D0C8226E85C4005A7BB4 /* MSALCacheConfig.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3727,6 +5511,38 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 28D1D56829BF62E900CE75F4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DE4F0F3129D6F1AA00D561FD /* MSALNativeAuthTokenIntegrationTests.swift in Sources */, + E25EA4EC2A4C9B75004C8E40 /* MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift in Sources */, + DEFB46F22A52C11400DBC006 /* MSALNativeAuthResetPasswordEndToEndTests.swift in Sources */, + 28D1D59C29C2266500CE75F4 /* Model.swift in Sources */, + 28D1D59E29C2392000CE75F4 /* MockAPIHandlerTest.swift in Sources */, + DE8EC8AC2A026FEF003FA561 /* MSALNativeAuthResetPasswordSubmitIntegrationTests.swift in Sources */, + DE8EC8A82A026FE2003FA561 /* MSALNativeAuthResetPasswordChallengeIntegrationTests.swift in Sources */, + 9B5D6D082A3CA55600521576 /* SignInDelegateSpies.swift in Sources */, + DEFB46F42A52C28100DBC006 /* ResetPasswordDelegateSpies.swift in Sources */, + DEFB46ED2A52BA3700DBC006 /* MSALNativeAuthSignOutEndToEndTests.swift in Sources */, + DE0D65C629D344F1005798B1 /* MSALNativeAuthSignInInitiateIntegrationTests.swift in Sources */, + 28D1D58029BF883D00CE75F4 /* MSALNativeAuthIntegrationBaseTests.swift in Sources */, + DE8EC8A92A026FE7003FA561 /* MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift in Sources */, + DE8EC8AA2A026FEA003FA561 /* MSALNativeAuthResetPasswordStartIntegrationTests.swift in Sources */, + 9B5D6D062A3CA0E300521576 /* MSALNativeAuthSignInUsernameAndPasswordEndToEndTests.swift in Sources */, + DE8EC8AB2A026FEC003FA561 /* MSALNativeAuthResetPasswordContinueIntegrationTests.swift in Sources */, + DE0D65CD29D5CE56005798B1 /* MSALNativeAuthSignInChallengeIntegrationTests.swift in Sources */, + E243F6AF29D446FC00DAC60F /* MSALNativeAuthSignUpStartIntegrationTests.swift in Sources */, + 9B235D9F2A3CFB4300657331 /* MSALNativeAuthEndToEndBaseTestCase.swift in Sources */, + E2BC027529D6E0C600041DBC /* MSALNativeAuthSignUpContinueIntegrationTests.swift in Sources */, + E23E955F29D4B9F7001DC59C /* MSALNativeAuthSignUpChallengeIntegrationTests.swift in Sources */, + 9B235DA12A3CFC4500657331 /* MSALNativeAuthSignInUsernameEndToEndTests.swift in Sources */, + E26E39242A4C2D7400063C07 /* SignUpDelegateSpies.swift in Sources */, + E272C4EC2A4447520013B805 /* MSALNativeAuthSignUpUsernameEndToEndTests.swift in Sources */, + 28D1D59229C2231C00CE75F4 /* MockAPIHandler.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 962E37A91E720C5D00DE71FE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -3832,73 +5648,226 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DE14D75E29897D9500F37BEF /* MSALNativeAuthUrlRequestSerializer.swift in Sources */, + DE14D75D29897D8000F37BEF /* MSALNativeAuthTelemetryApiId.swift in Sources */, B223B0B522ADF8C500FB8713 /* MSALLegacySharedADALAccount.m in Sources */, + DE0D657629BF73CB005798B1 /* MSALNativeAuthSignInChallengeRequestParameters.swift in Sources */, + DE92450E2A38601100C0389F /* MSALNativeAuthCredentialsControlling.swift in Sources */, B267569F228F335E000F01D7 /* MSALExternalAccountHandler.m in Sources */, + E235613129C9CEA8000E01CA /* MSALNativeAuthSignUpStartRequestParameters.swift in Sources */, + DE1D8AA829E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift in Sources */, + DEF1DD322AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift in Sources */, + DE0D65BF29D30BAE005798B1 /* MSALNativeAuthResponseError.swift in Sources */, + 8DDF473F2A98FE1C00126A47 /* MSALNativeAuthRequiredAttributes.swift in Sources */, + 285F36082A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift in Sources */, + DEE34F8CD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift in Sources */, 232D68CC223DB00500594BBD /* MSALTokenParameters.m in Sources */, + E235610E29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift in Sources */, 9D292B1028F05696007FE93C /* MSALWPJMetaData.m in Sources */, 1EF395FF246DFAD200647FDB /* MSALAuthScheme.m in Sources */, + E2C61FF029DEDB0200F15203 /* MSALNativeAuthSignUpContinueResponseError.swift in Sources */, + DEDB298B29D72D62008DA85B /* MSALNativeAuthInnerError.swift in Sources */, + E2C61FE129DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift in Sources */, + DEE34F75D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueRequestParameters.swift in Sources */, + 28DCD0AC29D736BC00C4601E /* SignInPasswordStartError.swift in Sources */, B253153223DD684E00432133 /* MSALSSOExtensionRequestHandler.m in Sources */, 23B1D35F22EA4798000954AF /* MSALPublicClientApplicationConfig.m in Sources */, + E2F626AD2A78119900C4A303 /* ResetPasswordStates+Internal.swift in Sources */, 9626D14E225828780019417B /* MSALGlobalConfig.m in Sources */, + 28A472EC2A276C3B003F988B /* MSALNativeAuthTokenValidatedResponse.swift in Sources */, 96B5E6DC2256D15A002232F9 /* MSALHTTPConfig.m in Sources */, + E2ACA48B2952302B00E98964 /* MSALNativeAuthRequestContext.swift in Sources */, + DEE34F7DD170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitRequestParameters.swift in Sources */, D61F5BCA1E59359900912CB8 /* MSALFramework.m in Sources */, + 28FDC4A62A38C00900E38BE1 /* SignInAfterSignUpDelegate.swift in Sources */, + 28DCD0B429D73BCE00C4601E /* ResetPasswordDelegates.swift in Sources */, B26756DB22922375000F01D7 /* MSALOauth2Authority.m in Sources */, 96B5E6E82256D174002232F9 /* MSALLoggerConfig.m in Sources */, + DEF9D999296EC848006CB384 /* MSALNativeAuthOperationTypes.swift in Sources */, + DECC1F9629521E35006D9FB1 /* MSALLogMask.m in Sources */, B221CEDD20C0AC60002F5E94 /* MSALAccountId.m in Sources */, + E2EFAD0F2A69BBB800D6C3DE /* ResetPasswordResults.swift in Sources */, + 28DCD0AA29D7344000C4601E /* SignInStates.swift in Sources */, + E243F69429D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift in Sources */, + E2C1D287299BA15D00B26449 /* MSALNativeAuthBaseController.swift in Sources */, B2E2A9432393191D00BA2EA3 /* MSIDInteractiveRequestParameters+MSALRequest.m in Sources */, + DEF9D99F296F08CE006CB384 /* MSALNativeAuthTelemetryProvider.swift in Sources */, + DE9245152A3875D700C0389F /* RetrieveAccessTokenError.swift in Sources */, + DE8BE7DC2A1F6BD2009642A5 /* MSALNativeAuthUserAccountResult.swift in Sources */, + 287708252A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift in Sources */, + DEE34F89D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionStatus.swift in Sources */, + 9BE7E3D52A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift in Sources */, + 287F65182983F77D00ED90BD /* MSALNativeAuthRequestParametersKey.swift in Sources */, 04D32CAE1FD615B3000B123E /* MSALErrorConverter.m in Sources */, B26756D222921C6D000F01D7 /* MSALADFSOauth2Provider.m in Sources */, + E26097C32948FC4D0060DD7C /* MSALNativeAuthLogging.swift in Sources */, + 2814B4DA2A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift in Sources */, 232D614C2248484C00260C42 /* MSALClaimsRequest.m in Sources */, B203459621AF77FB00B221AA /* MSALRedirectUri.m in Sources */, + DEE34F7BD170B71C00BC302A /* MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift in Sources */, + DEE34F7FD170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitResponse.swift in Sources */, + E284F5D929F28B4200DBED7D /* MSALNativeAuthSignUpController.swift in Sources */, + E2CD2E8D2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift in Sources */, + 28DCD0A229D7272300C4601E /* SignInDelegates.swift in Sources */, 1EE776C0246C98D300F7EBFC /* MSALAuthenticationSchemeBearer.m in Sources */, + 28DCD0B229D7392400C4601E /* ResetPasswordStates.swift in Sources */, 23A68A7620F5386A0071E435 /* MSALAADAuthority.m in Sources */, + 28DCD09A29D7192F00C4601E /* MSALNativeAuthError.swift in Sources */, + 28DCD09C29D71E7E00C4601E /* SignUpPasswordStartError.swift in Sources */, + 28FDC4A92A38C0D100E38BE1 /* SignInAfterSignUpError.swift in Sources */, 233E96FD22653EFC007FCE2A /* MSALTelemetryEventsObservingProxy.m in Sources */, + DE0D65C229D30C38005798B1 /* MSALNativeAuthSignInInitiateOauth2ErrorCode.swift in Sources */, + E284F5E429F2F28A00DBED7D /* MSALNativeAuthSignUpControlling.swift in Sources */, + DE0FECAC2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift in Sources */, 23A68A7C20F538B90071E435 /* MSALB2CAuthority.m in Sources */, + DEE34F48D170B71C00BC302A /* MSALNativeAuthResultFactory.swift in Sources */, 6077D4A922498D87001798A2 /* MSALTenantProfile.m in Sources */, A0274CD824B54A4E00BD198D /* MSALDevicePopManagerUtil.m in Sources */, + DE9245122A38736600C0389F /* CredentialsDelegates.swift in Sources */, B223B0C022ADFACB00FB8713 /* MSALLegacySharedAccount.m in Sources */, + E2EFACFE2A69915100D6C3DE /* SignInResults.swift in Sources */, D61BD2AF1EBD09F90007E484 /* MSALLogger.m in Sources */, + DEE34F82D170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift in Sources */, B253152C23DD66A300432133 /* MSALDeviceInfoProvider.m in Sources */, + E27332C02A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift in Sources */, + DEDB29A929DDAEB3008DA85B /* MSALNativeAuthTokenOauth2ErrorCode.swift in Sources */, + E206FCEF2979BC4600AF4400 /* MSALNativeAuthSignInController.swift in Sources */, + DE92450C2A385ED800C0389F /* MSALNativeAuthCredentialsController.swift in Sources */, B28BDA90217E9EAB003E5670 /* MSALOauth2ProviderFactory.m in Sources */, B2AA5D6A23A353F200BD47D8 /* MSALSignoutParameters.m in Sources */, + DEE34F65D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeResponse.swift in Sources */, D61BD2B01EBD09F90007E484 /* MSALPublicClientApplication.m in Sources */, + DEDB29AD29DDAF53008DA85B /* MSALNativeAuthTokenResponseError.swift in Sources */, + 2826933B2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift in Sources */, + DE0FECC72993ADAF00B139A8 /* MSALNativeAuthResendCodeParameters.swift in Sources */, + 28EDF94129E6D52E00A99F2A /* SignInStartError.swift in Sources */, D61BD2AD1EBD09F90007E484 /* MSALError.m in Sources */, + DE54B5AD2A459B0400460B34 /* MSALNativeAuthTokenResponseValidator.swift in Sources */, + 28DCD0A829D72F9A00C4601E /* AttributesRequiredError.swift in Sources */, + E2D3BC4F2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift in Sources */, 96B5E6F42256D197002232F9 /* MSALExtraQueryParameters.m in Sources */, 886F516429CCA58900F09471 /* MSALCIAMAuthority.m in Sources */, B223B0C622AE215D00FB8713 /* MSALLegacySharedAccountFactory.m in Sources */, + DEE34F72D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeResponseError.swift in Sources */, + E2B8532F2A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift in Sources */, B26756CC22921C5B000F01D7 /* MSALB2COauth2Provider.m in Sources */, + 28DCD0A029D7260B00C4601E /* MSALNativeAuthBaseState.swift in Sources */, + 287F650C2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift in Sources */, + DEDB29A529DDA9DC008DA85B /* MSALNativeAuthSignInInitiateResponseError.swift in Sources */, + E243F6A629D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift in Sources */, + 287F64D92981781A00ED90BD /* MSALNativeAuthSignInParameters.swift in Sources */, 96B5E6E22256D166002232F9 /* MSALTelemetryConfig.m in Sources */, + 28DCD0A429D72C7100C4601E /* SignUpStates.swift in Sources */, + DE0D65B929D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift in Sources */, + 28D5B05D2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift in Sources */, + DEF9D989296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift in Sources */, B253151B23DD607600432133 /* MSALDeviceInformation.m in Sources */, + 9BD2763D2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift in Sources */, + E2C61FED29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift in Sources */, 963377C1211E14C600943EE0 /* MSALWebviewType.m in Sources */, + E235613429C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift in Sources */, B27CCDF4229F9F4700CAD565 /* MSALAccountEnumerationParameters.m in Sources */, + DEDB29AC29DDAF53008DA85B /* MSALNativeAuthSignInChallengeResponseError.swift in Sources */, + 8D2733142AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift in Sources */, B227037322A4BA3E00030ADC /* MSALLegacySharedAccountsProvider.m in Sources */, - 8878C61229DC9AFB002F5F4B /* MSALCIAMOauth2Provider.m in Sources */, + E2ACA4952953415E00E98964 /* MSALNativeAuthGrantType.swift in Sources */, + DEE34F85D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift in Sources */, + 28F19BEB2A2F884D00575581 /* Array+joinScopes.swift in Sources */, + DE8EC8742A026BA0003FA561 /* MSALNativeAuthSignInRequestProvider.swift in Sources */, 232D616422485BA700260C42 /* MSALIndividualClaimRequestAdditionalInfo.m in Sources */, + 287708222A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift in Sources */, D61BD2BD1EBD0A010007E484 /* MSALTelemetry.m in Sources */, + DEE34F60D170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponseError.swift in Sources */, + 9BE7E3CB2A1CB70700CC3A62 /* MSALNativeAuthResetPasswordStartRequestProviderParameters.swift in Sources */, + DE54B5912A434B9B00460B34 /* MSALNativeAuthTokenController.swift in Sources */, + DEE34F8DD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponseError.swift in Sources */, D61BD2B11EBD09F90007E484 /* MSALResult.m in Sources */, 232D615E22485B4600260C42 /* MSALIndividualClaimRequest.m in Sources */, + DE54B5942A43587800460B34 /* MSALNativeAuthTokenRequestProvider.swift in Sources */, B26756C022921A71000F01D7 /* MSALOauth2Provider.m in Sources */, + E2C872C3294CDEE800C4F580 /* MSALNativeAuthRequestable.swift in Sources */, 1E72193B24773D1B00AB9B67 /* MSALHttpMethod.m in Sources */, + E243F69D29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift in Sources */, + DEE34F96D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift in Sources */, + 289E15592948E601006104D9 /* MSALNativeAuthCacheInterface.swift in Sources */, + 289E156D2948EB8A006104D9 /* MSALNativeAuthCacheAccessor.swift in Sources */, + E2C61FE729DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift in Sources */, + 289747B129799C6B00838C80 /* MSALNativeAuthInputValidator.swift in Sources */, + DEE34F7AD170B71C00BC302A /* MSALNativeAuthResetPasswordContinueResponseError.swift in Sources */, + 2884855C295DAFD400516492 /* MSALNativeAuthTokens.swift in Sources */, + 28E4D9032A30ABA200280921 /* ResendCodeError.swift in Sources */, + E2F6269D2A780DDE00C4A303 /* MSALNativeAuthPublicClientApplication+Internal.swift in Sources */, + DEE34F83D170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitResponseError.swift in Sources */, D61BD2C91EBD0A0F0007E484 /* MSALAuthority.m in Sources */, + E243F69A29D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift in Sources */, + DEE34F73D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift in Sources */, + DEDB29A829DDAEB3008DA85B /* MSALNativeAuthSignInChallengeOauth2ErrorCode.swift in Sources */, + DE03478A2A39ED6A003CB3B6 /* MSALCIAMOauth2Provider.m in Sources */, + E205D62E29B783FF003887BC /* MSALNativeAuthConfiguration.swift in Sources */, D61BD2B21EBD09F90007E484 /* MSALAccount.m in Sources */, + 287F64E92981786A00ED90BD /* MSALNativeAuthVerifyCodeParameters.swift in Sources */, + DE0D65B629CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift in Sources */, + E2EFAD092A69A34300D6C3DE /* CodeRequiredGenericResult.swift in Sources */, + E2EFAD0C2A69B45100D6C3DE /* SignUpResults.swift in Sources */, + DE0D65AC29CC6A5A005798B1 /* MSALNativeAuthSignInInitiateResponse.swift in Sources */, B266391C22B4B84600FEB673 /* NSString+MSALAccountIdenfiers.m in Sources */, + DEE34F87D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponse.swift in Sources */, 96B5E6D02256D152002232F9 /* MSALCacheConfig.m in Sources */, + 287F64E62981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift in Sources */, + E243F6A029D1FF9E00DAC60F /* MSALNativeAuthSignUpContinueRequestParameters.swift in Sources */, + DEE34F5CD170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponse.swift in Sources */, + DEE34FA1D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift in Sources */, + 9B2E93452A0D3801008A5DD2 /* MSALNativeAuthResetPasswordControlling.swift in Sources */, 232D68DE223DBA0700594BBD /* MSALInteractiveTokenParameters.m in Sources */, + E2B8532B2A1531DA007A4776 /* MSALNativeAuthSignUpValidatedResponses.swift in Sources */, + 28DCD0A629D72F6600C4601E /* PasswordRequiredError.swift in Sources */, + E2C61FE429DED15800F15203 /* MSALNativeAuthSignUpStartResponseError.swift in Sources */, + E243F6AA29D42FE900DAC60F /* MSALNativeAuthSignUpContinueRequestProviderParams.swift in Sources */, B2C17B0A1FC8DB2E0070A514 /* MSIDVersion.m in Sources */, + E2DC31C829B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift in Sources */, + 28DCD0AE29D737E600C4601E /* VerifyCodeError.swift in Sources */, + 289747B42979A3C800838C80 /* MSALNativeAuthParameters.swift in Sources */, + E2F626B02A78130700C4A303 /* SignInAfterSignUpState+Internal.swift in Sources */, B26756C622921C42000F01D7 /* MSALAADOauth2Provider.m in Sources */, + DEE34F12D170B71C00BC302A /* MSALNativeAuthResetPasswordStartRequestParameters.swift in Sources */, + 8D35C8E72A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift in Sources */, + 28DCD09229D7166F00C4601E /* SignUpDelegates.swift in Sources */, + DE0D656F29BF72F7005798B1 /* MSALNativeAuthSignInInitiateRequestParameters.swift in Sources */, + E2F626AA2A780F8200C4A303 /* SignInStates+Internal.swift in Sources */, 2338295722D7E49F001B8AD6 /* MSALWebviewParameters.m in Sources */, + E2F626A72A780F3D00C4A303 /* SignUpStates+Internal.swift in Sources */, + 2826932A2A0974750037B93A /* MSALNativeAuthTokenRequestParameters.swift in Sources */, + 28EDF93E29E6D43900A99F2A /* SignUpStartError.swift in Sources */, + DE94C9F029F2AF5E00C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParameters.swift in Sources */, D61BD2B31EBD09F90007E484 /* MSALPromptType.m in Sources */, + DEC1E425298BE18A00948BED /* MSALNativeAuthServerTelemetry.swift in Sources */, + 9B4EE9D82A1687AE00F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift in Sources */, + DEE34F61D170B71C00BC302A /* MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift in Sources */, + 28FDC49C2A38BFA900E38BE1 /* SignInAfterSignUpState.swift in Sources */, + 28DCD0B029D738DD00C4601E /* ResetPasswordStartError.swift in Sources */, B28BBD352211DC7D00F51723 /* MSALPublicClientStatusNotifications.m in Sources */, 23A68A8220F538DE0071E435 /* MSALADFSAuthority.m in Sources */, B29A56C222826EE20023F5E6 /* MSALSerializedADALCacheProvider.m in Sources */, B2C0E79F23AC7996006C9CAD /* MSALParameters.m in Sources */, + DE8EC8B62A053D80003FA561 /* MSALNativeAuthESTSApiErrorCodes.swift in Sources */, B21E07B3210E542C007E3A3C /* MSALRedirectUriVerifier.m in Sources */, + E2C61FEA29DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift in Sources */, 0D96DB3727850E3900DEAF87 /* MSALWipeCacheForAllAccountsConfig.m in Sources */, + DEE34F77D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueResponse.swift in Sources */, 96B5E6EE2256D180002232F9 /* MSALSliceConfig.m in Sources */, + 9B839A102A4D7CF600BCC6F6 /* MSAL.docc in Sources */, B2A3C28B2145FD0F0082525C /* MSALAccountsProvider.m in Sources */, + E2ACA47B29520C2200E98964 /* MSALNativeAuthEndpoint.swift in Sources */, 1EE776C6246C98E700F7EBFC /* MSALAuthenticationSchemePop.m in Sources */, + E2DC31BC29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift in Sources */, + 8D35C8F12A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift in Sources */, B223B0BA22ADF8E600FB8713 /* MSALLegacySharedMSAAccount.m in Sources */, + 2877081F2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift in Sources */, + E206FC5F296D65DE00AF4400 /* MSALNativeAuthInternalError.swift in Sources */, 232D68D8223DB8C200594BBD /* MSALSilentTokenParameters.m in Sources */, + DE729ECD2A1793A100A761D9 /* MSALNativeAuthChannelType.swift in Sources */, + E2EFAD162A70300B00D6C3DE /* MSALNativeAuthControllerTelemetryWrapper.swift in Sources */, + 28DE70D629FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3927,12 +5896,13 @@ D673F08F1E4CE6D70018BA91 /* MSALError.m in Sources */, 23A68A8320F538DE0071E435 /* MSALADFSAuthority.m in Sources */, 9D292B1128F05696007FE93C /* MSALWPJMetaData.m in Sources */, - 8878C61329DC9B07002F5F4B /* MSALCIAMOauth2Provider.m in Sources */, + DE9244DD2A31E1D500C0389F /* MSALCIAMOauth2Provider.m in Sources */, 23A68A7720F5386A0071E435 /* MSALAADAuthority.m in Sources */, 2338295822D7E49F001B8AD6 /* MSALWebviewParameters.m in Sources */, 1EF39600246DFAD200647FDB /* MSALAuthScheme.m in Sources */, 583BFD1024DC8EE80035B901 /* MSALRedirectUriVerifier.m in Sources */, B28BDA91217E9EAB003E5670 /* MSALOauth2ProviderFactory.m in Sources */, + 9B839A112A4D7CF600BCC6F6 /* MSAL.docc in Sources */, 96B5E6F52256D197002232F9 /* MSALExtraQueryParameters.m in Sources */, B26756CD22921C5B000F01D7 /* MSALB2COauth2Provider.m in Sources */, 96B5E6E32256D166002232F9 /* MSALTelemetryConfig.m in Sources */, @@ -3977,38 +5947,125 @@ 23A169B52073325500B051F3 /* MSALPublicClientApplicationTests.m in Sources */, D61F5BC01E5913BE00912CB8 /* SFSafariViewController+TestOverrides.m in Sources */, B2725ED022C04689009B454A /* MSALLegacySharedAccountFactoryTests.m in Sources */, + E20C218B2A7A805900E31598 /* SignInPasswordRequiredStateTests.swift in Sources */, + E20C21752A7A61B600E31598 /* SignUpDelegateSpies.swift in Sources */, + E2F5BE9D298A6CEB00C67EC7 /* MSALNativeAuthResultFactoryTests.swift in Sources */, + DE14096B2A38DE0E008E6F1E /* CredentialsDelegateSpies.swift in Sources */, + DEDB29B129DEC770008DA85B /* MSALNativeAuthRequestErrorHandlerTests.swift in Sources */, D69ADB3F1E516F9B00952049 /* MSALTestURLSessionDataTask.m in Sources */, + DEF1DD3C2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift in Sources */, B256121B217EA44900999876 /* MSALOauth2FactoryProducerTests.m in Sources */, + DECC1FB5295322A8006D9FB1 /* MSALNativeLoggingTests.swift in Sources */, D62746D91E9B5F1E00EFCE99 /* MSALAccountTests.m in Sources */, D69ADB3D1E516F9B00952049 /* MSIDTestURLSession+MSAL.m in Sources */, 2364C74B1FB3E5CB00835428 /* XCTestCase+HelperMethods.m in Sources */, + DEDD6F0829E83FD20017989F /* MSALNativeAuthRequestConfiguratorTests.swift in Sources */, B2725EB522BF2774009B454A /* MSALPublicClientApplicationAccountUpdateTests.m in Sources */, + E25BC07A2995423100588549 /* MSALNativeAuthNetworkMocks.swift in Sources */, + E22E20282A7936C50073A6FF /* MSALNativeAuthSignUpControllerMock.swift in Sources */, + DE94C9E429F19C4C00C1EC1F /* MSALNativeAuthResetPasswordContinueRequestParametersTest.swift in Sources */, B2725ECC22C0466E009B454A /* MSALLegacySharedADALAccountTests.m in Sources */, + DE0347A82A41AD08003CB3B6 /* MSALNativeAuthUserAccountResultStub.swift in Sources */, + E2CD2EB32A040012009F8FFA /* SignUpTestsValidatorHelpers.swift in Sources */, 23F32F0C1FF4789100B2905E /* MSIDTestURLResponse+MSAL.m in Sources */, D61F5BC31E59193500912CB8 /* MSALFakeViewController.m in Sources */, + DE5738B62A8E790100D9120D /* MSALNativeAuthTokenValidatedErrorTypeTests.swift in Sources */, + 9BB5180B2A2A2B5B00D6276A /* MSALNativeAuthResetPasswordControllerSpy.swift in Sources */, + DE94C9E229F19AA200C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift in Sources */, + E2F5BE8E29893A4100C67EC7 /* MSALNativeAuthEndpointTests.swift in Sources */, + 287F64F0298186EA00ED90BD /* MSALNativeAuthInputValidatorTest.swift in Sources */, + 8D61F9A12A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift in Sources */, 04D32CD01FD8AFF3000B123E /* MSALErrorConverterTests.m in Sources */, + E2F4DB2D2A1F5714009FBCD0 /* MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift in Sources */, + 287F6524298401AE00ED90BD /* MSALNativeAuthResponseSerializerTests.swift in Sources */, + E2CD2E4F29FC0451009F8FFA /* SignUpPasswordRequiredStateTests.swift in Sources */, + E2EBD6212A1BB4640049467A /* MSALNativeAuthSignUpRequestProviderMock.swift in Sources */, + E2F4DB242A1F525A009FBCD0 /* MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift in Sources */, A0274CDD24B54C8800BD198D /* MSALDevicePopManagerUtil.m in Sources */, + DE5738B82A8F76C600D9120D /* MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift in Sources */, + 9B2BBA372A3298080075F702 /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift in Sources */, B2725E7F22BD88BE009B454A /* NSStringAccountIdentifiersTest.m in Sources */, + 287F64D4297EC29400ED90BD /* MSALNativeAuthTelemetryProviderTests.swift in Sources */, + E22952682A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift in Sources */, + E286E2DD2A1BAEA800666DD0 /* MSALNativeAuthSignUpControllerTests.swift in Sources */, B2725EC522BF4865009B454A /* MSALMockExternalAccountHandler.m in Sources */, + 9BD2765F2A0E81CE00FBD033 /* ResetPasswordRequiredStateTests.swift in Sources */, D69ADB371E516F9B00952049 /* MSALTestCase.m in Sources */, + DE94C9E829F19E6B00C1EC1F /* MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift in Sources */, + DE0D659529C1DCC9005798B1 /* MSALNativeAuthSignInInitiateRequestParametersTest.swift in Sources */, + E2CD2E5129FC087A009F8FFA /* SignUpAttributesRequiredStateTests.swift in Sources */, + 28DE3FD02A0921E2003148A4 /* SignInTestsValidatorHelpers.swift in Sources */, B2725ECE22C04679009B454A /* MSALLegacySharedMSAAccountTests.m in Sources */, + 9B2BBA332A3297EA0075F702 /* MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift in Sources */, + 28CA6F5D29689F34004DB11D /* MSALNativeAuthCacheAccessorTest.swift in Sources */, + E2BC029829D766A800041DBC /* MSALNativeAuthSignUpChallengeRequestParametersTest.swift in Sources */, + DE5738C02A8F7C2000D9120D /* MSALNativeAuthSignUpStartResponseErrorTests.swift in Sources */, 233E970B226571AB007FCE2A /* MSALTelemetryAggregatedTests.m in Sources */, B2725ECA22C04661009B454A /* MSALLegacySharedAccountTests.m in Sources */, + 28B6494D2A0959EB00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTest.swift in Sources */, B253153B23DD717900432133 /* MSALDeviceInfoProviderTests.m in Sources */, + 9B61C91C2A27E57C00CE9E3A /* MSALNativeAuthResetPasswordResponseValidatorMock.swift in Sources */, + DE40A4D32A8F80C100928CEE /* MSALNativeAuthSignUpContinueResponseErrorTests.swift in Sources */, + DE94C9E029F198D600C1EC1F /* MSALNativeAuthResetPasswordStartRequestParametersTest.swift in Sources */, + DE14096D2A38DF41008E6F1E /* MSALNativeAuthCredentialsControllerTests.swift in Sources */, + DE5738B42A8E74DC00D9120D /* MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift in Sources */, + DE87DE6A2A39E80B0032BF9E /* MSALNativeAuthUserAccountResultTests.swift in Sources */, + E2BDD98B2A28FBDD00E3ED6B /* MSALNativeAuthErrorRequiredAttributesTests.swift in Sources */, + E2CD2E4A29FBEA36009F8FFA /* SignUpCodeSentStateTests.swift in Sources */, 23A68A9320F59E6B0071E435 /* NSString+MSALTestUtil.m in Sources */, + E25E6E512AA7725F0094461E /* MSALNativeAuthResetPasswordControllerMock.swift in Sources */, + 9B61C9132A27E51900CE9E3A /* MSALNativeAuthResetPasswordRequestProviderMock.swift in Sources */, 1E8FC6A3221F370C00B4D4C1 /* MSALResultTests.m in Sources */, + DE0D659629C1DCCC005798B1 /* MSALNativeAuthSignInChallengeRequestParametersTest.swift in Sources */, + 9BD2765A2A0E7E6F00FBD033 /* ResetPasswordTestValidatorHelpers.swift in Sources */, + DECC1FB329531032006D9FB1 /* MSALLogMaskTests.m in Sources */, B2ADD76E22C08B6A0093FD43 /* MSALLegacySharedAccountTestUtil.m in Sources */, 58B81F7124AC5D7200E8799E /* MSALTestCacheTokenResponse.m in Sources */, + DE0D659729C1DCCF005798B1 /* MSALNativeAuthTokenRequestParametersTest.swift in Sources */, + E25BC099299555C000588549 /* MSALNativeAuthTelemetryTestDispatcher.swift in Sources */, + E25BC0832995429D00588549 /* MSALNativeAuthCacheMocks.swift in Sources */, 960751BB2183E82C00F2BF2F /* MSALAccountIdTests.m in Sources */, + E20C217E2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift in Sources */, + E248917A2A1CFA6B001ECBE2 /* MSALNativeAuthConfigStubs.swift in Sources */, + 9B2BBA352A3297F80075F702 /* MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift in Sources */, + 287F64D5297EC29400ED90BD /* MSALNativeAuthCurrentRequestTelemetryTests.swift in Sources */, A0274CBE24B432B100BD198D /* MSALAuthSchemeTests.m in Sources */, B286BA00238A08F6007833AD /* MSALB2CPolicyTests.m in Sources */, + 9B2BBA2F2A3293330075F702 /* MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift in Sources */, + DE5738BC2A8F79A800D9120D /* MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift in Sources */, + E2EBD62A2A1BB7700049467A /* MSALNativeAuthSignUpResponseValidatorMock.swift in Sources */, + E25BC0852995430B00588549 /* MSALNativeAuthFactoriesMocks.swift in Sources */, + E2BC029C29D766CB00041DBC /* MSALNativeAuthSignUpContinueRequestParametersTest.swift in Sources */, + E2960A112A1F4D2F000F441B /* MSALNativeAuthSignUpChallengeResponseErrorTests.swift in Sources */, + DE94C9E629F19D9B00C1EC1F /* MSALNativeAuthResetPasswordSubmitRequestParametersTest.swift in Sources */, + 289747AC2979487900838C80 /* MSALNativeAuthUrlRequestSerializerTests.swift in Sources */, + DE14D76129898CF900F37BEF /* MSALNativeAuthTestCase.swift in Sources */, B2725ED222C0469A009B454A /* MSALLegacySharedAccountsProviderTests.m in Sources */, + E2BC029A29D766B200041DBC /* MSALNativeAuthSignUpStartRequestParametersTest.swift in Sources */, + E2C1D2D429A3992100B26449 /* MSALNativeAuthBaseControllerTests.swift in Sources */, + DE40A4CA2A8F801200928CEE /* MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift in Sources */, + E23E956929D5BD6B001DC59C /* MSALNativeAuthSignUpRequestProviderTests.swift in Sources */, + DE5738BE2A8F7AC600D9120D /* MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift in Sources */, 609AF9332256BD0C00E2978D /* MSALAccountsProviderTests.m in Sources */, + DE54B59F2A4452DB00460B34 /* MSALNativeAuthTokenResponseValidatorTests.swift in Sources */, + DE5738BA2A8F780E00D9120D /* MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift in Sources */, + E20C21842A7A6CA400E31598 /* SignInCodeRequiredStateTests.swift in Sources */, B2725EAC22BF2759009B454A /* MSALExternalAccountHandlerTests.m in Sources */, 232D6192224C53E500260C42 /* MSALClaimsRequestTests.m in Sources */, + 9B2BBA312A3296010075F702 /* MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift in Sources */, + E25E6E5A2AA7727D0094461E /* MSALNativeAuthCredentialsControllerMock.swift in Sources */, B286B9FD238A07A5007833AD /* MSALAcquireTokenTests.m in Sources */, + DE5738B22A8E71D500D9120D /* MSALNativeAuthResetPasswordContinueResponseErrorTests.swift in Sources */, + 9B6EECEF2A3146ED008ABA50 /* MSALNativeAuthResetPasswordResponseValidatorTests.swift in Sources */, + 28FDC4AE2A38D81100E38BE1 /* MSALNativeAuthSignInControllerMock.swift in Sources */, B281B33B226BC225009619AB /* MSALPublicClientApplicationConfigTests.m in Sources */, + E2F5BE9A29896ADB00C67EC7 /* MSALNativeAuthSignInControllerTests.swift in Sources */, + 9B4EE9D52A1686A900F243C1 /* MSALNativeAuthResetPasswordControllerTests.swift in Sources */, B29A56D52283D7430023F5E6 /* MSALAADAuthorityTests.m in Sources */, + 287F64F32981A00400ED90BD /* MSALNativeAuthPublicClientApplicationTest.swift in Sources */, + E2CD2EB52A0404DA009F8FFA /* MSALNativeAuthSignUpControllerSpy.swift in Sources */, + 9BD2765B2A0E7E7D00FBD033 /* ResetPasswordCodeSentStateTests.swift in Sources */, + E2F626B32A781CE300C4A303 /* SignInDelegatesSpies.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4075,6 +6132,16 @@ name = "IdentityTest Mac"; targetProxy = 231CE9DA1FEC678400E95D3E /* PBXContainerItemProxy */; }; + 28D1D57229BF62E900CE75F4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D65A6F421E3FD30A00C69FBA /* MSAL (iOS Framework) */; + targetProxy = 28D1D57129BF62E900CE75F4 /* PBXContainerItemProxy */; + }; + 28D1D57E29BF633900CE75F4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D672279E1EBD111900F3422A /* unit-test-host */; + targetProxy = 28D1D57D29BF633900CE75F4 /* PBXContainerItemProxy */; + }; 58BBA13325C141CA007B3EF6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D65A6F421E3FD30A00C69FBA /* MSAL (iOS Framework) */; @@ -4197,12 +6264,20 @@ isa = XCBuildConfiguration; baseConfigurationReference = 04A6B584226921CD0035C7C2 /* msal__static__lib__ios.xcconfig */; buildSettings = { + CLANG_ENABLE_MODULES = YES; COPY_PHASE_STRIP = NO; ENABLE_BITCODE = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_NAME = "MSAL (iOS Static Library)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -4210,11 +6285,18 @@ isa = XCBuildConfiguration; baseConfigurationReference = 04A6B584226921CD0035C7C2 /* msal__static__lib__ios.xcconfig */; buildSettings = { + CLANG_ENABLE_MODULES = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_BITCODE = NO; IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_NAME = "MSAL (iOS Static Library)"; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -4293,7 +6375,10 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = "$(SRCROOT)/test/app/mac/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -4302,7 +6387,11 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; - USER_HEADER_SEARCH_PATHS = "$(inherited) $IDCORE_PATH/src/** $(HOME)/aadoverrides"; + USER_HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$IDCORE_PATH/src/**", + "$(HOME)/aadoverrides", + ); }; name = Debug; }; @@ -4356,7 +6445,10 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = "$(SRCROOT)/test/app/mac/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -4364,7 +6456,161 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; - USER_HEADER_SEARCH_PATHS = "$(inherited) $IDCORE_PATH/src/** $(HOME)/aadoverrides"; + USER_HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$IDCORE_PATH/src/**", + "$(HOME)/aadoverrides", + ); + }; + name = Release; + }; + 28D1D57329BF62E900CE75F4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Manual; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = ""; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + HEADER_SEARCH_PATHS = $SRCROOT; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.microsoft.MSAL-iOS-Native-Auth-Integration-Tests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/unit-test-host.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/unit-test-host"; + USER_HEADER_SEARCH_PATHS = ( + "$(inherited)", + $IDCORE_PATH/src, + ); + }; + name = Debug; + }; + 28D1D57429BF62E900CE75F4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Manual; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = ""; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + HEADER_SEARCH_PATHS = $SRCROOT; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.microsoft.MSAL-iOS-Native-Auth-Integration-Tests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/unit-test-host.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/unit-test-host"; + USER_HEADER_SEARCH_PATHS = ( + "$(inherited)", + $IDCORE_PATH/src, + ); + VALIDATE_PRODUCT = YES; }; name = Release; }; @@ -4381,7 +6627,10 @@ GCC_OPTIMIZATION_LEVEL = 0; INFOPLIST_FILE = "$(SRCROOT)/test/automation/ios/resources/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MSALAutomationApp; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 4.0; @@ -4400,7 +6649,10 @@ ENABLE_BITCODE = NO; INFOPLIST_FILE = "$(SRCROOT)/test/automation/ios/resources/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MSALAutomationApp; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 4.0; @@ -4458,7 +6710,10 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = "$(SRCROOT)/test/unit/mac/unit-test-host/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -4519,7 +6774,10 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = "$(SRCROOT)/test/unit/mac/unit-test-host/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -4584,7 +6842,11 @@ GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = test/automation/tests/interactive/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MultiAppiOSTests; @@ -4648,7 +6910,11 @@ GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = test/automation/tests/interactive/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MultiAppiOSTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -4714,7 +6980,11 @@ GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = test/automation/tests/interactive/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks @executable_path/Frameworks $(inherited)"; + LD_RUNPATH_SEARCH_PATHS = ( + "@loader_path/Frameworks", + "@executable_path/Frameworks", + "$(inherited)", + ); MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.InteractiveiOSTests; @@ -4779,7 +7049,11 @@ GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = test/automation/tests/interactive/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks @executable_path/Frameworks $(inherited)"; + LD_RUNPATH_SEARCH_PATHS = ( + "@loader_path/Frameworks", + "@executable_path/Frameworks", + "$(inherited)", + ); MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.InteractiveiOSTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -4795,6 +7069,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = D61A64661E5AA6B40086D120 /* msal__test_app__ios.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = ""; CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; CODE_SIGN_ENTITLEMENTS = "MSAL Test App.entitlements"; @@ -4806,11 +7081,18 @@ GCC_OPTIMIZATION_LEVEL = 0; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MSALTestApp; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = "iOS Team Provisioning Profile"; - USER_HEADER_SEARCH_PATHS = "$(inherited) $IDCORE_PATH/src/** $(HOME)/aadoverrides"; + USER_HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$IDCORE_PATH/src/**", + "$(HOME)/aadoverrides", + ); }; name = Debug; }; @@ -4818,6 +7100,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = D61A64661E5AA6B40086D120 /* msal__test_app__ios.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = ""; CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; CODE_SIGN_ENTITLEMENTS = "MSAL Test App.entitlements"; @@ -4827,10 +7110,17 @@ ENABLE_BITCODE = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MSALTestApp; PROVISIONING_PROFILE = ""; - USER_HEADER_SEARCH_PATHS = "$(inherited) $IDCORE_PATH/src/** $(HOME)/aadoverrides"; + USER_HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$IDCORE_PATH/src/**", + "$(HOME)/aadoverrides", + ); }; name = Release; }; @@ -4838,14 +7128,27 @@ isa = XCBuildConfiguration; baseConfigurationReference = D65A6FE71E40002800C69FBA /* msal__framework__ios.xcconfig */; buildSettings = { + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; GCC_OPTIMIZATION_LEVEL = 0; + HEADER_SEARCH_PATHS = $SRCROOT; IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MARKETING_VERSION = 1.1.24; - USER_HEADER_SEARCH_PATHS = "$(inherited) $IDCORE_PATH/src/**"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + USER_HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$IDCORE_PATH/src/**", + ); }; name = Debug; }; @@ -4853,13 +7156,25 @@ isa = XCBuildConfiguration; baseConfigurationReference = D65A6FE71E40002800C69FBA /* msal__framework__ios.xcconfig */; buildSettings = { + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; + HEADER_SEARCH_PATHS = $SRCROOT; IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MARKETING_VERSION = 1.1.24; - USER_HEADER_SEARCH_PATHS = "$(inherited) $IDCORE_PATH/src/**"; + SWIFT_VERSION = 5.0; + USER_HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$IDCORE_PATH/src/**", + ); }; name = Release; }; @@ -4867,11 +7182,21 @@ isa = XCBuildConfiguration; baseConfigurationReference = D65A6FEB1E40002800C69FBA /* msal__framework__mac.xcconfig */; buildSettings = { + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "-"; + DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; GCC_OPTIMIZATION_LEVEL = 0; + HEADER_SEARCH_PATHS = $SRCROOT; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 10.13; MARKETING_VERSION = 1.1.24; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -4879,10 +7204,19 @@ isa = XCBuildConfiguration; baseConfigurationReference = D65A6FEB1E40002800C69FBA /* msal__framework__mac.xcconfig */; buildSettings = { + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "-"; + DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; + HEADER_SEARCH_PATHS = $SRCROOT; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 10.13; MARKETING_VERSION = 1.1.24; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -4891,15 +7225,30 @@ baseConfigurationReference = D65A6FE91E40002800C69FBA /* msal__unit_test__ios.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; + DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; GCC_OPTIMIZATION_LEVEL = 0; + HEADER_SEARCH_PATHS = $SRCROOT; IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/unit-test-host.app/unit-test-host"; - USER_HEADER_SEARCH_PATHS = "$(inherited) $IDCORE_PATH/src/** $IDCORE_PATH/tests/util/** $IDCORE_PATH/tests/mocks/**"; + USER_HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$IDCORE_PATH/src/**", + "$IDCORE_PATH/tests/util/**", + "$IDCORE_PATH/tests/mocks/**", + ); }; name = Debug; }; @@ -4908,14 +7257,28 @@ baseConfigurationReference = D65A6FE91E40002800C69FBA /* msal__unit_test__ios.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; + DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; + HEADER_SEARCH_PATHS = $SRCROOT; IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/unit-test-host.app/unit-test-host"; - USER_HEADER_SEARCH_PATHS = "$(inherited) $IDCORE_PATH/src/** $IDCORE_PATH/tests/util/** $IDCORE_PATH/tests/mocks/**"; + USER_HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$IDCORE_PATH/src/**", + "$IDCORE_PATH/tests/util/**", + "$IDCORE_PATH/tests/mocks/**", + ); }; name = Release; }; @@ -4929,7 +7292,12 @@ MACOSX_DEPLOYMENT_TARGET = 10.13; PROVISIONING_PROFILE_SPECIFIER = ""; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/unit-test-host-mac.app/Contents/MacOS/unit-test-host-mac"; - USER_HEADER_SEARCH_PATHS = "$(inherited) $IDCORE_PATH/src/** $IDCORE_PATH/tests/util/** $IDCORE_PATH/tests/mocks/**"; + USER_HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$IDCORE_PATH/src/**", + "$IDCORE_PATH/tests/util/**", + "$IDCORE_PATH/tests/mocks/**", + ); }; name = Debug; }; @@ -4942,7 +7310,12 @@ MACOSX_DEPLOYMENT_TARGET = 10.13; PROVISIONING_PROFILE_SPECIFIER = ""; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/unit-test-host-mac.app/Contents/MacOS/unit-test-host-mac"; - USER_HEADER_SEARCH_PATHS = "$(inherited) $IDCORE_PATH/src/** $IDCORE_PATH/tests/util/** $IDCORE_PATH/tests/mocks/**"; + USER_HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$IDCORE_PATH/src/**", + "$IDCORE_PATH/tests/util/**", + "$IDCORE_PATH/tests/mocks/**", + ); }; name = Release; }; @@ -5024,6 +7397,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 28D1D57C29BF62E900CE75F4 /* Build configuration list for PBXNativeTarget "MSAL iOS Native Auth Integration Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 28D1D57329BF62E900CE75F4 /* Debug */, + 28D1D57429BF62E900CE75F4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 962E37B91E720C5D00DE71FE /* Build configuration list for PBXNativeTarget "MSAL Test Automation (iOS)" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/unit-test-host-mac.xcscheme b/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/unit-test-host-mac.xcscheme new file mode 100644 index 0000000000..bdbc8c05a6 --- /dev/null +++ b/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/unit-test-host-mac.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/unit-test-host.xcscheme b/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/unit-test-host.xcscheme new file mode 100644 index 0000000000..1dbe886ea0 --- /dev/null +++ b/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/unit-test-host.xcscheme @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MSAL/NativeAuthEndToEndTestPlan.xctestplan b/MSAL/NativeAuthEndToEndTestPlan.xctestplan new file mode 100644 index 0000000000..8d6fef7036 --- /dev/null +++ b/MSAL/NativeAuthEndToEndTestPlan.xctestplan @@ -0,0 +1,77 @@ +{ + "configurations" : [ + { + "id" : "2A21CE4F-3AC3-481A-97AE-43C3291B8CD2", + "name" : "Test Tenant", + "options" : { + "environmentVariableEntries" : [ + { + "key" : "clientId", + "value" : "" + }, + { + "key" : "existingPasswordUserEmail", + "value" : "" + }, + { + "key" : "existingUserPassword", + "value" : "" + }, + { + "key" : "authorityURL", + "value" : "" + } + ] + } + }, + { + "id" : "0A110D07-5D21-4B70-8C37-00FF79C890B1", + "name" : "Mock API", + "options" : { + "environmentVariableEntries" : [ + { + "key" : "authorityURL", + "value" : "" + }, + { + "key" : "existingOTPUserEmail", + "value" : "" + }, + { + "key" : "existingPasswordUserEmail", + "value" : "" + }, + { + "key" : "existingUserPassword", + "value" : "" + }, + { + "key" : "clientId", + "value" : "" + }, + { + "key" : "useMockAPI", + "value" : "true" + }, + { + "key" : "mockAPIURL", + "value" : "" + } + ] + } + } + ], + "defaultOptions" : { + "testTimeoutsEnabled" : true + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:MSAL.xcodeproj", + "identifier" : "28D1D56B29BF62E900CE75F4", + "name" : "MSAL iOS Native Auth Integration Tests" + } + } + ], + "version" : 1 +} diff --git a/MSAL/module.modulemap b/MSAL/module.modulemap new file mode 100644 index 0000000000..89b8801f0b --- /dev/null +++ b/MSAL/module.modulemap @@ -0,0 +1,100 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//------------------------------------------------------------------------------ + +module MSAL_Private { + header "IdentityCore/IdentityCore/src/oauth2/account/MSIDAccountIdentifier.h" + header "IdentityCore/IdentityCore/src/oauth2/account/MSIDAccount.h" + header "IdentityCore/IdentityCore/src/oauth2/MSIDOauth2Factory.h" + header "IdentityCore/IdentityCore/src/oauth2/ciam/MSIDCIAMOauth2Factory.h" + header "IdentityCore/IdentityCore/src/oauth2/ciam/MSIDCIAMTokenResponse.h" + header "IdentityCore/IdentityCore/src/oauth2/token/MSIDAccessToken.h" + header "IdentityCore/IdentityCore/src/oauth2/token/MSIDRefreshToken.h" + header "IdentityCore/IdentityCore/src/oauth2/token/MSIDCredentialType.h" + header "IdentityCore/IdentityCore/src/oauth2/token/MSIDIdToken.h" + header "IdentityCore/IdentityCore/src/MSIDVersion.h" + header "IdentityCore/IdentityCore/src/cache/MSIDKeychainTokenCache.h" + header "IdentityCore/IdentityCore/src/cache/accessor/MSIDDefaultTokenCacheAccessor.h" + header "IdentityCore/IdentityCore/src/validation/MSIDCIAMAuthority.h" + header "IdentityCore/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemePop.h" + header "IdentityCore/IdentityCore/src/auth_scheme/MSIDAuthenticationScheme.h" + header "IdentityCore/IdentityCore/src/network/MSIDHttpRequest.h" + header "IdentityCore/IdentityCore/src/network/request_server_telemetry/MSIDHttpRequestServerTelemetryHandling.h" + header "IdentityCore/IdentityCore/src/parameters/MSIDRequestParameters.h" + header "IdentityCore/IdentityCore/src/logger/MSIDLogger.h" + header "IdentityCore/IdentityCore/src/logger/MSIDLogger+Internal.h" + header "IdentityCore/IdentityCore/src/logger/MSIDMaskedHashableLogParameter.h" + header "IdentityCore/IdentityCore/src/logger/MSIDMaskedUsernameLogParameter.h" + header "IdentityCore/IdentityCore/src/MSIDBasicContext.h" + header "src/native_auth/logger/MSALLogMask.h" + header "IdentityCore/IdentityCore/src/cache/metadata/MSIDAccountMetadataCacheAccessor.h" + header "IdentityCore/IdentityCore/src/telemetry/MSIDTelemetry.h" + header "IdentityCore/IdentityCore/src/telemetry/MSIDTelemetry+Internal.h" + header "IdentityCore/IdentityCore/src/telemetry/MSIDTelemetryEventInterface.h" + header "IdentityCore/IdentityCore/src/telemetry/MSIDTelemetryAPIEvent.h" + header "IdentityCore/IdentityCore/src/telemetry/MSIDTelemetryEventStrings.h" + header "IdentityCore/IdentityCore/src/network/request_serializer/MSIDRequestSerialization.h" + header "IdentityCore/IdentityCore/src/network/request_configurator/MSIDHttpRequestConfiguratorProtocol.h" + header "IdentityCore/IdentityCore/src/network/request_configurator/MSIDAADRequestConfigurator.h" + header "IdentityCore/IdentityCore/src/network/request_server_telemetry/MSIDAADTokenRequestServerTelemetry.h" + header "IdentityCore/IdentityCore/src/oauth2/MSIDTokenResponse.h" + header "IdentityCore/IdentityCore/src/oauth2/MSIDExternalSSOContext.h" + header "IdentityCore/IdentityCore/src/requests/result/MSIDTokenResult.h" + header "IdentityCore/IdentityCore/src/configuration/MSIDConfiguration.h" + header "IdentityCore/IdentityCore/src/validation/MSIDAuthority.h" + header "IdentityCore/IdentityCore/src/validation/MSIDAuthority+Internal.h" + header "IdentityCore/IdentityCore/src/network/response_serializer/MSIDResponseSerialization.h" + header "IdentityCore/IdentityCore/src/network/response_serializer/MSIDAADTokenResponseSerializer.h" + header "IdentityCore/IdentityCore/src/requests/sdk/MSIDTokenResponseValidator.h" + header "IdentityCore/IdentityCore/src/MSIDError.h" + header "IdentityCore/IdentityCore/src/MSIDTelemetryStringSerializable.h" + header "IdentityCore/IdentityCore/src/telemetry/request_telemetry/MSIDCurrentRequestTelemetry.h" + header "IdentityCore/IdentityCore/src/telemetry/request_telemetry/MSIDRequestTelemetryConstants.h" + header "IdentityCore/IdentityCore/src/telemetry/request_telemetry/MSIDCurrentRequestTelemetrySerializedItem.h" + header "IdentityCore/IdentityCore/src/util/NSError+MSIDServerTelemetryError.h" + header "IdentityCore/IdentityCore/src/MSIDErrorConverter.h" + header "IdentityCore/IdentityCore/src/network/error_handler/MSIDHttpRequestErrorHandling.h" + header "IdentityCore/IdentityCore/src/util/NSString+MSIDExtensions.h" + header "IdentityCore/IdentityCore/src/workplacejoin/MSIDWorkPlaceJoinConstants.h" + header "IdentityCore/IdentityCore/src/webview/embeddedWebview/challangeHandlers/MSIDPKeyAuthHandler.h" + header "src/configuration/external/ios/MSALLegacySharedADALAccount.h" + header "src/MSALPublicClientApplication+Internal.h" + header "IdentityCore/IdentityCore/src/MSIDError.h" + header "src/MSALAccount+Internal.h" + header "src/configuration/external/MSALExternalAccountHandler.h" + header "src/instance/MSALAccountsProvider.h" + header "src/instance/oauth2/ciam/MSALCIAMOauth2Provider.h" + header "src/MSALAccountId+Internal.h" + header "IdentityCore/IdentityCore/src/requests/sdk/msal/MSIDDefaultTokenResponseValidator.h" + header "IdentityCore/IdentityCore/src/network/error_handler/MSIDAADRequestErrorHandler.h" + export * +} + +module MSAL_Unit_Test_Private { + header "IdentityCore/IdentityCore/tests/util/MSIDTestIdentifiers.h" + header "IdentityCore/IdentityCore/tests/util/network/MSIDTestURLResponse.h" + header "IdentityCore/IdentityCore/tests/util/network/MSIDTestURLSession.h" +} diff --git a/MSAL/src/MSALAccount+Internal.h b/MSAL/src/MSALAccount+Internal.h index 60a97afb97..ab069fdff1 100644 --- a/MSAL/src/MSALAccount+Internal.h +++ b/MSAL/src/MSALAccount+Internal.h @@ -58,6 +58,9 @@ @param createTenantProfile Whether to create tenant profile based on the info of MSID account */ - (instancetype)initWithMSIDAccount:(MSIDAccount *)account createTenantProfile:(BOOL)createTenantProfile; +- (instancetype)initWithMSIDAccount:(MSIDAccount *)account + createTenantProfile:(BOOL) createTenantProfile + accountClaims:(NSDictionary *) accountClaims; - (instancetype)initWithMSALExternalAccount:(id)externalAccount oauth2Provider:(MSALOauth2Provider *)oauthProvider; diff --git a/MSAL/src/MSALAccount.m b/MSAL/src/MSALAccount.m index efd7a6777a..91f9dd902e 100644 --- a/MSAL/src/MSALAccount.m +++ b/MSAL/src/MSALAccount.m @@ -98,6 +98,15 @@ - (instancetype)initWithMSIDAccount:(MSIDAccount *)account return msalAccount; } +- (instancetype)initWithMSIDAccount:(MSIDAccount *)account + createTenantProfile:(BOOL) createTenantProfile + accountClaims:(NSDictionary *) accountClaims +{ + MSALAccount *msalAccount = [self initWithMSIDAccount:account createTenantProfile:createTenantProfile]; + msalAccount.accountClaims = account.isHomeTenantAccount ? accountClaims : nil; + return msalAccount; +} + - (instancetype)initWithMSALExternalAccount:(id)externalAccount oauth2Provider:(MSALOauth2Provider *)oauthProvider { diff --git a/MSAL/src/native_auth/MSALNativeAuthInternalError.swift b/MSAL/src/native_auth/MSALNativeAuthInternalError.swift new file mode 100644 index 0000000000..c4405ae444 --- /dev/null +++ b/MSAL/src/native_auth/MSALNativeAuthInternalError.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +enum MSALNativeAuthInternalError: Error, Equatable { + case invalidInput + case validationError + case tokenResultNotPresent + case serverProtectionPoliciesRequired(homeAccountId: String?) + case headerNotSerialized + case invalidAuthority + case invalidUrl + case missingResponseSerializer + case responseSerializationError + case invalidResponse + case invalidRequest + case generalError + case invalidAttributes +} diff --git a/MSAL/src/native_auth/cache/MSALNativeAuthCacheAccessor.swift b/MSAL/src/native_auth/cache/MSALNativeAuthCacheAccessor.swift new file mode 100644 index 0000000000..500f65f1cd --- /dev/null +++ b/MSAL/src/native_auth/cache/MSALNativeAuthCacheAccessor.swift @@ -0,0 +1,170 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +@_implementationOnly import MSAL_Private + +class MSALNativeAuthCacheAccessor: MSALNativeAuthCacheInterface { + + private let tokenCacheAccessor: MSIDDefaultTokenCacheAccessor = { + let dataSource = MSIDKeychainTokenCache() + return MSIDDefaultTokenCacheAccessor(dataSource: dataSource, otherCacheAccessors: []) + }() + + private let accountMetadataCache: MSIDAccountMetadataCacheAccessor = MSIDAccountMetadataCacheAccessor(dataSource: MSIDKeychainTokenCache()) + private let externalAccountProvider: MSALExternalAccountHandler = MSALExternalAccountHandler() + private let validator = MSIDTokenResponseValidator() + + func getTokens( + account: MSALAccount, + configuration: MSIDConfiguration, + context: MSIDRequestContext) throws -> MSALNativeAuthTokens { + let accountConfiguration = try getAccountConfiguration(configuration: configuration, account: account) + let idToken = try tokenCacheAccessor.getIDToken( + forAccount: account.lookupAccountIdentifier, + configuration: accountConfiguration, + idTokenType: MSIDCredentialType.MSIDIDTokenType, + context: context) + let refreshToken = try tokenCacheAccessor.getRefreshToken( + withAccount: account.lookupAccountIdentifier, + familyId: nil, + configuration: accountConfiguration, + context: context) + let accessToken = try tokenCacheAccessor.getAccessToken( + forAccount: account.lookupAccountIdentifier, + configuration: accountConfiguration, + context: context) + return MSALNativeAuthTokens(accessToken: accessToken, refreshToken: refreshToken, rawIdToken: idToken.rawIdToken) + } + + func getAllAccounts(configuration: MSIDConfiguration) throws -> [MSALAccount] { + let request = MSALAccountsProvider(tokenCache: tokenCacheAccessor, + accountMetadataCache: accountMetadataCache, + clientId: configuration.clientId, + externalAccountProvider: externalAccountProvider) + return try request?.allAccounts() ?? [] + } + + func validateAndSaveTokensAndAccount( + tokenResponse: MSIDTokenResponse, + configuration: MSIDConfiguration, + context: MSIDRequestContext) throws -> MSIDTokenResult? { + let ciamOauth2Provider = getCIAMOauth2Provider(clientId: configuration.clientId) + return try? validator.validateAndSave(tokenResponse, + oauthFactory: ciamOauth2Provider.msidOauth2Factory, + tokenCache: tokenCacheAccessor, + accountMetadataCache: accountMetadataCache, + requestParameters: getRequestParameters(tokenResponse: tokenResponse, + configuration: configuration, + context: context), + saveSSOStateOnly: false) + } + + // Here we create the MSIDRequestParameters required by the validateAndSave method + private func getRequestParameters( + tokenResponse: MSIDTokenResponse, + configuration: MSIDConfiguration, + context: MSIDRequestContext + ) -> MSIDRequestParameters { + + // We are creating the default MSIDRequestParameters to prevent unintended functionality changes. + // If the method `validateAndSaveTokenResponse` from `MSIDTokenResponseValidator` changes + // the implementation here also needs to change to match the properties needed by the method + // Currently only the required and used parameters are set + let parameters = MSIDRequestParameters() + // MSIDRequestParameters has to follow MSIDRequestContext protocol + parameters.correlationId = context.correlationId() + parameters.logComponent = context.logComponent() + parameters.telemetryRequestId = context.telemetryRequestId() + parameters.appRequestMetadata = context.appRequestMetadata() + + parameters.msidConfiguration = configuration + parameters.clientId = configuration.clientId + + let displayableId = tokenResponse.idTokenObj?.username() + let homeAccountId = tokenResponse.idTokenObj?.userId + + let accountIdentifier = MSIDAccountIdentifier(displayableId: displayableId, homeAccountId: homeAccountId) + parameters.accountIdentifier = accountIdentifier + parameters.authority = configuration.authority + parameters.instanceAware = false + let defaultOIDCScopesArray = MSALPublicClientApplication.defaultOIDCScopes().array as? [String] + parameters.oidcScope = defaultOIDCScopesArray?.joinScopes() + return parameters + } + + func removeTokens( + accountIdentifier: MSIDAccountIdentifier, + authority: MSIDAuthority, + clientId: String, + context: MSIDRequestContext) throws { + try tokenCacheAccessor.clearCache( + forAccount: accountIdentifier, + authority: authority, + clientId: clientId, + familyId: nil, + clearAccounts: false, + context: context) + } + + func clearCache( + accountIdentifier: MSIDAccountIdentifier, + authority: MSIDAuthority, + clientId: String, + context: MSIDRequestContext) throws { + try tokenCacheAccessor.clearCache( + forAccount: accountIdentifier, + authority: authority, + clientId: clientId, + familyId: nil, + clearAccounts: true, + context: context) + } + + private func getCIAMOauth2Provider(clientId: String) -> MSALCIAMOauth2Provider { + return MSALCIAMOauth2Provider(clientId: clientId, + tokenCache: tokenCacheAccessor, + accountMetadataCache: accountMetadataCache) + + } + + private func getAccountConfiguration(configuration: MSIDConfiguration, + account: MSALAccount) throws -> MSIDConfiguration? { + // When retrieving tokens from the cache, we first have to get the + // Tenant Id from the AccountMetadataCache. Because in NativeAuth + // We use only CIAM authorities, we retrieve using its provider + let ciamOauth2Provider = getCIAMOauth2Provider(clientId: configuration.clientId) + let accountConfiguration = configuration.copy() as? MSIDConfiguration + let errorPointer: NSErrorPointer = nil + let requestAuthority = ciamOauth2Provider.issuerAuthority(with: account, + request: configuration.authority, + instanceAware: false, + error: errorPointer) + if let errorPointer = errorPointer, let error = errorPointer.pointee { + throw error + } + accountConfiguration?.authority = requestAuthority + return accountConfiguration + } +} diff --git a/MSAL/src/native_auth/cache/MSALNativeAuthCacheInterface.swift b/MSAL/src/native_auth/cache/MSALNativeAuthCacheInterface.swift new file mode 100644 index 0000000000..d467ee8abf --- /dev/null +++ b/MSAL/src/native_auth/cache/MSALNativeAuthCacheInterface.swift @@ -0,0 +1,52 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthCacheInterface { + func getTokens( + account: MSALAccount, + configuration: MSIDConfiguration, + context: MSIDRequestContext) throws -> MSALNativeAuthTokens + + func getAllAccounts(configuration: MSIDConfiguration) throws -> [MSALAccount] + + func validateAndSaveTokensAndAccount( + tokenResponse: MSIDTokenResponse, + configuration: MSIDConfiguration, + context: MSIDRequestContext) throws -> MSIDTokenResult? + + func removeTokens( + accountIdentifier: MSIDAccountIdentifier, + authority: MSIDAuthority, + clientId: String, + context: MSIDRequestContext) throws + + func clearCache( + accountIdentifier: MSIDAccountIdentifier, + authority: MSIDAuthority, + clientId: String, + context: MSIDRequestContext) throws +} diff --git a/MSAL/src/native_auth/cache/MSALNativeAuthTokens.swift b/MSAL/src/native_auth/cache/MSALNativeAuthTokens.swift new file mode 100644 index 0000000000..13105e414f --- /dev/null +++ b/MSAL/src/native_auth/cache/MSALNativeAuthTokens.swift @@ -0,0 +1,37 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +class MSALNativeAuthTokens { + let accessToken: MSIDAccessToken? + let refreshToken: MSIDRefreshToken? + let rawIdToken: String? + + init(accessToken: MSIDAccessToken?, refreshToken: MSIDRefreshToken?, rawIdToken: String?) { + self.accessToken = accessToken + self.refreshToken = refreshToken + self.rawIdToken = rawIdToken + } +} diff --git a/MSAL/src/native_auth/configuration/MSALNativeAuthConfiguration.swift b/MSAL/src/native_auth/configuration/MSALNativeAuthConfiguration.swift new file mode 100644 index 0000000000..d0bcfaa616 --- /dev/null +++ b/MSAL/src/native_auth/configuration/MSALNativeAuthConfiguration.swift @@ -0,0 +1,49 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +struct MSALNativeAuthConfiguration { + var challengeTypesString: String { + return challengeTypes.map { $0.rawValue }.joined(separator: " ") + } + + let clientId: String + let authority: MSIDCIAMAuthority + let challengeTypes: [MSALNativeAuthInternalChallengeType] + var sliceConfig: MSALSliceConfig? + + init( + clientId: String, + authority: MSALCIAMAuthority, + challengeTypes: [MSALNativeAuthInternalChallengeType]) throws { + self.clientId = clientId + self.authority = try MSIDCIAMAuthority( + url: authority.url, + validateFormat: false, + context: MSALNativeAuthRequestContext() + ) + self.challengeTypes = challengeTypes + } +} diff --git a/MSAL/src/native_auth/controllers/MSALNativeAuthBaseController.swift b/MSAL/src/native_auth/controllers/MSALNativeAuthBaseController.swift new file mode 100644 index 0000000000..8cd4a1f86f --- /dev/null +++ b/MSAL/src/native_auth/controllers/MSALNativeAuthBaseController.swift @@ -0,0 +1,143 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +class MSALNativeAuthBaseController { + + typealias TelemetryInfo = (event: MSIDTelemetryAPIEvent?, context: MSALNativeAuthRequestContext) + let clientId: String + + init( + clientId: String + ) { + self.clientId = clientId + } + + func makeAndStartTelemetryEvent( + id: MSALNativeAuthTelemetryApiId, + context: MSIDRequestContext + ) -> MSIDTelemetryAPIEvent? { + let event = makeLocalTelemetryApiEvent( + name: MSID_TELEMETRY_EVENT_API_EVENT, + telemetryApiId: id, + context: context + ) + + startTelemetryEvent(event, context: context) + + return event + } + + func makeLocalTelemetryApiEvent( + name: String, + telemetryApiId: MSALNativeAuthTelemetryApiId, + context: MSIDRequestContext + ) -> MSIDTelemetryAPIEvent? { + let event = MSIDTelemetryAPIEvent( + name: name, + context: context + ) + + event?.setApiId(String(telemetryApiId.rawValue)) + event?.setCorrelationId(context.correlationId()) + event?.setClientId(clientId) + + return event + } + + func startTelemetryEvent(_ localEvent: MSIDTelemetryAPIEvent?, context: MSIDRequestContext) { + guard let eventName = localEvent?.property(withName: MSID_TELEMETRY_KEY_EVENT_NAME) else { + return MSALLogger.log( + level: .error, + context: context, + format: "Telemetry event nil not expected" + ) + } + + MSIDTelemetry.sharedInstance().startEvent( + context.telemetryRequestId(), + eventName: eventName + ) + } + + func stopTelemetryEvent(_ telemetryInfo: TelemetryInfo, error: Error? = nil) { + stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, error: error) + } + + func stopTelemetryEvent(_ localEvent: MSIDTelemetryAPIEvent?, context: MSIDRequestContext, error: Error? = nil) { + guard let event = localEvent else { + return MSALLogger.log( + level: .error, + context: context, + format: "Telemetry event nil not expected" + ) + } + + if let error = error as? NSError { + + if let key = MSIDErrorConverter.defaultErrorConverter?.oauthErrorKey(), + let oauthErrorCode = error.userInfo[key] as? String { + event.setOauthErrorCode(oauthErrorCode) + } + + event.setErrorCodeString(String(error.code)) + event.setErrorDomain(error.domain) + event.setResultStatus(MSID_TELEMETRY_VALUE_FAILED) + event.setIsSuccessfulStatus(MSID_TELEMETRY_VALUE_NO) + } else { + event.setResultStatus(MSID_TELEMETRY_VALUE_SUCCEEDED) + event.setIsSuccessfulStatus(MSID_TELEMETRY_VALUE_YES) + } + + MSIDTelemetry.sharedInstance().stopEvent(context.telemetryRequestId(), event: event) + MSIDTelemetry.sharedInstance().flush(context.telemetryRequestId()) + } + + func complete( + _ telemetryEvent: MSIDTelemetryAPIEvent?, + response: T? = nil, + error: Error? = nil, + context: MSIDRequestContext, + completion: @escaping (T?, Error?) -> Void + ) { + stopTelemetryEvent(telemetryEvent, context: context, error: error) + completion(response, error) + } + + func performRequest(_ request: MSIDHttpRequest, context: MSIDRequestContext) async -> Result { + return await withCheckedContinuation { continuation in + request.send { result, error in + if let error = error { + continuation.resume(returning: .failure(error)) + } else if let response = result as? T { + continuation.resume(returning: .success(response)) + } else { + MSALLogger.log(level: .error, context: context, format: "Error request - Both result and error are nil") + continuation.resume(returning: .failure(MSALNativeAuthInternalError.invalidResponse)) + } + } + } + } +} diff --git a/MSAL/src/native_auth/controllers/MSALNativeAuthControllerTelemetryWrapper.swift b/MSAL/src/native_auth/controllers/MSALNativeAuthControllerTelemetryWrapper.swift new file mode 100644 index 0000000000..c3578f5363 --- /dev/null +++ b/MSAL/src/native_auth/controllers/MSALNativeAuthControllerTelemetryWrapper.swift @@ -0,0 +1,38 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// The Controller sends this model to the public interface, which uses the `result` value to return to the user. +/// The `telemetryUpdate` gets called from the public interface, if it needs to tell the controller to update the telemetry +/// (ex: an optional delegate method not implemented by the external developer). +struct MSALNativeAuthControllerTelemetryWrapper { + let result: R + let telemetryUpdate: ((Result) -> Void)? + + init(_ result: R, telemetryUpdate: ((Result) -> Void)? = nil) { + self.result = result + self.telemetryUpdate = telemetryUpdate + } +} diff --git a/MSAL/src/native_auth/controllers/MSALNativeAuthTokenController.swift b/MSAL/src/native_auth/controllers/MSALNativeAuthTokenController.swift new file mode 100644 index 0000000000..1c1fa765ec --- /dev/null +++ b/MSAL/src/native_auth/controllers/MSALNativeAuthTokenController.swift @@ -0,0 +1,231 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +import Foundation + +class MSALNativeAuthTokenController: MSALNativeAuthBaseController { + + // MARK: - Variables + + let factory: MSALNativeAuthResultBuildable + private let requestProvider: MSALNativeAuthTokenRequestProviding + private let responseValidator: MSALNativeAuthTokenResponseValidating + private let cacheAccessor: MSALNativeAuthCacheInterface + + init( + clientId: String, + requestProvider: MSALNativeAuthTokenRequestProviding, + cacheAccessor: MSALNativeAuthCacheInterface, + factory: MSALNativeAuthResultBuildable, + responseValidator: MSALNativeAuthTokenResponseValidating + ) { + self.requestProvider = requestProvider + self.factory = factory + self.responseValidator = responseValidator + self.cacheAccessor = cacheAccessor + super.init( + clientId: clientId + ) + } + + func performAndValidateTokenRequest( + _ request: MSIDHttpRequest, + config: MSIDConfiguration, + context: MSALNativeAuthRequestContext) async -> MSALNativeAuthTokenValidatedResponse { + let ciamTokenResponse: Result = await performTokenRequest(request, context: context) + return responseValidator.validate( + context: context, + msidConfiguration: config, + result: ciamTokenResponse + ) + } + + func joinScopes(_ scopes: [String]?) -> [String] { + let defaultOIDCScopes = MSALPublicClientApplication.defaultOIDCScopes().array + guard let scopes = scopes else { + return defaultOIDCScopes as? [String] ?? [] + } + let joinedScopes = NSMutableOrderedSet(array: scopes) + joinedScopes.addObjects(from: defaultOIDCScopes) + return joinedScopes.array as? [String] ?? [] + } + + func createTokenRequest( + username: String? = nil, + password: String? = nil, + scopes: [String], + credentialToken: String? = nil, + oobCode: String? = nil, + signInSLT: String? = nil, + grantType: MSALNativeAuthGrantType, + includeChallengeType: Bool = true, + context: MSIDRequestContext) -> MSIDHttpRequest? { + do { + let params = MSALNativeAuthTokenRequestParameters( + context: context, + username: username, + credentialToken: credentialToken, + signInSLT: signInSLT, + grantType: grantType, + scope: scopes.joinScopes(), + password: password, + oobCode: oobCode, + includeChallengeType: includeChallengeType, + refreshToken: nil) + return try requestProvider.signInWithPassword(parameters: params, context: context) + } catch { + MSALLogger.log(level: .error, context: context, format: "Error creating SignIn Token Request: \(error)") + return nil + } + } + + func createRefreshTokenRequest( + scopes: [String], + refreshToken: String?, + context: MSIDRequestContext) -> MSIDHttpRequest? { + guard let refreshToken = refreshToken else { + MSALLogger.log(level: .error, context: context, format: "Error creating Refresh Token Request, refresh token is nil!") + return nil + } + do { + let params = MSALNativeAuthTokenRequestParameters( + context: context, + username: nil, + credentialToken: nil, + signInSLT: nil, + grantType: .refreshToken, + scope: scopes.joinScopes(), + password: nil, + oobCode: nil, + includeChallengeType: false, + refreshToken: refreshToken) + return try requestProvider.refreshToken(parameters: params, context: context) + } catch { + MSALLogger.log(level: .error, context: context, format: "Error creating Refresh Token Request: \(error)") + return nil + } + } + + func cacheTokenResponse( + _ tokenResponse: MSIDTokenResponse, + context: MSALNativeAuthRequestContext, + msidConfiguration: MSIDConfiguration + ) throws -> MSIDTokenResult { + let displayableId = tokenResponse.idTokenObj?.username() + let homeAccountId = tokenResponse.idTokenObj?.userId + + guard let accountIdentifier = MSIDAccountIdentifier(displayableId: displayableId, homeAccountId: homeAccountId) else { + MSALLogger.log(level: .error, context: context, format: "Error creating account identifier") + throw MSALNativeAuthInternalError.invalidResponse + } + + guard let result = cacheTokenResponseRetrieveTokenResult(tokenResponse, + context: context, + msidConfiguration: msidConfiguration) else { + MSALLogger.log(level: .error, context: context, format: "Error caching token response") + throw MSALNativeAuthInternalError.invalidResponse + } + + guard try responseValidator.validateAccount(with: result, + context: context, + accountIdentifier: accountIdentifier) else { + MSALLogger.log(level: .error, context: context, format: "Error validating account") + throw MSALNativeAuthInternalError.invalidResponse + } + + return result + } +} + +// Extension is required because Swift compiler throws an error due to +// name similarity with another Objective C function when building for Release +extension MSALNativeAuthTokenController { + + private func cacheTokenResponseRetrieveTokenResult( + _ tokenResponse: MSIDTokenResponse, + context: MSALNativeAuthRequestContext, + msidConfiguration: MSIDConfiguration + ) -> MSIDTokenResult? { + do { + // If there is an account existing already in the cache, we remove it + try clearAccount(msidConfiguration: msidConfiguration, context: context) + } catch { + MSALLogger.log(level: .error, context: context, format: "Error clearing account \(error) (ignoring)") + } + do { + let result = try cacheAccessor.validateAndSaveTokensAndAccount(tokenResponse: tokenResponse, + configuration: msidConfiguration, + context: context) + return result + } catch { + MSALLogger.log(level: .error, context: context, format: "Error caching response: \(error) (ignoring)") + } + return nil + } + + private func clearAccount(msidConfiguration: MSIDConfiguration, context: MSALNativeAuthRequestContext) throws { + do { + let accounts = try cacheAccessor.getAllAccounts(configuration: msidConfiguration) + if let account = accounts.first { + if let identifier = MSIDAccountIdentifier(displayableId: account.username, homeAccountId: account.identifier) { + try cacheAccessor.clearCache(accountIdentifier: identifier, + authority: msidConfiguration.authority, + clientId: msidConfiguration.clientId, + context: context) + } + } else { + MSALLogger.log(level: .error, + context: context, + format: "Error creating MSIDAccountIdentifier out of MSALAccount (ignoring)") + } + } catch { + MSALLogger.log(level: .error, context: context, format: "Error clearing previous account (ignoring)") + } + } + + private func performTokenRequest(_ request: MSIDHttpRequest, context: MSIDRequestContext) async -> Result { + return await withCheckedContinuation { continuation in + request.send { response, error in + if let error = error { + continuation.resume(returning: .failure(error)) + return + } + guard let responseDict = response as? [AnyHashable: Any] else { + continuation.resume(returning: .failure(MSALNativeAuthInternalError.invalidResponse)) + return + } + do { + let tokenResponse = try MSIDCIAMTokenResponse(jsonDictionary: responseDict) + tokenResponse.correlationId = request.context?.correlationId().uuidString + continuation.resume(returning: .success(tokenResponse)) + } catch { + MSALLogger.log(level: .error, context: context, format: "Error token request - Both result and error are nil") + continuation.resume(returning: .failure(MSALNativeAuthInternalError.invalidResponse)) + } + } + } + } +} diff --git a/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift new file mode 100644 index 0000000000..d9752fef25 --- /dev/null +++ b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift @@ -0,0 +1,192 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController, MSALNativeAuthCredentialsControlling { + + // MARK: - Variables + + private let cacheAccessor: MSALNativeAuthCacheInterface + + // MARK: - Init + + override init( + clientId: String, + requestProvider: MSALNativeAuthTokenRequestProviding, + cacheAccessor: MSALNativeAuthCacheInterface, + factory: MSALNativeAuthResultBuildable, + responseValidator: MSALNativeAuthTokenResponseValidating + ) { + self.cacheAccessor = cacheAccessor + super.init( + clientId: clientId, + requestProvider: requestProvider, + cacheAccessor: cacheAccessor, + factory: factory, + responseValidator: responseValidator + ) + } + + convenience init(config: MSALNativeAuthConfiguration) { + let factory = MSALNativeAuthResultFactory(config: config) + self.init( + clientId: config.clientId, + requestProvider: MSALNativeAuthTokenRequestProvider( + requestConfigurator: MSALNativeAuthRequestConfigurator(config: config)), + cacheAccessor: MSALNativeAuthCacheAccessor(), + factory: factory, + responseValidator: MSALNativeAuthTokenResponseValidator(factory: factory, + msidValidator: MSIDTokenResponseValidator()) + ) + } + + // MARK: Internal + + func retrieveUserAccountResult(context: MSALNativeAuthRequestContext) -> MSALNativeAuthUserAccountResult? { + let accounts = self.allAccounts() + if let account = accounts.first { + // We pass an empty array of scopes because that will return all tokens for that account identifier + // Because we expect to be only one access token per account at this point, it's ok for the array to be empty + guard let tokens = retrieveTokens(account: account, + scopes: [], + context: context) else { + MSALLogger.log(level: .verbose, context: nil, format: "No tokens found") + return nil + } + return factory.makeUserAccountResult(account: account, authTokens: tokens) + } else { + MSALLogger.log(level: .verbose, context: nil, format: "No account found") + } + return nil + } + + func refreshToken(context: MSALNativeAuthRequestContext, authTokens: MSALNativeAuthTokens) async -> Result { + MSALLogger.log(level: .verbose, context: context, format: "Refresh started") + let telemetryEvent = makeAndStartTelemetryEvent(id: .telemetryApiIdRefreshToken, context: context) + let scopes = authTokens.accessToken?.scopes.array as? [String] ?? [] + guard let request = createRefreshTokenRequest( + scopes: scopes, + refreshToken: authTokens.refreshToken?.refreshToken, + context: context + ) else { + stopTelemetryEvent(telemetryEvent, context: context, error: MSALNativeAuthInternalError.invalidRequest) + return .failure(RetrieveAccessTokenError(type: .generalError)) + } + let config = factory.makeMSIDConfiguration(scopes: scopes) + let response = await performAndValidateTokenRequest(request, config: config, context: context) + return handleTokenResponse( + response, + scopes: scopes, + context: context, + telemetryEvent: telemetryEvent + ) + } + + // MARK: - Private + + private func allAccounts() -> [MSALAccount] { + do { + // We pass an empty array of scopes because that will return all accounts + // that have been saved for the current Client Id. We expect only one account to exist at this point per Client Id + let config = factory.makeMSIDConfiguration(scopes: []) + return try cacheAccessor.getAllAccounts(configuration: config) + } catch { + MSALLogger.log( + level: .error, + context: nil, + format: "Error retrieving accounts \(error)") + } + return [] + } + + private func retrieveTokens( + account: MSALAccount, + scopes: [String], + context: MSALNativeAuthRequestContext + ) -> MSALNativeAuthTokens? { + do { + let config = factory.makeMSIDConfiguration(scopes: scopes) + return try cacheAccessor.getTokens(account: account, configuration: config, context: context) + } catch { + MSALLogger.log( + level: .error, + context: context, + format: "Error retrieving tokens: \(error)" + ) + } + return nil + } + + private func handleTokenResponse( + _ response: MSALNativeAuthTokenValidatedResponse, + scopes: [String], + context: MSALNativeAuthRequestContext, + telemetryEvent: MSIDTelemetryAPIEvent? + ) -> Result { + let config = factory.makeMSIDConfiguration(scopes: scopes) + switch response { + case .success(let tokenResponse): + return handleMSIDTokenResponse( + tokenResponse: tokenResponse, + telemetryEvent: telemetryEvent, + context: context, + config: config + ) + case .error(let errorType): + let error = errorType.convertToRetrieveAccessTokenError() + MSALLogger.log( + level: .error, + context: context, + format: "Refresh Token completed with error: \(error.errorDescription ?? "No error description")") + stopTelemetryEvent(telemetryEvent, context: context, error: error) + return .failure(error) + } + } + + private func handleMSIDTokenResponse( + tokenResponse: MSIDTokenResponse, + telemetryEvent: MSIDTelemetryAPIEvent?, + context: MSALNativeAuthRequestContext, + config: MSIDConfiguration + ) -> Result { + do { + let tokenResult = try cacheTokenResponse(tokenResponse, context: context, msidConfiguration: config) + telemetryEvent?.setUserInformation(tokenResult.account) + stopTelemetryEvent(telemetryEvent, context: context) + MSALLogger.log( + level: .verbose, + context: context, + format: "Refresh Token completed successfully") + return .success(tokenResult.accessToken.accessToken) + } catch { + MSALLogger.log( + level: .error, + context: context, + format: "Token Result was not created properly error - \(error)") + return .failure(RetrieveAccessTokenError(type: .generalError)) + } + } +} diff --git a/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsControlling.swift b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsControlling.swift new file mode 100644 index 0000000000..6b69b64016 --- /dev/null +++ b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsControlling.swift @@ -0,0 +1,30 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +protocol MSALNativeAuthCredentialsControlling { + func retrieveUserAccountResult(context: MSALNativeAuthRequestContext) -> MSALNativeAuthUserAccountResult? + func refreshToken(context: MSALNativeAuthRequestContext, authTokens: MSALNativeAuthTokens) async -> Result +} diff --git a/MSAL/src/native_auth/controllers/factories/MSALNativeAuthControllerFactory.swift b/MSAL/src/native_auth/controllers/factories/MSALNativeAuthControllerFactory.swift new file mode 100644 index 0000000000..6d36efd41e --- /dev/null +++ b/MSAL/src/native_auth/controllers/factories/MSALNativeAuthControllerFactory.swift @@ -0,0 +1,54 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +protocol MSALNativeAuthControllerBuildable { + func makeSignUpController() -> MSALNativeAuthSignUpControlling + func makeSignInController() -> MSALNativeAuthSignInControlling + func makeResetPasswordController() -> MSALNativeAuthResetPasswordControlling + func makeCredentialsController() -> MSALNativeAuthCredentialsControlling +} + +final class MSALNativeAuthControllerFactory: MSALNativeAuthControllerBuildable { + private let config: MSALNativeAuthConfiguration + + init(config: MSALNativeAuthConfiguration) { + self.config = config + } + + func makeSignUpController() -> MSALNativeAuthSignUpControlling { + return MSALNativeAuthSignUpController(config: config) + } + + func makeSignInController() -> MSALNativeAuthSignInControlling { + return MSALNativeAuthSignInController(config: config) + } + + func makeResetPasswordController() -> MSALNativeAuthResetPasswordControlling { + return MSALNativeAuthResetPasswordController(config: config) + } + + func makeCredentialsController() -> MSALNativeAuthCredentialsControlling { + return MSALNativeAuthCredentialsController(config: config) + } +} diff --git a/MSAL/src/native_auth/controllers/factories/MSALNativeAuthResultFactory.swift b/MSAL/src/native_auth/controllers/factories/MSALNativeAuthResultFactory.swift new file mode 100644 index 0000000000..edf1eb337f --- /dev/null +++ b/MSAL/src/native_auth/controllers/factories/MSALNativeAuthResultFactory.swift @@ -0,0 +1,97 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthResultBuildable { + + var config: MSALNativeAuthConfiguration {get} + + func makeUserAccountResult(tokenResult: MSIDTokenResult, context: MSIDRequestContext) -> MSALNativeAuthUserAccountResult? + + func makeUserAccountResult(account: MSALAccount, authTokens: MSALNativeAuthTokens) -> MSALNativeAuthUserAccountResult? + + func makeMSIDConfiguration(scopes: [String]) -> MSIDConfiguration +} + +final class MSALNativeAuthResultFactory: MSALNativeAuthResultBuildable { + + let config: MSALNativeAuthConfiguration + + init(config: MSALNativeAuthConfiguration) { + self.config = config + } + + func makeUserAccountResult(tokenResult: MSIDTokenResult, context: MSIDRequestContext) -> MSALNativeAuthUserAccountResult? { + var jsonDictionary: [AnyHashable: Any]? + do { + let claims = try MSIDIdTokenClaims.init(rawIdToken: tokenResult.rawIdToken) + jsonDictionary = claims.jsonDictionary() + if jsonDictionary == nil { + MSALLogger.log( + level: .error, + context: context, + format: "Initialising account without claims") + } + } catch { + MSALLogger.log( + level: .error, + context: context, + format: "Claims for account could not be created - \(error)" ) + } + guard let account = MSALAccount.init(msidAccount: tokenResult.account, + createTenantProfile: false, + accountClaims: jsonDictionary) else { + MSALLogger.log( + level: .error, + context: context, + format: "Account could not be created") + return nil + } + guard let refreshToken = tokenResult.refreshToken as? MSIDRefreshToken else { + MSALLogger.log( + level: .error, + context: context, + format: "Refresh token invalid, account result could not be created") + return nil + } + let authTokens = MSALNativeAuthTokens(accessToken: tokenResult.accessToken, + refreshToken: refreshToken, + rawIdToken: tokenResult.rawIdToken) + return .init(account: account, authTokens: authTokens, configuration: config, cacheAccessor: MSALNativeAuthCacheAccessor()) + } + + func makeUserAccountResult(account: MSALAccount, authTokens: MSALNativeAuthTokens) -> MSALNativeAuthUserAccountResult? { + return .init(account: account, authTokens: authTokens, configuration: config, cacheAccessor: MSALNativeAuthCacheAccessor()) + } + + func makeMSIDConfiguration(scopes: [String]) -> MSIDConfiguration { + return .init( + authority: config.authority, + redirectUri: nil, + clientId: config.clientId, + target: scopes.joinScopes() + ) + } +} diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift new file mode 100644 index 0000000000..5aa9d939c3 --- /dev/null +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift @@ -0,0 +1,537 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +// swiftlint:disable file_length +// swiftlint:disable:next type_body_length +final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, MSALNativeAuthResetPasswordControlling { + private let kNumberOfTimesToRetryPollCompletionCall = 5 + + private let requestProvider: MSALNativeAuthResetPasswordRequestProviding + private let responseValidator: MSALNativeAuthResetPasswordResponseValidating + + init( + config: MSALNativeAuthConfiguration, + requestProvider: MSALNativeAuthResetPasswordRequestProviding, + responseValidator: MSALNativeAuthResetPasswordResponseValidating + ) { + self.requestProvider = requestProvider + self.responseValidator = responseValidator + + super.init(clientId: config.clientId) + } + + convenience init(config: MSALNativeAuthConfiguration) { + self.init( + config: config, + requestProvider: MSALNativeAuthResetPasswordRequestProvider( + requestConfigurator: MSALNativeAuthRequestConfigurator(config: config), + telemetryProvider: MSALNativeAuthTelemetryProvider() + ), + responseValidator: MSALNativeAuthResetPasswordResponseValidator() + ) + } + + // MARK: - Internal interface methods + + func resetPassword(parameters: MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartResult { + let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordStart, context: parameters.context) + let response = await performStartRequest(parameters: parameters) + return await handleStartResponse(response, event: event, context: parameters.context) + } + + func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeResult { + let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordResendCode, context: context) + let response = await performChallengeRequest(passwordResetToken: passwordResetToken, context: context) + return await handleResendCodeChallengeResponse(response, event: event, context: context) + } + + func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordVerifyCodeResult { + let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordSubmitCode, context: context) + + let params = MSALNativeAuthResetPasswordContinueRequestParameters( + context: context, + passwordResetToken: passwordResetToken, + grantType: .oobCode, + oobCode: code + ) + + let response = await performContinueRequest(parameters: params) + return await handleSubmitCodeResponse(response, passwordResetToken: passwordResetToken, event: event, context: context) + } + + func submitPassword( + password: String, + passwordSubmitToken: String, + context: MSIDRequestContext + ) async -> ResetPasswordRequiredResult { + let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordSubmit, context: context) + + let params = MSALNativeAuthResetPasswordSubmitRequestParameters( + context: context, + passwordSubmitToken: passwordSubmitToken, + newPassword: password + ) + let submitRequestResponse = await performSubmitRequest(parameters: params) + return await handleSubmitPasswordResponse(submitRequestResponse, passwordSubmitToken: passwordSubmitToken, event: event, context: context) + } + + // MARK: - Start Request handling + + private func performStartRequest( + parameters: MSALNativeAuthResetPasswordStartRequestProviderParameters + ) async -> MSALNativeAuthResetPasswordStartValidatedResponse { + let request: MSIDHttpRequest + + do { + request = try requestProvider.start(parameters: parameters) + } catch { + MSALLogger.log(level: .error, context: parameters.context, format: "Error creating resetpassword/start request: \(error)") + return .unexpectedError + } + + MSALLogger.log(level: .info, context: parameters.context, format: "Performing resetpassword/start request") + + let result: Result = await performRequest(request, context: parameters.context) + return responseValidator.validate(result, with: parameters.context) + } + + private func handleStartResponse(_ response: MSALNativeAuthResetPasswordStartValidatedResponse, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext) async -> ResetPasswordStartResult { + + MSALLogger.log(level: .verbose, context: context, format: "Finished resetpassword/start request") + + switch response { + case .success(let passwordResetToken): + let challengeResponse = await performChallengeRequest(passwordResetToken: passwordResetToken, context: context) + return await handleChallengeResponse(challengeResponse, event: event, context: context) + case .redirect: + let error = ResetPasswordStartError(type: .browserRequired, message: MSALNativeAuthErrorMessage.browserRequired) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "redirect error in resetpassword/start request \(error.errorDescription ?? "No error description")") + return .error(error) + case .error(let apiError): + let error = apiError.toResetPasswordStartPublicError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Error in resetpassword/start request \(error.errorDescription ?? "No error description")") + return .error(error) + case .unexpectedError: + let error = ResetPasswordStartError(type: .generalError) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in resetpassword/start request \(error.errorDescription ?? "No error description")") + return .error(error) + } + } + + // MARK: - Challenge Request handling + + private func performChallengeRequest( + passwordResetToken: String, + context: MSIDRequestContext + ) async -> MSALNativeAuthResetPasswordChallengeValidatedResponse { + let request: MSIDHttpRequest + + do { + request = try requestProvider.challenge(token: passwordResetToken, context: context) + } catch { + MSALLogger.log(level: .error, context: context, format: "Error creating Challenge Request: \(error)") + return .unexpectedError + } + + MSALLogger.log(level: .info, context: context, format: "Performing resetpassword/challenge request") + + let result: Result = await performRequest(request, context: context) + return responseValidator.validate(result, with: context) + } + + private func handleChallengeResponse( + _ response: MSALNativeAuthResetPasswordChallengeValidatedResponse, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) async -> ResetPasswordStartResult { + switch response { + case .success(let sentTo, let channelTargetType, let codeLength, let challengeToken): + MSALLogger.log(level: .info, context: context, format: "Successful resetpassword/challenge request") + stopTelemetryEvent(event, context: context) + + return .codeRequired( + newState: ResetPasswordCodeRequiredState(controller: self, flowToken: challengeToken), + sentTo: sentTo, + channelTargetType: channelTargetType, + codeLength: codeLength + ) + case .error(let apiError): + let error = apiError.toResetPasswordStartPublicError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Error in resetpassword/challenge request \(error.errorDescription ?? "No error description")") + return .error(error) + case .redirect: + let error = ResetPasswordStartError(type: .browserRequired, message: MSALNativeAuthErrorMessage.browserRequired) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Redirect error in resetpassword/challenge request \(error.errorDescription ?? "No error description")") + return .error(error) + case .unexpectedError: + let error = ResetPasswordStartError(type: .generalError) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in resetpassword/challenge request \(error.errorDescription ?? "No error description")") + return .error(error) + } + } + + private func handleResendCodeChallengeResponse( + _ response: MSALNativeAuthResetPasswordChallengeValidatedResponse, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) async -> ResetPasswordResendCodeResult { + switch response { + case .success(let sentTo, let channelTargetType, let codeLength, let challengeToken): + stopTelemetryEvent(event, context: context) + MSALLogger.log(level: .info, context: context, format: "Successful resetpassword/challenge (resend code) request") + return .codeRequired( + newState: ResetPasswordCodeRequiredState(controller: self, flowToken: challengeToken), + sentTo: sentTo, + channelTargetType: channelTargetType, + codeLength: codeLength + ) + case .error(let apiError): + let error = apiError.toResendCodePublicError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Error in resetpassword/challenge request (resend code) \(error.errorDescription ?? "No error description")") + return .error(error: error, newState: nil) + case .redirect, + .unexpectedError: + let error = ResendCodeError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Error in resetpassword/challenge request (resend code) \(error.errorDescription ?? "No error description")") + return .error(error: error, newState: nil) + } + } + + // MARK: - Continue Request handling + + private func performContinueRequest( + parameters: MSALNativeAuthResetPasswordContinueRequestParameters + ) async -> MSALNativeAuthResetPasswordContinueValidatedResponse { + let request: MSIDHttpRequest + + do { + request = try requestProvider.continue(parameters: parameters) + } catch { + MSALLogger.log(level: .error, context: parameters.context, format: "Error creating Continue Request: \(error)") + return .unexpectedError + } + + MSALLogger.log(level: .info, context: parameters.context, format: "Performing resetpassword/continue request") + + let result: Result = await performRequest(request, context: parameters.context) + return responseValidator.validate(result, with: parameters.context) + } + + private func handleSubmitCodeResponse( + _ response: MSALNativeAuthResetPasswordContinueValidatedResponse, + passwordResetToken: String, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) async -> ResetPasswordVerifyCodeResult { + switch response { + case .success(let passwordSubmitToken): + stopTelemetryEvent(event, context: context) + MSALLogger.log(level: .info, context: context, format: "Successful resetpassword/continue request") + return .passwordRequired(newState: ResetPasswordRequiredState(controller: self, flowToken: passwordSubmitToken)) + case .error(let apiError): + let error = apiError.toVerifyCodePublicError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Error in resetpassword/continue request \(error.errorDescription ?? "No error description")") + return .error(error: error, newState: nil) + case .unexpectedError: + let error = VerifyCodeError(type: .generalError) + self.stopTelemetryEvent(event, context: context, error: error) + + MSALLogger.log(level: .error, + context: context, + format: "Error calling resetpassword/continue \(error.errorDescription ?? "No error description")") + + return .error(error: error, newState: nil) + case .invalidOOB: + let error = VerifyCodeError(type: .invalidCode) + self.stopTelemetryEvent(event, context: context, error: error) + + MSALLogger.log(level: .error, + context: context, + format: "Invalid code error calling resetpassword/continue \(error.errorDescription ?? "No error description")") + + let state = ResetPasswordCodeRequiredState(controller: self, flowToken: passwordResetToken) + return .error(error: error, newState: state) + } + } + + // MARK: - Submit Request handling + + private func performSubmitRequest( + parameters: MSALNativeAuthResetPasswordSubmitRequestParameters + ) async -> MSALNativeAuthResetPasswordSubmitValidatedResponse { + let request: MSIDHttpRequest + + do { + request = try requestProvider.submit(parameters: parameters) + } catch { + MSALLogger.log(level: .error, context: parameters.context, format: "Error creating Submit Request: \(error)") + return .unexpectedError + } + + MSALLogger.log(level: .info, context: parameters.context, format: "Performing resetpassword/submit request") + + let result: Result = await performRequest(request, context: parameters.context) + return responseValidator.validate(result, with: parameters.context) + } + + private func handleSubmitPasswordResponse( + _ response: MSALNativeAuthResetPasswordSubmitValidatedResponse, + passwordSubmitToken: String, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) async -> ResetPasswordRequiredResult { + MSALLogger.log(level: .info, context: context, format: "Finished resetpassword/submit request") + + switch response { + case .success(let passwordResetToken, let pollInterval): + return await doPollCompletionLoop( + passwordResetToken: passwordResetToken, + pollInterval: pollInterval, + retriesRemaining: kNumberOfTimesToRetryPollCompletionCall, + event: event, + context: context + ) + case .passwordError(let apiError): + let error = apiError.toPasswordRequiredPublicError() + self.stopTelemetryEvent(event, context: context, error: error) + + MSALLogger.log(level: .error, + context: context, + format: "Password error calling resetpassword/submit \(error.errorDescription ?? "No error description")") + + return .error(error: error, newState: ResetPasswordRequiredState(controller: self, flowToken: passwordSubmitToken)) + case .error(let apiError): + let error = apiError.toPasswordRequiredPublicError() + self.stopTelemetryEvent(event, context: context, error: error) + + MSALLogger.log(level: .error, + context: context, + format: "Error calling resetpassword/submit \(error.errorDescription ?? "No error description")") + + return .error(error: error, newState: nil) + case .unexpectedError: + let error = PasswordRequiredError(type: .generalError) + self.stopTelemetryEvent(event, context: context, error: error) + + MSALLogger.log(level: .error, + context: context, + format: "Error calling resetpassword/submit \(error.errorDescription ?? "No error description")") + + return .error(error: error, newState: nil) + } + } + + // MARK: - Poll Completion Request handling + + private func doPollCompletionLoop( + passwordResetToken: String, + pollInterval: Int, + retriesRemaining: Int, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) async -> ResetPasswordRequiredResult { + MSALLogger.log(level: .verbose, context: context, format: "performing poll completion request...") + + let pollCompletionResponse = await performPollCompletionRequest( + passwordResetToken: passwordResetToken, + context: context + ) + + MSALLogger.log(level: .verbose, context: context, format: "handling poll completion response...") + + return await handlePollCompletionResponse( + pollCompletionResponse, + pollInterval: pollInterval, + retriesRemaining: retriesRemaining, + passwordResetToken: passwordResetToken, + event: event, + context: context + ) + } + + private func performPollCompletionRequest( + passwordResetToken: String, + context: MSIDRequestContext + ) async -> MSALNativeAuthResetPasswordPollCompletionValidatedResponse { + let parameters = MSALNativeAuthResetPasswordPollCompletionRequestParameters( + context: context, + passwordResetToken: passwordResetToken + ) + let request: MSIDHttpRequest + + do { + request = try requestProvider.pollCompletion(parameters: parameters) + } catch { + MSALLogger.log(level: .error, context: parameters.context, format: "Error creating Poll Completion Request: \(error)") + return .unexpectedError + } + + MSALLogger.log(level: .info, context: parameters.context, format: "Performing resetpassword/poll_completion request") + + let result: Result = await performRequest( + request, + context: parameters.context + ) + return responseValidator.validate(result, with: parameters.context) + } + + private func handlePollCompletionResponse( + _ response: MSALNativeAuthResetPasswordPollCompletionValidatedResponse, + pollInterval: Int, + retriesRemaining: Int, + passwordResetToken: String, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) async -> ResetPasswordRequiredResult { + MSALLogger.log(level: .info, context: context, format: "Finished resetpassword/poll_completion") + + switch response { + case .success(let status): + switch status { + case .inProgress, + .notStarted: + + return await retryPollCompletion( + passwordResetToken: passwordResetToken, + pollInterval: pollInterval, + retriesRemaining: retriesRemaining, + event: event, + context: context + ) + case .succeeded: + stopTelemetryEvent(event, context: context) + + return .completed + case .failed: + let error = PasswordRequiredError(type: .generalError) + self.stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, context: context, format: "password poll success returned status 'failed'") + + return .error(error: error, newState: nil) + } + case .passwordError(let apiError): + let error = apiError.toPasswordRequiredPublicError() + self.stopTelemetryEvent(event, context: context, error: error) + + MSALLogger.log(level: .error, + context: context, + format: "Password error calling resetpassword/poll_completion \(error.errorDescription ?? "No error description")") + + return .error(error: error, newState: ResetPasswordRequiredState(controller: self, flowToken: passwordResetToken)) + case .error(let apiError): + let error = apiError.toPasswordRequiredPublicError() + self.stopTelemetryEvent(event, context: context, error: error) + + MSALLogger.log(level: .error, + context: context, + format: "Error calling resetpassword/poll_completion \(error.errorDescription ?? "No error description")") + + return .error(error: error, newState: nil) + case .unexpectedError: + let error = PasswordRequiredError(type: .generalError) + self.stopTelemetryEvent(event, context: context, error: error) + + MSALLogger.log(level: .error, + context: context, + format: "Error calling resetpassword/poll_completion \(error.errorDescription ?? "No error description")") + + return .error(error: error, newState: nil) + } + } + + private func retryPollCompletion( + passwordResetToken: String, + pollInterval: Int, + retriesRemaining: Int, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) async -> ResetPasswordRequiredResult { + guard retriesRemaining > 0 else { + let error = PasswordRequiredError(type: .generalError) + self.stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, context: context, format: "password poll completion did not complete in time") + + return .error(error: error, newState: nil) + } + + MSALLogger.log( + level: .info, + context: context, + format: "resetpassword: waiting for \(pollInterval) seconds before retrying" + ) + + do { + try await Task.sleep(nanoseconds: 1_000_000_000 * UInt64(pollInterval)) + } catch { + // Task.sleep can throw a CancellationError if the Task is cancelled. + // We don't expect that to ever happen here so we just log it and carry on + + MSALLogger.log( + level: .error, + context: context, + format: "resetpassword: Task.sleep unexpectedly threw an error: \(error). Ignoring..." + ) + } + + return await doPollCompletionLoop( + passwordResetToken: passwordResetToken, + pollInterval: pollInterval, + retriesRemaining: retriesRemaining - 1, + event: event, + context: context + ) + } +} +// swiftlint:enable file_length diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift new file mode 100644 index 0000000000..1462d798b7 --- /dev/null +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift @@ -0,0 +1,40 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthResetPasswordControlling: AnyObject { + + func resetPassword(parameters: MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartResult + + func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeResult + + func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordVerifyCodeResult + + func submitPassword( + password: String, + passwordSubmitToken: String, + context: MSIDRequestContext + ) async -> ResetPasswordRequiredResult +} diff --git a/MSAL/src/native_auth/controllers/responses/CodeRequiredGenericResult.swift b/MSAL/src/native_auth/controllers/responses/CodeRequiredGenericResult.swift new file mode 100644 index 0000000000..5d2c928b5b --- /dev/null +++ b/MSAL/src/native_auth/controllers/responses/CodeRequiredGenericResult.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// Result type that contains information about the code sent, the next state of the reset password process and possible errors. +enum CodeRequiredGenericResult { + /// Returned if a user has received an email with code. + /// + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + case codeRequired(newState: State, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) + + /// An error object indicating why the operation failed. + case error(error: Error, newState: State?) +} diff --git a/MSAL/src/native_auth/controllers/responses/ResetPasswordResults.swift b/MSAL/src/native_auth/controllers/responses/ResetPasswordResults.swift new file mode 100644 index 0000000000..952e4b7df2 --- /dev/null +++ b/MSAL/src/native_auth/controllers/responses/ResetPasswordResults.swift @@ -0,0 +1,61 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// Represents the result of starting the reset password process. +enum ResetPasswordStartResult { + /// Returned if a user has received an email with code. + /// + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + case codeRequired(newState: ResetPasswordCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) + + /// An error object indicating why the operation failed. + case error(ResetPasswordStartError) +} + +/// Result type that contains information about the code sent, the next state of the reset password process and possible errors. +/// See ``CodeRequiredGenericResult`` for more information. +typealias ResetPasswordResendCodeResult = CodeRequiredGenericResult + +/// Represents the result of verifying a reset password verification code. +enum ResetPasswordVerifyCodeResult { + /// Returned when a password is required. + case passwordRequired(newState: ResetPasswordRequiredState) + + /// An error object indicating why the operation failed. + case error(error: VerifyCodeError, newState: ResetPasswordCodeRequiredState?) +} + +/// Represents the result of verifying a reset password verification code. +enum ResetPasswordRequiredResult { + /// Returned after the reset password operation completed successfully. + case completed + + /// An error object indicating why the operation failed. + case error(error: PasswordRequiredError, newState: ResetPasswordRequiredState?) +} diff --git a/MSAL/src/native_auth/controllers/responses/SignInResults.swift b/MSAL/src/native_auth/controllers/responses/SignInResults.swift new file mode 100644 index 0000000000..7100a39bea --- /dev/null +++ b/MSAL/src/native_auth/controllers/responses/SignInResults.swift @@ -0,0 +1,82 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// Represents the result of sign in using password. +enum SignInPasswordStartResult { + /// Returned after the sign in operation completed successfully. An object representing the signed in user account is returned. + case completed(MSALNativeAuthUserAccountResult) + + /// Returned if a user registered with email and code tries to sign in using password. + /// In this case MSAL will discard the password and will continue the sign in flow with code. + /// + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + case codeRequired(newState: SignInCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) + + /// An error object indicating why the operation failed. + case error(SignInPasswordStartError) +} + +/// Represents the result of sign in using code. +enum SignInStartResult { + /// Returned if a user has received an email with code. + /// + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + case codeRequired(newState: SignInCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) + + /// Returned if a user registered with email and password tries to sign in using code. + case passwordRequired(newState: SignInPasswordRequiredState) + + /// An error object indicating why the operation failed. + case error(SignInStartError) +} + +/// Result type that contains information about the code sent, the next state of the reset password process and possible errors. +/// See ``CodeRequiredGenericResult`` for more information. +typealias SignInResendCodeResult = CodeRequiredGenericResult + +/// Result type that contains information about the state of the sign in process. +enum SignInPasswordRequiredResult { + /// Returned after the sign in operation completed successfully. An object representing the signed in user account is returned. + case completed(MSALNativeAuthUserAccountResult) + + /// An error object indicating why the operation failed. It may contain a ``SignInPasswordRequiredState`` to continue the flow. + case error(error: PasswordRequiredError, newState: SignInPasswordRequiredState?) +} + +/// Result type that contains information about the state of the sign in process. +enum SignInVerifyCodeResult { + /// Returned after the sign in operation completed successfully. An object representing the signed in user account is returned. + case completed(MSALNativeAuthUserAccountResult) + + /// An error object indicating why the operation failed. It may contain a ``SignInPasswordRequiredState`` to continue the flow. + case error(error: VerifyCodeError, newState: SignInCodeRequiredState?) +} diff --git a/MSAL/src/native_auth/controllers/responses/SignUpResults.swift b/MSAL/src/native_auth/controllers/responses/SignUpResults.swift new file mode 100644 index 0000000000..f36ad9695e --- /dev/null +++ b/MSAL/src/native_auth/controllers/responses/SignUpResults.swift @@ -0,0 +1,113 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum SignUpPasswordStartResult { + /// Returned if a user has received an email with code. + /// + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + case codeRequired(newState: SignUpCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) + + /// Returned when the attributes sent are invalid. + case attributesInvalid([String]) + + /// An error object indicating why the operation failed. + case error(SignUpPasswordStartError) +} + +enum SignUpStartResult { + /// Returned if a user has received an email with code. + /// + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + case codeRequired(newState: SignUpCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) + + /// Returned when the attributes sent are invalid. + case attributesInvalid([String]) + + /// An error object indicating why the operation failed. + case error(SignUpStartError) +} + +/// An object of this type is returned after a user submits the code sent to their email/phone. +/// It contains the next state of the flow with follow on methods, depending on the server's response. +enum SignUpVerifyCodeResult { + /// Returned after the sign up operation completed successfully. + case completed(SignInAfterSignUpState) + + /// Returned when a password is required. + case passwordRequired(SignUpPasswordRequiredState) + + /// Returned when attributes are required. + case attributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) + + /// An error object indicating why the operation failed. + case error(error: VerifyCodeError, newState: SignUpCodeRequiredState?) +} + +enum SignUpResendCodeResult { + /// Returned if a user has received an email with code. + /// + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + case codeRequired(newState: SignUpCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) + + /// An error object indicating why the operation failed. + case error(ResendCodeError) +} + +/// An object of this type is returned after a user submits their password. +/// It contains the next state of the flow with follow on methods, depending on the server's response. +enum SignUpPasswordRequiredResult { + /// Returned after the sign up operation completed successfully. + case completed(SignInAfterSignUpState) + + /// Returned when attributes are required. + case attributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) + + /// An error object indicating why the operation failed. + case error(error: PasswordRequiredError, newState: SignUpPasswordRequiredState?) +} + +enum SignUpAttributesRequiredResult { + /// Returned after the sign up operation completed successfully. + case completed(SignInAfterSignUpState) + + /// Returned when attributes are required. + case attributesRequired(attributes: [MSALNativeAuthRequiredAttributes], state: SignUpAttributesRequiredState) + + /// Returned when the attributes sent are invalid. + case attributesInvalid(attributes: [String], newState: SignUpAttributesRequiredState) + + /// An error object indicating why the operation failed. + case error(error: AttributesRequiredError) +} diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift new file mode 100644 index 0000000000..c4e0415800 --- /dev/null +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift @@ -0,0 +1,592 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +// swiftlint:disable file_length +// swiftlint:disable:next type_body_length +final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALNativeAuthSignInControlling { + + // MARK: - Variables + + private let signInRequestProvider: MSALNativeAuthSignInRequestProviding + private let signInResponseValidator: MSALNativeAuthSignInResponseValidating + + // MARK: - Init + + init( + clientId: String, + signInRequestProvider: MSALNativeAuthSignInRequestProviding, + tokenRequestProvider: MSALNativeAuthTokenRequestProviding, + cacheAccessor: MSALNativeAuthCacheInterface, + factory: MSALNativeAuthResultBuildable, + signInResponseValidator: MSALNativeAuthSignInResponseValidating, + tokenResponseValidator: MSALNativeAuthTokenResponseValidating + ) { + self.signInRequestProvider = signInRequestProvider + self.signInResponseValidator = signInResponseValidator + super.init( + clientId: clientId, + requestProvider: tokenRequestProvider, + cacheAccessor: cacheAccessor, + factory: factory, + responseValidator: tokenResponseValidator + ) + } + + convenience init(config: MSALNativeAuthConfiguration) { + let factory = MSALNativeAuthResultFactory(config: config) + self.init( + clientId: config.clientId, + signInRequestProvider: MSALNativeAuthSignInRequestProvider( + requestConfigurator: MSALNativeAuthRequestConfigurator(config: config)), + tokenRequestProvider: MSALNativeAuthTokenRequestProvider( + requestConfigurator: MSALNativeAuthRequestConfigurator(config: config)), + cacheAccessor: MSALNativeAuthCacheAccessor(), + factory: factory, + signInResponseValidator: MSALNativeAuthSignInResponseValidator(), + tokenResponseValidator: MSALNativeAuthTokenResponseValidator( + factory: factory, + msidValidator: MSIDTokenResponseValidator()) + ) + } + + // MARK: - Internal + + func signIn(params: MSALNativeAuthSignInWithPasswordParameters) async -> SignInPasswordControllerResponse { + MSALLogger.log(level: .verbose, context: params.context, format: "SignIn with username and password started") + let telemetryInfo = TelemetryInfo( + event: makeAndStartTelemetryEvent(id: .telemetryApiIdSignInWithPasswordStart, context: params.context), + context: params.context + ) + + let initiateValidatedResponse = await performAndValidateSignInInitiate(username: params.username, telemetryInfo: telemetryInfo) + let result = await handleInitiateResponse(initiateValidatedResponse, telemetryInfo: telemetryInfo) + + switch result { + case .success(let challengeValidatedResponse): + return await handleChallengeResponse(challengeValidatedResponse, params: params, telemetryInfo: telemetryInfo) + case .failure(let error): + return .init(.error(error.convertToSignInPasswordStartError())) + } + } + + func signIn(params: MSALNativeAuthSignInWithCodeParameters) async -> SignInCodeControllerResponse { + MSALLogger.log(level: .verbose, context: params.context, format: "SignIn started") + let telemetryInfo = TelemetryInfo( + event: makeAndStartTelemetryEvent(id: .telemetryApiIdSignInWithCodeStart, context: params.context), + context: params.context + ) + + let initiateValidatedResponse = await performAndValidateSignInInitiate(username: params.username, telemetryInfo: telemetryInfo) + let result = await handleInitiateResponse(initiateValidatedResponse, telemetryInfo: telemetryInfo) + + switch result { + case .success(let challengeValidatedResponse): + return await handleChallengeResponse(challengeValidatedResponse, params: params, telemetryInfo: telemetryInfo) + case .failure(let error): + return .init(.error(error.convertToSignInStartError())) + } + } + + func signIn( + username: String, + slt: String?, + scopes: [String]?, + context: MSALNativeAuthRequestContext + ) async -> Result { + MSALLogger.log(level: .verbose, context: context, format: "SignIn after signUp started") + let telemetryInfo = TelemetryInfo( + event: makeAndStartTelemetryEvent(id: .telemetryApiIdSignInAfterSignUp, context: context), + context: context + ) + guard let slt = slt else { + MSALLogger.log(level: .error, context: context, format: "SignIn not available because SLT is nil") + let error = SignInAfterSignUpError(message: MSALNativeAuthErrorMessage.signInNotAvailable) + stopTelemetryEvent(telemetryInfo, error: error) + return .failure(error) + } + let scopes = joinScopes(scopes) + guard let request = createTokenRequest( + username: username, + scopes: scopes, + signInSLT: slt, + grantType: .slt, + context: context + ) else { + let error = SignInAfterSignUpError() + stopTelemetryEvent(telemetryInfo, error: error) + return .failure(error) + } + let config = factory.makeMSIDConfiguration(scopes: scopes) + let response = await performAndValidateTokenRequest(request, config: config, context: context) + + return await withCheckedContinuation { continuation in + handleTokenResponse( + response, + scopes: scopes, + telemetryInfo: telemetryInfo, + onSuccess: { accountResult in + continuation.resume(returning: .success(accountResult)) + }, + onError: { error in + continuation.resume(returning: .failure(SignInAfterSignUpError(message: error.errorDescription))) + } + ) + } + } + + // swiftlint:disable:next function_body_length + func submitCode( + _ code: String, + credentialToken: String, + context: MSALNativeAuthRequestContext, + scopes: [String] + ) async -> SignInVerifyCodeResult { + let telemetryInfo = TelemetryInfo( + event: makeAndStartTelemetryEvent(id: .telemetryApiIdSignInSubmitCode, context: context), + context: context + ) + guard let request = createTokenRequest( + scopes: scopes, + credentialToken: credentialToken, + oobCode: code, + grantType: .oobCode, + includeChallengeType: false, + context: context) else { + MSALLogger.log(level: .error, context: context, format: "SignIn, submit code: unable to create token request") + + return processSubmitCodeFailure( + errorType: .generalError, + telemetryInfo: telemetryInfo, + scopes: scopes, + credentialToken: credentialToken, + context: context + ) + } + let config = factory.makeMSIDConfiguration(scopes: scopes) + let response = await performAndValidateTokenRequest(request, config: config, context: context) + switch response { + case .success(let tokenResponse): + return await withCheckedContinuation { continuation in + handleMSIDTokenResponse( + tokenResponse: tokenResponse, + context: context, + telemetryInfo: telemetryInfo, + config: config, + onSuccess: { accountResult in + continuation.resume(returning: .completed(accountResult)) + }, + onError: { [weak self] error in + MSALLogger.log(level: .error, context: context, format: "SignIn submit code, token request failed with error \(error)") + guard let self = self else { return } + continuation.resume(returning: self.processSubmitCodeFailure( + errorType: .generalError, + telemetryInfo: telemetryInfo, + scopes: scopes, + credentialToken: credentialToken, + context: context + )) + } + ) + } + case .error(let errorType): + return processSubmitCodeFailure( + errorType: errorType, + telemetryInfo: telemetryInfo, + scopes: scopes, + credentialToken: credentialToken, + context: context + ) + } + } + + // swiftlint:disable:next function_body_length + func submitPassword( + _ password: String, + username: String, + credentialToken: String, + context: MSALNativeAuthRequestContext, + scopes: [String] + ) async -> SignInPasswordRequiredResult { + let telemetryInfo = TelemetryInfo( + event: makeAndStartTelemetryEvent(id: .telemetryApiIdSignInSubmitPassword, context: context), + context: context + ) + guard let request = createTokenRequest( + username: username, + password: password, + scopes: scopes, + credentialToken: credentialToken, + grantType: .password, + context: context) else { + MSALLogger.log(level: .error, context: context, format: "SignIn, submit password: unable to create token request") + return processSubmitPasswordFailure( + errorType: .generalError, + telemetryInfo: telemetryInfo, + username: username, + credentialToken: credentialToken, + scopes: scopes + ) + } + let config = factory.makeMSIDConfiguration(scopes: scopes) + let response = await performAndValidateTokenRequest(request, config: config, context: context) + switch response { + case .success(let tokenResponse): + return await withCheckedContinuation { continuation in + handleMSIDTokenResponse( + tokenResponse: tokenResponse, + context: context, + telemetryInfo: telemetryInfo, + config: config, + onSuccess: { accountResult in + continuation.resume(returning: .completed(accountResult)) + }, + onError: { [weak self] error in + MSALLogger.log(level: .error, context: context, format: "SignIn submit password, token request failed with error \(error)") + guard let self = self else { return } + continuation.resume(returning: self.processSubmitPasswordFailure( + errorType: .generalError, + telemetryInfo: telemetryInfo, + username: username, + credentialToken: credentialToken, + scopes: scopes + )) + } + ) + } + + case .error(let errorType): + return processSubmitPasswordFailure( + errorType: errorType, + telemetryInfo: telemetryInfo, + username: username, + credentialToken: credentialToken, + scopes: scopes + ) + } + } + + func resendCode( + credentialToken: String, + context: MSALNativeAuthRequestContext, + scopes: [String] + ) async -> SignInResendCodeResult { + let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignInResendCode, context: context) + let result = await performAndValidateChallengeRequest(credentialToken: credentialToken, context: context) + switch result { + case .passwordRequired: + let error = ResendCodeError() + MSALLogger.log(level: .error, context: context, format: "SignIn ResendCode: received unexpected password required API result") + stopTelemetryEvent(event, context: context, error: error) + return .error(error: error, newState: nil) + case .error(let challengeError): + let error = ResendCodeError() + MSALLogger.log(level: .error, context: context, format: "SignIn ResendCode: received challenge error response: \(challengeError)") + stopTelemetryEvent(event, context: context, error: error) + return .error(error: error, newState: SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken)) + case .codeRequired(let credentialToken, let sentTo, let channelType, let codeLength): + let state = SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken) + stopTelemetryEvent(event, context: context) + return .codeRequired(newState: state, sentTo: sentTo, channelTargetType: channelType, codeLength: codeLength) + } + } + + // MARK: - Private + + private func processSubmitCodeFailure( + errorType: MSALNativeAuthTokenValidatedErrorType, + telemetryInfo: TelemetryInfo, + scopes: [String], + credentialToken: String, + context: MSALNativeAuthRequestContext + ) -> SignInVerifyCodeResult { + MSALLogger.log( + level: .error, + context: context, + format: "SignIn completed with errorType: \(errorType)") + stopTelemetryEvent(telemetryInfo, error: errorType) + let state = SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken) + return .error(error: errorType.convertToVerifyCodeError(), newState: state) + } + + private func processSubmitPasswordFailure( + errorType: MSALNativeAuthTokenValidatedErrorType, + telemetryInfo: TelemetryInfo, + username: String, + credentialToken: String, + scopes: [String] + ) -> SignInPasswordRequiredResult { + MSALLogger.log( + level: .error, + context: telemetryInfo.context, + format: "SignIn with username and password completed with errorType: \(errorType)") + stopTelemetryEvent(telemetryInfo, error: errorType) + let state = SignInPasswordRequiredState(scopes: scopes, username: username, controller: self, flowToken: credentialToken) + return .error(error: errorType.convertToPasswordRequiredError(), newState: state) + } + + private func performAndValidateSignInInitiate( + username: String, + telemetryInfo: TelemetryInfo + ) async -> MSALNativeAuthSignInInitiateValidatedResponse { + guard let request = createInitiateRequest(username: username, context: telemetryInfo.context) else { + let error = MSALNativeAuthSignInInitiateValidatedErrorType.invalidRequest(message: nil) + stopTelemetryEvent(telemetryInfo, error: error) + return .error(error) + } + + let initiateResponse: Result = await performRequest(request, context: telemetryInfo.context) + let validatedResponse = signInResponseValidator.validate(context: telemetryInfo.context, result: initiateResponse) + + return validatedResponse + } + + private func handleInitiateResponse( + _ validatedResponse: MSALNativeAuthSignInInitiateValidatedResponse, + telemetryInfo: TelemetryInfo + ) async -> Result { + switch validatedResponse { + case .success(let credentialToken): + let challengeValidatedResponse = await performAndValidateChallengeRequest( + credentialToken: credentialToken, + context: telemetryInfo.context + ) + return .success(challengeValidatedResponse) + case .error(let error): + MSALLogger.log(level: .error, context: telemetryInfo.context, format: "SignIn: an error occurred after calling /initiate API: \(error)") + stopTelemetryEvent(telemetryInfo, error: error) + return .failure(error) + } + } + + private func handleTokenResponse( + _ response: MSALNativeAuthTokenValidatedResponse, + scopes: [String], + telemetryInfo: TelemetryInfo, + onSuccess: @escaping (MSALNativeAuthUserAccountResult) -> Void, + onError: @escaping (SignInPasswordStartError) -> Void + ) { + let config = factory.makeMSIDConfiguration(scopes: scopes) + switch response { + case .success(let tokenResponse): + return handleMSIDTokenResponse( + tokenResponse: tokenResponse, + context: telemetryInfo.context, + telemetryInfo: telemetryInfo, + config: config, + onSuccess: onSuccess, + onError: onError + ) + case .error(let errorType): + let error = errorType.convertToSignInPasswordStartError() + MSALLogger.log(level: .error, + context: telemetryInfo.context, + format: "SignIn completed with errorType: \(error.errorDescription ?? "No error description")") + stopTelemetryEvent(telemetryInfo, error: error) + onError(error) + } + } + + private func handleMSIDTokenResponse( + tokenResponse: MSIDTokenResponse, + context: MSALNativeAuthRequestContext, + telemetryInfo: TelemetryInfo, + config: MSIDConfiguration, + onSuccess: @escaping (MSALNativeAuthUserAccountResult) -> Void, + onError: @escaping (SignInPasswordStartError) -> Void + ) { + do { + let tokenResult = try cacheTokenResponse(tokenResponse, context: context, msidConfiguration: config) + + if let userAccountResult = factory.makeUserAccountResult(tokenResult: tokenResult, context: context) { + MSALLogger.log(level: .verbose, context: context, format: "SignIn completed successfully") + telemetryInfo.event?.setUserInformation(tokenResult.account) + stopTelemetryEvent(telemetryInfo) + onSuccess(userAccountResult) + } else { + let errorType = MSALNativeAuthTokenValidatedErrorType.generalError + MSALLogger.log(level: .error, context: telemetryInfo.context, format: "SignIn completed with error. Error creating UserAccountResult") + stopTelemetryEvent(telemetryInfo, error: errorType) + onError(errorType.convertToSignInPasswordStartError()) + } + } catch { + let errorType = MSALNativeAuthTokenValidatedErrorType.generalError + MSALLogger.log(level: .error, context: telemetryInfo.context, format: "SignIn completed with error \(error)") + stopTelemetryEvent(telemetryInfo, error: errorType) + onError(errorType.convertToSignInPasswordStartError()) + } + } + + private func handleChallengeResponse( + _ validatedResponse: MSALNativeAuthSignInChallengeValidatedResponse, + params: MSALNativeAuthSignInWithCodeParameters, + telemetryInfo: TelemetryInfo + ) async -> SignInCodeControllerResponse { + let scopes = joinScopes(params.scopes) + + switch validatedResponse { + case .passwordRequired(let credentialToken): + let state = SignInPasswordRequiredState( + scopes: scopes, + username: params.username, + controller: self, + flowToken: credentialToken + ) + + return .init(.passwordRequired(newState: state), telemetryUpdate: { [weak self] result in + switch result { + case .success: + MSALLogger.log(level: .verbose, context: telemetryInfo.context, format: "SignIn, password required") + self?.stopTelemetryEvent(telemetryInfo) + case .failure(let error): + MSALLogger.log( + level: .error, + context: telemetryInfo.context, + format: "SignIn error: \(error.errorDescription ?? "No error description")" + ) + self?.stopTelemetryEvent(telemetryInfo, error: error) + } + }) + case .codeRequired(let credentialToken, let sentTo, let channelType, let codeLength): + let state = SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken) + stopTelemetryEvent(telemetryInfo) + return .init(.codeRequired(newState: state, sentTo: sentTo, channelTargetType: channelType, codeLength: codeLength)) + case .error(let challengeError): + let error = challengeError.convertToSignInStartError() + MSALLogger.log(level: .error, + context: telemetryInfo.context, + format: "SignIn, completed with error: \(error.errorDescription ?? "No error description")") + stopTelemetryEvent(telemetryInfo, error: error) + return .init(.error(error)) + } + } + + // swiftlint:disable:next function_body_length + private func handleChallengeResponse( + _ validatedResponse: MSALNativeAuthSignInChallengeValidatedResponse, + params: MSALNativeAuthSignInWithPasswordParameters, + telemetryInfo: TelemetryInfo + ) async -> SignInPasswordControllerResponse { + let scopes = joinScopes(params.scopes) + + switch validatedResponse { + case .codeRequired(let credentialToken, let sentTo, let channelType, let codeLength): + MSALLogger.log(level: .warning, context: telemetryInfo.context, format: MSALNativeAuthErrorMessage.codeRequiredForPasswordUserLog) + let result: SignInPasswordStartResult = .codeRequired( + newState: SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken), + sentTo: sentTo, + channelTargetType: channelType, + codeLength: codeLength + ) + + return .init(result, telemetryUpdate: { [weak self] result in + switch result { + case .success: + self?.stopTelemetryEvent(telemetryInfo) + case .failure(let error): + MSALLogger.log( + level: .error, + context: telemetryInfo.context, + format: "SignIn error \(error.errorDescription ?? "No error description")" + ) + self?.stopTelemetryEvent(telemetryInfo, error: error) + } + }) + case .passwordRequired(let credentialToken): + guard let request = createTokenRequest( + username: params.username, + password: params.password, + scopes: scopes, + credentialToken: credentialToken, + grantType: .password, + context: telemetryInfo.context + ) else { + stopTelemetryEvent(telemetryInfo, error: MSALNativeAuthInternalError.invalidRequest) + return .init(.error(SignInPasswordStartError(type: .generalError))) + } + + let config = factory.makeMSIDConfiguration(scopes: scopes) + let response = await performAndValidateTokenRequest(request, config: config, context: telemetryInfo.context) + + return await withCheckedContinuation { continuation in + handleTokenResponse(response, + scopes: scopes, + telemetryInfo: telemetryInfo, + onSuccess: { accountResult in + continuation.resume(returning: SignInPasswordControllerResponse(.completed(accountResult))) + }, + onError: { error in + continuation.resume(returning: SignInPasswordControllerResponse(.error(error))) + } + ) + } + case .error(let challengeError): + let error = challengeError.convertToSignInPasswordStartError() + MSALLogger.log(level: .error, + context: telemetryInfo.context, + format: "SignIn, completed with error: \(error.errorDescription ?? "No error description")") + stopTelemetryEvent(telemetryInfo, error: error) + return .init(.error(error)) + } + } + + private func performAndValidateChallengeRequest( + credentialToken: String, + context: MSALNativeAuthRequestContext + ) async -> MSALNativeAuthSignInChallengeValidatedResponse { + guard let challengeRequest = createChallengeRequest(credentialToken: credentialToken, context: context) else { + MSALLogger.log(level: .error, context: context, format: "SignIn ResendCode: Cannot create Challenge request object") + return .error(.invalidRequest(message: nil)) + } + let challengeResponse: Result = await performRequest(challengeRequest, context: context) + return signInResponseValidator.validate(context: context, result: challengeResponse) + } + + private func createInitiateRequest(username: String, context: MSIDRequestContext) -> MSIDHttpRequest? { + let params = MSALNativeAuthSignInInitiateRequestParameters(context: context, username: username) + do { + return try signInRequestProvider.inititate(parameters: params, context: context) + } catch { + MSALLogger.log(level: .error, context: context, format: "Error creating SignIn Initiate Request: \(error)") + return nil + } + } + + private func createChallengeRequest( + credentialToken: String, + context: MSIDRequestContext + ) -> MSIDHttpRequest? { + do { + let params = MSALNativeAuthSignInChallengeRequestParameters( + context: context, + credentialToken: credentialToken + ) + return try signInRequestProvider.challenge(parameters: params, context: context) + } catch { + MSALLogger.log(level: .error, context: context, format: "Error creating SignIn Challenge Request: \(error)") + return nil + } + } +} diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift new file mode 100644 index 0000000000..d2c75df5cd --- /dev/null +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift @@ -0,0 +1,53 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +protocol MSALNativeAuthSignInControlling { + typealias SignInPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper + typealias SignInCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper + + func signIn(params: MSALNativeAuthSignInWithPasswordParameters) async -> SignInPasswordControllerResponse + + func signIn(params: MSALNativeAuthSignInWithCodeParameters) async -> SignInCodeControllerResponse + + func signIn( + username: String, + slt: String?, + scopes: [String]?, + context: MSALNativeAuthRequestContext + ) async -> Result + + func submitCode(_ code: String, credentialToken: String, context: MSALNativeAuthRequestContext, scopes: [String]) async -> SignInVerifyCodeResult + + func submitPassword( + _ password: String, + username: String, + credentialToken: String, + context: MSALNativeAuthRequestContext, + scopes: [String] + ) async -> SignInPasswordRequiredResult + + func resendCode(credentialToken: String, context: MSALNativeAuthRequestContext, scopes: [String]) async -> SignInResendCodeResult +} diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithCodeParameters.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithCodeParameters.swift new file mode 100644 index 0000000000..eea8924352 --- /dev/null +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithCodeParameters.swift @@ -0,0 +1,40 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +class MSALNativeAuthSignInWithCodeParameters { + let username: String + let context: MSALNativeAuthRequestContext + let scopes: [String]? + + init( + username: String, + context: MSALNativeAuthRequestContext, + scopes: [String]?) { + self.username = username + self.context = context + self.scopes = scopes + } +} diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithPasswordParameters.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithPasswordParameters.swift new file mode 100644 index 0000000000..4626f0b496 --- /dev/null +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithPasswordParameters.swift @@ -0,0 +1,41 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +class MSALNativeAuthSignInWithPasswordParameters: MSALNativeAuthSignInWithCodeParameters { + let password: String + + init( + username: String, + password: String, + context: MSALNativeAuthRequestContext, + scopes: [String]?) { + self.password = password + super.init( + username: username, + context: context, + scopes: scopes) + } +} diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift new file mode 100644 index 0000000000..a4291aabcc --- /dev/null +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift @@ -0,0 +1,664 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +// swiftlint:disable file_length +// swiftlint:disable:next type_body_length +final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNativeAuthSignUpControlling { + + // MARK: - Variables + + private let requestProvider: MSALNativeAuthSignUpRequestProviding + private let responseValidator: MSALNativeAuthSignUpResponseValidating + private let signInController: MSALNativeAuthSignInControlling + + // MARK: - Init + + init( + config: MSALNativeAuthConfiguration, + requestProvider: MSALNativeAuthSignUpRequestProviding, + responseValidator: MSALNativeAuthSignUpResponseValidating, + signInController: MSALNativeAuthSignInControlling + ) { + self.requestProvider = requestProvider + self.responseValidator = responseValidator + self.signInController = signInController + super.init(clientId: config.clientId) + } + + convenience init(config: MSALNativeAuthConfiguration) { + self.init( + config: config, + requestProvider: MSALNativeAuthSignUpRequestProvider( + requestConfigurator: MSALNativeAuthRequestConfigurator(config: config), + telemetryProvider: MSALNativeAuthTelemetryProvider() + ), + responseValidator: MSALNativeAuthSignUpResponseValidator(), + signInController: MSALNativeAuthSignInController(config: config) + ) + } + + // MARK: - Internal + + func signUpStartPassword(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) async -> SignUpStartPasswordControllerResponse { + let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpPasswordStart, context: parameters.context) + let result = await performAndValidateStartRequest(parameters: parameters) + return await handleSignUpStartPasswordResult(result, username: parameters.username, event: event, context: parameters.context) + } + + func signUpStartCode(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) async -> SignUpStartCodeControllerResponse { + let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpCodeStart, context: parameters.context) + let result = await performAndValidateStartRequest(parameters: parameters) + return await handleSignUpStartCodeResult(result, username: parameters.username, event: event, context: parameters.context) + } + + func resendCode(username: String, context: MSIDRequestContext, signUpToken: String) async -> SignUpResendCodeResult { + let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpResendCode, context: context) + let challengeResult = await performAndValidateChallengeRequest(signUpToken: signUpToken, context: context) + return handleResendCodeResult(challengeResult, username: username, event: event, context: context) + } + + func submitCode(_ code: String, username: String, signUpToken: String, context: MSIDRequestContext) async -> SignUpSubmitCodeControllerResponse { + let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpSubmitCode, context: context) + let params = MSALNativeAuthSignUpContinueRequestProviderParams(grantType: .oobCode, signUpToken: signUpToken, oobCode: code, context: context) + + let result = await performAndValidateContinueRequest(parameters: params) + return await handleSubmitCodeResult(result, username: username, signUpToken: signUpToken, event: event, context: context) + } + + func submitPassword( + _ password: String, + username: String, + signUpToken: String, + context: MSIDRequestContext + ) async -> SignUpSubmitPasswordControllerResponse { + let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpSubmitPassword, context: context) + + let params = MSALNativeAuthSignUpContinueRequestProviderParams( + grantType: .password, + signUpToken: signUpToken, + password: password, + context: context + ) + let continueRequestResult = await performAndValidateContinueRequest(parameters: params) + return handleSubmitPasswordResult(continueRequestResult, username: username, signUpToken: signUpToken, event: event, context: context) + } + + func submitAttributes( + _ attributes: [String: Any], + username: String, + signUpToken: String, + context: MSIDRequestContext + ) async -> SignUpAttributesRequiredResult { + let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpSubmitAttributes, context: context) + let params = MSALNativeAuthSignUpContinueRequestProviderParams( + grantType: .attributes, + signUpToken: signUpToken, + attributes: attributes, + context: context + ) + + let result = await performAndValidateContinueRequest(parameters: params) + return handleSubmitAttributesResult(result, username: username, signUpToken: signUpToken, event: event, context: context) + } + + // MARK: - Start Request handling + + private func performAndValidateStartRequest( + parameters: MSALNativeAuthSignUpStartRequestProviderParameters + ) async -> MSALNativeAuthSignUpStartValidatedResponse { + let request: MSIDHttpRequest + + do { + request = try requestProvider.start(parameters: parameters) + } catch { + MSALLogger.log(level: .error, context: parameters.context, format: "Error while creating Start Request: \(error)") + return .unexpectedError + } + + MSALLogger.log(level: .info, context: parameters.context, format: "Performing signup/start request") + + let response: Result = await performRequest(request, context: parameters.context) + return responseValidator.validate(response, with: parameters.context) + } + + // swiftlint:disable:next function_body_length + private func handleSignUpStartPasswordResult( + _ result: MSALNativeAuthSignUpStartValidatedResponse, + username: String, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) async -> SignUpStartPasswordControllerResponse { + switch result { + case .verificationRequired(let signUpToken, let attributes): + MSALLogger.log( + level: .info, + context: context, + format: "verification_required received from signup/start with password request for attributes: \(attributes)" + ) + let challengeResult = await performAndValidateChallengeRequest(signUpToken: signUpToken, context: context) + return handleSignUpPasswordChallengeResult(challengeResult, username: username, event: event, context: context) + case .attributeValidationFailed(let invalidAttributes): + MSALLogger.log( + level: .error, + context: context, + format: "attribute_validation_failed received from signup/start with password request for attributes: \(invalidAttributes)" + ) + let message = String(format: MSALNativeAuthErrorMessage.attributeValidationFailedSignUpStart, invalidAttributes.description) + let error = SignUpPasswordStartError(type: .generalError, message: message) + return .init(.attributesInvalid(invalidAttributes), telemetryUpdate: { [weak self] result in + switch result { + case .success: + self?.stopTelemetryEvent(event, context: context, error: error) + case .failure(let error): + MSALLogger.log( + level: .error, + context: context, + format: "SignUp with password error: \(error.errorDescription ?? "No error description")" + ) + self?.stopTelemetryEvent(event, context: context, error: error) + } + }) + case .redirect: + let error = SignUpPasswordStartError(type: .browserRequired) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "redirect error in signup/start with password request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + case .error(let apiError): + let error = apiError.toSignUpStartPasswordPublicError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Error in signup/start with password request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + case .invalidUsername(let apiError): + let error = SignUpPasswordStartError(type: .invalidUsername, message: apiError.errorDescription) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "InvalidUsername in signup/start with password request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + case .invalidClientId(let apiError): + let error = SignUpPasswordStartError(type: .generalError, message: apiError.errorDescription) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Invalid Client Id in signup/start with password request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + case .unexpectedError: + let error = SignUpPasswordStartError(type: .generalError) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/start with password request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + } + } + + // swiftlint:disable:next function_body_length + private func handleSignUpStartCodeResult( + _ result: MSALNativeAuthSignUpStartValidatedResponse, + username: String, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) async -> SignUpStartCodeControllerResponse { + switch result { + case .verificationRequired(let signUpToken, let unverifiedAttributes): + MSALLogger.log( + level: .info, + context: context, + format: "verification_required received from signup/start request for attributes: \(unverifiedAttributes)" + ) + let challengeResult = await performAndValidateChallengeRequest(signUpToken: signUpToken, context: context) + return handleSignUpCodeChallengeResult(challengeResult, username: username, event: event, context: context) + case .attributeValidationFailed(let invalidAttributes): + MSALLogger.log( + level: .error, + context: context, + format: "attribute_validation_failed received from signup/start request for attributes: \(invalidAttributes)" + ) + let message = String(format: MSALNativeAuthErrorMessage.attributeValidationFailedSignUpStart, invalidAttributes.description) + let error = SignUpStartError(type: .generalError, message: message) + return .init(.attributesInvalid(invalidAttributes), telemetryUpdate: { [weak self] result in + switch result { + case .success: + self?.stopTelemetryEvent(event, context: context, error: error) + case .failure(let error): + MSALLogger.log(level: .error, context: context, format: "SignUp error \(error.errorDescription ?? "No error description")") + self?.stopTelemetryEvent(event, context: context, error: error) + } + }) + case .redirect: + let error = SignUpStartError(type: .browserRequired) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Redirect error in signup/start request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + case .error(let apiError): + let error = apiError.toSignUpStartPublicError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Error in signup/start request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + case .invalidUsername(let apiError): + let error = SignUpStartError(type: .invalidUsername, message: apiError.errorDescription) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "InvalidUsername in signup/start request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + case .invalidClientId(let apiError): + let error = SignUpStartError(type: .generalError, message: apiError.errorDescription) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Invalid Client Id in signup/start request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + case .unexpectedError: + let error = SignUpStartError(type: .generalError) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/start request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + } + } + + // MARK: - Challenge Request handling + + private func performAndValidateChallengeRequest( + signUpToken: String, + context: MSIDRequestContext + ) async -> MSALNativeAuthSignUpChallengeValidatedResponse { + let request: MSIDHttpRequest + + do { + request = try requestProvider.challenge(token: signUpToken, context: context) + } catch { + MSALLogger.log(level: .error, context: context, format: "Error while creating Challenge Request: \(error)") + return .unexpectedError + } + + MSALLogger.log(level: .info, context: context, format: "Performing signup/challenge request") + + let result: Result = await performRequest(request, context: context) + return responseValidator.validate(result, with: context) + } + + private func handleSignUpPasswordChallengeResult( + _ result: MSALNativeAuthSignUpChallengeValidatedResponse, + username: String, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) -> SignUpStartPasswordControllerResponse { + switch result { + case .codeRequired(let sentTo, let challengeType, let codeLength, let signUpToken): + MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge password request") + stopTelemetryEvent(event, context: context) + return SignUpStartPasswordControllerResponse( + .codeRequired( + newState: SignUpCodeRequiredState(controller: self, username: username, flowToken: signUpToken), + sentTo: sentTo, + channelTargetType: challengeType, + codeLength: codeLength + ) + ) + case .error(let apiError): + let error = apiError.toSignUpPasswordStartPublicError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Error in signup/challenge password request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + case .redirect: + let error = SignUpPasswordStartError(type: .browserRequired) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Redirect error in signup/challenge password request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + case .unexpectedError, + .passwordRequired: + let error = SignUpPasswordStartError(type: .generalError) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/challenge password request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + } + } + + private func handleSignUpCodeChallengeResult( + _ result: MSALNativeAuthSignUpChallengeValidatedResponse, + username: String, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) -> SignUpStartCodeControllerResponse { + switch result { + case .codeRequired(let sentTo, let challengeType, let codeLength, let signUpToken): + MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge request") + stopTelemetryEvent(event, context: context) + return SignUpStartCodeControllerResponse( + .codeRequired( + newState: SignUpCodeRequiredState(controller: self, username: username, flowToken: signUpToken), + sentTo: sentTo, + channelTargetType: challengeType, + codeLength: codeLength + ) + ) + case .error(let apiError): + let error = apiError.toSignUpStartPublicError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Error in signup/challenge request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + case .redirect: + let error = SignUpStartError(type: .browserRequired) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Redirect error in signup/challenge request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + case .unexpectedError, + .passwordRequired: + let error = SignUpStartError(type: .generalError) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/challenge request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) + } + } + + private func handleResendCodeResult( + _ result: MSALNativeAuthSignUpChallengeValidatedResponse, + username: String, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) -> SignUpResendCodeResult { + switch result { + case .codeRequired(let sentTo, let challengeType, let codeLength, let signUpToken): + MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge resendCode request") + stopTelemetryEvent(event, context: context) + return .codeRequired( + newState: SignUpCodeRequiredState(controller: self, username: username, flowToken: signUpToken), + sentTo: sentTo, + channelTargetType: challengeType, + codeLength: codeLength + ) + case .error(let apiError): + let error = apiError.toResendCodePublicError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Error in signup/challenge resendCode request \(error.errorDescription ?? "No error description")") + return .error(error) + case .redirect, + .unexpectedError, + .passwordRequired: + let error = ResendCodeError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/challenge resendCode request \(error.errorDescription ?? "No error description")") + return .error(error) + } + } + + /// This method handles the /challenge response after receiving a "credential_required" error + private func handlePerformChallengeAfterContinueRequest( + _ result: MSALNativeAuthSignUpChallengeValidatedResponse, + username: String, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) -> SignUpSubmitCodeControllerResponse { + switch result { + case .passwordRequired(let signUpToken): + MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge request after credential_required") + + let state = SignUpPasswordRequiredState(controller: self, username: username, flowToken: signUpToken) + + return .init(.passwordRequired(state), telemetryUpdate: { [weak self] result in + switch result { + case .success: + self?.stopTelemetryEvent(event, context: context) + case .failure(let error): + MSALLogger.log(level: .error, context: context, format: "SignUp error \(error.errorDescription ?? "No error description")") + self?.stopTelemetryEvent(event, context: context, error: error) + } + }) + case .redirect: + let error = VerifyCodeError(type: .browserRequired) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Redirect error in signup/challenge request \(error.errorDescription ?? "No error description")") + return .init(.error(error: error, newState: nil)) + case .error, + .codeRequired, + .unexpectedError: + let error = VerifyCodeError(type: .generalError) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/challenge request \(error.errorDescription ?? "No error description")") + return .init(.error(error: error, newState: nil)) + } + } + + // MARK: - Continue Request handling + + private func performAndValidateContinueRequest( + parameters: MSALNativeAuthSignUpContinueRequestProviderParams + ) async -> MSALNativeAuthSignUpContinueValidatedResponse { + let request: MSIDHttpRequest + + do { + request = try requestProvider.continue(parameters: parameters) + } catch { + MSALLogger.log(level: .error, context: parameters.context, format: "Error while creating Continue Request: \(error)") + return .unexpectedError + } + + MSALLogger.log(level: .info, context: parameters.context, format: "Performing signup/continue request") + + let result: Result = await performRequest(request, context: parameters.context) + return responseValidator.validate(result, with: parameters.context) + } + + private func handleSubmitCodeResult( + _ result: MSALNativeAuthSignUpContinueValidatedResponse, + username: String, + signUpToken: String, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) async -> SignUpSubmitCodeControllerResponse { + switch result { + case .success(let slt): + let state = createSignInAfterSignUpStateUsingSLT(slt, username: username, event: event, context: context) + return .init(.completed(state)) + case .invalidUserInput: + MSALLogger.log(level: .error, context: context, format: "invalid_user_input error in signup/continue request") + + let error = VerifyCodeError(type: .invalidCode) + stopTelemetryEvent(event, context: context, error: error) + let state = SignUpCodeRequiredState(controller: self, username: username, flowToken: signUpToken) + return .init(.error(error: error, newState: state)) + case .credentialRequired(let signUpToken): + MSALLogger.log(level: .verbose, context: context, format: "credential_required received in signup/continue request") + + let result = await performAndValidateChallengeRequest(signUpToken: signUpToken, context: context) + return handlePerformChallengeAfterContinueRequest(result, username: username, event: event, context: context) + case .attributesRequired(let signUpToken, let attributes): + MSALLogger.log(level: .verbose, context: context, format: "attributes_required received in signup/continue request: \(attributes)") + + let state = SignUpAttributesRequiredState(controller: self, username: username, flowToken: signUpToken) + return .init(.attributesRequired(attributes: attributes, newState: state), telemetryUpdate: { [weak self] result in + switch result { + case .success: + self?.stopTelemetryEvent(event, context: context) + case .failure(let error): + MSALLogger.log(level: .error, context: context, format: "SignUp error \(error.errorDescription ?? "No error description")") + self?.stopTelemetryEvent(event, context: context, error: error) + } + }) + case .error(let apiError): + let error = apiError.toVerifyCodePublicError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Error in signup/continue request \(error.errorDescription ?? "No error description")") + return .init(.error(error: error, newState: nil)) + case .attributeValidationFailed, + .unexpectedError: + let error = VerifyCodeError(type: .generalError) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/continue request \(error.errorDescription ?? "No error description")") + return .init(.error(error: error, newState: nil)) + } + } + + private func handleSubmitPasswordResult( + _ result: MSALNativeAuthSignUpContinueValidatedResponse, + username: String, + signUpToken: String, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) -> SignUpSubmitPasswordControllerResponse { + switch result { + case .success(let slt): + let state = createSignInAfterSignUpStateUsingSLT(slt, username: username, event: event, context: context) + return .init(.completed(state)) + case .invalidUserInput(let error): + let error = error.toPasswordRequiredPublicError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log( + level: .error, + context: context, + format: "invalid_user_input error in signup/continue submitPassword request \(error.errorDescription ?? "No error description")" + ) + + let state = SignUpPasswordRequiredState(controller: self, username: username, flowToken: signUpToken) + return .init(.error(error: error, newState: state)) + case .attributesRequired(let signUpToken, let attributes): + MSALLogger.log(level: .verbose, context: context, format: "attributes_required received in signup/continue request: \(attributes)") + + let state = SignUpAttributesRequiredState(controller: self, username: username, flowToken: signUpToken) + + return .init(.attributesRequired(attributes: attributes, newState: state), telemetryUpdate: { [weak self] result in + switch result { + case .success: + self?.stopTelemetryEvent(event, context: context) + case .failure(let error): + MSALLogger.log(level: .error, context: context, format: "SignUp error \(error.errorDescription ?? "No error description")") + self?.stopTelemetryEvent(event, context: context, error: error) + } + }) + case .error(let apiError): + let error = apiError.toPasswordRequiredPublicError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/continue submitPassword request \(error.errorDescription ?? "No error description")") + return .init(.error(error: error, newState: nil)) + case .attributeValidationFailed, + .credentialRequired, + .unexpectedError: + let error = PasswordRequiredError(type: .generalError) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/continue submitPassword request \(error.errorDescription ?? "No error description")") + return .init(.error(error: error, newState: nil)) + } + } + + private func handleSubmitAttributesResult( + _ result: MSALNativeAuthSignUpContinueValidatedResponse, + username: String, + signUpToken: String, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) -> SignUpAttributesRequiredResult { + switch result { + case .success(let slt): + let state = createSignInAfterSignUpStateUsingSLT(slt, username: username, event: event, context: context) + return .completed(state) + case .attributesRequired(let signUpToken, let attributes): + let error = AttributesRequiredError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "attributes_required received in signup/continue submitAttributes request: \(attributes)") + + let state = SignUpAttributesRequiredState(controller: self, username: username, flowToken: signUpToken) + return .attributesRequired(attributes: attributes, state: state) + case .attributeValidationFailed(let signUpToken, let invalidAttributes): + let message = "attribute_validation_failed from signup/continue submitAttributes request. Make sure these attributes are correct: \(invalidAttributes)" // swiftlint:disable:this line_length + MSALLogger.log(level: .error, context: context, format: message) + + let errorMessage = String(format: MSALNativeAuthErrorMessage.attributeValidationFailed, invalidAttributes.description) + let error = AttributesRequiredError(message: errorMessage) + stopTelemetryEvent(event, context: context, error: error) + + let state = SignUpAttributesRequiredState(controller: self, username: username, flowToken: signUpToken) + return .attributesInvalid(attributes: invalidAttributes, newState: state) + case .error(let apiError): + let error = apiError.toAttributesRequiredPublicError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Error in signup/continue submitAttributes request \(error.errorDescription ?? "No error description")") + return .error(error: error) + case .credentialRequired, + .unexpectedError, + .invalidUserInput: + let error = AttributesRequiredError() + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/continue submitAttributes request \(error.errorDescription ?? "No error description")") + return .error(error: error) + } + } + + private func createSignInAfterSignUpStateUsingSLT( + _ slt: String?, + username: String, + event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext + ) -> SignInAfterSignUpState { + MSALLogger.log(level: .info, context: context, format: "SignUp completed successfully") + stopTelemetryEvent(event, context: context) + return SignInAfterSignUpState(controller: signInController, username: username, slt: slt) + } +} diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift new file mode 100644 index 0000000000..7e79e734ca --- /dev/null +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift @@ -0,0 +1,55 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthSignUpControlling: AnyObject { + + typealias SignUpStartPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper + typealias SignUpStartCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper + typealias SignUpSubmitCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper + typealias SignUpSubmitPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper + + func signUpStartPassword(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) async -> SignUpStartPasswordControllerResponse + + func signUpStartCode(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) async -> SignUpStartCodeControllerResponse + + func resendCode(username: String, context: MSIDRequestContext, signUpToken: String) async -> SignUpResendCodeResult + + func submitCode(_ code: String, username: String, signUpToken: String, context: MSIDRequestContext) async -> SignUpSubmitCodeControllerResponse + + func submitPassword( + _ password: String, + username: String, + signUpToken: String, + context: MSIDRequestContext + ) async -> SignUpSubmitPasswordControllerResponse + + func submitAttributes( + _ attributes: [String: Any], + username: String, + signUpToken: String, + context: MSIDRequestContext + ) async -> SignUpAttributesRequiredResult +} diff --git a/MSAL/src/native_auth/extension/Array+joinScopes.swift b/MSAL/src/native_auth/extension/Array+joinScopes.swift new file mode 100644 index 0000000000..23b6765269 --- /dev/null +++ b/MSAL/src/native_auth/extension/Array+joinScopes.swift @@ -0,0 +1,31 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +extension Array where Element: StringProtocol { + func joinScopes() -> String { + return self.joined(separator: " ") + } +} diff --git a/MSAL/src/native_auth/input_validator/MSALNativeAuthInputValidator.swift b/MSAL/src/native_auth/input_validator/MSALNativeAuthInputValidator.swift new file mode 100644 index 0000000000..e5e19da5ae --- /dev/null +++ b/MSAL/src/native_auth/input_validator/MSALNativeAuthInputValidator.swift @@ -0,0 +1,35 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +protocol MSALNativeAuthInputValidating { + func isInputValid(_ input: String) -> Bool +} + +final class MSALNativeAuthInputValidator: MSALNativeAuthInputValidating { + func isInputValid(_ input: String) -> Bool { + return !input.isEmpty + } +} diff --git a/MSAL/src/native_auth/logger/MSALLogMask.h b/MSAL/src/native_auth/logger/MSALLogMask.h new file mode 100644 index 0000000000..c8aad7f450 --- /dev/null +++ b/MSAL/src/native_auth/logger/MSALLogMask.h @@ -0,0 +1,55 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MSALLogMask : NSObject + +/// Terms used in to clasify data: +/// - PII - Personally identifiable Information +/// - EUII - End User identifiable Information such as UPN, username, email +/// - EUPII - End User Pseudonymous Identifiers +/// - OII - Organization Identifiable Information + +/// Used for masking any PII (Personally identifiable Information) including EUII and EUPI as long as log level is MSIDLogMaskingSettingsMaskAllPII +/// - Parameter parameter: Any object that needs to be masked ++ (MSIDMaskedLogParameter*) maskPII:(nullable id) parameter; + +/// Used for masking any EUII (End User identifiable Information) such as UPN, username, email as long as log level is MSIDLogMaskingSettingsMaskEUIIOnly or below +/// - Parameter parameter: Any object that needs to be masked ++ (MSIDMaskedLogParameter*) maskEUII:(nullable id) parameter; + +/// Used for masking any Trackable User Information such as Accounts or URLs that should be hashed as long as log level is MSIDLogMaskingSettingsMaskAllPII +/// - Parameter parameter: Any object that needs to be masked via hashing ++ (MSIDMaskedHashableLogParameter*) maskTrackablePII:(nullable id) parameter; + +/// Used for masking any Username (email, id, account identifier) that should be hashed as long as log level is MSIDLogMaskingSettingsMaskEUIIOnly or below +/// - Parameter parameter: Any Username that needs to be masked via hashing ++ (MSIDMaskedUsernameLogParameter*) maskUsername:(nullable id) parameter; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/native_auth/logger/MSALLogMask.m b/MSAL/src/native_auth/logger/MSALLogMask.m new file mode 100644 index 0000000000..22b44512b4 --- /dev/null +++ b/MSAL/src/native_auth/logger/MSALLogMask.m @@ -0,0 +1,45 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "MSALLogMask.h" + +@implementation MSALLogMask + ++ (MSIDMaskedLogParameter*) maskPII:(nullable id) parameter { + return MSID_PII_LOG_MASKABLE(parameter); +} + ++ (MSIDMaskedLogParameter*) maskEUII:(nullable id) parameter { + return MSID_EUII_ONLY_LOG_MASKABLE(parameter); +} + ++ (MSIDMaskedHashableLogParameter*) maskTrackablePII:(nullable id) parameter { + return MSID_PII_LOG_TRACKABLE(parameter); +} + ++ (MSIDMaskedUsernameLogParameter*) maskUsername:(nullable id) parameter { + return MSID_PII_LOG_EMAIL(parameter); +} + +@end diff --git a/MSAL/src/native_auth/logger/MSALNativeAuthLogging.swift b/MSAL/src/native_auth/logger/MSALNativeAuthLogging.swift new file mode 100644 index 0000000000..11847f9425 --- /dev/null +++ b/MSAL/src/native_auth/logger/MSALNativeAuthLogging.swift @@ -0,0 +1,150 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALLogging { + static func log( + level: MSIDLogLevel, + context: MSIDRequestContext?, + filename: String, + lineNumber: Int, + function: String, + format: String, + _ args: CVarArg...) + static func logPII( + level: MSIDLogLevel, + context: MSIDRequestContext?, + filename: String, + lineNumber: Int, + function: String, + format: String, + _ args: CVarArg...) + static func log( + level: MSIDLogLevel, + correlationId: UUID?, + filename: String, + lineNumber: Int, + function: String, + format: String, + _ args: CVarArg...) + static func logPII( + level: MSIDLogLevel, + correlationId: UUID?, + filename: String, + lineNumber: Int, + function: String, + format: String, + _ args: CVarArg...) +} + +extension MSALLogger: MSALLogging { + private static func logCommon(level: MSIDLogLevel, + context: MSIDRequestContext? = nil, + correlationId: UUID? = nil, + containsPII: Bool, + filename: String = #fileID, + lineNumber: Int = #line, + function: String = #function, + format: String, + _ args: CVaListPointer) { + MSIDLogger.shared().log(with: level, + context: context, + correlationId: correlationId, + containsPII: containsPII, + filename: filename, + lineNumber: UInt(lineNumber), + function: function, + format: format, + formatArgs: args) + } + + static func log(level: MSIDLogLevel, + context: MSIDRequestContext?, + filename: String = #fileID, + lineNumber: Int = #line, + function: String = #function, + format: String, + _ args: CVarArg...) { + logCommon(level: level, + context: context, + containsPII: false, + filename: filename, + lineNumber: lineNumber, + function: function, + format: format, + getVaList(args)) + } + + static func logPII(level: MSIDLogLevel, + context: MSIDRequestContext?, + filename: String = #fileID, + lineNumber: Int = #line, + function: String = #function, + format: String, + _ args: CVarArg...) { + logCommon(level: level, + context: context, + containsPII: true, + filename: filename, + lineNumber: lineNumber, + function: function, + format: format, + getVaList(args)) + } + + static func log(level: MSIDLogLevel, + correlationId: UUID?, + filename: String = #fileID, + lineNumber: Int = #line, + function: String = #function, + format: String, + _ args: CVarArg...) { + logCommon(level: level, + correlationId: correlationId, + containsPII: false, + filename: filename, + lineNumber: lineNumber, + function: function, + format: format, + getVaList(args)) + } + + static func logPII(level: MSIDLogLevel, + correlationId: UUID?, + filename: String = #fileID, + lineNumber: Int = #line, + function: String = #function, + format: String, + _ args: CVarArg...) { + logCommon(level: level, + correlationId: correlationId, + containsPII: true, + filename: filename, + lineNumber: lineNumber, + function: function, + format: format, + getVaList(args)) + } +} diff --git a/MSAL/src/native_auth/network/MSALNativeAuthCustomErrorSerializer.swift b/MSAL/src/native_auth/network/MSALNativeAuthCustomErrorSerializer.swift new file mode 100644 index 0000000000..e15c33a62f --- /dev/null +++ b/MSAL/src/native_auth/network/MSALNativeAuthCustomErrorSerializer.swift @@ -0,0 +1,35 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthCustomErrorSerializer: NSObject, MSIDResponseSerialization { + func responseObject(for httpResponse: HTTPURLResponse?, data: Data?, context: MSIDRequestContext?) throws -> Any { + let customError = try JSONDecoder().decode(T.self, from: data ?? Data()) + // the successfuly constructed "customError" needs to be thrown, since the previous "try" command just validates the object (error) decoding + throw customError + } +} diff --git a/MSAL/src/native_auth/network/MSALNativeAuthEndpoint.swift b/MSAL/src/native_auth/network/MSALNativeAuthEndpoint.swift new file mode 100644 index 0000000000..796dba68f9 --- /dev/null +++ b/MSAL/src/native_auth/network/MSALNativeAuthEndpoint.swift @@ -0,0 +1,38 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +enum MSALNativeAuthEndpoint: String, CaseIterable { + case signUpStart = "/signup/v1.0/start" + case signUpChallenge = "/signup/v1.0/challenge" + case signUpContinue = "/signup/v1.0/continue" + case signInInitiate = "/oauth2/v2.0/initiate" + case signInChallenge = "/oauth2/v2.0/challenge" + case token = "/oauth2/v2.0/token" + case resetPasswordStart = "/resetpassword/v1.0/start" + case resetPasswordChallenge = "/resetpassword/v1.0/challenge" + case resetPasswordContinue = "/resetpassword/v1.0/continue" + case resetPasswordComplete = "/resetpassword/v1.0/complete" + case resetPasswordSubmit = "/resetpassword/v1.0/submit" + case resetpasswordPollCompletion = "/resetpassword/v1.0/poll_completion" +} diff --git a/MSAL/src/native_auth/network/MSALNativeAuthGrantType.swift b/MSAL/src/native_auth/network/MSALNativeAuthGrantType.swift new file mode 100644 index 0000000000..c14e1a7864 --- /dev/null +++ b/MSAL/src/native_auth/network/MSALNativeAuthGrantType.swift @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +enum MSALNativeAuthGrantType: String { + case password + case otp = "passwordless_otp" + case oobCode = "oob" + case refreshToken = "refresh_token" + case slt + case attributes +} diff --git a/MSAL/src/native_auth/network/MSALNativeAuthInternalChallengeType.swift b/MSAL/src/native_auth/network/MSALNativeAuthInternalChallengeType.swift new file mode 100644 index 0000000000..5af18320ab --- /dev/null +++ b/MSAL/src/native_auth/network/MSALNativeAuthInternalChallengeType.swift @@ -0,0 +1,30 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +enum MSALNativeAuthInternalChallengeType: String, Decodable { + case oob + case password + case otp + case redirect +} diff --git a/MSAL/src/native_auth/network/MSALNativeAuthInternalChannelType.swift b/MSAL/src/native_auth/network/MSALNativeAuthInternalChannelType.swift new file mode 100644 index 0000000000..6d8bdd666b --- /dev/null +++ b/MSAL/src/native_auth/network/MSALNativeAuthInternalChannelType.swift @@ -0,0 +1,37 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +enum MSALNativeAuthInternalChannelType: String, Decodable { + case phone + case email + + func toPublicChannelType() -> MSALNativeAuthChannelType { + switch self { + case .phone: + return .phone + case .email: + return .email + } + } +} diff --git a/MSAL/src/native_auth/network/MSALNativeAuthRequestConfigurator.swift b/MSAL/src/native_auth/network/MSALNativeAuthRequestConfigurator.swift new file mode 100644 index 0000000000..1e0172a130 --- /dev/null +++ b/MSAL/src/native_auth/network/MSALNativeAuthRequestConfigurator.swift @@ -0,0 +1,271 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@_implementationOnly import MSAL_Private + +enum MSALNativeAuthRequestConfiguratorType { + enum SignUp { + case start(MSALNativeAuthSignUpStartRequestParameters) + case challenge(MSALNativeAuthSignUpChallengeRequestParameters) + case `continue`(MSALNativeAuthSignUpContinueRequestParameters) + } + + enum SignIn { + case initiate(MSALNativeAuthSignInInitiateRequestParameters) + case challenge(MSALNativeAuthSignInChallengeRequestParameters) + } + + enum ResetPassword { + case start(MSALNativeAuthResetPasswordStartRequestParameters) + case challenge(MSALNativeAuthResetPasswordChallengeRequestParameters) + case `continue`(MSALNativeAuthResetPasswordContinueRequestParameters) + case submit(MSALNativeAuthResetPasswordSubmitRequestParameters) + case pollCompletion(MSALNativeAuthResetPasswordPollCompletionRequestParameters) + } + + enum Token { + case signInWithPassword(MSALNativeAuthTokenRequestParameters) + case refreshToken(MSALNativeAuthTokenRequestParameters) + } + + case signUp(SignUp) + case signIn(SignIn) + case resetPassword(ResetPassword) + case token(Token) +} + +class MSALNativeAuthRequestConfigurator: MSIDAADRequestConfigurator { + let config: MSALNativeAuthConfiguration + + init(config: MSALNativeAuthConfiguration) { + self.config = config + } + + func configure(configuratorType: MSALNativeAuthRequestConfiguratorType, + request: MSIDHttpRequest, + telemetryProvider: MSALNativeAuthTelemetryProviding) throws { + switch configuratorType { + case .signUp(let subType): + try signUpConfigure(subType, request, telemetryProvider) + case .signIn(let subType): + try signInConfigure(subType, request, telemetryProvider) + case .resetPassword(let subType): + try resetPasswordConfigure(subType, request, telemetryProvider) + case .token(let subType): + try tokenConfigure(subType, request, telemetryProvider) + } + } + + private func signUpConfigure(_ subType: MSALNativeAuthRequestConfiguratorType.SignUp, + _ request: MSIDHttpRequest, + _ telemetryProvider: MSALNativeAuthTelemetryProviding) throws { + switch subType { + case .start(let parameters): + let responseSerializer = MSALNativeAuthResponseSerializer() + let telemetry = telemetryProvider.telemetryForSignUp(type: .signUpStart) + let errorHandler = MSALNativeAuthResponseErrorHandler() + try configure(request: request, + parameters: parameters, + responseSerializer: responseSerializer, + telemetry: telemetry, + errorHandler: errorHandler) + case .challenge(let parameters): + let responseSerializer = MSALNativeAuthResponseSerializer() + let telemetry = telemetryProvider.telemetryForSignUp(type: .signUpChallenge) + let errorHandler = MSALNativeAuthResponseErrorHandler() + try configure(request: request, + parameters: parameters, + responseSerializer: responseSerializer, + telemetry: telemetry, + errorHandler: errorHandler) + case .continue(let parameters): + let responseSerializer = MSALNativeAuthResponseSerializer() + let telemetry = telemetryProvider.telemetryForSignUp(type: .signUpContinue) + let errorHandler = MSALNativeAuthResponseErrorHandler() + try configure(request: request, + parameters: parameters, + responseSerializer: responseSerializer, + telemetry: telemetry, + errorHandler: errorHandler) + } + } + + private func signInConfigure(_ subType: MSALNativeAuthRequestConfiguratorType.SignIn, + _ request: MSIDHttpRequest, + _ telemetryProvider: MSALNativeAuthTelemetryProviding) throws { + switch subType { + case .initiate(let parameters): + let responseSerializer = MSALNativeAuthResponseSerializer() + let telemetry = telemetryProvider.telemetryForSignIn(type: .signInInitiate) + let errorHandler = MSALNativeAuthResponseErrorHandler() + try configure(request: request, + parameters: parameters, + responseSerializer: responseSerializer, + telemetry: telemetry, + errorHandler: errorHandler) + case .challenge(let parameters): + let responseSerializer = MSALNativeAuthResponseSerializer() + let telemetry = telemetryProvider.telemetryForSignIn(type: .signInChallenge) + let errorHandler = MSALNativeAuthResponseErrorHandler() + try configure(request: request, + parameters: parameters, + responseSerializer: responseSerializer, + telemetry: telemetry, + errorHandler: errorHandler) + } + } + + private func resetPasswordConfigure(_ subType: MSALNativeAuthRequestConfiguratorType.ResetPassword, + _ request: MSIDHttpRequest, + _ telemetryProvider: MSALNativeAuthTelemetryProviding) throws { + switch subType { + case .start(let parameters): + let responseSerializer = MSALNativeAuthResponseSerializer() + let telemetry = telemetryProvider.telemetryForResetPassword(type: .resetPasswordStart) + let errorHandler = MSALNativeAuthResponseErrorHandler() + try configure(request: request, + parameters: parameters, + responseSerializer: responseSerializer, + telemetry: telemetry, + errorHandler: errorHandler) + case .challenge(let parameters): + let responseSerializer = MSALNativeAuthResponseSerializer() + let telemetry = telemetryProvider.telemetryForResetPassword(type: .resetPasswordChallenge) + let errorHandler = MSALNativeAuthResponseErrorHandler() + try configure(request: request, + parameters: parameters, + responseSerializer: responseSerializer, + telemetry: telemetry, + errorHandler: errorHandler) + case .continue(let parameters): + let responseSerializer = MSALNativeAuthResponseSerializer() + let telemetry = telemetryProvider.telemetryForResetPassword(type: .resetPasswordContinue) + let errorHandler = MSALNativeAuthResponseErrorHandler() + try configure(request: request, + parameters: parameters, + responseSerializer: responseSerializer, + telemetry: telemetry, + errorHandler: errorHandler) + case .submit(let parameters): + let responseSerializer = MSALNativeAuthResponseSerializer() + let telemetry = telemetryProvider.telemetryForResetPassword(type: .resetPasswordSubmit) + let errorHandler = MSALNativeAuthResponseErrorHandler() + try configure(request: request, + parameters: parameters, + responseSerializer: responseSerializer, + telemetry: telemetry, + errorHandler: errorHandler) + case .pollCompletion(let parameters): + let responseSerializer = + MSALNativeAuthResponseSerializer() + let telemetry = telemetryProvider.telemetryForResetPassword(type: .resetPasswordPollCompletion) + let errorHandler = + MSALNativeAuthResponseErrorHandler() + try configure(request: request, + parameters: parameters, + responseSerializer: responseSerializer, + telemetry: telemetry, + errorHandler: errorHandler) + } + } + + private func tokenConfigure(_ subType: MSALNativeAuthRequestConfiguratorType.Token, + _ request: MSIDHttpRequest, + _ telemetryProvider: MSALNativeAuthTelemetryProviding) throws { + switch subType { + case .signInWithPassword(let parameters): + let telemetry = telemetryProvider.telemetryForToken(type: .signInWithPassword) + let errorHandler = MSALNativeAuthResponseErrorHandler() + try configure(request: request, + parameters: parameters, + telemetry: telemetry, + errorHandler: errorHandler) + case .refreshToken(let parameters): + let telemetry = telemetryProvider.telemetryForToken(type: .refreshToken) + let errorHandler = MSALNativeAuthResponseErrorHandler() + try configure(request: request, + parameters: parameters, + telemetry: telemetry, + errorHandler: errorHandler) + } + } + + private func configure( + request: MSIDHttpRequest, + parameters: MSALNativeAuthRequestable, + responseSerializer: MSALNativeAuthResponseSerializer, + telemetry: MSALNativeAuthCurrentRequestTelemetry, + errorHandler: MSALNativeAuthResponseErrorHandler + ) throws { + try configure(request: request, + parameters: parameters, + telemetry: telemetry, + errorHandler: errorHandler) + request.responseSerializer = responseSerializer + } + + // For the SignInToken endpoint the Response serialiser should not be set + // Because we cannot have optional Generic Types parameters at call time + // especially with Decodable we have to have another method name + // This might be removed in the future if the response from the /token endpoint changes + private func configure( + request: MSIDHttpRequest, + parameters: MSALNativeAuthRequestable, + telemetry: MSALNativeAuthCurrentRequestTelemetry, + errorHandler: MSALNativeAuthResponseErrorHandler + ) throws { + try configureAllRequests(request: request, parameters: parameters) + request.requestSerializer = MSALNativeAuthUrlRequestSerializer( + context: parameters.context, + encoding: .wwwFormUrlEncoded + ) + request.serverTelemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetry, + context: parameters.context + ) + request.errorHandler = errorHandler + } + + private func configureAllRequests(request: MSIDHttpRequest, + parameters: MSALNativeAuthRequestable) throws { + request.context = parameters.context + request.parameters = parameters.makeRequestBody(config: config) + + do { + let endpointUrl = try parameters.makeEndpointUrl(config: config) + request.urlRequest = URLRequest(url: endpointUrl) + request.urlRequest?.httpMethod = MSALParameterStringForHttpMethod(.POST) + } catch { + MSALLogger.log( + level: .error, + context: parameters.context, + format: "Endpoint could not be created: \(error)" + ) + throw MSALNativeAuthInternalError.invalidRequest + } + configure(request) + } +} diff --git a/MSAL/src/native_auth/network/MSALNativeAuthRequestParametersKey.swift b/MSAL/src/native_auth/network/MSALNativeAuthRequestParametersKey.swift new file mode 100644 index 0000000000..73646795a2 --- /dev/null +++ b/MSAL/src/native_auth/network/MSALNativeAuthRequestParametersKey.swift @@ -0,0 +1,48 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthRequestParametersKey: String { + case clientId = "client_id" + case challengeType = "challenge_type" + case grantType = "grant_type" + case username + case email + case password + case scope + case credentialToken = "credential_token" + case flowToken + case oobCode = "oob" + case otp + case customAttributes + case signInSLT = "signin_slt" + case attributes + case signUpToken = "signup_token" + case passwordResetToken = "password_reset_token" + case passwordSubmitToken = "password_submit_token" + case newPassword = "new_password" + case clientInfo = "client_info" + case refreshToken = "refresh_token" +} diff --git a/MSAL/src/native_auth/network/MSALNativeAuthResponseErrorHandler.swift b/MSAL/src/native_auth/network/MSALNativeAuthResponseErrorHandler.swift new file mode 100644 index 0000000000..7f5574f52b --- /dev/null +++ b/MSAL/src/native_auth/network/MSALNativeAuthResponseErrorHandler.swift @@ -0,0 +1,51 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthResponseErrorHandler: NSObject, MSIDHttpRequestErrorHandling { + + // swiftlint:disable:next function_parameter_count + func handleError( + _ error: Error?, + httpResponse: HTTPURLResponse?, + data: Data?, + httpRequest: MSIDHttpRequestProtocol?, + responseSerializer: MSIDResponseSerialization?, + externalSSOContext ssoContext: MSIDExternalSSOContext?, + context: MSIDRequestContext?, + completionBlock: MSIDHttpRequestDidCompleteBlock? + ) { + MSIDAADRequestErrorHandler().handleError(error, + httpResponse: httpResponse, + data: data, + httpRequest: httpRequest, + responseSerializer: MSALNativeAuthCustomErrorSerializer(), + externalSSOContext: ssoContext, + context: context, + completionBlock: completionBlock) + } +} diff --git a/MSAL/src/native_auth/network/MSALNativeAuthResponseSerializer.swift b/MSAL/src/native_auth/network/MSALNativeAuthResponseSerializer.swift new file mode 100644 index 0000000000..bd545ed2bb --- /dev/null +++ b/MSAL/src/native_auth/network/MSALNativeAuthResponseSerializer.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthResponseSerializer: NSObject, MSIDResponseSerialization { + + func responseObject(for httpResponse: HTTPURLResponse?, data: Data?, context: MSIDRequestContext?) throws -> Any { + guard let data = data else { + throw MSALNativeAuthInternalError.responseSerializationError + } + + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + + return try decoder.decode(T.self, from: data) + } +} diff --git a/MSAL/src/native_auth/network/MSALNativeAuthUrlRequestSerializer.swift b/MSAL/src/native_auth/network/MSALNativeAuthUrlRequestSerializer.swift new file mode 100644 index 0000000000..fa561fff6c --- /dev/null +++ b/MSAL/src/native_auth/network/MSALNativeAuthUrlRequestSerializer.swift @@ -0,0 +1,94 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +enum MSALNativeAuthUrlRequestEncoding: String { + case wwwFormUrlEncoded = "application/x-www-form-urlencoded" + case json = "application/json" +} + +final class MSALNativeAuthUrlRequestSerializer: NSObject, MSIDRequestSerialization { + + private let context: MSIDRequestContext + private let encoding: MSALNativeAuthUrlRequestEncoding + + init(context: MSIDRequestContext, encoding: MSALNativeAuthUrlRequestEncoding) { + self.context = context + self.encoding = encoding + } + + func serialize( + with request: URLRequest, + parameters: [AnyHashable: Any], + headers: [AnyHashable: Any] + ) -> URLRequest { + + var request = request + var requestHeaders: [String: String] = [:] + + // Convert entries from `headers` to a dictionary [String: String] + + headers.forEach { + if let key = $0.key as? String, let value = $0.value as? String { + requestHeaders[key] = value + } else { + MSALLogger.log(level: .error, context: context, format: "Header serialization failed") + } + } + + if encoding == .json { + if JSONSerialization.isValidJSONObject(parameters) { + do { + let jsonData = try JSONSerialization.data(withJSONObject: parameters) + request.httpBody = jsonData + } catch { + MSALLogger.log( + level: .error, + context: context, + format: "HTTP body request serialization failed with error: \(error.localizedDescription)" + ) + } + } else { + MSALLogger.log(level: .error, context: context, format: "HTTP body request serialization failed") + } + } else { + let encodedBody = formUrlEncode(parameters) + request.httpBody = encodedBody.data(using: .utf8) + } + + requestHeaders["Content-Type"] = encoding.rawValue + request.allHTTPHeaderFields = requestHeaders + + return request + } + + private func formUrlEncode(_ parameters: [AnyHashable: Any]) -> String { + parameters.map { + let encodedKey = (($0.key as? String) ?? "").msidWWWFormURLEncode() ?? "" + let encodedValue = (($0.value as? String) ?? "").msidWWWFormURLEncode() ?? "" + return "\(encodedKey)=\(encodedValue)" + }.joined(separator: "&") + } +} diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorCodes.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorCodes.swift new file mode 100644 index 0000000000..32210dd480 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorCodes.swift @@ -0,0 +1,35 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This enum contains all the handled error cases from eSTS in error_codes +enum MSALNativeAuthESTSApiErrorCodes: Int { + case userNotFound = 50034 + case invalidCredentials = 50126 + case invalidOTP = 50181 + case incorrectOTP = 501811 + case OTPNoCacheEntryForUser = 50184 + case strongAuthRequired = 50076 + case userNotHaveAPassword = 500222 + case invalidRequestParameter = 90100 +} diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorDescriptions.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorDescriptions.swift new file mode 100644 index 0000000000..86ee5dffd3 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorDescriptions.swift @@ -0,0 +1,31 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +// This enum contains all the handled error cases from eSTS in error_descriptions +enum MSALNativeAuthESTSApiErrorDescriptions: String, CaseIterable { + case usernameParameterIsEmptyOrNotValid = "username parameter is empty or not valid" + case clientIdParameterIsEmptyOrNotValid = "client_id parameter is empty or not valid" +} diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift new file mode 100644 index 0000000000..dd97229bb1 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift @@ -0,0 +1,42 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// swiftlint:disable line_length +enum MSALNativeAuthErrorMessage { + static let invalidScope = "Invalid scope" + static let delegateNotImplemented = "MSALNativeAuth has called an optional delegate method that has not been implemented" + static let unsupportedMFA = "MFA currently not supported. Use the browser instead" + static let browserRequired = "Browser required. Use acquireTokenInteractively instead" + static let userDoesNotHavePassword = "User does not have password associated with account" + static let invalidServerResponse = "Invalid server response" + static let userNotFound = "User does not exist" + static let attributeValidationFailedSignUpStart = "Check the invalid attributes and start the sign-up process again. Invalid attributes: %@" + static let attributeValidationFailed = "Invalid attributes: %@" + static let signInNotAvailable = "Sign In is not available at this point, please use the standalone sign in methods" + static let passwordRequiredNotImplemented = "Implementation of onSignInPasswordRequired required" + static let codeRequiredNotImplemented = "Implementation of onSignInCodeRequired required" + static let codeRequiredForPasswordUserLog = "This user does not have a password associated with their account. SDK will call `delegate.onSignInCodeRequired()` and the entered password will be ignored" +} + +// swiftlint:enable line_length diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthInnerError.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthInnerError.swift new file mode 100644 index 0000000000..16c0cb2f99 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthInnerError.swift @@ -0,0 +1,34 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthInnerError: Decodable, Equatable { + let error: String + let errorDescription: String? + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + } +} diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift new file mode 100644 index 0000000000..6f2a400213 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift @@ -0,0 +1,35 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +protocol MSALNativeAuthResponseError: Error, Decodable, Equatable { + associatedtype ErrorCode: RawRepresentable where ErrorCode.RawValue == String + + var error: ErrorCode { get } + var errorDescription: String? { get } + var errorCodes: [Int]? { get } + var errorURI: String? { get } + var innerErrors: [MSALNativeAuthInnerError]? { get } +} diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift new file mode 100644 index 0000000000..8fd2cc2043 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthResetPasswordChallengeOauth2ErrorCode: String, Decodable, CaseIterable { + case invalidRequest = "invalid_request" + case invalidClient = "invalid_client" + case expiredToken = "expired_token" + case unsupportedChallengeType = "unsupported_challenge_type" +} diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift new file mode 100644 index 0000000000..25ec42d489 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift @@ -0,0 +1,67 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthResetPasswordChallengeResponseError: MSALNativeAuthResponseError { + + let error: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode + let errorDescription: String? + let errorCodes: [Int]? + let errorURI: String? + let innerErrors: [MSALNativeAuthInnerError]? + let target: String? + + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + case errorCodes = "error_codes" + case errorURI = "error_uri" + case innerErrors = "inner_errors" + case target + } +} + +extension MSALNativeAuthResetPasswordChallengeResponseError { + + func toResetPasswordStartPublicError() -> ResetPasswordStartError { + switch error { + case .invalidRequest, + .invalidClient, + .unsupportedChallengeType, + .expiredToken: + return .init(type: .generalError, message: errorDescription) + } + } + + func toResendCodePublicError() -> ResendCodeError { + switch error { + case .invalidClient, + .unsupportedChallengeType, + .expiredToken, + .invalidRequest: + return .init(message: errorDescription) + } + } +} diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift new file mode 100644 index 0000000000..27fec6c774 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift @@ -0,0 +1,34 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthResetPasswordContinueOauth2ErrorCode: String, Decodable, CaseIterable { + case invalidRequest = "invalid_request" + case invalidClient = "invalid_client" + case invalidGrant = "invalid_grant" + case expiredToken = "expired_token" + case verificationRequired = "verification_required" + case invalidOOBValue = "invalid_oob_value" +} diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift new file mode 100644 index 0000000000..3db3d0f7f5 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift @@ -0,0 +1,62 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthResetPasswordContinueResponseError: MSALNativeAuthResponseError { + + let error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode + let errorDescription: String? + let errorCodes: [Int]? + let errorURI: String? + let innerErrors: [MSALNativeAuthInnerError]? + let target: String? + let passwordResetToken: String? + + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + case errorCodes = "error_codes" + case errorURI = "error_uri" + case innerErrors = "inner_errors" + case target + case passwordResetToken = "password_reset_token" + } +} + +extension MSALNativeAuthResetPasswordContinueResponseError { + + func toVerifyCodePublicError() -> VerifyCodeError { + switch error { + case .invalidOOBValue: + return .init(type: .invalidCode, message: errorDescription) + case .invalidClient, + .expiredToken, + .invalidRequest, + .invalidGrant, + .verificationRequired: + return .init(type: .generalError, message: errorDescription) + } + } +} diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift new file mode 100644 index 0000000000..aec42a88d2 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift @@ -0,0 +1,37 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode: String, Decodable, CaseIterable { + case invalidRequest = "invalid_request" + case invalidClient = "invalid_client" + case expiredToken = "expired_token" + case passwordTooWeak = "password_too_weak" + case passwordTooShort = "password_too_short" + case passwordTooLong = "password_too_long" + case passwordRecentlyUsed = "password_recently_used" + case passwordBanned = "password_banned" + case userNotFound = "user_not_found" +} diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift new file mode 100644 index 0000000000..e96898b754 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift @@ -0,0 +1,63 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthResetPasswordPollCompletionResponseError: MSALNativeAuthResponseError { + + let error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode + let errorDescription: String? + let errorCodes: [Int]? + let errorURI: String? + let innerErrors: [MSALNativeAuthInnerError]? + let target: String? + + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + case errorCodes = "error_codes" + case errorURI = "error_uri" + case innerErrors = "inner_errors" + case target + } +} + +extension MSALNativeAuthResetPasswordPollCompletionResponseError { + + func toPasswordRequiredPublicError() -> PasswordRequiredError { + switch error { + case .passwordTooWeak, + .passwordTooShort, + .passwordTooLong, + .passwordRecentlyUsed, + .passwordBanned: + return .init(type: .invalidPassword, message: errorDescription) + case .invalidClient, + .expiredToken, + .invalidRequest, + .userNotFound: + return .init(type: .generalError, message: errorDescription) + } + } +} diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift new file mode 100644 index 0000000000..c136e4a571 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthResetPasswordStartOauth2ErrorCode: String, Decodable, CaseIterable { + case invalidRequest = "invalid_request" + case invalidClient = "invalid_client" + case userNotFound = "user_not_found" + case unsupportedChallengeType = "unsupported_challenge_type" +} diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift new file mode 100644 index 0000000000..d9aa86dc1f --- /dev/null +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift @@ -0,0 +1,44 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthResetPasswordStartResponseError: MSALNativeAuthResponseError { + + let error: MSALNativeAuthResetPasswordStartOauth2ErrorCode + let errorDescription: String? + let errorCodes: [Int]? + let errorURI: String? + let innerErrors: [MSALNativeAuthInnerError]? + let target: String? + + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + case errorCodes = "error_codes" + case errorURI = "error_uri" + case innerErrors = "inner_errors" + case target + } +} diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift new file mode 100644 index 0000000000..de0e3d1724 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift @@ -0,0 +1,36 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthResetPasswordSubmitOauth2ErrorCode: String, Decodable, CaseIterable { + case invalidRequest = "invalid_request" + case invalidClient = "invalid_client" + case expiredToken = "expired_token" + case passwordTooWeak = "password_too_weak" + case passwordTooShort = "password_too_short" + case passwordTooLong = "password_too_long" + case passwordRecentlyUsed = "password_recently_used" + case passwordBanned = "password_banned" +} diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift new file mode 100644 index 0000000000..96c473bca1 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift @@ -0,0 +1,62 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthResetPasswordSubmitResponseError: MSALNativeAuthResponseError { + + let error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode + let errorDescription: String? + let errorCodes: [Int]? + let errorURI: String? + let innerErrors: [MSALNativeAuthInnerError]? + let target: String? + + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + case errorCodes = "error_codes" + case errorURI = "error_uri" + case innerErrors = "inner_errors" + case target + } +} + +extension MSALNativeAuthResetPasswordSubmitResponseError { + + func toPasswordRequiredPublicError() -> PasswordRequiredError { + switch error { + case .passwordTooWeak, + .passwordTooShort, + .passwordTooLong, + .passwordRecentlyUsed, + .passwordBanned: + return .init(type: .invalidPassword, message: errorDescription) + case .invalidClient, + .expiredToken, + .invalidRequest: + return .init(type: .generalError, message: errorDescription) + } + } +} diff --git a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeOauth2ErrorCode.swift new file mode 100644 index 0000000000..62f0afad5a --- /dev/null +++ b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeOauth2ErrorCode.swift @@ -0,0 +1,33 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthSignInChallengeOauth2ErrorCode: String, Decodable { + case invalidRequest = "invalid_request" + case unauthorizedClient = "unauthorized_client" + case invalidGrant = "invalid_grant" + case expiredToken = "expired_token" + case unsupportedChallengeType = "unsupported_challenge_type" +} diff --git a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift new file mode 100644 index 0000000000..308b5d8153 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift @@ -0,0 +1,42 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthSignInChallengeResponseError: MSALNativeAuthResponseError { + + let error: MSALNativeAuthSignInChallengeOauth2ErrorCode + let errorDescription: String? + let errorCodes: [Int]? + let errorURI: String? + let innerErrors: [MSALNativeAuthInnerError]? + + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + case errorCodes = "error_codes" + case errorURI = "error_uri" + case innerErrors = "inner_errors" + } +} diff --git a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateOauth2ErrorCode.swift new file mode 100644 index 0000000000..57c98fdb65 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateOauth2ErrorCode.swift @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthSignInInitiateOauth2ErrorCode: String, Decodable, CaseIterable { + case invalidRequest = "invalid_request" + case unauthorizedClient = "unauthorized_client" + case invalidGrant = "invalid_grant" + case unsupportedChallengeType = "unsupported_challenge_type" +} diff --git a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift new file mode 100644 index 0000000000..0b77edf5a9 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift @@ -0,0 +1,42 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthSignInInitiateResponseError: MSALNativeAuthResponseError { + + let error: MSALNativeAuthSignInInitiateOauth2ErrorCode + let errorDescription: String? + let errorCodes: [Int]? + let errorURI: String? + let innerErrors: [MSALNativeAuthInnerError]? + + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + case errorCodes = "error_codes" + case errorURI = "error_uri" + case innerErrors = "inner_errors" + } +} diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthErrorBasicAttributes.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthErrorBasicAttributes.swift new file mode 100644 index 0000000000..1733027336 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthErrorBasicAttributes.swift @@ -0,0 +1,33 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +class MSALNativeAuthErrorBasicAttributes: NSObject, Decodable { + let name: String + + init(name: String) { + self.name = name + } +} diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthRequiredAttributeOptions.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthRequiredAttributeOptions.swift new file mode 100644 index 0000000000..b40687982a --- /dev/null +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthRequiredAttributeOptions.swift @@ -0,0 +1,29 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +class MSALNativeAuthRequiredAttributeOptions: Decodable { + let regex: String? +} diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthRequiredAttributesInternal.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthRequiredAttributesInternal.swift new file mode 100644 index 0000000000..c7076db9f6 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthRequiredAttributesInternal.swift @@ -0,0 +1,47 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +class MSALNativeAuthRequiredAttributesInternal: NSObject, Decodable { + let name: String + let type: String + let required: Bool + let options: MSALNativeAuthRequiredAttributeOptions? + + init(name: String, type: String, required: Bool, options: MSALNativeAuthRequiredAttributeOptions? = nil) { + self.name = name + self.type = type + self.required = required + self.options = options + } + + override var description: String { + return "\(name)" + } + + func toRequiredAttributesPublic() -> MSALNativeAuthRequiredAttributes { + MSALNativeAuthRequiredAttributes(name: name, type: type, required: required, regex: options?.regex) + } +} diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift new file mode 100644 index 0000000000..1ae84bcc4c --- /dev/null +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthSignUpChallengeOauth2ErrorCode: String, Decodable, CaseIterable { + case invalidRequest = "invalid_request" + case unauthorizedClient = "unauthorized_client" + case unsupportedChallengeType = "unsupported_challenge_type" + case expiredToken = "expired_token" +} diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift new file mode 100644 index 0000000000..c1aa02f9a7 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift @@ -0,0 +1,84 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthSignUpChallengeResponseError: MSALNativeAuthResponseError { + let error: MSALNativeAuthSignUpChallengeOauth2ErrorCode + let errorDescription: String? + let errorCodes: [Int]? + let errorURI: String? + let innerErrors: [MSALNativeAuthInnerError]? + + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + case errorCodes = "error_codes" + case errorURI = "error_uri" + case innerErrors = "inner_errors" + } +} + +extension MSALNativeAuthSignUpChallengeResponseError { + + func toSignUpPasswordStartPublicError() -> SignUpPasswordStartError { + switch error { + case .unauthorizedClient, + .unsupportedChallengeType, + .expiredToken, + .invalidRequest: + return .init(type: .generalError, message: errorDescription) + } + } + + func toSignUpStartPublicError() -> SignUpStartError { + switch error { + case .unauthorizedClient, + .unsupportedChallengeType, + .expiredToken, + .invalidRequest: + return .init(type: .generalError, message: errorDescription) + } + } + + func toResendCodePublicError() -> ResendCodeError { + switch error { + case .unauthorizedClient, + .unsupportedChallengeType, + .expiredToken, + .invalidRequest: + return .init(message: errorDescription) + } + } + + func toPasswordRequiredPublicError() -> PasswordRequiredError { + switch error { + case .unauthorizedClient, + .unsupportedChallengeType, + .expiredToken, + .invalidRequest: + return .init(type: .generalError, message: errorDescription) + } + } +} diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCode.swift new file mode 100644 index 0000000000..7a60eabc2f --- /dev/null +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCode.swift @@ -0,0 +1,43 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthSignUpContinueOauth2ErrorCode: String, Decodable, CaseIterable { + case invalidRequest = "invalid_request" + case unauthorizedClient = "unauthorized_client" + case invalidGrant = "invalid_grant" + case expiredToken = "expired_token" + case passwordTooWeak = "password_too_weak" + case passwordTooShort = "password_too_short" + case passwordTooLong = "password_too_long" + case passwordRecentlyUsed = "password_recently_used" + case passwordBanned = "password_banned" + case userAlreadyExists = "user_already_exists" + case attributesRequired = "attributes_required" + case verificationRequired = "verification_required" + case attributeValidationFailed = "attribute_validation_failed" + case credentialRequired = "credential_required" + case invalidOOBValue = "invalid_oob_value" +} diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift new file mode 100644 index 0000000000..1e63957eb9 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift @@ -0,0 +1,100 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthSignUpContinueResponseError: MSALNativeAuthResponseError { + let error: MSALNativeAuthSignUpContinueOauth2ErrorCode + let errorDescription: String? + let errorCodes: [Int]? + let errorURI: String? + let innerErrors: [MSALNativeAuthInnerError]? + let signUpToken: String? + let requiredAttributes: [MSALNativeAuthRequiredAttributesInternal]? + let unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes]? + let invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? + + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + case errorCodes = "error_codes" + case errorURI = "error_uri" + case innerErrors = "inner_errors" + case signUpToken = "signup_token" + case requiredAttributes = "required_attributes" + case unverifiedAttributes = "unverified_attributes" + case invalidAttributes = "invalid_attributes" + } +} + +extension MSALNativeAuthSignUpContinueResponseError { + + func toVerifyCodePublicError() -> VerifyCodeError { + switch error { + case .invalidOOBValue: + return .init(type: .invalidCode, message: errorDescription) + case .unauthorizedClient, + .expiredToken, + .invalidRequest, + .invalidGrant, + .passwordTooWeak, + .passwordTooShort, + .passwordTooLong, + .passwordRecentlyUsed, + .passwordBanned, + .userAlreadyExists, + .attributesRequired, + .verificationRequired, + .credentialRequired, + .attributeValidationFailed: + return .init(type: .generalError, message: errorDescription) + } + } + + func toPasswordRequiredPublicError() -> PasswordRequiredError { + switch error { + case .passwordTooWeak, + .passwordTooShort, + .passwordTooLong, + .passwordRecentlyUsed, + .passwordBanned: + return .init(type: .invalidPassword, message: errorDescription) + case .unauthorizedClient, + .expiredToken, + .invalidRequest, + .invalidGrant, + .userAlreadyExists, + .attributesRequired, + .verificationRequired, + .credentialRequired, + .attributeValidationFailed, + .invalidOOBValue: + return .init(type: .generalError, message: errorDescription) + } + } + + func toAttributesRequiredPublicError() -> AttributesRequiredError { + return AttributesRequiredError(message: errorDescription) + } +} diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCode.swift new file mode 100644 index 0000000000..92c97f8831 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCode.swift @@ -0,0 +1,41 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthSignUpStartOauth2ErrorCode: String, Decodable, CaseIterable, Equatable { + case invalidRequest = "invalid_request" + case unauthorizedClient = "unauthorized_client" + case unsupportedChallengeType = "unsupported_challenge_type" + case passwordTooWeak = "password_too_weak" + case passwordTooShort = "password_too_short" + case passwordTooLong = "password_too_long" + case passwordRecentlyUsed = "password_recently_used" + case passwordBanned = "password_banned" + case userAlreadyExists = "user_already_exists" + case attributesRequired = "attributes_required" + case verificationRequired = "verification_required" + case unsupportedAuthMethod = "unsupported_auth_method" + case attributeValidationFailed = "attribute_validation_failed" +} diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift new file mode 100644 index 0000000000..af469ae349 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift @@ -0,0 +1,92 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthSignUpStartResponseError: MSALNativeAuthResponseError { + + let error: MSALNativeAuthSignUpStartOauth2ErrorCode + let errorDescription: String? + let errorCodes: [Int]? + let errorURI: String? + let innerErrors: [MSALNativeAuthInnerError]? + let signUpToken: String? + let unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes]? + let invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? + + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + case errorCodes = "error_codes" + case errorURI = "error_uri" + case innerErrors = "inner_errors" + case signUpToken = "signup_token" + case unverifiedAttributes = "unverified_attributes" + case invalidAttributes = "invalid_attributes" + } +} + +extension MSALNativeAuthSignUpStartResponseError { + + func toSignUpStartPasswordPublicError() -> SignUpPasswordStartError { + switch error { + case .passwordTooWeak, + .passwordTooShort, + .passwordTooLong, + .passwordRecentlyUsed, + .passwordBanned: + return .init(type: .invalidPassword, message: errorDescription) + case .userAlreadyExists: + return .init(type: .userAlreadyExists, message: errorDescription) + case .attributeValidationFailed, + .attributesRequired, + .unauthorizedClient, + .unsupportedChallengeType, + .unsupportedAuthMethod, + .invalidRequest, + .verificationRequired: /// .verificationRequired is not supported by the API team yet. We treat it as an unexpectedError in the validator + return .init(type: .generalError, message: errorDescription) + } + } + + func toSignUpStartPublicError() -> SignUpStartError { + switch error { + case .userAlreadyExists: + return .init(type: .userAlreadyExists, message: errorDescription) + case .attributeValidationFailed, + .attributesRequired, + .unauthorizedClient, + .invalidRequest, + .passwordTooWeak, /// password errors should not occur when signing up code + .passwordTooShort, + .passwordTooLong, + .passwordRecentlyUsed, + .passwordBanned, + .unsupportedAuthMethod, + .unsupportedChallengeType, + .verificationRequired: /// .verificationRequired is not supported by the API team yet. We treat it as an unexpectedError in the validator + return .init(type: .generalError, message: errorDescription) + } + } +} diff --git a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenOauth2ErrorCode.swift new file mode 100644 index 0000000000..f5709b3f9b --- /dev/null +++ b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenOauth2ErrorCode.swift @@ -0,0 +1,38 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthTokenOauth2ErrorCode: String, Decodable { + case invalidRequest = "invalid_request" + case unauthorizedClient = "unauthorized_client" + case invalidClient = "invalid_client" + case invalidGrant = "invalid_grant" + case expiredToken = "expired_token" + case expiredRefreshToken = "expired_refresh_token" + case unsupportedChallengeType = "unsupported_challenge_type" + case invalidScope = "invalid_scope" + case authorizationPending = "authorization_pending" + case slowDown = "slow_down" +} diff --git a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift new file mode 100644 index 0000000000..2c1ee53590 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift @@ -0,0 +1,44 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthTokenResponseError: MSALNativeAuthResponseError { + + let error: MSALNativeAuthTokenOauth2ErrorCode + let errorDescription: String? + let errorCodes: [Int]? + let errorURI: String? + let innerErrors: [MSALNativeAuthInnerError]? + let credentialToken: String? + + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + case errorCodes = "error_codes" + case errorURI = "error_uri" + case innerErrors = "inner_errors" + case credentialToken = "credential_token" + } +} diff --git a/MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestContext.swift b/MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestContext.swift new file mode 100644 index 0000000000..f9971b2aab --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestContext.swift @@ -0,0 +1,62 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthRequestContext: MSIDRequestContext { + + private let _correlationId: UUID + private let _telemetryRequestId: String = MSIDTelemetry.sharedInstance().generateRequestId() + + init(correlationId: UUID? = nil) { + _correlationId = correlationId ?? UUID() + } + + func correlationId() -> UUID { + _correlationId + } + + func logComponent() -> String { + MSIDVersion.sdkName() + } + + func telemetryRequestId() -> String { + _telemetryRequestId + } + + func appRequestMetadata() -> [AnyHashable: Any] { + guard let metadata = Bundle.main.infoDictionary else { + return [:] + } + + let appName = metadata["CFBundleDisplayName"] ?? (metadata["CFBundleName"] ?? "") + let appVersion = metadata["CFBundleShortVersionString"] ?? "" + + return [ + MSID_VERSION_KEY: MSIDVersion.sdkVersion() ?? "", + MSID_APP_NAME_KEY: appName, + MSID_APP_VER_KEY: appVersion + ] + } +} diff --git a/MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestable.swift b/MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestable.swift new file mode 100644 index 0000000000..1b03df47e5 --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestable.swift @@ -0,0 +1,51 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthRequestable { + var endpoint: MSALNativeAuthEndpoint { get } + var context: MSIDRequestContext { get } + + func makeEndpointUrl(config: MSALNativeAuthConfiguration) throws -> URL + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] +} + +extension MSALNativeAuthRequestable { + + func makeEndpointUrl(config: MSALNativeAuthConfiguration) throws -> URL { + var components = URLComponents(url: config.authority.url, resolvingAgainstBaseURL: true) + components?.path += endpoint.rawValue + + if let dataCenter = config.sliceConfig?.dc { + components?.queryItems = [URLQueryItem(name: "dc", value: dataCenter)] + } + + guard let url = components?.url else { + throw MSALNativeAuthInternalError.invalidUrl + } + + return url + } +} diff --git a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParameters.swift b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParameters.swift new file mode 100644 index 0000000000..4368cb7430 --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParameters.swift @@ -0,0 +1,41 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +struct MSALNativeAuthResetPasswordChallengeRequestParameters: MSALNativeAuthRequestable { + let endpoint: MSALNativeAuthEndpoint = .resetPasswordChallenge + let context: MSIDRequestContext + let passwordResetToken: String + + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { + typealias Key = MSALNativeAuthRequestParametersKey + + return [ + Key.clientId.rawValue: config.clientId, + Key.passwordResetToken.rawValue: passwordResetToken, + Key.challengeType.rawValue: config.challengeTypesString + ].compactMapValues { $0 } + } +} diff --git a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParameters.swift b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParameters.swift new file mode 100644 index 0000000000..d2021a03a8 --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParameters.swift @@ -0,0 +1,44 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +struct MSALNativeAuthResetPasswordContinueRequestParameters: MSALNativeAuthRequestable { + let endpoint: MSALNativeAuthEndpoint = .resetPasswordContinue + let context: MSIDRequestContext + let passwordResetToken: String + let grantType: MSALNativeAuthGrantType + let oobCode: String? + + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { + typealias Key = MSALNativeAuthRequestParametersKey + + return [ + Key.clientId.rawValue: config.clientId, + Key.passwordResetToken.rawValue: passwordResetToken, + Key.grantType.rawValue: grantType.rawValue, + Key.oobCode.rawValue: oobCode + ].compactMapValues { $0 } + } +} diff --git a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift new file mode 100644 index 0000000000..1f2a10f01e --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift @@ -0,0 +1,40 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +struct MSALNativeAuthResetPasswordPollCompletionRequestParameters: MSALNativeAuthRequestable { + let endpoint: MSALNativeAuthEndpoint = .resetpasswordPollCompletion + let context: MSIDRequestContext + let passwordResetToken: String + + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { + typealias Key = MSALNativeAuthRequestParametersKey + + return [ + Key.clientId.rawValue: config.clientId, + Key.passwordResetToken.rawValue: passwordResetToken + ] + } +} diff --git a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordStartRequestParameters.swift b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordStartRequestParameters.swift new file mode 100644 index 0000000000..85c726f984 --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordStartRequestParameters.swift @@ -0,0 +1,42 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +struct MSALNativeAuthResetPasswordStartRequestParameters: MSALNativeAuthRequestable { + let endpoint: MSALNativeAuthEndpoint = .resetPasswordStart + let context: MSIDRequestContext + let username: String + + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { + typealias Key = MSALNativeAuthRequestParametersKey + + return [ + Key.clientId.rawValue: config.clientId, + Key.username.rawValue: username, + Key.challengeType.rawValue: config.challengeTypesString + ] + + } +} diff --git a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordSubmitRequestParameters.swift b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordSubmitRequestParameters.swift new file mode 100644 index 0000000000..13bb4dd1f6 --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordSubmitRequestParameters.swift @@ -0,0 +1,42 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +struct MSALNativeAuthResetPasswordSubmitRequestParameters: MSALNativeAuthRequestable { + let endpoint: MSALNativeAuthEndpoint = .resetPasswordSubmit + let context: MSIDRequestContext + let passwordSubmitToken: String + let newPassword: String + + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { + typealias Key = MSALNativeAuthRequestParametersKey + + return [ + Key.clientId.rawValue: config.clientId, + Key.passwordSubmitToken.rawValue: passwordSubmitToken, + Key.newPassword.rawValue: newPassword + ] + } +} diff --git a/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParameters.swift b/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParameters.swift new file mode 100644 index 0000000000..d372563f3d --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParameters.swift @@ -0,0 +1,41 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +struct MSALNativeAuthSignInChallengeRequestParameters: MSALNativeAuthRequestable { + let endpoint: MSALNativeAuthEndpoint = .signInChallenge + let context: MSIDRequestContext + let credentialToken: String + + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { + typealias Key = MSALNativeAuthRequestParametersKey + + return [ + Key.clientId.rawValue: config.clientId, + Key.credentialToken.rawValue: credentialToken, + Key.challengeType.rawValue: config.challengeTypesString + ].compactMapValues { $0 } + } +} diff --git a/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInInitiateRequestParameters.swift b/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInInitiateRequestParameters.swift new file mode 100644 index 0000000000..c0c7b08b6e --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInInitiateRequestParameters.swift @@ -0,0 +1,41 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +struct MSALNativeAuthSignInInitiateRequestParameters: MSALNativeAuthRequestable { + let endpoint: MSALNativeAuthEndpoint = .signInInitiate + let context: MSIDRequestContext + let username: String + + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { + typealias Key = MSALNativeAuthRequestParametersKey + + return [ + Key.clientId.rawValue: config.clientId, + Key.username.rawValue: username, + Key.challengeType.rawValue: config.challengeTypesString + ] + } +} diff --git a/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParameters.swift b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParameters.swift new file mode 100644 index 0000000000..a4c0f98db9 --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParameters.swift @@ -0,0 +1,41 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +struct MSALNativeAuthSignUpChallengeRequestParameters: MSALNativeAuthRequestable { + let endpoint: MSALNativeAuthEndpoint = .signUpChallenge + let signUpToken: String + let context: MSIDRequestContext + + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { + typealias Key = MSALNativeAuthRequestParametersKey + + return [ + Key.clientId.rawValue: config.clientId, + Key.signUpToken.rawValue: signUpToken, + Key.challengeType.rawValue: config.challengeTypesString + ].compactMapValues { $0 } + } +} diff --git a/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParameters.swift b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParameters.swift new file mode 100644 index 0000000000..880e673a67 --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParameters.swift @@ -0,0 +1,48 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +struct MSALNativeAuthSignUpContinueRequestParameters: MSALNativeAuthRequestable { + let endpoint: MSALNativeAuthEndpoint = .signUpContinue + let grantType: MSALNativeAuthGrantType + let signUpToken: String + let password: String? + let oobCode: String? + let attributes: String? + let context: MSIDRequestContext + + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { + typealias Key = MSALNativeAuthRequestParametersKey + + return [ + Key.clientId.rawValue: config.clientId, + Key.grantType.rawValue: grantType.rawValue, + Key.signUpToken.rawValue: signUpToken, + Key.password.rawValue: password, + Key.oobCode.rawValue: oobCode, + Key.attributes.rawValue: attributes + ].compactMapValues { $0 } + } +} diff --git a/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpStartRequestParameters.swift b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpStartRequestParameters.swift new file mode 100644 index 0000000000..b3224f7118 --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpStartRequestParameters.swift @@ -0,0 +1,45 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +struct MSALNativeAuthSignUpStartRequestParameters: MSALNativeAuthRequestable { + let endpoint: MSALNativeAuthEndpoint = .signUpStart + let username: String + let password: String? + let attributes: String? + let context: MSIDRequestContext + + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { + typealias Key = MSALNativeAuthRequestParametersKey + + return [ + Key.clientId.rawValue: config.clientId, + Key.username.rawValue: username, + Key.password.rawValue: password, + Key.attributes.rawValue: attributes, + Key.challengeType.rawValue: config.challengeTypesString + ].compactMapValues { $0 } + } +} diff --git a/MSAL/src/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParameters.swift b/MSAL/src/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParameters.swift new file mode 100644 index 0000000000..a053878c2c --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParameters.swift @@ -0,0 +1,62 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +struct MSALNativeAuthTokenRequestParameters: MSALNativeAuthRequestable { + let endpoint: MSALNativeAuthEndpoint = .token + let context: MSIDRequestContext + let username: String? + let credentialToken: String? + let signInSLT: String? + let grantType: MSALNativeAuthGrantType + let scope: String? + let password: String? + let oobCode: String? + let includeChallengeType: Bool + let clientInfo = true + let refreshToken: String? + + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { + typealias Key = MSALNativeAuthRequestParametersKey + var parameters = [ + Key.clientId.rawValue: config.clientId, + Key.username.rawValue: username, + Key.credentialToken.rawValue: credentialToken, + Key.signInSLT.rawValue: signInSLT, + Key.grantType.rawValue: grantType.rawValue, + Key.scope.rawValue: scope, + Key.password.rawValue: password, + Key.oobCode.rawValue: oobCode, + Key.clientInfo.rawValue: clientInfo.description, + Key.refreshToken.rawValue: refreshToken + ] + + if includeChallengeType { + parameters[Key.challengeType.rawValue] = config.challengeTypesString + } + + return parameters.compactMapValues { $0 } + } +} diff --git a/MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordRequestProvider.swift b/MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordRequestProvider.swift new file mode 100644 index 0000000000..4b678432ae --- /dev/null +++ b/MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordRequestProvider.swift @@ -0,0 +1,137 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthResetPasswordRequestProviding { + func start( + parameters: MSALNativeAuthResetPasswordStartRequestProviderParameters + ) throws -> MSIDHttpRequest + + func challenge( + token: String, + context: MSIDRequestContext + ) throws -> MSIDHttpRequest + + func `continue`( + parameters: MSALNativeAuthResetPasswordContinueRequestParameters + ) throws -> MSIDHttpRequest + + func submit( + parameters: MSALNativeAuthResetPasswordSubmitRequestParameters + ) throws -> MSIDHttpRequest + + func pollCompletion( + parameters: MSALNativeAuthResetPasswordPollCompletionRequestParameters + ) throws -> MSIDHttpRequest +} + +final class MSALNativeAuthResetPasswordRequestProvider: MSALNativeAuthResetPasswordRequestProviding { + + // MARK: - Variables + private let requestConfigurator: MSALNativeAuthRequestConfigurator + private let telemetryProvider: MSALNativeAuthTelemetryProviding + + // MARK: - Init + + init( + requestConfigurator: MSALNativeAuthRequestConfigurator, + telemetryProvider: MSALNativeAuthTelemetryProviding = MSALNativeAuthTelemetryProvider() + ) { + self.requestConfigurator = requestConfigurator + self.telemetryProvider = telemetryProvider + } + + // MARK: - Reset Password Start + + func start( + parameters: MSALNativeAuthResetPasswordStartRequestProviderParameters + ) throws -> MSIDHttpRequest { + + let requestParams = MSALNativeAuthResetPasswordStartRequestParameters( + context: parameters.context, + username: parameters.username + ) + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .resetPassword(.start(requestParams)), + request: request, + telemetryProvider: telemetryProvider) + return request + } + + // MARK: - Reset Password Challenge + + func challenge(token: String, context: MSIDRequestContext) throws -> MSIDHttpRequest { + let requestParams = MSALNativeAuthResetPasswordChallengeRequestParameters( + context: context, + passwordResetToken: token + ) + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .resetPassword(.challenge(requestParams)), + request: request, + telemetryProvider: telemetryProvider) + return request + } + + // MARK: - Reset Password Continue + + func `continue`( + parameters: MSALNativeAuthResetPasswordContinueRequestParameters + ) throws -> MSIDHttpRequest { + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .resetPassword(.continue(parameters)), + request: request, + telemetryProvider: telemetryProvider) + return request + } + + // MARK: - Reset Password Submit + + func submit( + parameters: MSALNativeAuthResetPasswordSubmitRequestParameters + ) throws -> MSIDHttpRequest { + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .resetPassword(.submit(parameters)), + request: request, + telemetryProvider: telemetryProvider) + return request + } + + // MARK: - Reset Password Poll Completion + + func pollCompletion( + parameters: MSALNativeAuthResetPasswordPollCompletionRequestParameters + ) throws -> MSIDHttpRequest { + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .resetPassword(.pollCompletion(parameters)), + request: request, + telemetryProvider: telemetryProvider) + return request + } +} diff --git a/MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordStartRequestProviderParameters.swift b/MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordStartRequestProviderParameters.swift new file mode 100644 index 0000000000..c54536ea19 --- /dev/null +++ b/MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordStartRequestProviderParameters.swift @@ -0,0 +1,30 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthResetPasswordStartRequestProviderParameters { + let username: String + let context: MSALNativeAuthRequestContext +} diff --git a/MSAL/src/native_auth/network/responses/MSALNativeAuthResendCodeRequestResponse.swift b/MSAL/src/native_auth/network/responses/MSALNativeAuthResendCodeRequestResponse.swift new file mode 100644 index 0000000000..36fc3360f4 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/MSALNativeAuthResendCodeRequestResponse.swift @@ -0,0 +1,35 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthResendCodeRequestResponse: Decodable { + + // MARK: - Variables + let credentialToken: String + + enum CodingKeys: String, CodingKey { + case credentialToken = "flowToken" + } +} diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordChallengeResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordChallengeResponse.swift new file mode 100644 index 0000000000..3c352b2454 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordChallengeResponse.swift @@ -0,0 +1,36 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthResetPasswordChallengeResponse: Decodable { + + // MARK: - Variables + let challengeType: MSALNativeAuthInternalChallengeType + let bindingMethod: String? + let challengeTargetLabel: String? + let challengeChannel: MSALNativeAuthInternalChannelType? + let passwordResetToken: String? + let codeLength: Int? +} diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordContinueResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordContinueResponse.swift new file mode 100644 index 0000000000..8576d31b66 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordContinueResponse.swift @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthResetPasswordContinueResponse: Decodable { + + // MARK: - Variables + let passwordSubmitToken: String + let expiresIn: Int +} diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionResponse.swift new file mode 100644 index 0000000000..87d5ff11d3 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionResponse.swift @@ -0,0 +1,33 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthResetPasswordPollCompletionResponse: Decodable { + + // MARK: - Variables + let status: MSALNativeAuthResetPasswordPollCompletionStatus + let signInSLT: String? + let expiresIn: Int? +} diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionStatus.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionStatus.swift new file mode 100644 index 0000000000..b3857e471e --- /dev/null +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionStatus.swift @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthResetPasswordPollCompletionStatus: String, Decodable { + case succeeded + case inProgress = "in_progress" + case failed + case notStarted = "not_started" +} diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift new file mode 100644 index 0000000000..0f75b757cb --- /dev/null +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift @@ -0,0 +1,42 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthResetPasswordStartResponse: Decodable { + + // MARK: - Variables + let passwordResetToken: String? + let challengeType: MSALNativeAuthInternalChallengeType? + + enum CodingKeys: String, CodingKey { + case passwordResetToken + case challengeType + } + + init(passwordResetToken: String?, challengeType: MSALNativeAuthInternalChallengeType?) { + self.passwordResetToken = passwordResetToken + self.challengeType = challengeType + } +} diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordSubmitResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordSubmitResponse.swift new file mode 100644 index 0000000000..9aaece1819 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordSubmitResponse.swift @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthResetPasswordSubmitResponse: Decodable { + + // MARK: - Variables + let passwordResetToken: String + let pollInterval: Int +} diff --git a/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInChallengeResponse.swift b/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInChallengeResponse.swift new file mode 100644 index 0000000000..029cf29c68 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInChallengeResponse.swift @@ -0,0 +1,37 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthSignInChallengeResponse: Decodable { + + // MARK: - Variables + let credentialToken: String? + let challengeType: MSALNativeAuthInternalChallengeType + let bindingMethod: String? + let challengeTargetLabel: String? + let challengeChannel: MSALNativeAuthInternalChannelType? + let codeLength: Int? + let interval: Int? +} diff --git a/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInInitiateResponse.swift b/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInInitiateResponse.swift new file mode 100644 index 0000000000..4f26b545b9 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInInitiateResponse.swift @@ -0,0 +1,37 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthSignInInitiateResponse: Decodable { + + // MARK: - Variables + let credentialToken: String? + let challengeType: MSALNativeAuthInternalChallengeType? + + enum CodingKeys: String, CodingKey { + case credentialToken + case challengeType + } +} diff --git a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpChallengeResponse.swift b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpChallengeResponse.swift new file mode 100644 index 0000000000..ed62bb1bc8 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpChallengeResponse.swift @@ -0,0 +1,41 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthSignUpChallengeResponse: Decodable { + let challengeType: MSALNativeAuthInternalChallengeType? + let bindingMethod: String? + let interval: Int? + let challengeTargetLabel: String? + let challengeChannel: MSALNativeAuthInternalChannelType? + let signUpToken: String? + let codeLength: Int? + + enum CodingKeys: String, CodingKey { + case challengeType, bindingMethod, interval, challengeTargetLabel, challengeChannel, codeLength + // API returns signup_token not sign_up_token + case signUpToken = "signupToken" + } +} diff --git a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpContinueResponse.swift b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpContinueResponse.swift new file mode 100644 index 0000000000..e43999f7fb --- /dev/null +++ b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpContinueResponse.swift @@ -0,0 +1,37 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthSignUpContinueResponse: Decodable { + let signinSLT: String? + let expiresIn: Int? + let signupToken: String? + + enum CodingKeys: String, CodingKey { + case expiresIn, signupToken + // API returns signin_slt not sign_in_slt + case signinSLT = "signinSlt" + } +} diff --git a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpStartResponse.swift b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpStartResponse.swift new file mode 100644 index 0000000000..27702343d3 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpStartResponse.swift @@ -0,0 +1,30 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +struct MSALNativeAuthSignUpStartResponse: Decodable { + let signupToken: String? + let challengeType: MSALNativeAuthInternalChallengeType? +} diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift new file mode 100644 index 0000000000..b23159692b --- /dev/null +++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift @@ -0,0 +1,273 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthResetPasswordResponseValidating { + func validate(_ result: Result, + with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordStartValidatedResponse + func validate(_ result: Result, + with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordChallengeValidatedResponse + func validate(_ result: Result, + with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordContinueValidatedResponse + func validate(_ result: Result, + with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordSubmitValidatedResponse + func validate(_ result: Result, + with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordPollCompletionValidatedResponse +} + +final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPasswordResponseValidating { + + // MARK: - Start Request + + func validate(_ result: Result, + with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordStartValidatedResponse { + switch result { + case .success(let response): + return handleStartSuccess(response, with: context) + case .failure(let error): + return handleStartFailed(error, with: context) + } + } + + private func handleStartSuccess(_ response: MSALNativeAuthResetPasswordStartResponse, + with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordStartValidatedResponse { + if response.challengeType == .redirect { + return .redirect + } else if let passwordResetToken = response.passwordResetToken { + return .success(passwordResetToken: passwordResetToken) + } else { + MSALLogger.log(level: .error, + context: context, + format: "resetpassword/start returned success with unexpected response body") + + return .unexpectedError + } + } + + private func handleStartFailed(_ error: Error, + with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordStartValidatedResponse { + guard let apiError = error as? MSALNativeAuthResetPasswordStartResponseError else { + MSALLogger.log(level: .error, + context: context, + format: "Error type not expected") + + return .unexpectedError + } + + switch apiError.error { + case .invalidRequest: + if apiError.errorCodes?.first == MSALNativeAuthESTSApiErrorCodes.userNotHaveAPassword.rawValue { + return .error(.userDoesNotHavePassword) + } else { + return .error(.invalidRequest(message: apiError.errorDescription)) + } + case .invalidClient: + return .error(.invalidClient(message: apiError.errorDescription)) + case .userNotFound: + return .error(.userNotFound(message: apiError.errorDescription)) + case .unsupportedChallengeType: + return .error(.unsupportedChallengeType(message: apiError.errorDescription)) + } + } + + // MARK: - Challenge Request + + func validate( + _ result: Result, + with context: MSIDRequestContext + ) -> MSALNativeAuthResetPasswordChallengeValidatedResponse { + switch result { + case .success(let response): + return handleChallengeSuccess(response, with: context) + case .failure(let error): + return handleChallengeError(error, with: context) + } + } + + private func handleChallengeSuccess( + _ response: MSALNativeAuthResetPasswordChallengeResponse, + with context: MSIDRequestContext + ) -> MSALNativeAuthResetPasswordChallengeValidatedResponse { + switch response.challengeType { + case .redirect: + return .redirect + case .oob: + if let sentTo = response.challengeTargetLabel, + let channelTargetType = response.challengeChannel?.toPublicChannelType(), + let codeLength = response.codeLength, + let passwordResetToken = response.passwordResetToken { + return .success( + sentTo, + channelTargetType, + codeLength, + passwordResetToken + ) + } else { + MSALLogger.log(level: .error, context: context, format: "Missing expected fields from backend") + return .unexpectedError + } + case .password, + .otp: + MSALLogger.log(level: .error, context: context, format: "ChallengeType not expected") + return .unexpectedError + } + } + + private func handleChallengeError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordChallengeValidatedResponse { + guard let apiError = error as? MSALNativeAuthResetPasswordChallengeResponseError else { + MSALLogger.log(level: .info, context: context, format: "Error type not expected") + return .unexpectedError + } + + return .error(apiError) + } + + // MARK: - Continue Request + + func validate( + _ result: Result, + with context: MSIDRequestContext + ) -> MSALNativeAuthResetPasswordContinueValidatedResponse { + switch result { + case .success(let response): + return handleContinueSuccess(response) + case .failure(let error): + return handleContinueError(error, with: context) + } + } + + private func handleContinueSuccess( + _ response: MSALNativeAuthResetPasswordContinueResponse + ) -> MSALNativeAuthResetPasswordContinueValidatedResponse { + return .success(passwordSubmitToken: response.passwordSubmitToken) + } + + private func handleContinueError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordContinueValidatedResponse { + guard let apiError = error as? MSALNativeAuthResetPasswordContinueResponseError else { + MSALLogger.log(level: .error, context: context, format: "continue returned unexpected error type") + return .unexpectedError + } + + switch apiError.error { + case .invalidOOBValue: + return .invalidOOB + case .invalidClient, + .invalidGrant, + .expiredToken, + .invalidRequest: + return .error(apiError) + case .verificationRequired: + MSALLogger.log(level: .error, context: context, format: "verificationRequired is not supported yet") + return .unexpectedError + } + } + + // MARK: - Submit Request + + func validate( + _ result: Result, + with context: MSIDRequestContext + ) -> MSALNativeAuthResetPasswordSubmitValidatedResponse { + switch result { + case .success(let response): + return handleSubmitSuccess(response) + case .failure(let error): + return handleSubmitError(error, with: context) + } + } + + private func handleSubmitSuccess( + _ response: MSALNativeAuthResetPasswordSubmitResponse + ) -> MSALNativeAuthResetPasswordSubmitValidatedResponse { + return .success( + passwordResetToken: response.passwordResetToken, + pollInterval: response.pollInterval + ) + } + + private func handleSubmitError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordSubmitValidatedResponse { + guard let apiError = error as? MSALNativeAuthResetPasswordSubmitResponseError else { + MSALLogger.log(level: .error, context: context, format: "submit returned unexpected error type") + return .unexpectedError + } + + switch apiError.error { + case .passwordTooWeak, + .passwordTooShort, + .passwordTooLong, + .passwordRecentlyUsed, + .passwordBanned: + return .passwordError(error: apiError) + case .invalidRequest, + .invalidClient, + .expiredToken: + return .error(apiError) + } + } + + // MARK: - Poll Completion Request + + func validate( + _ result: Result, + with context: MSIDRequestContext + ) -> MSALNativeAuthResetPasswordPollCompletionValidatedResponse { + switch result { + case .success(let response): + return handlePollCompletionSuccess(response) + case .failure(let error): + return handlePollCompletionError(error, with: context) + } + } + + private func handlePollCompletionSuccess( + _ response: MSALNativeAuthResetPasswordPollCompletionResponse + ) -> MSALNativeAuthResetPasswordPollCompletionValidatedResponse { + return .success(status: response.status) + } + + private func handlePollCompletionError( + _ error: Error, + with context: MSIDRequestContext + ) -> MSALNativeAuthResetPasswordPollCompletionValidatedResponse { + guard let apiError = error as? MSALNativeAuthResetPasswordPollCompletionResponseError else { + MSALLogger.log(level: .error, context: context, format: "Poll Completion returned unexpected error type") + return .unexpectedError + } + + switch apiError.error { + case .passwordTooWeak, + .passwordTooShort, + .passwordTooLong, + .passwordRecentlyUsed, + .passwordBanned: + return .passwordError(error: apiError) + case .userNotFound, + .invalidRequest, + .invalidClient, + .expiredToken: + return .error(apiError) + } + } +} diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift new file mode 100644 index 0000000000..3e77c380b9 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift @@ -0,0 +1,79 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +enum MSALNativeAuthResetPasswordStartValidatedResponse { + case success(passwordResetToken: String) + case redirect + case error(MSALNativeAuthResetPasswordStartValidatedErrorType) + case unexpectedError +} + +enum MSALNativeAuthResetPasswordStartValidatedErrorType: Error { + case invalidRequest(message: String?) + case invalidClient(message: String?) + case userNotFound(message: String?) + case unsupportedChallengeType(message: String?) + case userDoesNotHavePassword + + func toResetPasswordStartPublicError() -> ResetPasswordStartError { + switch self { + case .userNotFound(let message): + return .init(type: .userNotFound, message: message) + case .unsupportedChallengeType(let message), + .invalidRequest(let message), + .invalidClient(let message): + return .init(type: .generalError, message: message) + case .userDoesNotHavePassword: + return .init(type: .userDoesNotHavePassword, message: MSALNativeAuthErrorMessage.userDoesNotHavePassword) + } + } +} + +enum MSALNativeAuthResetPasswordChallengeValidatedResponse: Equatable { + case success(_ sentTo: String, _ channelTargetType: MSALNativeAuthChannelType, _ codeLength: Int, _ resetPasswordChallengeToken: String) + case redirect + case error(MSALNativeAuthResetPasswordChallengeResponseError) + case unexpectedError +} + +enum MSALNativeAuthResetPasswordContinueValidatedResponse: Equatable { + case success(passwordSubmitToken: String) + case invalidOOB + case error(MSALNativeAuthResetPasswordContinueResponseError) + case unexpectedError +} + +enum MSALNativeAuthResetPasswordSubmitValidatedResponse: Equatable { + case success(passwordResetToken: String, pollInterval: Int) + case passwordError(error: MSALNativeAuthResetPasswordSubmitResponseError) + case error(MSALNativeAuthResetPasswordSubmitResponseError) + case unexpectedError +} + +enum MSALNativeAuthResetPasswordPollCompletionValidatedResponse: Equatable { + case success(status: MSALNativeAuthResetPasswordPollCompletionStatus) + case passwordError(error: MSALNativeAuthResetPasswordPollCompletionResponseError) + case error(MSALNativeAuthResetPasswordPollCompletionResponseError) + case unexpectedError +} diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift new file mode 100644 index 0000000000..78673d87c2 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift @@ -0,0 +1,160 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthSignInResponseValidating { + func validate( + context: MSALNativeAuthRequestContext, + result: Result + ) -> MSALNativeAuthSignInChallengeValidatedResponse + + func validate( + context: MSALNativeAuthRequestContext, + result: Result + ) -> MSALNativeAuthSignInInitiateValidatedResponse +} + +final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseValidating { + + func validate( + context: MSALNativeAuthRequestContext, + result: Result + ) -> MSALNativeAuthSignInChallengeValidatedResponse { + switch result { + case .success(let challengeResponse): + return handleSuccessfulSignInChallengeResult(context, response: challengeResponse) + case .failure(let signInChallengeResponseError): + guard let signInChallengeResponseError = + signInChallengeResponseError as? MSALNativeAuthSignInChallengeResponseError else { + MSALLogger.log( + level: .error, + context: context, + format: "SignIn Challenge: Error type not expected, error: \(signInChallengeResponseError)") + return .error(.invalidServerResponse) + } + return handleFailedSignInChallengeResult(context, error: signInChallengeResponseError) + } + } + + func validate( + context: MSALNativeAuthRequestContext, + result: Result + ) -> MSALNativeAuthSignInInitiateValidatedResponse { + switch result { + case .success(let initiateResponse): + if initiateResponse.challengeType == .redirect { + return .error(.redirect) + } + if let credentialToken = initiateResponse.credentialToken { + return .success(credentialToken: credentialToken) + } + MSALLogger.log(level: .error, context: context, format: "SignIn Initiate: challengeType and credential token empty") + return .error(.invalidServerResponse) + case .failure(let responseError): + guard let initiateResponseError = responseError as? MSALNativeAuthSignInInitiateResponseError else { + MSALLogger.log( + level: .error, + context: context, + format: "SignIn Initiate: Error type not expected, error: \(responseError)") + return .error(.invalidServerResponse) + } + return handleFailedSignInInitiateResult(context, error: initiateResponseError) + } + } + + // MARK: private methods + + private func handleSuccessfulSignInChallengeResult( + _ context: MSALNativeAuthRequestContext, + response: MSALNativeAuthSignInChallengeResponse) -> MSALNativeAuthSignInChallengeValidatedResponse { + switch response.challengeType { + case .otp: + MSALLogger.log( + level: .error, + context: context, + format: "SignIn Challenge: Received unexpected challenge type: \(response.challengeType)") + return .error(.invalidServerResponse) + case .oob: + guard let credentialToken = response.credentialToken, + let targetLabel = response.challengeTargetLabel, + let codeLength = response.codeLength, + let channelType = response.challengeChannel else { + MSALLogger.log( + level: .error, + context: context, + format: "SignIn Challenge: Invalid response with challenge type oob, response: \(response)") + return .error(.invalidServerResponse) + } + return .codeRequired( + credentialToken: credentialToken, + sentTo: targetLabel, + channelType: channelType.toPublicChannelType(), + codeLength: codeLength) + case .password: + guard let credentialToken = response.credentialToken else { + MSALLogger.log( + level: .error, + context: context, + format: "SignIn Challenge: Expected credential token not nil with credential type password") + return .error(.invalidServerResponse) + } + return .passwordRequired(credentialToken: credentialToken) + case .redirect: + return .error(.redirect) + } + } + + private func handleFailedSignInChallengeResult( + _ context: MSALNativeAuthRequestContext, + error: MSALNativeAuthSignInChallengeResponseError) -> MSALNativeAuthSignInChallengeValidatedResponse { + switch error.error { + case .invalidRequest: + return .error(.invalidRequest(message: error.errorDescription)) + case .unauthorizedClient: + return .error(.invalidClient(message: error.errorDescription)) + case .invalidGrant: + return .error(.invalidToken(message: error.errorDescription)) + case .expiredToken: + return .error(.expiredToken(message: error.errorDescription)) + case .unsupportedChallengeType: + return .error(.unsupportedChallengeType(message: error.errorDescription)) + } + } + + private func handleFailedSignInInitiateResult( + _ context: MSALNativeAuthRequestContext, + error: MSALNativeAuthSignInInitiateResponseError) -> MSALNativeAuthSignInInitiateValidatedResponse { + switch error.error { + case .invalidRequest: + return .error(.invalidRequest(message: error.errorDescription)) + case .unauthorizedClient: + return .error(.invalidClient(message: error.errorDescription)) + case .unsupportedChallengeType: + return .error(.unsupportedChallengeType(message: error.errorDescription)) + case .invalidGrant: + return .error(.userNotFound(message: error.errorDescription)) + } + } +} diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift new file mode 100644 index 0000000000..836d2e6cae --- /dev/null +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift @@ -0,0 +1,76 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthSignInChallengeValidatedResponse { + case codeRequired(credentialToken: String, sentTo: String, channelType: MSALNativeAuthChannelType, codeLength: Int) + case passwordRequired(credentialToken: String) + case error(MSALNativeAuthSignInChallengeValidatedErrorType) +} + +enum MSALNativeAuthSignInChallengeValidatedErrorType: Error { + case redirect + case expiredToken(message: String?) + case invalidToken(message: String?) + case invalidClient(message: String?) + case invalidRequest(message: String?) + case invalidServerResponse + case userNotFound(message: String?) + case unsupportedChallengeType(message: String?) + + func convertToSignInStartError() -> SignInStartError { + switch self { + case .redirect: + return .init(type: .browserRequired) + case .invalidServerResponse: + return .init(type: .generalError) + case .expiredToken(let message), + .invalidToken(let message), + .invalidRequest(let message): + return .init(type: .generalError, message: message) + case .invalidClient(let message): + return .init(type: .generalError, message: message) + case .userNotFound(let message): + return .init(type: .userNotFound, message: message) + case .unsupportedChallengeType(let message): + return .init(type: .generalError, message: message) + } + } + + func convertToSignInPasswordStartError() -> SignInPasswordStartError { + switch self { + case .redirect: + return .init(type: .browserRequired) + case .expiredToken, .invalidToken, .invalidRequest, .invalidServerResponse: + return .init(type: .generalError) + case .invalidClient(let message): + return .init(type: .generalError, message: message) + case .userNotFound: + return .init(type: .userNotFound) + case .unsupportedChallengeType(let message): + return .init(type: .generalError, message: message) + } + } +} diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift new file mode 100644 index 0000000000..09ff8221ed --- /dev/null +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift @@ -0,0 +1,69 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthSignInInitiateValidatedResponse { + case success(credentialToken: String) + case error(MSALNativeAuthSignInInitiateValidatedErrorType) +} + +enum MSALNativeAuthSignInInitiateValidatedErrorType: Error { + case redirect + case invalidClient(message: String?) + case invalidRequest(message: String?) + case invalidServerResponse + case userNotFound(message: String?) + case unsupportedChallengeType(message: String?) + + func convertToSignInStartError() -> SignInStartError { + switch self { + case .redirect: + return .init(type: .browserRequired) + case .userNotFound(let message): + return .init(type: .userNotFound, message: message) + case .invalidServerResponse: + return .init(type: .generalError) + case .invalidClient(let message), + .unsupportedChallengeType(let message), + .invalidRequest(let message): + return .init(type: .generalError, message: message) + } + } + + func convertToSignInPasswordStartError() -> SignInPasswordStartError { + switch self { + case .redirect: + return .init(type: .browserRequired) + case .userNotFound(let message): + return .init(type: .userNotFound, message: message) + case .invalidServerResponse: + return .init(type: .generalError) + case .invalidClient(let message), + .unsupportedChallengeType(let message), + .invalidRequest(let message): + return .init(type: .generalError, message: message) + } + } +} diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift new file mode 100644 index 0000000000..b78496043a --- /dev/null +++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift @@ -0,0 +1,274 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthSignUpResponseValidating { + func validate( + _ result: Result, with context: MSIDRequestContext + ) -> MSALNativeAuthSignUpStartValidatedResponse + func validate( + _ result: Result, + with context: MSIDRequestContext + ) -> MSALNativeAuthSignUpChallengeValidatedResponse + func validate( + _ result: Result, with context: MSIDRequestContext + ) -> MSALNativeAuthSignUpContinueValidatedResponse +} + +final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseValidating { + + // MARK: - Start Request + + func validate( + _ result: Result, with context: MSIDRequestContext + ) -> MSALNativeAuthSignUpStartValidatedResponse { + switch result { + case .success(let response): + return handleStartSuccess(response, with: context) + case .failure(let error): + return handleStartFailed(error, with: context) + } + } + + private func handleStartSuccess( + _ response: MSALNativeAuthSignUpStartResponse, with context: MSIDRequestContext + ) -> MSALNativeAuthSignUpStartValidatedResponse { + if response.challengeType == .redirect { + return .redirect + } else { + MSALLogger.log( + level: .error, + context: context, + format: "Unexpected response in signup/start. SDK expects only 200 with redirect challenge_type" + ) + return .unexpectedError + } + } + + private func handleStartFailed(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthSignUpStartValidatedResponse { + guard let apiError = error as? MSALNativeAuthSignUpStartResponseError else { + MSALLogger.log(level: .error, context: context, format: "Error type not expected") + return .unexpectedError + } + + switch apiError.error { + case .verificationRequired: + if let signUpToken = apiError.signUpToken, let unverifiedAttributes = apiError.unverifiedAttributes, !unverifiedAttributes.isEmpty { + return .verificationRequired(signUpToken: signUpToken, unverifiedAttributes: extractAttributeNames(from: unverifiedAttributes)) + } else { + MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/start for verification_required error") + return .unexpectedError + } + case .attributeValidationFailed: + if let invalidAttributes = apiError.invalidAttributes, !invalidAttributes.isEmpty { + return .attributeValidationFailed(invalidAttributes: extractAttributeNames(from: invalidAttributes)) + } else { + MSALLogger.log( + level: .error, + context: context, + format: "Missing expected fields in signup/start for attribute_validation_failed error" + ) + return .unexpectedError + } + case .invalidRequest where isSignUpStartInvalidRequestParameter( + apiError, + knownErrorDescription: MSALNativeAuthESTSApiErrorDescriptions.usernameParameterIsEmptyOrNotValid.rawValue): + return .invalidUsername(apiError) + case .invalidRequest where isSignUpStartInvalidRequestParameter( + apiError, + knownErrorDescription: MSALNativeAuthESTSApiErrorDescriptions.clientIdParameterIsEmptyOrNotValid.rawValue): + return .invalidClientId(apiError) + default: + return .error(apiError) + } + } + + // MARK: - Challenge Request + + func validate( + _ result: Result, + with context: MSIDRequestContext + ) -> MSALNativeAuthSignUpChallengeValidatedResponse { + switch result { + case .success(let response): + return handleChallengeSuccess(response, with: context) + case .failure(let error): + return handleChallengeError(error, with: context) + } + } + + private func handleChallengeSuccess( + _ response: MSALNativeAuthSignUpChallengeResponse, + with context: MSIDRequestContext + ) -> MSALNativeAuthSignUpChallengeValidatedResponse { + guard let challengeTypeIssued = response.challengeType else { + MSALLogger.log(level: .error, context: context, format: "Missing ChallengeType from backend in signup/challenge response") + return .unexpectedError + } + + switch challengeTypeIssued { + case .redirect: + return .redirect + case .oob: + if let sentTo = response.challengeTargetLabel, + let channelType = response.challengeChannel?.toPublicChannelType(), + let codeLength = response.codeLength, + let signUpChallengeToken = response.signUpToken { + return .codeRequired(sentTo, channelType, codeLength, signUpChallengeToken) + } else { + MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/challenge with challenge_type = oob") + return .unexpectedError + } + case .password: + if let signUpToken = response.signUpToken { + return .passwordRequired(signUpToken) + } else { + MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/challenge with challenge_type = password") + return .unexpectedError + } + case .otp: + MSALLogger.log(level: .error, context: context, format: "ChallengeType OTP not expected for signup/challenge") + return .unexpectedError + } + } + + private func handleChallengeError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthSignUpChallengeValidatedResponse { + guard let apiError = error as? MSALNativeAuthSignUpChallengeResponseError else { + MSALLogger.log(level: .error, context: context, format: "Error type not expected") + return .unexpectedError + } + + return .error(apiError) + } + + // MARK: - Continue Request + + func validate( + _ result: Result, + with context: MSIDRequestContext + ) -> MSALNativeAuthSignUpContinueValidatedResponse { + switch result { + case .success(let response): + // Even if the `signInSLT` is nil, the signUp flow is considered successfully completed + return .success(response.signinSLT) + case .failure(let error): + return handleContinueError(error, with: context) + } + } + + // swiftlint:disable:next cyclomatic_complexity + private func handleContinueError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthSignUpContinueValidatedResponse { + guard let apiError = error as? MSALNativeAuthSignUpContinueResponseError else { + return .unexpectedError + } + + switch apiError.error { + case .invalidOOBValue, + .passwordTooWeak, + .passwordTooShort, + .passwordTooLong, + .passwordRecentlyUsed, + .passwordBanned: + return .invalidUserInput(apiError) + case .attributeValidationFailed: + if let signUpToken = apiError.signUpToken, let invalidAttributes = apiError.invalidAttributes, !invalidAttributes.isEmpty { + return .attributeValidationFailed(signUpToken: signUpToken, invalidAttributes: extractAttributeNames(from: invalidAttributes)) + } else { + MSALLogger.log( + level: .error, + context: context, + format: "Missing expected fields in signup/continue for attribute_validation_failed error" + ) + return .unexpectedError + } + case .credentialRequired: + if let signUpToken = apiError.signUpToken { + return .credentialRequired(signUpToken: signUpToken) + } else { + MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/continue for credential_required error") + return .unexpectedError + } + case .attributesRequired: + if let signUpToken = apiError.signUpToken, let requiredAttributes = apiError.requiredAttributes, !requiredAttributes.isEmpty { + return .attributesRequired(signUpToken: signUpToken, requiredAttributes: requiredAttributes.map { $0.toRequiredAttributesPublic() }) + } else { + MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/continue for attributes_required error") + return .unexpectedError + } + // TODO: .verificationRequired is not supported by the API team yet. We treat it as an unexpectedError + case .verificationRequired: + MSALLogger.log(level: .error, context: context, format: "verificationRequired is not supported yet") + return .unexpectedError + case .unauthorizedClient, + .invalidGrant, + .expiredToken, + .userAlreadyExists: + return .error(apiError) + case .invalidRequest: + return handleInvalidRequestError(apiError) + } + } + + private func handleInvalidRequestError(_ error: MSALNativeAuthSignUpContinueResponseError) -> MSALNativeAuthSignUpContinueValidatedResponse { + guard let errorCode = error.errorCodes?.first, let knownErrorCode = MSALNativeAuthESTSApiErrorCodes(rawValue: errorCode) else { + return .error(error) + } + switch knownErrorCode { + case .invalidOTP, + .incorrectOTP, + .OTPNoCacheEntryForUser: + return .invalidUserInput( + MSALNativeAuthSignUpContinueResponseError( + error: .invalidOOBValue, + errorDescription: error.errorDescription, + errorCodes: error.errorCodes, + errorURI: error.errorURI, + innerErrors: error.innerErrors, + signUpToken: error.signUpToken, + requiredAttributes: error.requiredAttributes, + unverifiedAttributes: error.unverifiedAttributes, + invalidAttributes: error.invalidAttributes)) + case .userNotFound, + .invalidCredentials, + .strongAuthRequired, + .userNotHaveAPassword, + .invalidRequestParameter: + return .error(error) + } + } + + private func isSignUpStartInvalidRequestParameter(_ apiError: MSALNativeAuthSignUpStartResponseError, knownErrorDescription: String) -> Bool { + guard let errorCode = apiError.errorCodes?.first, + let knownErrorCode = MSALNativeAuthESTSApiErrorCodes(rawValue: errorCode), + let errorDescription = apiError.errorDescription else { + return false + } + return knownErrorCode == .invalidRequestParameter && errorDescription.contains(knownErrorDescription) + } + + private func extractAttributeNames(from attributes: [MSALNativeAuthErrorBasicAttributes]) -> [String] { + return attributes.map { $0.name } + } +} diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift new file mode 100644 index 0000000000..44be0edbbf --- /dev/null +++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift @@ -0,0 +1,53 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +enum MSALNativeAuthSignUpStartValidatedResponse: Equatable { + case verificationRequired(signUpToken: String, unverifiedAttributes: [String]) + case attributeValidationFailed(invalidAttributes: [String]) + case redirect + case error(MSALNativeAuthSignUpStartResponseError) + // TODO: Special errors handled separately. Remove after refactor validated error handling + case invalidUsername(MSALNativeAuthSignUpStartResponseError) + case invalidClientId(MSALNativeAuthSignUpStartResponseError) + case unexpectedError +} + +enum MSALNativeAuthSignUpChallengeValidatedResponse: Equatable { + case codeRequired(_ sentTo: String, _ channelType: MSALNativeAuthChannelType, _ codeLength: Int, _ signUpChallengeToken: String) + case passwordRequired(_ signUpChallengeToken: String) + case redirect + case error(MSALNativeAuthSignUpChallengeResponseError) + case unexpectedError +} + +enum MSALNativeAuthSignUpContinueValidatedResponse: Equatable { + case success(_ signInSLT: String?) + /// error that represents invalidOOB or invalidPassword, depending on which State the input comes from. + case invalidUserInput(_ error: MSALNativeAuthSignUpContinueResponseError) + case credentialRequired(signUpToken: String) + case attributesRequired(signUpToken: String, requiredAttributes: [MSALNativeAuthRequiredAttributes]) + case attributeValidationFailed(signUpToken: String, invalidAttributes: [String]) + case error(MSALNativeAuthSignUpContinueResponseError) + case unexpectedError +} diff --git a/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift new file mode 100644 index 0000000000..826fa7ec48 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift @@ -0,0 +1,222 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthTokenResponseValidating { + func validate( + context: MSALNativeAuthRequestContext, + msidConfiguration: MSIDConfiguration, + result: Result + ) -> MSALNativeAuthTokenValidatedResponse + + func validateAccount( + with tokenResult: MSIDTokenResult, + context: MSIDRequestContext, + accountIdentifier: MSIDAccountIdentifier + ) throws -> Bool +} + +final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseValidating { + private let factory: MSALNativeAuthResultBuildable + private let msidValidator: MSIDTokenResponseValidator + + init( + factory: MSALNativeAuthResultBuildable, + msidValidator: MSIDTokenResponseValidator + ) { + self.factory = factory + self.msidValidator = msidValidator + } + + func validate( + context: MSALNativeAuthRequestContext, + msidConfiguration: MSIDConfiguration, + result: Result + ) -> MSALNativeAuthTokenValidatedResponse { + switch result { + case .success(let tokenResponse): + return .success(tokenResponse) + case .failure(let tokenResponseError): + guard let tokenResponseError = + tokenResponseError as? MSALNativeAuthTokenResponseError else { + MSALLogger.log( + level: .error, + context: context, + format: "Token: Error type not expected, error: \(tokenResponseError)") + return .error(.invalidServerResponse) + } + return handleFailedTokenResult(context, tokenResponseError) + } + } + + func validateAccount( + with tokenResult: MSIDTokenResult, + context: MSIDRequestContext, + accountIdentifier: MSIDAccountIdentifier + ) throws -> Bool { + var error: NSError? + let validAccount = msidValidator.validateAccount( + accountIdentifier, + tokenResult: tokenResult, + correlationID: context.correlationId(), + error: &error + ) + if let error = error { + throw error + } + return validAccount + } + + private func handleFailedTokenResult( + _ context: MSALNativeAuthRequestContext, + _ responseError: MSALNativeAuthTokenResponseError) -> MSALNativeAuthTokenValidatedResponse { + switch responseError.error { + case .invalidRequest: + return handleInvalidRequestErrorCodes(responseError.errorCodes, errorDescription: responseError.errorDescription, context: context) + case .invalidClient, + .unauthorizedClient: + return .error(.invalidClient(message: responseError.errorDescription)) + case .invalidGrant: + return handleInvalidGrantErrorCodes(responseError.errorCodes, errorDescription: responseError.errorDescription, context: context) + case .expiredToken: + return .error(.expiredToken(message: responseError.errorDescription)) + case .expiredRefreshToken: + return .error(.expiredRefreshToken(message: responseError.errorDescription)) + case .unsupportedChallengeType: + return .error(.unsupportedChallengeType(message: responseError.errorDescription)) + case .invalidScope: + return .error(.invalidScope(message: responseError.errorDescription)) + case .authorizationPending: + return .error(.authorizationPending(message: responseError.errorDescription)) + case .slowDown: + return .error(.slowDown(message: responseError.errorDescription)) + } + } + + private func handleInvalidRequestErrorCodes( + _ errorCodes: [Int]?, + errorDescription: String?, + context: MSALNativeAuthRequestContext + ) -> MSALNativeAuthTokenValidatedResponse { + return handleInvalidResponseErrorCodes( + errorCodes, + errorDescription: errorDescription, + context: context, + useInvalidRequestAsDefaultResult: true, + errorCodesConverterFunction: convertInvalidRequestErrorCodeToErrorType + ) + } + + private func handleInvalidGrantErrorCodes( + _ errorCodes: [Int]?, + errorDescription: String?, + context: MSALNativeAuthRequestContext + ) -> MSALNativeAuthTokenValidatedResponse { + return handleInvalidResponseErrorCodes( + errorCodes, + errorDescription: errorDescription, + context: context, + errorCodesConverterFunction: convertInvalidGrantErrorCodeToErrorType + ) + } + + private func handleInvalidResponseErrorCodes( + _ errorCodes: [Int]?, + errorDescription: String?, + context: MSALNativeAuthRequestContext, + useInvalidRequestAsDefaultResult: Bool = false, + errorCodesConverterFunction: (MSALNativeAuthESTSApiErrorCodes, String?) -> MSALNativeAuthTokenValidatedErrorType + ) -> MSALNativeAuthTokenValidatedResponse { + guard var errorCodes = errorCodes, !errorCodes.isEmpty else { + MSALLogger.log(level: .error, context: context, format: "/token error - Empty error_codes received") + return useInvalidRequestAsDefaultResult ? .error(.invalidRequest(message: errorDescription)) : .error(.generalError) + } + + let validatedResponse: MSALNativeAuthTokenValidatedResponse + let firstErrorCode = errorCodes.removeFirst() + + if let knownErrorCode = MSALNativeAuthESTSApiErrorCodes(rawValue: firstErrorCode) { + validatedResponse = .error(errorCodesConverterFunction(knownErrorCode, errorDescription)) + } else { + MSALLogger.log(level: .error, context: context, format: "/token error - Unknown code received in error_codes: \(firstErrorCode)") + validatedResponse = useInvalidRequestAsDefaultResult ? .error(.invalidRequest(message: errorDescription)) : .error(.generalError) + } + + // Log the rest of error_codes + + errorCodes.forEach { errorCode in + let errorMessage: String + + if let knownErrorCode = MSALNativeAuthESTSApiErrorCodes(rawValue: errorCode) { + errorMessage = "/token error - ESTS error received in error_codes: \(knownErrorCode) (ignoring)" + } else { + errorMessage = "/token error - Unknown ESTS received in error_codes with code: \(errorCode) (ignoring)" + } + + MSALLogger.log(level: .verbose, context: context, format: errorMessage) + } + + return validatedResponse + } + + private func convertInvalidGrantErrorCodeToErrorType( + _ errorCode: MSALNativeAuthESTSApiErrorCodes, + errorDescription: String? + ) -> MSALNativeAuthTokenValidatedErrorType { + switch errorCode { + case .userNotFound: + return .userNotFound(message: errorDescription) + case .invalidCredentials: + return .invalidPassword(message: errorDescription) + case .invalidOTP, + .incorrectOTP, + .OTPNoCacheEntryForUser: + return .invalidOOBCode(message: errorDescription) + case .strongAuthRequired: + return .strongAuthRequired(message: errorDescription) + case .userNotHaveAPassword, + .invalidRequestParameter: + return .generalError + } + } + + private func convertInvalidRequestErrorCodeToErrorType( + _ errorCode: MSALNativeAuthESTSApiErrorCodes, + errorDescription: String? + ) -> MSALNativeAuthTokenValidatedErrorType { + switch errorCode { + case .invalidOTP, + .incorrectOTP, + .OTPNoCacheEntryForUser: + return .invalidOOBCode(message: errorDescription) + case .userNotFound, + .invalidCredentials, + .strongAuthRequired, + .userNotHaveAPassword, + .invalidRequestParameter: + return .invalidRequest(message: errorDescription) + } + } +} diff --git a/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift new file mode 100644 index 0000000000..34043e98ab --- /dev/null +++ b/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift @@ -0,0 +1,128 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +enum MSALNativeAuthTokenValidatedResponse { + case success(MSIDTokenResponse) + case error(MSALNativeAuthTokenValidatedErrorType) +} + +enum MSALNativeAuthTokenValidatedErrorType: Error { + case generalError + case expiredToken(message: String?) + case expiredRefreshToken(message: String?) + case invalidClient(message: String?) + case invalidRequest(message: String?) + case invalidServerResponse + case userNotFound(message: String?) + case invalidPassword(message: String?) + case invalidOOBCode(message: String?) + case unsupportedChallengeType(message: String?) + case strongAuthRequired(message: String?) + case invalidScope(message: String?) + case authorizationPending(message: String?) + case slowDown(message: String?) + + func convertToSignInPasswordStartError() -> SignInPasswordStartError { + switch self { + case .expiredToken(let message), + .authorizationPending(let message), + .slowDown(let message), + .invalidRequest(let message), + .invalidOOBCode(let message), + .invalidClient(let message), + .unsupportedChallengeType(let message), + .invalidScope(let message): + return SignInPasswordStartError(type: .generalError, message: message) + case .generalError: + return SignInPasswordStartError(type: .generalError) + case .invalidServerResponse: + return SignInPasswordStartError(type: .generalError, message: MSALNativeAuthErrorMessage.invalidServerResponse) + case .userNotFound(let message): + return SignInPasswordStartError(type: .userNotFound, message: message) + case .invalidPassword(let message): + return SignInPasswordStartError(type: .invalidPassword, message: message) + case .strongAuthRequired(let message): + return SignInPasswordStartError(type: .browserRequired, message: message) + case .expiredRefreshToken(let message): + MSALLogger.log(level: .error, context: nil, format: "Error not treated - \(self))") + return SignInPasswordStartError(type: .generalError, message: message) + } + } + + func convertToRetrieveAccessTokenError() -> RetrieveAccessTokenError { + switch self { + case .expiredToken(let message), + .authorizationPending(let message), + .slowDown(let message), + .invalidRequest(let message), + .invalidClient(let message), + .unsupportedChallengeType(let message), + .invalidScope(let message): + return RetrieveAccessTokenError(type: .generalError, message: message) + case .generalError: + return RetrieveAccessTokenError(type: .generalError) + case .invalidServerResponse: + return RetrieveAccessTokenError(type: .generalError, message: MSALNativeAuthErrorMessage.invalidServerResponse) + case .expiredRefreshToken: + return RetrieveAccessTokenError(type: .refreshTokenExpired) + case .strongAuthRequired(let message): + return RetrieveAccessTokenError(type: .browserRequired, message: message) + case .userNotFound(let message), + .invalidPassword(let message), + .invalidOOBCode(let message): + MSALLogger.log(level: .error, context: nil, format: "Error not treated - \(self))") + return RetrieveAccessTokenError(type: .generalError, message: message) + } + } + + func convertToVerifyCodeError() -> VerifyCodeError { + switch self { + case .invalidOOBCode(let message): + return VerifyCodeError(type: .invalidCode, message: message) + case .strongAuthRequired(let message): + return VerifyCodeError(type: .browserRequired, message: message) + case .expiredToken(let message), + .authorizationPending(let message), + .slowDown(let message), + .invalidRequest(let message), + .invalidClient(let message), + .unsupportedChallengeType(let message), + .invalidScope(let message), + .expiredRefreshToken(let message), + .userNotFound(let message), + .invalidPassword(let message): + return VerifyCodeError(type: .generalError, message: message) + case .generalError: + return VerifyCodeError(type: .generalError) + case .invalidServerResponse: + return VerifyCodeError(type: .generalError, message: MSALNativeAuthErrorMessage.invalidServerResponse) + } + } + + func convertToPasswordRequiredError() -> PasswordRequiredError { + return PasswordRequiredError(signInPasswordError: convertToSignInPasswordStartError()) + } +} diff --git a/MSAL/src/native_auth/network/sign_in/MSALNativeAuthSignInRequestProvider.swift b/MSAL/src/native_auth/network/sign_in/MSALNativeAuthSignInRequestProvider.swift new file mode 100644 index 0000000000..aa36b1d8fb --- /dev/null +++ b/MSAL/src/native_auth/network/sign_in/MSALNativeAuthSignInRequestProvider.swift @@ -0,0 +1,83 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthSignInRequestProviding { + func inititate( + parameters: MSALNativeAuthSignInInitiateRequestParameters, + context: MSIDRequestContext + ) throws -> MSIDHttpRequest + + func challenge( + parameters: MSALNativeAuthSignInChallengeRequestParameters, + context: MSIDRequestContext + ) throws -> MSIDHttpRequest +} + +final class MSALNativeAuthSignInRequestProvider: MSALNativeAuthSignInRequestProviding { + + // MARK: - Variables + private let requestConfigurator: MSALNativeAuthRequestConfigurator + private let telemetryProvider: MSALNativeAuthTelemetryProviding + + // MARK: - Init + + init( + requestConfigurator: MSALNativeAuthRequestConfigurator, + telemetryProvider: MSALNativeAuthTelemetryProviding = MSALNativeAuthTelemetryProvider() + ) { + self.requestConfigurator = requestConfigurator + self.telemetryProvider = telemetryProvider + } + + // MARK: - SignIn Initiate + + func inititate( + parameters: MSALNativeAuthSignInInitiateRequestParameters, + context: MSIDRequestContext + ) throws -> MSIDHttpRequest { + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .signIn(.initiate(parameters)), + request: request, + telemetryProvider: telemetryProvider) + + return request + } + + // MARK: - SignIn Challenge + + func challenge( + parameters: MSALNativeAuthSignInChallengeRequestParameters, + context: MSIDRequestContext + ) throws -> MSIDHttpRequest { + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .signIn(.challenge(parameters)), + request: request, + telemetryProvider: telemetryProvider) + return request + } +} diff --git a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpContinueRequestProviderParams.swift b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpContinueRequestProviderParams.swift new file mode 100644 index 0000000000..3b6baeed14 --- /dev/null +++ b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpContinueRequestProviderParams.swift @@ -0,0 +1,50 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +struct MSALNativeAuthSignUpContinueRequestProviderParams { + let grantType: MSALNativeAuthGrantType + let signUpToken: String + let password: String? + let oobCode: String? + let attributes: [String: Any]? + let context: MSIDRequestContext + + init( + grantType: MSALNativeAuthGrantType, + signUpToken: String, + password: String? = nil, + oobCode: String? = nil, + attributes: [String: Any]? = nil, + context: MSIDRequestContext + ) { + self.grantType = grantType + self.signUpToken = signUpToken + self.password = password + self.oobCode = oobCode + self.attributes = attributes + self.context = context + } +} diff --git a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift new file mode 100644 index 0000000000..64274f246e --- /dev/null +++ b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift @@ -0,0 +1,99 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthSignUpRequestProviding { + func start(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) throws -> MSIDHttpRequest + func challenge(token: String, context: MSIDRequestContext) throws -> MSIDHttpRequest + func `continue`(parameters: MSALNativeAuthSignUpContinueRequestProviderParams) throws -> MSIDHttpRequest +} + +final class MSALNativeAuthSignUpRequestProvider: MSALNativeAuthSignUpRequestProviding { + + private let requestConfigurator: MSALNativeAuthRequestConfigurator + private let telemetryProvider: MSALNativeAuthTelemetryProviding + + init(requestConfigurator: MSALNativeAuthRequestConfigurator, + telemetryProvider: MSALNativeAuthTelemetryProviding) { + self.requestConfigurator = requestConfigurator + self.telemetryProvider = telemetryProvider + } + + func start(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) throws -> MSIDHttpRequest { + guard let attributes = try formatAttributes(parameters.attributes) else { + throw MSALNativeAuthInternalError.invalidAttributes + } + + let params = MSALNativeAuthSignUpStartRequestParameters( + username: parameters.username, + password: parameters.password, + attributes: attributes, + context: parameters.context + ) + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .signUp(.start(params)), + request: request, + telemetryProvider: telemetryProvider) + return request + } + + func challenge(token: String, context: MSIDRequestContext) throws -> MSIDHttpRequest { + let params = MSALNativeAuthSignUpChallengeRequestParameters( + signUpToken: token, + context: context + ) + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .signUp(.challenge(params)), + request: request, + telemetryProvider: telemetryProvider) + return request + } + + func `continue`(parameters: MSALNativeAuthSignUpContinueRequestProviderParams) throws -> MSIDHttpRequest { + let attributesFormatted = try parameters.attributes.map { try formatAttributes($0) } ?? nil + + let params = MSALNativeAuthSignUpContinueRequestParameters( + grantType: parameters.grantType, + signUpToken: parameters.signUpToken, + password: parameters.password, + oobCode: parameters.oobCode, + attributes: attributesFormatted, + context: parameters.context + ) + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .signUp(.continue(params)), + request: request, + telemetryProvider: telemetryProvider) + return request + } + + private func formatAttributes(_ attributes: [String: Any]) throws -> String? { + let data = try JSONSerialization.data(withJSONObject: attributes) + return String(data: data, encoding: .utf8) + } +} diff --git a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpStartRequestProviderParameters.swift b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpStartRequestProviderParameters.swift new file mode 100644 index 0000000000..74a37d0f95 --- /dev/null +++ b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpStartRequestProviderParameters.swift @@ -0,0 +1,30 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +struct MSALNativeAuthSignUpStartRequestProviderParameters { + let username: String + let password: String? + let attributes: [String: Any] + let context: MSALNativeAuthRequestContext +} diff --git a/MSAL/src/native_auth/network/token/MSALNativeAuthTokenRequestProvider.swift b/MSAL/src/native_auth/network/token/MSALNativeAuthTokenRequestProvider.swift new file mode 100644 index 0000000000..a18db4508e --- /dev/null +++ b/MSAL/src/native_auth/network/token/MSALNativeAuthTokenRequestProvider.swift @@ -0,0 +1,80 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthTokenRequestProviding { + func signInWithPassword( + parameters: MSALNativeAuthTokenRequestParameters, + context: MSIDRequestContext + ) throws -> MSIDHttpRequest + + func refreshToken( + parameters: MSALNativeAuthTokenRequestParameters, + context: MSIDRequestContext + ) throws -> MSIDHttpRequest +} + +final class MSALNativeAuthTokenRequestProvider: MSALNativeAuthTokenRequestProviding { + + // MARK: - Variables + private let requestConfigurator: MSALNativeAuthRequestConfigurator + private let telemetryProvider: MSALNativeAuthTelemetryProviding + + // MARK: - Init + + init( + requestConfigurator: MSALNativeAuthRequestConfigurator, + telemetryProvider: MSALNativeAuthTelemetryProviding = MSALNativeAuthTelemetryProvider() + ) { + self.requestConfigurator = requestConfigurator + self.telemetryProvider = telemetryProvider + } + + // MARK: - Token + + func signInWithPassword( + parameters: MSALNativeAuthTokenRequestParameters, + context: MSIDRequestContext + ) throws -> MSIDHttpRequest { + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .token(.signInWithPassword(parameters)), + request: request, + telemetryProvider: telemetryProvider) + return request + } + + func refreshToken( + parameters: MSALNativeAuthTokenRequestParameters, + context: MSIDRequestContext + ) throws -> MSIDHttpRequest { + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .token(.refreshToken(parameters)), + request: request, + telemetryProvider: telemetryProvider) + return request + } +} diff --git a/MSAL/src/native_auth/public/MSALNativeAuthChallengeTypes.h b/MSAL/src/native_auth/public/MSALNativeAuthChallengeTypes.h new file mode 100644 index 0000000000..b1860d0e21 --- /dev/null +++ b/MSAL/src/native_auth/public/MSALNativeAuthChallengeTypes.h @@ -0,0 +1,38 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef MSALNativeAuthChallengeTypes_h +#define MSALNativeAuthChallengeTypes_h + +/// The set of capabilities that an application wishes to support for Native Auth operations. +/// +/// Valid options are: +/// * OOB: The application can support asking a user to supply a verification code that is sent by email. +/// * Password: The application can support asking a user to supply a password +typedef NS_OPTIONS(NSInteger, MSALNativeAuthChallengeTypes) { + MSALNativeAuthChallengeTypeOOB = 1 << 0, + MSALNativeAuthChallengeTypePassword = 1 << 1 +}; + +#endif /* MSALNativeAuthChallengeTypes_h */ diff --git a/MSAL/src/native_auth/public/MSALNativeAuthChannelType.swift b/MSAL/src/native_auth/public/MSALNativeAuthChannelType.swift new file mode 100644 index 0000000000..2af38fe411 --- /dev/null +++ b/MSAL/src/native_auth/public/MSALNativeAuthChannelType.swift @@ -0,0 +1,31 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public enum MSALNativeAuthChannelType: Int { + case email + case phone +} diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift new file mode 100644 index 0000000000..108f16676f --- /dev/null +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift @@ -0,0 +1,152 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +extension MSALNativeAuthPublicClientApplication { + + func signUpUsingPasswordInternal( + username: String, + password: String, + attributes: [String: Any]?, + correlationId: UUID? + ) async -> MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse { + guard inputValidator.isInputValid(username) else { + return .init(.error(SignUpPasswordStartError(type: .invalidUsername))) + } + guard inputValidator.isInputValid(password) else { + return .init(.error(SignUpPasswordStartError(type: .invalidPassword))) + } + + let controller = controllerFactory.makeSignUpController() + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + let parameters = MSALNativeAuthSignUpStartRequestProviderParameters( + username: username, + password: password, + attributes: attributes ?? [:], + context: context + ) + + return await controller.signUpStartPassword(parameters: parameters) + } + + func signUpInternal( + username: String, + attributes: [String: Any]?, + correlationId: UUID? + ) async -> MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse { + guard inputValidator.isInputValid(username) else { + return .init(.error(SignUpStartError(type: .invalidUsername))) + } + + let controller = controllerFactory.makeSignUpController() + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + let parameters = MSALNativeAuthSignUpStartRequestProviderParameters( + username: username, + password: nil, + attributes: attributes ?? [:], + context: context + ) + + return await controller.signUpStartCode(parameters: parameters) + } + + func signInUsingPasswordInternal( + username: String, + password: String, + scopes: [String]?, + correlationId: UUID? + ) async -> MSALNativeAuthSignInControlling.SignInPasswordControllerResponse { + guard inputValidator.isInputValid(username) else { + return .init(.error(SignInPasswordStartError(type: .invalidUsername))) + } + + guard inputValidator.isInputValid(password) else { + return .init(.error(SignInPasswordStartError(type: .invalidPassword))) + } + + let controller = controllerFactory.makeSignInController() + + let params = MSALNativeAuthSignInWithPasswordParameters( + username: username, + password: password, + context: MSALNativeAuthRequestContext(correlationId: correlationId), + scopes: scopes + ) + + return await controller.signIn(params: params) + } + + func signInInternal( + username: String, + scopes: [String]?, + correlationId: UUID? + ) async -> MSALNativeAuthSignInControlling.SignInCodeControllerResponse { + guard inputValidator.isInputValid(username) else { + return .init(.error(SignInStartError(type: .invalidUsername))) + } + let controller = controllerFactory.makeSignInController() + let params = MSALNativeAuthSignInWithCodeParameters( + username: username, + context: MSALNativeAuthRequestContext(correlationId: correlationId), + scopes: scopes + ) + return await controller.signIn(params: params) + } + + func resetPasswordInternal(username: String, correlationId: UUID?) async -> ResetPasswordStartResult { + guard inputValidator.isInputValid(username) else { + return .error(ResetPasswordStartError(type: .invalidUsername)) + } + + let controller = controllerFactory.makeResetPasswordController() + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + return await controller.resetPassword( + parameters: .init( + username: username, + context: context + ) + ) + } + + static func getInternalChallengeTypes( + _ challengeTypes: MSALNativeAuthChallengeTypes + ) -> [MSALNativeAuthInternalChallengeType] { + var internalChallengeTypes = [MSALNativeAuthInternalChallengeType]() + + if challengeTypes.contains(.OOB) { + internalChallengeTypes.append(.oob) + } + + if challengeTypes.contains(.password) { + internalChallengeTypes.append(.password) + } + + internalChallengeTypes.append(.redirect) + return internalChallengeTypes + } +} diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift new file mode 100644 index 0000000000..302324c816 --- /dev/null +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift @@ -0,0 +1,312 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objcMembers +public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplication { + + let controllerFactory: MSALNativeAuthControllerBuildable + let inputValidator: MSALNativeAuthInputValidating + private let internalChallengeTypes: [MSALNativeAuthInternalChallengeType] + + /// Initialize a MSALNativePublicClientApplication with a given configuration and challenge types + /// - Parameters: + /// - config: Configuration for PublicClientApplication + /// - challengeTypes: The set of capabilities that this application can support as an ``MSALNativeAuthChallengeTypes`` optionset + /// - Throws: An error that occurred creating the application object + public init( + configuration config: MSALPublicClientApplicationConfig, + challengeTypes: MSALNativeAuthChallengeTypes) throws { + guard let ciamAuthority = config.authority as? MSALCIAMAuthority else { + throw MSALNativeAuthInternalError.invalidAuthority + } + + self.internalChallengeTypes = + MSALNativeAuthPublicClientApplication.getInternalChallengeTypes(challengeTypes) + + var nativeConfiguration = try MSALNativeAuthConfiguration( + clientId: config.clientId, + authority: ciamAuthority, + challengeTypes: internalChallengeTypes + ) + nativeConfiguration.sliceConfig = config.sliceConfig + + self.controllerFactory = MSALNativeAuthControllerFactory(config: nativeConfiguration) + self.inputValidator = MSALNativeAuthInputValidator() + + try super.init(configuration: config) + } + + /// Initialize a MSALNativePublicClientApplication. + /// - Parameters: + /// - clientId: The client ID of the application, this should come from the app developer portal. + /// - tenantSubdomain: The subdomain of the tenant, this should come from the app developer portal. + /// - challengeTypes: The set of capabilities that this application can support as an ``MSALNativeAuthChallengeTypes`` optionset + /// - redirectUri: Optional. The redirect URI for the application, this should come from the app developer portal. + /// - Throws: An error that occurred creating the application object + public init( + clientId: String, + tenantSubdomain: String, + challengeTypes: MSALNativeAuthChallengeTypes, + redirectUri: String? = nil) throws { + let ciamAuthority = try MSALNativeAuthAuthorityProvider() + .authority(rawTenant: tenantSubdomain) + + self.internalChallengeTypes = MSALNativeAuthPublicClientApplication.getInternalChallengeTypes(challengeTypes) + let nativeConfiguration = try MSALNativeAuthConfiguration( + clientId: clientId, + authority: ciamAuthority, + challengeTypes: internalChallengeTypes + ) + + self.controllerFactory = MSALNativeAuthControllerFactory(config: nativeConfiguration) + self.inputValidator = MSALNativeAuthInputValidator() + + let configuration = MSALPublicClientApplicationConfig( + clientId: clientId, + redirectUri: redirectUri, + authority: ciamAuthority + ) + + // we need to bypass redirect URI validation because we don't need a redirect URI for Native Auth scenarios + configuration.bypassRedirectURIValidation = redirectUri == nil + let defaultRedirectUri = String(format: "msauth.%@://auth", Bundle.main.bundleIdentifier ?? "") + // we need to set a default redirect URI value to ensure IdentityCore checks the bypassRedirectURIValidation flag + configuration.redirectUri = redirectUri ?? defaultRedirectUri + + try super.init(configuration: configuration) + } + + init( + controllerFactory: MSALNativeAuthControllerBuildable, + inputValidator: MSALNativeAuthInputValidating, + internalChallengeTypes: [MSALNativeAuthInternalChallengeType] + ) { + self.controllerFactory = controllerFactory + self.inputValidator = inputValidator + self.internalChallengeTypes = internalChallengeTypes + + super.init() + } + + // MARK: delegate methods + + /// Sign up a user with a given username and password. + /// - Parameters: + /// - username: Username for the new account. + /// - password: Password to be used for the new account. + /// - attributes: Optional. User attributes to be used during account creation. + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the Sign Up flow. + public func signUpUsingPassword( + username: String, + password: String, + attributes: [String: Any]? = nil, + correlationId: UUID? = nil, + delegate: SignUpPasswordStartDelegate + ) { + Task { + let controllerResponse = await signUpUsingPasswordInternal( + username: username, + password: password, + attributes: attributes, + correlationId: correlationId + ) + + switch controllerResponse.result { + case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): + await delegate.onSignUpCodeRequired( + newState: newState, + sentTo: sentTo, + channelTargetType: channelTargetType, + codeLength: codeLength + ) + case .attributesInvalid(let attributes): + if let signUpAttributesMethod = delegate.onSignUpAttributesInvalid { + controllerResponse.telemetryUpdate?(.success(())) + await signUpAttributesMethod(attributes) + } else { + let error = SignUpPasswordStartError(type: .generalError, message: MSALNativeAuthErrorMessage.codeRequiredNotImplemented) + controllerResponse.telemetryUpdate?(.failure(error)) + await delegate.onSignUpPasswordError(error: error) + } + case .error(let error): + await delegate.onSignUpPasswordError(error: error) + } + } + } + + /// Sign up a user with a given username. + /// - Parameters: + /// - username: Username for the new account. + /// - attributes: Optional. User attributes to be used during account creation. + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the Sign Up flow. + public func signUp( + username: String, + attributes: [String: Any]? = nil, + correlationId: UUID? = nil, + delegate: SignUpStartDelegate + ) { + Task { + let controllerResponse = await signUpInternal(username: username, attributes: attributes, correlationId: correlationId) + + switch controllerResponse.result { + case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): + await delegate.onSignUpCodeRequired( + newState: newState, + sentTo: sentTo, + channelTargetType: channelTargetType, + codeLength: codeLength + ) + case .attributesInvalid(let attributes): + if let signUpAttributesMethod = delegate.onSignUpAttributesInvalid { + controllerResponse.telemetryUpdate?(.success(())) + await signUpAttributesMethod(attributes) + } else { + let error = SignUpStartError(type: .generalError, message: MSALNativeAuthErrorMessage.codeRequiredNotImplemented) + controllerResponse.telemetryUpdate?(.failure(error)) + await delegate.onSignUpError(error: error) + } + case .error(let error): + await delegate.onSignUpError(error: error) + } + } + } + + /// Sign in a user with a given username and password. + /// - Parameters: + /// - username: Username for the account. + /// - password: Password for the account. + /// - scopes: Optional. Permissions you want included in the access token received after sign in flow has completed. + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the Sign In flow. + public func signInUsingPassword( + username: String, + password: String, + scopes: [String]? = nil, + correlationId: UUID? = nil, + delegate: SignInPasswordStartDelegate + ) { + Task { + let controllerResponse = await signInUsingPasswordInternal( + username: username, + password: password, + scopes: scopes, + correlationId: correlationId + ) + + switch controllerResponse.result { + case .completed(let result): + await delegate.onSignInCompleted(result: result) + case .codeRequired(let newState, let sentTo, let channelType, let codeLength): + if let codeRequiredMethod = delegate.onSignInCodeRequired { + controllerResponse.telemetryUpdate?(.success(())) + await codeRequiredMethod(newState, sentTo, channelType, codeLength) + } else { + let error = SignInPasswordStartError(type: .generalError, message: MSALNativeAuthErrorMessage.codeRequiredNotImplemented) + controllerResponse.telemetryUpdate?(.failure(error)) + await delegate.onSignInPasswordError(error: error) + } + case .error(let error): + await delegate.onSignInPasswordError(error: error) + } + } + } + + /// Sign in a user with a given username. + /// - Parameters: + /// - username: Username for the account + /// - scopes: Optional. Permissions you want included in the access token received after sign in flow has completed. + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the Sign In flow. + public func signIn( + username: String, + scopes: [String]? = nil, + correlationId: UUID? = nil, + delegate: SignInStartDelegate + ) { + Task { + let controllerResponse = await signInInternal( + username: username, + scopes: scopes, + correlationId: correlationId + ) + + switch controllerResponse.result { + case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): + await delegate.onSignInCodeRequired(newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength) + case .passwordRequired(let newState): + if let passwordRequiredMethod = delegate.onSignInPasswordRequired { + controllerResponse.telemetryUpdate?(.success(())) + await passwordRequiredMethod(newState) + } else { + let error = SignInStartError(type: .generalError, message: MSALNativeAuthErrorMessage.passwordRequiredNotImplemented) + controllerResponse.telemetryUpdate?(.failure(error)) + await delegate.onSignInError(error: error) + } + case .error(let error): + await delegate.onSignInError(error: error) + } + } + } + + /// Reset the password for a given username. + /// - Parameters: + /// - username: Username for the account. + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the Reset Password flow. + public func resetPassword( + username: String, + correlationId: UUID? = nil, + delegate: ResetPasswordStartDelegate + ) { + Task { + let result = await resetPasswordInternal(username: username, correlationId: correlationId) + + switch result { + case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): + await delegate.onResetPasswordCodeRequired( + newState: newState, + sentTo: sentTo, + channelTargetType: channelTargetType, + codeLength: codeLength + ) + case .error(let error): + await delegate.onResetPasswordError(error: error) + } + } + } + + /// Retrieve the current signed in account from the cache. + /// - Parameter correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - Returns: An object representing the account information if present in the local cache. + public func getNativeAuthUserAccount(correlationId: UUID? = nil) -> MSALNativeAuthUserAccountResult? { + let controller = controllerFactory.makeCredentialsController() + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + return controller.retrieveUserAccountResult(context: context) + } +} diff --git a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift new file mode 100644 index 0000000000..06cd793ffa --- /dev/null +++ b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift @@ -0,0 +1,45 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +extension MSALNativeAuthUserAccountResult { + + func getAccessTokenInternal(forceRefresh: Bool, correlationId: UUID?) async -> Result { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + if let accessToken = self.authTokens.accessToken { + if forceRefresh || accessToken.isExpired() { + let controllerFactory = MSALNativeAuthControllerFactory(config: configuration) + let credentialsController = controllerFactory.makeCredentialsController() + return await credentialsController.refreshToken(context: context, authTokens: authTokens) + } else { + return .success(accessToken.accessToken) + } + } else { + MSALLogger.log(level: .error, context: context, format: "Retrieve Access Token: Existing token not found") + return .failure(RetrieveAccessTokenError(type: .tokenNotFound)) + } + } +} diff --git a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift new file mode 100644 index 0000000000..2a0e4d4823 --- /dev/null +++ b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift @@ -0,0 +1,100 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// Class that groups account and token information. +@objc public class MSALNativeAuthUserAccountResult: NSObject { + /// The account object that holds account information. + @objc public let account: MSALAccount + + let authTokens: MSALNativeAuthTokens + let configuration: MSALNativeAuthConfiguration + private let cacheAccessor: MSALNativeAuthCacheInterface + + /// Get the ID token for the account. + @objc public var idToken: String? { + authTokens.rawIdToken + } + + /// Get the list of permissions for the access token for the account if present. + @objc public var scopes: [String] { + authTokens.accessToken?.scopes.array as? [String] ?? [] + } + + /// Get the expiration date for the access token for the account if present. + @objc public var expiresOn: Date? { + authTokens.accessToken?.expiresOn + } + + init( + account: MSALAccount, + authTokens: MSALNativeAuthTokens, + configuration: MSALNativeAuthConfiguration, + cacheAccessor: MSALNativeAuthCacheInterface + ) { + self.account = account + self.authTokens = authTokens + self.configuration = configuration + self.cacheAccessor = cacheAccessor + } + + /// Removes all the data from the cache. + @objc public func signOut() { + let context = MSALNativeAuthRequestContext() + + do { + try cacheAccessor.clearCache( + accountIdentifier: account.lookupAccountIdentifier, + authority: configuration.authority, + clientId: configuration.clientId, + context: context + ) + } catch { + MSALLogger.log( + level: .error, + context: context, + format: "Clearing MSAL token cache for the current account failed with error %@: \(error)" + ) + } + } + + /// Retrieves an access token for the account. + /// - Parameters: + /// - forceRefresh: Ignore any existing access token in the cache and force MSAL to get a new access token from the service. + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the Get Access Token flow. + @objc public func getAccessToken(forceRefresh: Bool = false, correlationId: UUID? = nil, delegate: CredentialsDelegate) { + Task { + let controllerResponse = await getAccessTokenInternal(forceRefresh: forceRefresh, correlationId: correlationId) + + switch controllerResponse { + case .success(let accessToken): + await delegate.onAccessTokenRetrieveCompleted(accessToken: accessToken) + case .failure(let error): + await delegate.onAccessTokenRetrieveError(error: error) + } + } + } +} diff --git a/MSAL/src/native_auth/public/parameters/MSALNativeAuthParameters.swift b/MSAL/src/native_auth/public/parameters/MSALNativeAuthParameters.swift new file mode 100644 index 0000000000..6a804602be --- /dev/null +++ b/MSAL/src/native_auth/public/parameters/MSALNativeAuthParameters.swift @@ -0,0 +1,38 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objcMembers +public class MSALNativeAuthParameters: NSObject { + + /** + UUID to correlate this request with the server. + */ + public let correlationId: UUID? + + init(correlationId: UUID? = nil) { + self.correlationId = correlationId + } +} diff --git a/MSAL/src/native_auth/public/parameters/MSALNativeAuthResendCodeParameters.swift b/MSAL/src/native_auth/public/parameters/MSALNativeAuthResendCodeParameters.swift new file mode 100644 index 0000000000..0bbaa23828 --- /dev/null +++ b/MSAL/src/native_auth/public/parameters/MSALNativeAuthResendCodeParameters.swift @@ -0,0 +1,37 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objcMembers +final public class MSALNativeAuthResendCodeParameters: MSALNativeAuthParameters { + + public let credentialToken: String + + public init(credentialToken: String, + correlationId: UUID? = nil) { + self.credentialToken = credentialToken + super.init(correlationId: correlationId) + } +} diff --git a/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInOTPParameters.swift b/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInOTPParameters.swift new file mode 100644 index 0000000000..e3544efc91 --- /dev/null +++ b/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInOTPParameters.swift @@ -0,0 +1,38 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objcMembers +final public class MSALNativeAuthSignInOTPParameters: MSALNativeAuthParameters { + + public let email: String + public let scopes: [String] + + public init(email: String, scopes: [String] = [], correlationId: UUID? = nil) { + self.email = email + self.scopes = scopes + super.init(correlationId: correlationId) + } +} diff --git a/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInParameters.swift b/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInParameters.swift new file mode 100644 index 0000000000..cf6d9729b6 --- /dev/null +++ b/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInParameters.swift @@ -0,0 +1,43 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objcMembers +final public class MSALNativeAuthSignInParameters: MSALNativeAuthParameters { + + public let email: String + public let password: String + public let scopes: [String] + + public init(email: String, + password: String, + scopes: [String] = [], + correlationId: UUID? = nil) { + self.email = email + self.password = password + self.scopes = scopes + super.init(correlationId: correlationId) + } +} diff --git a/MSAL/src/native_auth/public/parameters/MSALNativeAuthVerifyCodeParameters.swift b/MSAL/src/native_auth/public/parameters/MSALNativeAuthVerifyCodeParameters.swift new file mode 100644 index 0000000000..c3818806dc --- /dev/null +++ b/MSAL/src/native_auth/public/parameters/MSALNativeAuthVerifyCodeParameters.swift @@ -0,0 +1,40 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objcMembers +final public class MSALNativeAuthVerifyCodeParameters: MSALNativeAuthParameters { + + public let credentialToken: String + public let otp: String + + public init(credentialToken: String, + otp: String, + correlationId: UUID? = nil) { + self.credentialToken = credentialToken + self.otp = otp + super.init(correlationId: correlationId) + } +} diff --git a/MSAL/src/native_auth/public/state_machine/MSALNativeAuthRequiredAttributes.swift b/MSAL/src/native_auth/public/state_machine/MSALNativeAuthRequiredAttributes.swift new file mode 100644 index 0000000000..33258fb5a1 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/MSALNativeAuthRequiredAttributes.swift @@ -0,0 +1,41 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class MSALNativeAuthRequiredAttributes: NSObject { + public let name: String + public let type: String + public let required: Bool + public let regex: String? + + init(name: String, type: String, required: Bool, regex: String? = nil) { + self.name = name + self.type = type + self.required = required + self.regex = regex + super.init() + } +} diff --git a/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift new file mode 100644 index 0000000000..584f349563 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift @@ -0,0 +1,36 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public protocol CredentialsDelegate { + /// Notifies the delegate that the operation completed successfully. + /// - Parameter accessToken: The access token string. + @MainActor func onAccessTokenRetrieveCompleted(accessToken: String) + + /// Notifies the delegate that the operation resulted in an error. + /// - Parameter error: An error object indicating why the operation failed. + @MainActor func onAccessTokenRetrieveError(error: RetrieveAccessTokenError) +} diff --git a/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift new file mode 100644 index 0000000000..083a7de56a --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift @@ -0,0 +1,92 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public protocol ResetPasswordStartDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameter error: An error object indicating why the operation failed. + @MainActor func onResetPasswordError(error: ResetPasswordStartError) + + /// Notifies the delegate that a verification code is required from the user to continue. + /// - Parameters: + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + @MainActor func onResetPasswordCodeRequired( + newState: ResetPasswordCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int + ) +} + +@objc +public protocol ResetPasswordVerifyCodeDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameters: + /// - error: An error object indicating why the operation failed. + /// - newState: An object representing the new state of the flow with follow on methods. + @MainActor func onResetPasswordVerifyCodeError(error: VerifyCodeError, newState: ResetPasswordCodeRequiredState?) + + /// Notifies the delegate that a password is required from the user to continue. + /// - Parameter newState: An object representing the new state of the flow with follow on methods. + @MainActor func onPasswordRequired(newState: ResetPasswordRequiredState) +} + +@objc +public protocol ResetPasswordResendCodeDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameters: + /// - error: An error object indicating why the operation failed. + /// - newState: An object representing the new state of the flow with follow on methods. + @MainActor func onResetPasswordResendCodeError(error: ResendCodeError, newState: ResetPasswordCodeRequiredState?) + + /// Notifies the delegate that a verification code is required from the user to continue. + /// - Parameters: + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + @MainActor func onResetPasswordResendCodeRequired( + newState: ResetPasswordCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int + ) +} + +@objc +public protocol ResetPasswordRequiredDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameters: + /// - error: An error object indicating why the operation failed. + /// - newState: An object representing the new state of the flow with follow on methods. + @MainActor func onResetPasswordRequiredError(error: PasswordRequiredError, newState: ResetPasswordRequiredState?) + + /// Notifies the delegate that the reset password operation completed successfully. + @MainActor func onResetPasswordCompleted() +} diff --git a/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterSignUpDelegate.swift b/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterSignUpDelegate.swift new file mode 100644 index 0000000000..95169051fe --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterSignUpDelegate.swift @@ -0,0 +1,36 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public protocol SignInAfterSignUpDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameter error: An error object indicating why the operation failed. + @MainActor func onSignInAfterSignUpError(error: SignInAfterSignUpError) + + /// Notifies the delegate that the sign in operation completed successfully. + /// - Parameter result: An object representing the signed in user account. + @MainActor func onSignInCompleted(result: MSALNativeAuthUserAccountResult) +} diff --git a/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift new file mode 100644 index 0000000000..6942dbc6b4 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift @@ -0,0 +1,115 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public protocol SignInPasswordStartDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameter error: An error object indicating why the operation failed. + @MainActor func onSignInPasswordError(error: SignInPasswordStartError) + + /// Notifies the delegate that a verification code is required from the user to continue. + /// - Note: If a flow requires a code but this optional method is not implemented, then ``onSignInPasswordError(error:)`` will be called. + /// - Parameters: + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + @MainActor @objc optional func onSignInCodeRequired(newState: SignInCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int) + + /// Notifies the delegate that the sign in operation completed successfully. + /// - Parameter result: An object representing the signed in user account. + @MainActor func onSignInCompleted(result: MSALNativeAuthUserAccountResult) +} + +@objc +public protocol SignInStartDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameter error: An error object indicating why the operation failed. + @MainActor func onSignInError(error: SignInStartError) + + /// Notifies the delegate that a verification code is required from the user to continue. + /// - Parameters: + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + @MainActor func onSignInCodeRequired(newState: SignInCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int) + + /// Notifies the delegate that a password is required from the user to continue. + /// - Note: If a flow requires a password but this optional method is not implemented, then ``onSignInError(error:)`` will be called. + /// - Parameter newState: An object representing the new state of the flow with follow on methods. + @MainActor @objc optional func onSignInPasswordRequired(newState: SignInPasswordRequiredState) +} + +@objc +public protocol SignInPasswordRequiredDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameters: + /// - error: An error object indicating why the operation failed. + /// - newState: An object representing the new state of the flow with follow on methods. + @MainActor func onSignInPasswordRequiredError(error: PasswordRequiredError, newState: SignInPasswordRequiredState?) + + /// Notifies the delegate that the sign in operation completed successfully. + /// - Parameter result: An object representing the signed in user account. + @MainActor func onSignInCompleted(result: MSALNativeAuthUserAccountResult) +} + +@objc +public protocol SignInResendCodeDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameter error: An error object indicating why the operation failed. + @MainActor func onSignInResendCodeError(error: ResendCodeError, newState: SignInCodeRequiredState?) + + /// Notifies the delegate that a verification code is required from the user to continue. + /// - Parameters: + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + @MainActor func onSignInResendCodeCodeRequired(newState: SignInCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int) +} + +@objc +public protocol SignInVerifyCodeDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameters: + /// - error: An error object indicating why the operation failed. + /// - newState: An object representing the new state of the flow with follow on methods. + @MainActor func onSignInVerifyCodeError(error: VerifyCodeError, newState: SignInCodeRequiredState?) + + /// Notifies the delegate that the sign in operation completed successfully. + /// - Parameter result: An object representing the signed in user account. + @MainActor func onSignInCompleted(result: MSALNativeAuthUserAccountResult) +} diff --git a/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift new file mode 100644 index 0000000000..3caa85c9e6 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift @@ -0,0 +1,159 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public protocol SignUpPasswordStartDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameter error: An error object indicating why the operation failed. + @MainActor func onSignUpPasswordError(error: SignUpPasswordStartError) + + /// Notifies the delegate that a verification code is required from the user to continue. + /// - Parameters: + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + @MainActor func onSignUpCodeRequired(newState: SignUpCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int) + + /// Notifies the delegate that invalid attributes were sent. + /// - Note: If a flow requires attributes but this optional method is not implemented, then ``onSignUpPasswordError(error)`` will be called. + /// - Parameter attributeNames: List of attribute names that failed validation. + @MainActor @objc optional func onSignUpAttributesInvalid(attributeNames: [String]) +} + +@objc +public protocol SignUpStartDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameter error: An error object indicating why the operation failed. + @MainActor func onSignUpError(error: SignUpStartError) + + /// Notifies the delegate that a verification code is required from the user to continue. + /// - Parameters: + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + @MainActor func onSignUpCodeRequired(newState: SignUpCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int) + + /// Notifies the delegate that invalid attributes were sent. + /// - Note: If a flow requires attributes but this optional method is not implemented, then ``onSignUpError(error)`` will be called. + /// - Parameter attributeNames: List of attribute names that failed validation. + @MainActor @objc optional func onSignUpAttributesInvalid(attributeNames: [String]) +} + +@objc +public protocol SignUpVerifyCodeDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameters: + /// - error: An error object indicating why the operation failed. + /// - newState: An object representing the new state of the flow with follow on methods. + @MainActor func onSignUpVerifyCodeError(error: VerifyCodeError, newState: SignUpCodeRequiredState?) + + /// Notifies the delegate that attributes are required from the user to continue. + /// - Note: If a flow requires attributes but this optional method is not implemented, then ``onSignUpVerifyCodeError(error:newState:)`` will be called. + /// - Parameters: + /// - attributes: List of required attributes. + /// - newState: An object representing the new state of the flow with follow on methods. + @MainActor @objc optional func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) + + /// Notifies the delegate that a password is required from the user to continue. + /// - Note: If a flow requires a password but this optional method is not implemented, then ``onSignUpVerifyCodeError(error:newState:)`` will be called. + /// - Parameter newState: An object representing the new state of the flow with follow on methods. + @MainActor @objc optional func onSignUpPasswordRequired(newState: SignUpPasswordRequiredState) + + /// Notifies the delegate that the sign up operation completed successfully. + /// - Parameter newState: An object representing the new state of the flow with follow on methods. + @MainActor func onSignUpCompleted(newState: SignInAfterSignUpState) +} + +@objc +public protocol SignUpResendCodeDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameter error: An error object indicating why the operation failed. + @MainActor func onSignUpResendCodeError(error: ResendCodeError) + + /// Notifies the delegate that a verification code is required from the user to continue. + /// - Parameters: + /// - newState: An object representing the new state of the flow with follow on methods. + /// - sentTo: The email/phone number that the code was sent to. + /// - channelTargetType: The channel (email/phone) the code was sent through. + /// - codeLength: The length of the code required. + @MainActor func onSignUpResendCodeCodeRequired( + newState: SignUpCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int + ) +} + +@objc +public protocol SignUpPasswordRequiredDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameters: + /// - error: An error object indicating why the operation failed. + /// - newState: An object representing the new state of the flow with follow on methods. + @MainActor func onSignUpPasswordRequiredError(error: PasswordRequiredError, newState: SignUpPasswordRequiredState?) + + /// Notifies the delegate that attributes are required from the user to continue. + /// - Note: If a flow requires attributes but this optional method is not implemented, then ``onSignUpPasswordRequiredError(error:newState:)`` will be called. + /// - Parameters: + /// - attributes: List of required attributes. + /// - newState: An object representing the new state of the flow with follow on methods. + @MainActor @objc optional func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) + + /// Notifies the delegate that the sign up operation completed successfully. + /// - Parameter newState: An object representing the new state of the flow with follow on methods. + @MainActor func onSignUpCompleted(newState: SignInAfterSignUpState) +} + +@objc +public protocol SignUpAttributesRequiredDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameter error: An error object indicating why the operation failed. + @MainActor func onSignUpAttributesRequiredError(error: AttributesRequiredError) + + /// Notifies the delegate that there are some required attributes to be sent. + /// - Parameters: + /// - attributes: List of required attributes. + /// - newState: An object representing the new state of the flow with follow on methods. + @MainActor func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) + + /// Notifies the delegate that invalid attributes were sent. + /// - Parameters: + /// - attributeNames: List of attribute names that failed validation. + /// - newState: An object representing the new state of the flow with follow on methods. + @MainActor func onSignUpAttributesInvalid(attributeNames: [String], newState: SignUpAttributesRequiredState) + + /// Notifies the delegate that the sign up operation completed successfully. + /// - Parameter newState: An object representing the new state of the flow with follow on methods. + @MainActor func onSignUpCompleted(newState: SignInAfterSignUpState) +} diff --git a/MSAL/src/native_auth/public/state_machine/error/AttributesRequiredError.swift b/MSAL/src/native_auth/public/state_machine/error/AttributesRequiredError.swift new file mode 100644 index 0000000000..6ab96f409a --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/error/AttributesRequiredError.swift @@ -0,0 +1,36 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class AttributesRequiredError: MSALNativeAuthError { + public override var errorDescription: String? { + if let description = super.errorDescription { + return description + } + + return "General error" + } +} diff --git a/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift b/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift new file mode 100644 index 0000000000..102612a6ec --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift @@ -0,0 +1,38 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class MSALNativeAuthError: NSObject, LocalizedError { + private let message: String? + + init(message: String? = nil) { + self.message = message + } + + public var errorDescription: String? { + message + } +} diff --git a/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift b/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift new file mode 100644 index 0000000000..9296efe220 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift @@ -0,0 +1,70 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class PasswordRequiredError: MSALNativeAuthError { + /// An error type indicating the type of error that occurred + @objc public let type: PasswordRequiredErrorType + + init(type: PasswordRequiredErrorType, message: String? = nil) { + self.type = type + super.init(message: message) + } + + init(signInPasswordError: SignInPasswordStartError) { + switch signInPasswordError.type { + case .browserRequired: + self.type = .browserRequired + case .invalidPassword: + self.type = .invalidPassword + default: + self.type = .generalError + } + super.init(message: signInPasswordError.errorDescription) + } + + public override var errorDescription: String? { + if let description = super.errorDescription { + return description + } + + switch type { + case .browserRequired: + return "Browser required" + case .invalidPassword: + return "Invalid password" + case .generalError: + return "General error" + } + } +} + +@objc +public enum PasswordRequiredErrorType: Int { + case browserRequired + case generalError + case invalidPassword +} diff --git a/MSAL/src/native_auth/public/state_machine/error/ResendCodeError.swift b/MSAL/src/native_auth/public/state_machine/error/ResendCodeError.swift new file mode 100644 index 0000000000..36a399b03e --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/error/ResendCodeError.swift @@ -0,0 +1,36 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class ResendCodeError: MSALNativeAuthError { + public override var errorDescription: String? { + if let description = super.errorDescription { + return description + } + + return "General error" + } +} diff --git a/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift b/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift new file mode 100644 index 0000000000..2871a9e2b7 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift @@ -0,0 +1,64 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class ResetPasswordStartError: MSALNativeAuthError { + /// An error type indicating the type of error that occurred + @objc public let type: ResetPasswordStartErrorType + + init(type: ResetPasswordStartErrorType, message: String? = nil) { + self.type = type + super.init(message: message) + } + + public override var errorDescription: String? { + if let description = super.errorDescription { + return description + } + + switch type { + case .browserRequired: + return "Browser required" + case .generalError: + return "General error" + case .userDoesNotHavePassword: + return "User does not have a password" + case .userNotFound: + return "User not found" + case .invalidUsername: + return "Invalid username" + } + } +} + +@objc +public enum ResetPasswordStartErrorType: Int { + case browserRequired + case generalError + case userDoesNotHavePassword + case userNotFound + case invalidUsername +} diff --git a/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift b/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift new file mode 100644 index 0000000000..c0eb0fc3d1 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift @@ -0,0 +1,61 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class RetrieveAccessTokenError: MSALNativeAuthError { + /// An error type indicating the type of error that occurred + @objc public let type: RetrieveAccessTokenErrorType + + init(type: RetrieveAccessTokenErrorType, message: String? = nil) { + self.type = type + super.init(message: message) + } + + public override var errorDescription: String? { + if let description = super.errorDescription { + return description + } + + switch type { + case .generalError: + return "General error" + case .refreshTokenExpired: + return "Refresh token expired" + case .tokenNotFound: + return "Token not found" + case .browserRequired: + return "Browser required" + } + } +} + +@objc +public enum RetrieveAccessTokenErrorType: Int { + case generalError + case refreshTokenExpired + case tokenNotFound + case browserRequired +} diff --git a/MSAL/src/native_auth/public/state_machine/error/SignInAfterSignUpError.swift b/MSAL/src/native_auth/public/state_machine/error/SignInAfterSignUpError.swift new file mode 100644 index 0000000000..da3eaf13a6 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/error/SignInAfterSignUpError.swift @@ -0,0 +1,36 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class SignInAfterSignUpError: MSALNativeAuthError { + public override var errorDescription: String? { + if let description = super.errorDescription { + return description + } + + return "General error" + } +} diff --git a/MSAL/src/native_auth/public/state_machine/error/SignInPasswordStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignInPasswordStartError.swift new file mode 100644 index 0000000000..c5d97dea3f --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/error/SignInPasswordStartError.swift @@ -0,0 +1,64 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class SignInPasswordStartError: MSALNativeAuthError { + /// An error type indicating the type of error that occurred + @objc public let type: SignInPasswordStartErrorType + + init(type: SignInPasswordStartErrorType, message: String? = nil) { + self.type = type + super.init(message: message) + } + + public override var errorDescription: String? { + if let description = super.errorDescription { + return description + } + + switch type { + case .browserRequired: + return "Browser required" + case .userNotFound: + return "User not found" + case .invalidPassword: + return "Invalid password" + case .invalidUsername: + return "Invalid username" + case .generalError: + return "General error" + } + } +} + +@objc +public enum SignInPasswordStartErrorType: Int { + case browserRequired + case userNotFound + case invalidPassword + case invalidUsername + case generalError +} diff --git a/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift new file mode 100644 index 0000000000..41b20f02e5 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift @@ -0,0 +1,61 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class SignInStartError: MSALNativeAuthError { + /// An error type indicating the type of error that occurred + @objc public let type: SignInStartErrorType + + init(type: SignInStartErrorType, message: String? = nil) { + self.type = type + super.init(message: message) + } + + public override var errorDescription: String? { + if let description = super.errorDescription { + return description + } + + switch type { + case .browserRequired: + return "Browser required" + case .userNotFound: + return "User not found" + case .invalidUsername: + return "Invalid username" + case .generalError: + return "General error" + } + } +} + +@objc +public enum SignInStartErrorType: Int { + case browserRequired + case userNotFound + case invalidUsername + case generalError +} diff --git a/MSAL/src/native_auth/public/state_machine/error/SignUpPasswordStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignUpPasswordStartError.swift new file mode 100644 index 0000000000..acaac33130 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/error/SignUpPasswordStartError.swift @@ -0,0 +1,65 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class SignUpPasswordStartError: MSALNativeAuthError { + /// An error type indicating the type of error that occurred + @objc public let type: SignUpPasswordStartErrorType + + init(type: SignUpPasswordStartErrorType, message: String? = nil) { + self.type = type + super.init(message: message) + } + + public override var errorDescription: String? { + if let description = super.errorDescription { + return description + } + + switch type { + case .browserRequired: + return "Browser required" + case .userAlreadyExists: + return "User already exists" + case .invalidPassword: + return "Invalid password" + case .invalidUsername: + return "Invalid username" + case .generalError: + return "General error" + } + } + +} + +@objc +public enum SignUpPasswordStartErrorType: Int { + case browserRequired + case userAlreadyExists + case invalidPassword + case invalidUsername + case generalError +} diff --git a/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift new file mode 100644 index 0000000000..5eb4eb203d --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift @@ -0,0 +1,61 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class SignUpStartError: MSALNativeAuthError { + /// An error type indicating the type of error that occurred + @objc public let type: SignUpStartErrorType + + init(type: SignUpStartErrorType, message: String? = nil) { + self.type = type + super.init(message: message) + } + + public override var errorDescription: String? { + if let description = super.errorDescription { + return description + } + + switch type { + case .browserRequired: + return "Browser required" + case .userAlreadyExists: + return "User already exists" + case .invalidUsername: + return "Invalid username" + case .generalError: + return "General error" + } + } +} + +@objc +public enum SignUpStartErrorType: Int { + case browserRequired + case userAlreadyExists + case invalidUsername + case generalError +} diff --git a/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift b/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift new file mode 100644 index 0000000000..ae44d284b3 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift @@ -0,0 +1,58 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class VerifyCodeError: MSALNativeAuthError { + /// An error type indicating the type of error that occurred + @objc public let type: VerifyCodeErrorType + + init(type: VerifyCodeErrorType, message: String? = nil) { + self.type = type + super.init(message: message) + } + + public override var errorDescription: String? { + if let description = super.errorDescription { + return description + } + + switch type { + case .browserRequired: + return "Browser required" + case .generalError: + return "General error" + case .invalidCode: + return "Invalid code" + } + } +} + +@objc +public enum VerifyCodeErrorType: Int { + case browserRequired + case generalError + case invalidCode +} diff --git a/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift b/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift new file mode 100644 index 0000000000..e4e78023b6 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift @@ -0,0 +1,34 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class MSALNativeAuthBaseState: NSObject { + let flowToken: String + + init(flowToken: String) { + self.flowToken = flowToken + } +} diff --git a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift new file mode 100644 index 0000000000..5b0e9ad342 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift @@ -0,0 +1,58 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +extension ResetPasswordCodeRequiredState { + + func resendCodeInternal(correlationId: UUID?) async -> ResetPasswordResendCodeResult { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + return await controller.resendCode(passwordResetToken: flowToken, context: context) + } + + func submitCodeInternal(code: String, correlationId: UUID?) async -> ResetPasswordVerifyCodeResult { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + guard inputValidator.isInputValid(code) else { + MSALLogger.log(level: .error, context: context, format: "ResetPassword flow, invalid code") + return .error(error: VerifyCodeError(type: .invalidCode), newState: self) + } + + return await controller.submitCode(code: code, passwordResetToken: flowToken, context: context) + } +} + +extension ResetPasswordRequiredState { + + func submitPasswordInternal(password: String, correlationId: UUID?) async -> ResetPasswordRequiredResult { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + guard inputValidator.isInputValid(password) else { + MSALLogger.log(level: .error, context: context, format: "ResetPassword flow, invalid password") + return .error(error: PasswordRequiredError(type: .invalidPassword), newState: self) + } + + return await controller.submitPassword(password: password, passwordSubmitToken: flowToken, context: context) + } +} diff --git a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift new file mode 100644 index 0000000000..775f3996c7 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift @@ -0,0 +1,105 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objcMembers +public class ResetPasswordBaseState: MSALNativeAuthBaseState { + let controller: MSALNativeAuthResetPasswordControlling + let inputValidator: MSALNativeAuthInputValidating + + init( + controller: MSALNativeAuthResetPasswordControlling, + flowToken: String, + inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator() + ) { + self.controller = controller + self.inputValidator = inputValidator + super.init(flowToken: flowToken) + } +} + +/// An object of this type is created when a user is required to supply a verification code to continue a reset password flow. +@objcMembers public class ResetPasswordCodeRequiredState: ResetPasswordBaseState { + /// Requests the server to resend the verification code to the user. + /// - Parameters: + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the operation. + public func resendCode(correlationId: UUID? = nil, delegate: ResetPasswordResendCodeDelegate) { + Task { + let result = await resendCodeInternal(correlationId: correlationId) + + switch result { + case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): + await delegate.onResetPasswordResendCodeRequired( + newState: newState, + sentTo: sentTo, + channelTargetType: channelTargetType, + codeLength: codeLength + ) + case .error(let error, let newState): + await delegate.onResetPasswordResendCodeError(error: error, newState: newState) + } + } + } + + /// Submits the code to the server for verification. + /// - Parameters: + /// - code: Verification code that the user supplied. + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the operation. + public func submitCode(code: String, correlationId: UUID? = nil, delegate: ResetPasswordVerifyCodeDelegate) { + Task { + let result = await submitCodeInternal(code: code, correlationId: correlationId) + + switch result { + case .passwordRequired(let newState): + await delegate.onPasswordRequired(newState: newState) + case .error(let error, let newState): + await delegate.onResetPasswordVerifyCodeError(error: error, newState: newState) + } + } + } +} + +/// An object of this type is created when a user is required to supply a password to continue a reset password flow. +@objcMembers public class ResetPasswordRequiredState: ResetPasswordBaseState { + /// Submits the password to the server for verification. + /// - Parameters: + /// - password: Password that the user supplied. + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the operation. + public func submitPassword(password: String, correlationId: UUID? = nil, delegate: ResetPasswordRequiredDelegate) { + Task { + let result = await submitPasswordInternal(password: password, correlationId: correlationId) + + switch result { + case .completed: + await delegate.onResetPasswordCompleted() + case .error(let error, let newState): + await delegate.onResetPasswordRequiredError(error: error, newState: newState) + } + } + } +} diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift new file mode 100644 index 0000000000..920d110966 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift @@ -0,0 +1,33 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +extension SignInAfterSignUpState { + + func signInInternal(scopes: [String]?, correlationId: UUID?) async -> Result { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + return await controller.signIn(username: username, slt: slt, scopes: scopes, context: context) + } +} diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift new file mode 100644 index 0000000000..6a83a290c6 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift @@ -0,0 +1,61 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// An object of this type is created when a user has signed up successfully. +@objcMembers public class SignInAfterSignUpState: NSObject { + + let controller: MSALNativeAuthSignInControlling + let username: String + let slt: String? + + init(controller: MSALNativeAuthSignInControlling, username: String, slt: String?) { + self.username = username + self.slt = slt + self.controller = controller + } + + /// Sign in the user that signed up. + /// - Parameters: + /// - scopes: Optional. Permissions you want included in the access token received after sign in flow has completed. + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the Sign In flow. + public func signIn( + scopes: [String]? = nil, + correlationId: UUID? = nil, + delegate: SignInAfterSignUpDelegate + ) { + Task { + let controllerResult = await signInInternal(scopes: scopes, correlationId: correlationId) + + switch controllerResult { + case .success(let accountResult): + await delegate.onSignInCompleted(result: accountResult) + case .failure(let error): + await delegate.onSignInAfterSignUpError(error: error) + } + } + } +} diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift new file mode 100644 index 0000000000..9a3cfe47bb --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift @@ -0,0 +1,64 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +extension SignInCodeRequiredState { + + func submitCodeInternal(code: String, correlationId: UUID?) async -> SignInVerifyCodeResult { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + MSALLogger.log(level: .verbose, context: context, format: "SignIn flow, code submitted") + guard inputValidator.isInputValid(code) else { + MSALLogger.log(level: .error, context: context, format: "SignIn flow, invalid code") + return .error(error: VerifyCodeError(type: .invalidCode), newState: self) + } + + return await controller.submitCode(code, credentialToken: flowToken, context: context, scopes: scopes) + } + + func resendCodeInternal(correlationId: UUID?) async -> SignInResendCodeResult { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + MSALLogger.log(level: .verbose, context: context, format: "SignIn flow, resend code requested") + + return await controller.resendCode(credentialToken: flowToken, context: context, scopes: scopes) + } +} + +extension SignInPasswordRequiredState { + + func submitPasswordInternal( + password: String, + correlationId: UUID? + ) async -> SignInPasswordRequiredResult { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + MSALLogger.log(level: .info, context: context, format: "SignIn flow, password submitted") + + guard inputValidator.isInputValid(password) else { + MSALLogger.log(level: .error, context: context, format: "SignIn flow, invalid password") + return .error(error: PasswordRequiredError(type: .invalidPassword), newState: self) + } + + return await controller.submitPassword(password, username: username, credentialToken: flowToken, context: context, scopes: scopes) + } +} diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift b/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift new file mode 100644 index 0000000000..876c28fc80 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift @@ -0,0 +1,130 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objcMembers public class SignInBaseState: MSALNativeAuthBaseState { + let controller: MSALNativeAuthSignInControlling + let inputValidator: MSALNativeAuthInputValidating + + init( + controller: MSALNativeAuthSignInControlling, + inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator(), + flowToken: String) { + self.controller = controller + self.inputValidator = inputValidator + super.init(flowToken: flowToken) + } +} + +/// An object of this type is created when a user is required to supply a verification code to continue a sign in flow. +@objcMembers public class SignInCodeRequiredState: SignInBaseState { + + let scopes: [String] + + init( + scopes: [String], + controller: MSALNativeAuthSignInControlling, + inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator(), + flowToken: String) { + self.scopes = scopes + super.init(controller: controller, inputValidator: inputValidator, flowToken: flowToken) + } + + /// Requests the server to resend the verification code to the user. + /// - Parameters: + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the operation. + public func resendCode(correlationId: UUID? = nil, delegate: SignInResendCodeDelegate) { + Task { + let result = await resendCodeInternal(correlationId: correlationId) + + switch result { + case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): + await delegate.onSignInResendCodeCodeRequired( + newState: newState, + sentTo: sentTo, + channelTargetType: channelTargetType, + codeLength: codeLength + ) + case .error(let error, let newState): + await delegate.onSignInResendCodeError(error: error, newState: newState) + } + } + } + + /// Submits the code to the server for verification. + /// - Parameters: + /// - code: Verification code that the user supplies. + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the operation. + public func submitCode(code: String, correlationId: UUID? = nil, delegate: SignInVerifyCodeDelegate) { + Task { + let result = await submitCodeInternal(code: code, correlationId: correlationId) + + switch result { + case .completed(let accountResult): + await delegate.onSignInCompleted(result: accountResult) + case .error(let error, let newState): + await delegate.onSignInVerifyCodeError(error: error, newState: newState) + } + } + } +} + +/// An object of this type is created when a user is required to supply a password to continue a sign in flow. +@objcMembers public class SignInPasswordRequiredState: SignInBaseState { + + let scopes: [String] + let username: String + + init( + scopes: [String], + username: String, + controller: MSALNativeAuthSignInControlling, + inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator(), + flowToken: String) { + self.scopes = scopes + self.username = username + super.init(controller: controller, inputValidator: inputValidator, flowToken: flowToken) + } + + /// Submits the password to the server for verification. + /// - Parameters: + /// - password: Password that the user supplied. + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the operation. + public func submitPassword(password: String, correlationId: UUID? = nil, delegate: SignInPasswordRequiredDelegate) { + Task { + let result = await submitPasswordInternal(password: password, correlationId: correlationId) + + switch result { + case .completed(let accountResult): + await delegate.onSignInCompleted(result: accountResult) + case .error(let error, let newState): + await delegate.onSignInPasswordRequiredError(error: error, newState: newState) + } + } + } +} diff --git a/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift new file mode 100644 index 0000000000..0938e599b0 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift @@ -0,0 +1,69 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +extension SignUpCodeRequiredState { + + func resendCodeInternal(correlationId: UUID?) async -> SignUpResendCodeResult { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + return await controller.resendCode(username: username, context: context, signUpToken: flowToken) + } + + func submitCodeInternal(code: String, correlationId: UUID?) async -> MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + guard inputValidator.isInputValid(code) else { + MSALLogger.log(level: .error, context: context, format: "SignUp flow, invalid code") + return .init(.error(error: VerifyCodeError(type: .invalidCode), newState: self)) + } + + return await controller.submitCode(code, username: username, signUpToken: flowToken, context: context) + } +} + +extension SignUpPasswordRequiredState { + + func submitPasswordInternal( + password: String, + correlationId: UUID? + ) async -> MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + guard inputValidator.isInputValid(password) else { + MSALLogger.log(level: .error, context: context, format: "SignUp flow, invalid password") + return .init(.error(error: PasswordRequiredError(type: .invalidPassword), newState: self)) + } + + return await controller.submitPassword(password, username: username, signUpToken: flowToken, context: context) + } +} + +extension SignUpAttributesRequiredState { + + func submitAttributesInternal(attributes: [String: Any], correlationId: UUID?) async -> SignUpAttributesRequiredResult { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + return await controller.submitAttributes(attributes, username: username, signUpToken: flowToken, context: context) + } +} diff --git a/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift b/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift new file mode 100644 index 0000000000..b9823a1fd6 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift @@ -0,0 +1,165 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objcMembers +public class SignUpBaseState: MSALNativeAuthBaseState { + let controller: MSALNativeAuthSignUpControlling + let username: String + let inputValidator: MSALNativeAuthInputValidating + + init( + controller: MSALNativeAuthSignUpControlling, + username: String, + flowToken: String, + inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator() + ) { + self.controller = controller + self.username = username + self.inputValidator = inputValidator + super.init(flowToken: flowToken) + } +} + +/// An object of this type is created when a user is required to supply a verification code to continue a sign up flow. +@objcMembers public class SignUpCodeRequiredState: SignUpBaseState { + /// Requests the server to resend the verification code to the user. + /// - Parameters: + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the operation. + public func resendCode(correlationId: UUID? = nil, delegate: SignUpResendCodeDelegate) { + Task { + let result = await resendCodeInternal(correlationId: correlationId) + + switch result { + case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): + await delegate.onSignUpResendCodeCodeRequired( + newState: newState, + sentTo: sentTo, + channelTargetType: channelTargetType, + codeLength: codeLength + ) + case .error(let error): + await delegate.onSignUpResendCodeError(error: error) + } + } + } + + /// Submits the code to the server for verification. + /// - Parameters: + /// - code: Verification code that the user supplies. + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the operation. + public func submitCode(code: String, correlationId: UUID? = nil, delegate: SignUpVerifyCodeDelegate) { + Task { + let controllerResponse = await submitCodeInternal(code: code, correlationId: correlationId) + + switch controllerResponse.result { + case .completed(let state): + await delegate.onSignUpCompleted(newState: state) + case .passwordRequired(let state): + if let function = delegate.onSignUpPasswordRequired { + controllerResponse.telemetryUpdate?(.success(())) + await function(state) + } else { + let error = VerifyCodeError(type: .generalError, message: MSALNativeAuthErrorMessage.delegateNotImplemented) + controllerResponse.telemetryUpdate?(.failure(error)) + await delegate.onSignUpVerifyCodeError(error: error, newState: nil) + } + case .attributesRequired(let attributes, let state): + if let function = delegate.onSignUpAttributesRequired { + controllerResponse.telemetryUpdate?(.success(())) + await function(attributes, state) + } else { + let error = VerifyCodeError(type: .generalError, message: MSALNativeAuthErrorMessage.delegateNotImplemented) + controllerResponse.telemetryUpdate?(.failure(error)) + await delegate.onSignUpVerifyCodeError(error: error, newState: nil) + } + case .error(let error, let state): + await delegate.onSignUpVerifyCodeError(error: error, newState: state) + } + } + } +} + +/// An object of this type is created when a user is required to supply a password to continue a sign up flow. +@objcMembers public class SignUpPasswordRequiredState: SignUpBaseState { + + /// Submits the password to the server for verification. + /// - Parameters: + /// - password: Password that the user supplied. + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + /// - delegate: Delegate that receives callbacks for the operation. + public func submitPassword(password: String, correlationId: UUID? = nil, delegate: SignUpPasswordRequiredDelegate) { + Task { + let controllerResponse = await submitPasswordInternal(password: password, correlationId: correlationId) + + switch controllerResponse.result { + case .completed(let state): + await delegate.onSignUpCompleted(newState: state) + case .attributesRequired(let attributes, let state): + if let function = delegate.onSignUpAttributesRequired { + controllerResponse.telemetryUpdate?(.success(())) + await function(attributes, state) + } else { + let error = PasswordRequiredError(type: .generalError, message: MSALNativeAuthErrorMessage.delegateNotImplemented) + controllerResponse.telemetryUpdate?(.failure(error)) + await delegate.onSignUpPasswordRequiredError(error: error, newState: nil) + } + case .error(let error, let state): + await delegate.onSignUpPasswordRequiredError(error: error, newState: state) + } + } + } +} + +/// An object of this type is created when a user is required to supply attributes to continue a sign up flow. +@objcMembers public class SignUpAttributesRequiredState: SignUpBaseState { + /// Submits the attributes to the server for verification. + /// - Parameters: + /// - attributes: Dictionary of attributes that the user supplied. + /// - delegate: Delegate that receives callbacks for the operation. + /// - correlationId: Optional. UUID to correlate this request with the server for debugging. + public func submitAttributes( + attributes: [String: Any], + delegate: SignUpAttributesRequiredDelegate, + correlationId: UUID? = nil + ) { + Task { + let result = await submitAttributesInternal(attributes: attributes, correlationId: correlationId) + + switch result { + case .completed(let state): + await delegate.onSignUpCompleted(newState: state) + case .error(let error): + await delegate.onSignUpAttributesRequiredError(error: error) + case .attributesRequired(let attributes, let state): + await delegate.onSignUpAttributesRequired(attributes: attributes, newState: state) + case .attributesInvalid(let attributes, let state): + await delegate.onSignUpAttributesInvalid(attributeNames: attributes, newState: state) + } + } + } +} diff --git a/MSAL/src/native_auth/telemetry/MSALNativeAuthCurrentRequestTelemetry.swift b/MSAL/src/native_auth/telemetry/MSALNativeAuthCurrentRequestTelemetry.swift new file mode 100644 index 0000000000..d8d430ae58 --- /dev/null +++ b/MSAL/src/native_auth/telemetry/MSALNativeAuthCurrentRequestTelemetry.swift @@ -0,0 +1,59 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthCurrentRequestTelemetry: NSObject, MSIDTelemetryStringSerializable { + let apiId: MSALNativeAuthTelemetryApiId + let operationType: MSALNativeAuthOperationType + private let schemaVersion: Int + private let platformFields: [String]? + + init(apiId: MSALNativeAuthTelemetryApiId, + operationType: MSALNativeAuthOperationType, + platformFields: [String]?) { + self.schemaVersion = HTTP_REQUEST_TELEMETRY_SCHEMA_VERSION + self.apiId = apiId + self.operationType = operationType + self.platformFields = platformFields + } + + func telemetryString() -> String { + return serializeCurrentTelemetryString() + } + + private func serializeCurrentTelemetryString() -> String { + let currentTelemetryFields = createSerializedItem() + return currentTelemetryFields.serialize() ?? "" + } + + private func createSerializedItem() -> MSIDCurrentRequestTelemetrySerializedItem { + let defaultFields: [NSNumber] = [.init(value: apiId.rawValue), + .init(value: operationType)] + return .init(schemaVersion: .init(value: schemaVersion), + defaultFields: defaultFields, + platformFields: platformFields) + } +} diff --git a/MSAL/src/native_auth/telemetry/MSALNativeAuthOperationTypes.swift b/MSAL/src/native_auth/telemetry/MSALNativeAuthOperationTypes.swift new file mode 100644 index 0000000000..0a4e8d9ce4 --- /dev/null +++ b/MSAL/src/native_auth/telemetry/MSALNativeAuthOperationTypes.swift @@ -0,0 +1,78 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +@_implementationOnly import MSAL_Private + +typealias MSALNativeAuthOperationType = Int + +enum MSALNativeAuthSignUpType: MSALNativeAuthOperationType { + case signUpWithPassword = 0 + case signUpWithOTP = 1 + case signUpWithMFA = 2 + case signUpStart = 3 + case signUpChallenge = 4 + case signUpContinue = 5 +} + +enum MSALNativeAuthSignInType: MSALNativeAuthOperationType { + case signInWithOTP = 0 + case signInWithMFA = 1 + case signInInitiate = 2 + case signInChallenge = 3 +} + +enum MSALNativeAuthTokenType: MSALNativeAuthOperationType { + case signInWithPassword = 0 + case refreshToken = 1 + +} +enum MSALNAtiveAuthResetPasswordType: MSALNativeAuthOperationType { + case resetPasswordStart = 0 + case resetPasswordChallenge = 1 + case resetPasswordContinue = 2 + case resetPasswordSubmit = 3 + case resetPasswordPollCompletion = 4 +} + +enum MSALNativeAuthResetPasswordStartType: MSALNativeAuthOperationType { + case resetPasswordStart = 0 +} + +enum MSALNativeAuthResetPasswordCompleteType: MSALNativeAuthOperationType { + case resetPasswordComplete = 0 +} + +enum MSALNativeAuthResendCodeType: MSALNativeAuthOperationType { + case resendCode = 0 +} + +enum MSALNativeAuthVerifyCodeType: MSALNativeAuthOperationType { + case verifyCode = 0 +} + +enum MSALNativeAuthSignOutType: MSALNativeAuthOperationType { + case signOutAction = 0 + case signOutForced = 1 +} diff --git a/MSAL/src/native_auth/telemetry/MSALNativeAuthServerTelemetry.swift b/MSAL/src/native_auth/telemetry/MSALNativeAuthServerTelemetry.swift new file mode 100644 index 0000000000..7c2cea330f --- /dev/null +++ b/MSAL/src/native_auth/telemetry/MSALNativeAuthServerTelemetry.swift @@ -0,0 +1,67 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +@_implementationOnly import MSAL_Private + +class MSALNativeAuthServerTelemetry: NSObject, MSIDHttpRequestServerTelemetryHandling { + + let currentRequestTelemetry: MSALNativeAuthCurrentRequestTelemetry + let context: MSIDRequestContext + private let lastRequestTelemetry: MSIDLastRequestTelemetry + init(currentRequestTelemetry: MSALNativeAuthCurrentRequestTelemetry, + context: MSIDRequestContext) { + self.currentRequestTelemetry = currentRequestTelemetry + self.context = context + self.lastRequestTelemetry = MSIDLastRequestTelemetry.sharedInstance() + } + + func handleError(_ error: Error?, context: MSIDRequestContext) { + guard let error = error else { return } + let errorString = (error as NSError).msidServerTelemetryErrorString() + handleError(error, errorString: errorString, context: context) + } + + func handleError(_ error: Error?, errorString: String, context: MSIDRequestContext) { + lastRequestTelemetry.update(withApiId: currentRequestTelemetry.apiId.rawValue, + errorString: errorString, + context: context) + } + + func setTelemetryToRequest(_ request: MSIDHttpRequestProtocol) { + + let currentRequestTelemetryString = currentRequestTelemetry.telemetryString() + let lastRequestTelemetryString = lastRequestTelemetry.telemetryString() + + guard let mutableUrlRequest = (request.urlRequest as NSURLRequest).mutableCopy() as? NSMutableURLRequest else { + MSALLogger.log(level: .error, + context: context, + format: "Mutable copy of request could not be made for telemetry") + return + } + mutableUrlRequest.setValue(currentRequestTelemetryString, forHTTPHeaderField: "x-client-current-telemetry") + mutableUrlRequest.setValue(lastRequestTelemetryString, forHTTPHeaderField: "x-client-last-telemetry") + request.urlRequest = mutableUrlRequest as URLRequest + } +} diff --git a/MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryApiId.swift b/MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryApiId.swift new file mode 100644 index 0000000000..57b1aa78ca --- /dev/null +++ b/MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryApiId.swift @@ -0,0 +1,57 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthTelemetryApiId: Int { + // TODO: Resolve the below comment about the correct definitions of these constants: + // Until we know exactly how to define them, + // to prevent any clashes with existing id's + // a number that is unlikely to be used has been added + case telemetryApiIdSignUp = 75001 + case telemetryApiIdToken = 75002 + case telemetryApiIdRefreshToken = 75003 + case telemetryApiIdResendCode = 75006 + case telemetryApiIdVerifyCode = 75007 + case telemetryApiIdSignOut = 75008 + case telemetryApiIdResetPassword = 75009 + case telemetryApiIdSignInWithPasswordStart = 74001 + case telemetryApiIdSignInWithCodeStart = 74002 + case telemetryApiIdSignInAfterSignUp = 740014 + case telemetryApiIdSignInSubmitCode = 74003 + case telemetryApiIdSignInResendCode = 74004 + case telemetryApiIdSignInSubmitPassword = 74005 + case telemetryApiIdResetPasswordStart = 74011 + case telemetryApiIdResetPasswordResendCode = 74012 + case telemetryApiIdResetPasswordSubmitCode = 74013 + case telemetryApiIdResetPasswordSubmit = 75028 + case telemetryApiIdSignUpPasswordStart = 75019 + case telemetryApiIdSignUpPasswordChallenge = 75015 + case telemetryApiIdSignUpCodeStart = 75010 + case telemetryApiIdSignUpResendCode = 75011 + case telemetryApiIdSignUpSubmitCode = 75012 + case telemetryApiIdSignUpSubmitPassword = 75013 + case telemetryApiIdSignUpSubmitAttributes = 75014 + +} diff --git a/MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryProvider.swift b/MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryProvider.swift new file mode 100644 index 0000000000..e24929bf46 --- /dev/null +++ b/MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryProvider.swift @@ -0,0 +1,108 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +protocol MSALNativeAuthTelemetryProviding { + func telemetryForSignUp( + type: MSALNativeAuthSignUpType) -> MSALNativeAuthCurrentRequestTelemetry + func telemetryForSignIn( + type: MSALNativeAuthSignInType) -> MSALNativeAuthCurrentRequestTelemetry + func telemetryForToken( + type: MSALNativeAuthTokenType) -> MSALNativeAuthCurrentRequestTelemetry + func telemetryForResetPassword( + type: MSALNAtiveAuthResetPasswordType) -> MSALNativeAuthCurrentRequestTelemetry + func telemetryForResetPasswordStart( + type: MSALNativeAuthResetPasswordStartType) -> MSALNativeAuthCurrentRequestTelemetry + func telemetryForResendCode( + type: MSALNativeAuthResendCodeType) -> MSALNativeAuthCurrentRequestTelemetry + func telemetryForVerifyCode( + type: MSALNativeAuthVerifyCodeType) -> MSALNativeAuthCurrentRequestTelemetry + func telemetryForSignOut( + type: MSALNativeAuthSignOutType) -> MSALNativeAuthCurrentRequestTelemetry +} + +class MSALNativeAuthTelemetryProvider: MSALNativeAuthTelemetryProviding { + func telemetryForSignUp( + type: MSALNativeAuthSignUpType) -> MSALNativeAuthCurrentRequestTelemetry { + return MSALNativeAuthCurrentRequestTelemetry( + apiId: .telemetryApiIdSignUpCodeStart, + operationType: type.rawValue, + platformFields: nil) + } + + func telemetryForSignIn( + type: MSALNativeAuthSignInType) -> MSALNativeAuthCurrentRequestTelemetry { + return MSALNativeAuthCurrentRequestTelemetry( + apiId: .telemetryApiIdSignInWithCodeStart, + operationType: type.rawValue, + platformFields: nil) + } + + func telemetryForToken( + type: MSALNativeAuthTokenType) -> MSALNativeAuthCurrentRequestTelemetry { + return MSALNativeAuthCurrentRequestTelemetry( + apiId: .telemetryApiIdToken, + operationType: type.rawValue, + platformFields: nil) + } + + func telemetryForResetPassword(type: MSALNAtiveAuthResetPasswordType) -> MSALNativeAuthCurrentRequestTelemetry { + return MSALNativeAuthCurrentRequestTelemetry( + apiId: .telemetryApiIdResetPassword, + operationType: type.rawValue, + platformFields: nil) + } + + func telemetryForResetPasswordStart( + type: MSALNativeAuthResetPasswordStartType) -> MSALNativeAuthCurrentRequestTelemetry { + return MSALNativeAuthCurrentRequestTelemetry( + apiId: .telemetryApiIdResetPasswordStart, + operationType: type.rawValue, + platformFields: nil) + } + + func telemetryForResendCode( + type: MSALNativeAuthResendCodeType) -> MSALNativeAuthCurrentRequestTelemetry { + return MSALNativeAuthCurrentRequestTelemetry( + apiId: .telemetryApiIdResendCode, + operationType: type.rawValue, + platformFields: nil) + } + + func telemetryForVerifyCode( + type: MSALNativeAuthVerifyCodeType) -> MSALNativeAuthCurrentRequestTelemetry { + return MSALNativeAuthCurrentRequestTelemetry( + apiId: .telemetryApiIdVerifyCode, + operationType: type.rawValue, + platformFields: nil) + } + + func telemetryForSignOut( + type: MSALNativeAuthSignOutType) -> MSALNativeAuthCurrentRequestTelemetry { + return MSALNativeAuthCurrentRequestTelemetry( + apiId: .telemetryApiIdSignOut, + operationType: type.rawValue, + platformFields: nil) + } +} diff --git a/MSAL/src/native_auth/validation/MSALNativeAuthAuthorityProvider.swift b/MSAL/src/native_auth/validation/MSALNativeAuthAuthorityProvider.swift new file mode 100644 index 0000000000..692da5c0a3 --- /dev/null +++ b/MSAL/src/native_auth/validation/MSALNativeAuthAuthorityProvider.swift @@ -0,0 +1,42 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthAuthorityProviding { + func authority(rawTenant: String) throws -> MSALCIAMAuthority +} + +final class MSALNativeAuthAuthorityProvider: MSALNativeAuthAuthorityProviding { + + func authority(rawTenant: String) throws -> MSALCIAMAuthority { + let ciamUrlString = "https://\(rawTenant).ciamlogin.com" + guard let url = URL(string: ciamUrlString) else { + assert(false, "URL for default CIAM Authority must be valid") + throw MSALNativeAuthInternalError.invalidAuthority + } + + return try MSALCIAMAuthority(url: url) + } +} diff --git a/MSAL/src/public/MSAL.h b/MSAL/src/public/MSAL.h index abb924a56a..72ba322336 100644 --- a/MSAL/src/public/MSAL.h +++ b/MSAL/src/public/MSAL.h @@ -80,6 +80,7 @@ FOUNDATION_EXPORT const unsigned char MSAL__Framework_VersionString[]; #import #import #if TARGET_OS_IPHONE +#import #import #endif #import diff --git a/MSAL/test/integration/native_auth/MockAPIHandlerTest.swift b/MSAL/test/integration/native_auth/MockAPIHandlerTest.swift new file mode 100644 index 0000000000..d28fced0f2 --- /dev/null +++ b/MSAL/test/integration/native_auth/MockAPIHandlerTest.swift @@ -0,0 +1,45 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest + +final class MockAPIHandlerTest: MSALNativeAuthIntegrationBaseTests { + + func testAddNewResponse() async { + do { + try await mockAPIHandler.addResponse(endpoint: .signInInitiate, correlationId: correlationId, responses: [.invalidClient, .userNotFound]) + } catch { + XCTFail("Unexpected error: \(error)") + } + } + + func testGetAllConfig() async { + do { + print(try await mockAPIHandler.getAllConfig()) + } catch { + XCTFail("Unexpected error: \(error)") + } + } + +} diff --git a/MSAL/test/integration/native_auth/common/MSALNativeAuthIntegrationBaseTests.swift b/MSAL/test/integration/native_auth/common/MSALNativeAuthIntegrationBaseTests.swift new file mode 100644 index 0000000000..55e8b33469 --- /dev/null +++ b/MSAL/test/integration/native_auth/common/MSALNativeAuthIntegrationBaseTests.swift @@ -0,0 +1,127 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthIntegrationBaseTests: XCTestCase { + + var defaultTimeout: TimeInterval = 5 + let mockAPIHandler = MockAPIHandler() + let correlationId = UUID() + let config: MSALNativeAuthConfiguration = try! MSALNativeAuthConfiguration(clientId: UUID().uuidString, + authority: MSALCIAMAuthority(url: URL(string: (ProcessInfo.processInfo.environment["mockAPIURL"] ?? "") + "/test")!), + challengeTypes: [.password, .oob, .redirect]) + var sut: MSIDHttpRequest! + + override func tearDown() { + try? mockAPIHandler.clearQueues(correlationId: correlationId) + } + + // MARK: - Utility methods + + func performTestSucceed() async throws -> T { + return try await withCheckedThrowingContinuation { continuation in + let exp = expectation(description: "msal_native_auth_integration_test_exp") + + sut.send { response, error in + guard error == nil else { + XCTFail("Error should be nil") + continuation.resume(throwing: MockAPIError.invalidRequest) + return + } + + guard let response = response as? T else { + XCTFail("Response should be castable to `T`") + continuation.resume(throwing: MockAPIError.invalidRequest) + return + } + + continuation.resume(returning: response) + exp.fulfill() + } + + wait(for: [exp], timeout: defaultTimeout) + } + } + + @discardableResult + func perform_testFail( + endpoint: MockAPIEndpoint, + response: MockAPIResponse, + expectedError: Error + ) async throws -> Error { + try await mockResponse(response, endpoint: endpoint) + let response: Error = try await perform_uncheckedTestFail() + + XCTAssertEqual(response.error.rawValue, expectedError.error.rawValue) + + // TODO: Fix these checks + if expectedError.errorDescription != nil { + XCTAssertNotNil(response.errorDescription) + } + if expectedError.errorCodes != nil { + XCTAssertEqual(response.errorCodes, expectedError.errorCodes) + } + + if expectedError.errorURI != nil { + XCTAssertNotNil(response.errorURI) + } + return response + } + + func mockResponse(_ response: MockAPIResponse, endpoint: MockAPIEndpoint) async throws { + try await mockAPIHandler.addResponse( + endpoint: endpoint, + correlationId: correlationId, + responses: [response] + ) + } + + func perform_uncheckedTestFail() async throws -> T { + return try await withCheckedThrowingContinuation { continuation in + let exp = expectation(description: "msal_native_auth_integration_test_exp") + + sut.send { response, error in + guard response == nil else { + XCTFail("Response should be nil") + continuation.resume(throwing: MockAPIError.invalidRequest) + return + } + + guard let error = error as? T else { + XCTFail("Error should be MSALNativeAuthResponseError") + continuation.resume(throwing: MockAPIError.invalidRequest) + return + } + + continuation.resume(returning: error) + exp.fulfill() + } + + wait(for: [exp], timeout: defaultTimeout) + } + } +} diff --git a/MSAL/test/integration/native_auth/common/MockAPIHandler.swift b/MSAL/test/integration/native_auth/common/MockAPIHandler.swift new file mode 100644 index 0000000000..d40301784a --- /dev/null +++ b/MSAL/test/integration/native_auth/common/MockAPIHandler.swift @@ -0,0 +1,80 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest + +class MockAPIHandler { + + private let baseURL = (ProcessInfo.processInfo.environment["mockAPIURL"] ?? "") + "/config/" + + func clearQueues(correlationId: UUID) throws { + guard let url = URL(string: baseURL + "all") else { + XCTFail("Invalid Delete URL") + throw MockAPIError.invalidURL + } + guard let body = try? JSONEncoder().encode(ClearQueueRequestBody(correlationId: correlationId)) else { + XCTFail("Invalid Request") + throw MockAPIError.invalidRequest + } + Task { + try await performHTTPCall(url: url, body: body, httpMethod: "DELETE") + } + } + + func getAllConfig() async throws -> [String: Any] { + guard let url = URL(string: baseURL + "all") else { + XCTFail("Invalid get all config URL") + throw MockAPIError.invalidURL + } + let result = try await performHTTPCall(url: url) + return try JSONSerialization.jsonObject(with: result, options: []) as? [String: Any] ?? [:] + } + + func addResponse(endpoint: MockAPIEndpoint, correlationId: UUID, responses: [MockAPIResponse]) async throws { + guard let url = URL(string: baseURL + "response") else { + XCTFail("Invalid add response URL") + throw MockAPIError.invalidURL + } + guard let body = try? JSONEncoder().encode( + AddResponsesRequestBody(endpoint: endpoint.rawValue, responseList: responses.map({$0.rawValue}), correlationId: correlationId) + ) else { + XCTFail("Invalid Request") + throw MockAPIError.invalidRequest + } + _ = try await performHTTPCall(url: url, body: body, httpMethod: "POST") + } + + private func performHTTPCall(url: URL, body: Data? = nil, httpMethod: String = "GET") async throws -> Data { + var request = URLRequest(url: url) + request.httpBody = body + request.httpMethod = httpMethod + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + let (data, response) = try await URLSession.shared.data(for: request) + + guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { + throw MockAPIError.invalidServerResponse + } + return data + } +} diff --git a/MSAL/test/integration/native_auth/common/Model.swift b/MSAL/test/integration/native_auth/common/Model.swift new file mode 100644 index 0000000000..822c709cc5 --- /dev/null +++ b/MSAL/test/integration/native_auth/common/Model.swift @@ -0,0 +1,103 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MockAPIError: Error { + case invalidServerResponse + case invalidURL + case invalidRequest +} + +enum MockAPIEndpoint: String { + case signInInitiate = "SignInInitiate" + case signInChallenge = "SignInChallenge" + case signInToken = "SignInToken" + case signUpStart = "SignUpStart" + case signUpChallenge = "SignUpChallenge" + case signUpContinue = "SignUpContinue" + case resetPasswordStart = "SSPRStart" + case resetPasswordChallenge = "SSPRChallenge" + case resetPasswordContinue = "SSPRContinue" + case resetPasswordSubmit = "SSPRSubmit" + case resetPasswordPollCompletion = "SSPRPoll" +} + +enum MockAPIResponse: String { + case invalidRequest = "InvalidRequest" + case invalidToken = "InvalidToken" + case invalidClient = "InvalidClient" + case invalidGrant = "InvalidGrant" + case invalidScope = "InvalidScope" + case expiredToken = "ExpiredToken" + case invalidPurposeToken = "InvalidPurposeToken" + case unsupportedAuthMethod = "UnsupportedAuthMethod" + case userAlreadyExists = "UserAlreadyExists" + case userNotFound = "UserNotFound" + case explicityUserNotFound = "ExplicityUserNotFound" + case slowDown = "SlowDown" + case invalidPassword = "InvalidPassword" + case invalidOOBValue = "InvalidOOBValue" + case passwordTooWeak = "PasswordTooWeak" + case passwordTooShort = "PasswordTooShort" + case passwordTooLong = "PasswordTooLong" + case passwordRecentlyUsed = "PasswordRecentlyUsed" + case passwordBanned = "PasswordBanned" + case authorizationPending = "AuthorizationPending" + case challengeTypePassword = "ChallengeTypePassword" + case challengeTypeOOB = "ChallengeTypeOOB" + case unsupportedChallengeType = "UnsupportedChallengeType" + case challengeTypeRedirect = "ChallengeTypeRedirect" + case credentialRequired = "CredentialRequired" + case initiateSuccess = "InitiateSuccess" + case tokenSuccess = "TokenSuccess" + case attributesRequired = "AttributesRequired" + case invalidAttributes = "InvalidAttributes" + case verificationRequired = "VerificationRequired" + case attributeValidationFailed = "AttributeValidationFailed" + case invalidSignUpToken = "InvalidSignupToken" + case explicitInvalidOOBValue = "ExplicitInvalidOOBValue" + case invalidPasswordResetToken = "InvalidPasswordResetToken" + case ssprStartSuccess = "SSPRStartSuccess" + case ssprContinueSuccess = "SSPRContinueSuccess" + case ssprSubmitSuccess = "SSPRSubmitSuccess" + case ssprPollSuccess = "SSPRPollSuccess" + case ssprPollInProgress = "SSPRPollInProgress" + case ssprPollFailed = "SSPRPollFailed" + case ssprPollNotStarted = "SSPRPollNotStarted" + case signUpContinueSuccess = "SignUpContinueSuccess" + case invalidUsername = "InvalidUsername" +} + +// MARK: request body + +struct ClearQueueRequestBody: Encodable { + var correlationId: UUID +} + +struct AddResponsesRequestBody: Encodable { + var endpoint: String + var responseList: [String] + var correlationId: UUID +} diff --git a/MSAL/test/integration/native_auth/end_to_end/MSALNativeAuthEndToEndBaseTestCase.swift b/MSAL/test/integration/native_auth/end_to_end/MSALNativeAuthEndToEndBaseTestCase.swift new file mode 100644 index 0000000000..e38db0189f --- /dev/null +++ b/MSAL/test/integration/native_auth/end_to_end/MSALNativeAuthEndToEndBaseTestCase.swift @@ -0,0 +1,77 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +import MSAL + +class MSALNativeAuthEndToEndBaseTestCase: XCTestCase { + let mockAPIHandler = MockAPIHandler() + let correlationId = UUID() + var defaultTimeout: TimeInterval = 5 + + var sut: MSALNativeAuthPublicClientApplication! + var usingMockAPI = false + + class Configuration: NSObject { + static let clientId = ProcessInfo.processInfo.environment["clientId"] ?? "" + static let authorityURLString = ProcessInfo.processInfo.environment["authorityURL"] ?? "" + static let authorityURL = URL(string: authorityURLString) ?? URL(string: "https://microsoft.com") + + static let authority = try? MSALCIAMAuthority(url: authorityURL!) + } + + func mockResponse(_ response: MockAPIResponse, endpoint: MockAPIEndpoint) async throws { + try await mockAPIHandler.addResponse( + endpoint: endpoint, + correlationId: correlationId, + responses: [response] + ) + } + + override func tearDown() { + try? mockAPIHandler.clearQueues(correlationId: correlationId) + } + + override func setUpWithError() throws { + try super.setUpWithError() + + sut = try MSALNativeAuthPublicClientApplication( + configuration: MSALPublicClientApplicationConfig( + clientId: Configuration.clientId, + redirectUri: nil, + authority: Configuration.authority + ), + challengeTypes: [.OOB, .password] + ) + + let useMockAPIBooleanString = ProcessInfo.processInfo.environment["useMockAPI"] ?? "false" + usingMockAPI = Bool(useMockAPIBooleanString) ?? false + + if usingMockAPI { + print("🤖🤖🤖 Using mock API: \(Configuration.authorityURLString)") + } else { + print("👩‍💻👩‍💻👩‍💻 Using test tenant: \(Configuration.authorityURLString)") + } + } +} diff --git a/MSAL/test/integration/native_auth/end_to_end/reset_password/MSALNativeAuthResetPasswordEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/reset_password/MSALNativeAuthResetPasswordEndToEndTests.swift new file mode 100644 index 0000000000..b93e1dd47f --- /dev/null +++ b/MSAL/test/integration/native_auth/end_to_end/reset_password/MSALNativeAuthResetPasswordEndToEndTests.swift @@ -0,0 +1,82 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +import XCTest + +final class MSALNativeAuthResetPasswordEndToEndTests: MSALNativeAuthEndToEndBaseTestCase { + + private let usernameOTP = ProcessInfo.processInfo.environment["existingOTPUserEmail"] ?? "" + + override func setUpWithError() throws { + try super.setUpWithError() + try XCTSkipIf(!usingMockAPI) + } + + // Hero Scenario 2.3.1. SSPR – without automatic sign in + func test_resetPassword_withoutAutomaticSignIn_succeeds() async throws { + let codeRequiredExp = expectation(description: "code required") + let resetPasswordStartDelegate = ResetPasswordStartDelegateSpy(expectation: codeRequiredExp) + + if usingMockAPI { + try await mockResponse(.ssprStartSuccess, endpoint: .resetPasswordStart) + } + + sut.resetPassword(username: usernameOTP, delegate: resetPasswordStartDelegate) + + await fulfillment(of: [codeRequiredExp], timeout: defaultTimeout) + XCTAssertTrue(resetPasswordStartDelegate.onResetPasswordCodeRequiredCalled) + XCTAssertEqual(resetPasswordStartDelegate.channelTargetType, .email) + XCTAssertFalse(resetPasswordStartDelegate.sentTo?.isEmpty ?? true) + XCTAssertNotNil(resetPasswordStartDelegate.codeLength) + + // Now submit the code... + + let passwordRequiredExp = expectation(description: "password required") + let resetPasswordVerifyDelegate = ResetPasswordVerifyCodeDelegateSpy(expectation: passwordRequiredExp) + + if usingMockAPI { + try await mockResponse(.ssprContinueSuccess, endpoint: .resetPasswordContinue) + } + + resetPasswordStartDelegate.newState?.submitCode(code: "1234", delegate: resetPasswordVerifyDelegate) + + await fulfillment(of: [passwordRequiredExp], timeout: defaultTimeout) + XCTAssertTrue(resetPasswordVerifyDelegate.onPasswordRequiredCalled) + + // Now submit the password... + let resetPasswordCompletedExp = expectation(description: "reset password completed") + let resetPasswordRequiredDelegate = ResetPasswordRequiredDelegateSpy(expectation: resetPasswordCompletedExp) + + if usingMockAPI { + try await mockResponse(.ssprSubmitSuccess, endpoint: .resetPasswordSubmit) + } + + resetPasswordVerifyDelegate.newPasswordRequiredState?.submitPassword(password: "password", delegate: resetPasswordRequiredDelegate) + + await fulfillment(of: [resetPasswordCompletedExp], timeout: defaultTimeout) + XCTAssertTrue(resetPasswordRequiredDelegate.onResetPasswordCompletedCalled) + } + +} diff --git a/MSAL/test/integration/native_auth/end_to_end/reset_password/ResetPasswordDelegateSpies.swift b/MSAL/test/integration/native_auth/end_to_end/reset_password/ResetPasswordDelegateSpies.swift new file mode 100644 index 0000000000..37827a1e7b --- /dev/null +++ b/MSAL/test/integration/native_auth/end_to_end/reset_password/ResetPasswordDelegateSpies.swift @@ -0,0 +1,119 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +import XCTest +import MSAL + +class ResetPasswordStartDelegateSpy: ResetPasswordStartDelegate { + private let expectation: XCTestExpectation + private(set) var onResetPasswordErrorCalled = false + private(set) var onResetPasswordCodeRequiredCalled = false + private(set) var error: MSAL.ResetPasswordStartError? + private(set) var newState: MSAL.ResetPasswordCodeRequiredState? + private(set) var sentTo: String? + private(set) var channelTargetType: MSAL.MSALNativeAuthChannelType? + private(set) var codeLength: Int? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onResetPasswordError(error: MSAL.ResetPasswordStartError) { + onResetPasswordErrorCalled = true + self.error = error + + expectation.fulfill() + } + + func onResetPasswordCodeRequired( + newState: MSAL.ResetPasswordCodeRequiredState, + sentTo: String, + channelTargetType: MSAL.MSALNativeAuthChannelType, + codeLength: Int + ) { + onResetPasswordCodeRequiredCalled = true + self.newState = newState + self.sentTo = sentTo + self.channelTargetType = channelTargetType + self.codeLength = codeLength + + expectation.fulfill() + } +} + +class ResetPasswordVerifyCodeDelegateSpy: ResetPasswordVerifyCodeDelegate { + private let expectation: XCTestExpectation + private(set) var onResetPasswordVerifyCodeErrorCalled = false + private(set) var onPasswordRequiredCalled = false + private(set) var error: MSAL.VerifyCodeError? + private(set) var newCodeRequiredState: MSAL.ResetPasswordCodeRequiredState? + private(set) var newPasswordRequiredState: MSAL.ResetPasswordRequiredState? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onResetPasswordVerifyCodeError(error: MSAL.VerifyCodeError, newState: MSAL.ResetPasswordCodeRequiredState?) { + onResetPasswordVerifyCodeErrorCalled = true + self.error = error + newCodeRequiredState = newState + + expectation.fulfill() + } + + func onPasswordRequired(newState: MSAL.ResetPasswordRequiredState) { + onPasswordRequiredCalled = true + newPasswordRequiredState = newState + + expectation.fulfill() + } +} + +class ResetPasswordRequiredDelegateSpy: ResetPasswordRequiredDelegate { + private let expectation: XCTestExpectation + private(set) var onResetPasswordRequiredErrorCalled = false + private(set) var onResetPasswordCompletedCalled = false + private(set) var error: MSAL.PasswordRequiredError? + private(set) var newPasswordRequiredState: MSAL.ResetPasswordRequiredState? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onResetPasswordRequiredError(error: MSAL.PasswordRequiredError, newState: MSAL.ResetPasswordRequiredState?) { + onResetPasswordRequiredErrorCalled = true + + self.error = error + newPasswordRequiredState = newState + + expectation.fulfill() + } + + func onResetPasswordCompleted() { + onResetPasswordCompletedCalled = true + + expectation.fulfill() + } +} diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUserNameAndPasswordEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUserNameAndPasswordEndToEndTests.swift new file mode 100644 index 0000000000..a6f531f581 --- /dev/null +++ b/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUserNameAndPasswordEndToEndTests.swift @@ -0,0 +1,97 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +import XCTest + +final class MSALNativeAuthSignInUsernameAndPasswordEndToEndTests: MSALNativeAuthEndToEndBaseTestCase { + func test_signInUsingPasswordWithUnknownUsernameResultsInError() async throws { + try XCTSkipIf(!usingMockAPI) + + let signInExpectation = expectation(description: "signing in") + let signInDelegateSpy = SignInPasswordStartDelegateSpy(expectation: signInExpectation) + + let unknownUsername = UUID().uuidString + + if usingMockAPI { + try await mockResponse(.initiateSuccess, endpoint: .signInInitiate) + try await mockResponse(.challengeTypePassword, endpoint: .signInChallenge) + try await mockResponse(.userNotFound, endpoint: .signInToken) + } + + sut.signInUsingPassword(username: unknownUsername, password: "testpass", correlationId: correlationId, delegate: signInDelegateSpy) + + await fulfillment(of: [signInExpectation], timeout: 2) + + XCTAssertTrue(signInDelegateSpy.onSignInPasswordErrorCalled) + XCTAssertEqual(signInDelegateSpy.error?.type, .userNotFound) + } + + func test_signInWithKnownUsernameInvalidPasswordResultsInError() async throws { + try XCTSkipIf(!usingMockAPI) + + let signInExpectation = expectation(description: "signing in") + let signInDelegateSpy = SignInPasswordStartDelegateSpy(expectation: signInExpectation) + + let username = ProcessInfo.processInfo.environment["existingPasswordUserEmail"] ?? "" + + if usingMockAPI { + try await mockResponse(.initiateSuccess, endpoint: .signInInitiate) + try await mockResponse(.challengeTypePassword, endpoint: .signInChallenge) + try await mockResponse(.invalidPassword, endpoint: .signInToken) + } + + sut.signInUsingPassword(username: username, password: "An Invalid Password", correlationId: correlationId, delegate: signInDelegateSpy) + + await fulfillment(of: [signInExpectation], timeout: 2) + + XCTAssertTrue(signInDelegateSpy.onSignInPasswordErrorCalled) + XCTAssertEqual(signInDelegateSpy.error?.type, .invalidPassword) + } + + // Hero Scenario 2.2.1. Sign in – Email and Password on SINGLE screen (Email & Password) + func test_signInUsingPasswordWithKnownUsernameResultsInSuccess() async throws { + try XCTSkipIf(!usingMockAPI) + + let signInExpectation = expectation(description: "signing in") + let signInDelegateSpy = SignInPasswordStartDelegateSpy(expectation: signInExpectation) + + let username = ProcessInfo.processInfo.environment["existingPasswordUserEmail"] ?? "" + let password = ProcessInfo.processInfo.environment["existingUserPassword"] ?? "" + + if usingMockAPI { + try await mockResponse(.initiateSuccess, endpoint: .signInInitiate) + try await mockResponse(.challengeTypePassword, endpoint: .signInChallenge) + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } + + sut.signInUsingPassword(username: username, password: password, correlationId: correlationId, delegate: signInDelegateSpy) + + await fulfillment(of: [signInExpectation], timeout: 2) + + XCTAssertTrue(signInDelegateSpy.onSignInCompletedCalled) + XCTAssertNotNil(signInDelegateSpy.result?.idToken) + XCTAssertEqual(signInDelegateSpy.result?.account.username, username) + } +} diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUsernameEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUsernameEndToEndTests.swift new file mode 100644 index 0000000000..f6a0581918 --- /dev/null +++ b/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUsernameEndToEndTests.swift @@ -0,0 +1,248 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +import XCTest + +final class MSALNativeAuthSignInUsernameEndToEndTests: MSALNativeAuthEndToEndBaseTestCase { + func test_signInWithUnknownUsernameResultsInError() async throws { + try XCTSkipIf(!usingMockAPI) + + let signInExpectation = expectation(description: "signing in") + let signInDelegateSpy = SignInStartDelegateSpy(expectation: signInExpectation) + + let unknownUsername = UUID().uuidString + + if usingMockAPI { + try await mockResponse(.userNotFound, endpoint: .signInInitiate) + } + + sut.signIn(username: unknownUsername, correlationId: correlationId, delegate: signInDelegateSpy) + + await fulfillment(of: [signInExpectation], timeout: 2) + + XCTAssertTrue(signInDelegateSpy.onSignInErrorCalled) + XCTAssertEqual(signInDelegateSpy.error?.type, .userNotFound) + } + + func test_signInWithKnownUsernameResultsInOTPSent() async throws { + try XCTSkipIf(!usingMockAPI) + + let signInExpectation = expectation(description: "signing in") + let signInDelegateSpy = SignInStartDelegateSpy(expectation: signInExpectation) + + let username = ProcessInfo.processInfo.environment["existingOTPUserEmail"] ?? "" + + if usingMockAPI { + try await mockResponse(.initiateSuccess, endpoint: .signInInitiate) + try await mockResponse(.challengeTypeOOB, endpoint: .signInChallenge) + } + + sut.signIn(username: username, correlationId: correlationId, delegate: signInDelegateSpy) + + await fulfillment(of: [signInExpectation], timeout: 2) + + XCTAssertTrue(signInDelegateSpy.onSignInCodeRequiredCalled) + XCTAssertNotNil(signInDelegateSpy.newStateCodeRequired) + XCTAssertNotNil(signInDelegateSpy.sentTo) + } + + func test_signInAndSendingIncorrectOTPResultsInError() async throws { + try XCTSkipIf(!usingMockAPI) + + let signInExpectation = expectation(description: "signing in") + let verifyCodeExpectation = expectation(description: "verifying code") + let signInDelegateSpy = SignInStartDelegateSpy(expectation: signInExpectation) + let signInVerifyCodeDelegateSpy = SignInVerifyCodeDelegateSpy(expectation: verifyCodeExpectation) + + let username = ProcessInfo.processInfo.environment["existingOTPUserEmail"] ?? "" + + if usingMockAPI { + try await mockResponse(.initiateSuccess, endpoint: .signInInitiate) + try await mockResponse(.challengeTypeOOB, endpoint: .signInChallenge) + } + + sut.signIn(username: username, correlationId: correlationId, delegate: signInDelegateSpy) + + await fulfillment(of: [signInExpectation], timeout: 2) + + XCTAssertTrue(signInDelegateSpy.onSignInCodeRequiredCalled) + XCTAssertNotNil(signInDelegateSpy.newStateCodeRequired) + XCTAssertNotNil(signInDelegateSpy.sentTo) + + // Now submit the code.. + + if usingMockAPI { + try await mockResponse(.invalidOOBValue, endpoint: .signInToken) + } + + signInDelegateSpy.newStateCodeRequired?.submitCode(code: "badc0d3", correlationId: correlationId, delegate: signInVerifyCodeDelegateSpy) + + await fulfillment(of: [verifyCodeExpectation], timeout: 2) + + XCTAssertTrue(signInVerifyCodeDelegateSpy.onSignInVerifyCodeErrorCalled) + XCTAssertNotNil(signInVerifyCodeDelegateSpy.error) + XCTAssertEqual(signInVerifyCodeDelegateSpy.error?.type, .invalidCode) + } + + // Hero Scenario 1.2.1. Sign in (Email & Email OTP) + func test_signInAndSendingCorrectOTPResultsInSuccess() async throws { + try XCTSkipIf(!usingMockAPI) + + let signInExpectation = expectation(description: "signing in") + let verifyCodeExpectation = expectation(description: "verifying code") + let signInDelegateSpy = SignInStartDelegateSpy(expectation: signInExpectation) + let signInVerifyCodeDelegateSpy = SignInVerifyCodeDelegateSpy(expectation: verifyCodeExpectation) + + let username = ProcessInfo.processInfo.environment["existingOTPUserEmail"] ?? "" + let otp = "" + + if usingMockAPI { + try await mockResponse(.initiateSuccess, endpoint: .signInInitiate) + try await mockResponse(.challengeTypeOOB, endpoint: .signInChallenge) + } + + sut.signIn(username: username, correlationId: correlationId, delegate: signInDelegateSpy) + + await fulfillment(of: [signInExpectation], timeout: 2) + + XCTAssertTrue(signInDelegateSpy.onSignInCodeRequiredCalled) + XCTAssertNotNil(signInDelegateSpy.newStateCodeRequired) + XCTAssertNotNil(signInDelegateSpy.sentTo) + + // Now submit the code.. + + if usingMockAPI { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } else { + // TODO: Replace this with retrieving the OTP from email + XCTAssertNotEqual(otp, "") + } + + signInDelegateSpy.newStateCodeRequired?.submitCode(code: otp, correlationId: correlationId, delegate: signInVerifyCodeDelegateSpy) + + await fulfillment(of: [verifyCodeExpectation], timeout: 2) + + XCTAssertTrue(signInVerifyCodeDelegateSpy.onSignInCompletedCalled) + XCTAssertNotNil(signInVerifyCodeDelegateSpy.result) + XCTAssertNotNil(signInVerifyCodeDelegateSpy.result?.idToken) + XCTAssertEqual(signInVerifyCodeDelegateSpy.result?.account.username, username) + } + + func test_signInWithKnownPasswordUsernameResultsInPasswordSent() async throws { + try XCTSkipIf(!usingMockAPI) + + let signInExpectation = expectation(description: "signing in") + let signInDelegateSpy = SignInStartDelegateSpy(expectation: signInExpectation) + + let username = ProcessInfo.processInfo.environment["existingPasswordUserEmail"] ?? "" + + if usingMockAPI { + try await mockResponse(.initiateSuccess, endpoint: .signInInitiate) + try await mockResponse(.challengeTypePassword, endpoint: .signInChallenge) + } + + sut.signIn(username: username, correlationId: correlationId, delegate: signInDelegateSpy) + + await fulfillment(of: [signInExpectation], timeout: 2) + + XCTAssertTrue(signInDelegateSpy.onSignInPasswordRequiredCalled) + XCTAssertNotNil(signInDelegateSpy.newStatePasswordRequired) + } + + func test_signInAndSendingIncorrectPasswordResultsInError() async throws { + try XCTSkipIf(!usingMockAPI) + + let signInExpectation = expectation(description: "signing in") + let passwordRequiredExpectation = expectation(description: "verifying password") + let signInDelegateSpy = SignInStartDelegateSpy(expectation: signInExpectation) + let signInPasswordRequiredDelegateSpy = SignInPasswordRequiredDelegateSpy(expectation: passwordRequiredExpectation) + + let username = ProcessInfo.processInfo.environment["existingPasswordUserEmail"] ?? "" + + if usingMockAPI { + try await mockResponse(.initiateSuccess, endpoint: .signInInitiate) + try await mockResponse(.challengeTypePassword, endpoint: .signInChallenge) + } + + sut.signIn(username: username, correlationId: correlationId, delegate: signInDelegateSpy) + + await fulfillment(of: [signInExpectation], timeout: 2) + + XCTAssertTrue(signInDelegateSpy.onSignInPasswordRequiredCalled) + XCTAssertNotNil(signInDelegateSpy.newStatePasswordRequired) + + // Now submit the password.. + + if usingMockAPI { + try await mockResponse(.invalidPassword, endpoint: .signInToken) + } + + signInDelegateSpy.newStatePasswordRequired?.submitPassword(password: "An Invalid Password", correlationId: correlationId, delegate: signInPasswordRequiredDelegateSpy) + + await fulfillment(of: [passwordRequiredExpectation], timeout: 2) + + XCTAssertTrue(signInPasswordRequiredDelegateSpy.onSignInPasswordRequiredErrorCalled) + XCTAssertEqual(signInPasswordRequiredDelegateSpy.error?.type, .invalidPassword) + } + + // Hero Scenario 2.2.2. Sign in – Email and Password on MULTIPLE screens (Email & Password) + func test_signInAndSendingCorrectPasswordResultsInSuccess() async throws { + try XCTSkipIf(!usingMockAPI) + + let signInExpectation = expectation(description: "signing in") + let passwordRequiredExpectation = expectation(description: "verifying password") + let signInDelegateSpy = SignInStartDelegateSpy(expectation: signInExpectation) + let signInPasswordRequiredDelegateSpy = SignInPasswordRequiredDelegateSpy(expectation: passwordRequiredExpectation) + + let username = ProcessInfo.processInfo.environment["existingPasswordUserEmail"] ?? "" + let password = ProcessInfo.processInfo.environment["existingUserPassword"] ?? "" + + if usingMockAPI { + try await mockResponse(.initiateSuccess, endpoint: .signInInitiate) + try await mockResponse(.challengeTypePassword, endpoint: .signInChallenge) + } + + sut.signIn(username: username, correlationId: correlationId, delegate: signInDelegateSpy) + + await fulfillment(of: [signInExpectation], timeout: 2) + + XCTAssertTrue(signInDelegateSpy.onSignInPasswordRequiredCalled) + XCTAssertNotNil(signInDelegateSpy.newStatePasswordRequired) + + // Now submit the password.. + + if usingMockAPI { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } + + signInDelegateSpy.newStatePasswordRequired?.submitPassword(password: password, correlationId: correlationId, delegate: signInPasswordRequiredDelegateSpy) + + await fulfillment(of: [passwordRequiredExpectation], timeout: 2) + + XCTAssertTrue(signInPasswordRequiredDelegateSpy.onSignInCompletedCalled) + XCTAssertNotNil(signInPasswordRequiredDelegateSpy.result?.idToken) + XCTAssertEqual(signInPasswordRequiredDelegateSpy.result?.account.username, username) + } +} diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_in/SignInDelegateSpies.swift b/MSAL/test/integration/native_auth/end_to_end/sign_in/SignInDelegateSpies.swift new file mode 100644 index 0000000000..a3e6174e88 --- /dev/null +++ b/MSAL/test/integration/native_auth/end_to_end/sign_in/SignInDelegateSpies.swift @@ -0,0 +1,152 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +import XCTest +import MSAL + +class SignInPasswordStartDelegateSpy: SignInPasswordStartDelegate { + private let expectation: XCTestExpectation + private(set) var onSignInPasswordErrorCalled = false + private(set) var onSignInCompletedCalled = false + private(set) var error: MSAL.SignInPasswordStartError? + private(set) var result: MSAL.MSALNativeAuthUserAccountResult? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + public func onSignInPasswordError(error: MSAL.SignInPasswordStartError) { + onSignInPasswordErrorCalled = true + self.error = error + + expectation.fulfill() + } + + public func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) { + onSignInCompletedCalled = true + self.result = result + + expectation.fulfill() + } +} + +class SignInStartDelegateSpy: SignInStartDelegate { + private let expectation: XCTestExpectation + + private(set) var onSignInErrorCalled = false + private(set) var error: MSAL.SignInStartError? + + private(set) var onSignInCodeRequiredCalled = false + private(set) var newStateCodeRequired: MSAL.SignInCodeRequiredState? + private(set) var sentTo: String? + private(set) var channelTargetType: MSAL.MSALNativeAuthChannelType? + private(set) var codeLength: Int? + + private(set) var onSignInPasswordRequiredCalled = false + private(set) var newStatePasswordRequired: MSAL.SignInPasswordRequiredState? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + public func onSignInError(error: MSAL.SignInStartError) { + onSignInErrorCalled = true + self.error = error + + expectation.fulfill() + } + + public func onSignInCodeRequired(newState: MSAL.SignInCodeRequiredState, sentTo: String, channelTargetType: MSAL.MSALNativeAuthChannelType, codeLength: Int) { + onSignInCodeRequiredCalled = true + self.newStateCodeRequired = newState + self.sentTo = sentTo + self.channelTargetType = channelTargetType + self.codeLength = codeLength + + expectation.fulfill() + } + + public func onSignInPasswordRequired(newState: SignInPasswordRequiredState) { + onSignInPasswordRequiredCalled = true + self.newStatePasswordRequired = newState + + expectation.fulfill() + } +} + +class SignInVerifyCodeDelegateSpy: SignInVerifyCodeDelegate { + private let expectation: XCTestExpectation + + private(set) var onSignInVerifyCodeErrorCalled = false + private(set) var error: MSAL.VerifyCodeError? + + private(set) var onSignInCompletedCalled = false + private(set) var result: MSAL.MSALNativeAuthUserAccountResult? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + public func onSignInVerifyCodeError(error: MSAL.VerifyCodeError, newState: MSAL.SignInCodeRequiredState?) { + onSignInVerifyCodeErrorCalled = true + self.error = error + + expectation.fulfill() + } + + public func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) { + onSignInCompletedCalled = true + self.result = result + + expectation.fulfill() + } +} + +class SignInPasswordRequiredDelegateSpy: SignInPasswordRequiredDelegate { + private let expectation: XCTestExpectation + private(set) var onSignInPasswordRequiredErrorCalled = false + private(set) var onSignInCompletedCalled = false + private(set) var error: MSAL.PasswordRequiredError? + private(set) var result: MSAL.MSALNativeAuthUserAccountResult? + private(set) var newState: MSAL.SignInPasswordRequiredState? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + func onSignInPasswordRequiredError(error: MSAL.PasswordRequiredError, newState: MSAL.SignInPasswordRequiredState?) { + onSignInPasswordRequiredErrorCalled = true + self.error = error + self.newState = newState + + expectation.fulfill() + } + + func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) { + onSignInCompletedCalled = true + self.result = result + + expectation.fulfill() + } +} diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_out/MSALNativeAuthSignOutEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_out/MSALNativeAuthSignOutEndToEndTests.swift new file mode 100644 index 0000000000..e3404152f9 --- /dev/null +++ b/MSAL/test/integration/native_auth/end_to_end/sign_out/MSALNativeAuthSignOutEndToEndTests.swift @@ -0,0 +1,194 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +import XCTest + +final class MSALNativeAuthSignOutEndToEndTests: MSALNativeAuthEndToEndBaseTestCase { + func test_noSignOutAfterSignInOTPAccountStillPresent() async throws { + try XCTSkipIf(!usingMockAPI) + + let signInExpectation = expectation(description: "signing in") + let verifyCodeExpectation = expectation(description: "verifying code") + let signInDelegateSpy = SignInStartDelegateSpy(expectation: signInExpectation) + let signInVerifyCodeDelegateSpy = SignInVerifyCodeDelegateSpy(expectation: verifyCodeExpectation) + + let username = ProcessInfo.processInfo.environment["existingOTPUserEmail"] ?? "" + let otp = "" + + if usingMockAPI { + try await mockResponse(.initiateSuccess, endpoint: .signInInitiate) + try await mockResponse(.challengeTypeOOB, endpoint: .signInChallenge) + } + + sut.signIn(username: username, correlationId: correlationId, delegate: signInDelegateSpy) + + await fulfillment(of: [signInExpectation], timeout: defaultTimeout) + + XCTAssertTrue(signInDelegateSpy.onSignInCodeRequiredCalled) + XCTAssertNotNil(signInDelegateSpy.newStateCodeRequired) + XCTAssertNotNil(signInDelegateSpy.sentTo) + + // Now submit the code.. + + if usingMockAPI { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } else { + // TODO: Replace this with retrieving the OTP from email + XCTAssertNotEqual(otp, "") + } + + signInDelegateSpy.newStateCodeRequired?.submitCode(code: otp, correlationId: correlationId, delegate: signInVerifyCodeDelegateSpy) + + await fulfillment(of: [verifyCodeExpectation], timeout: defaultTimeout) + + XCTAssertTrue(signInVerifyCodeDelegateSpy.onSignInCompletedCalled) + XCTAssertNotNil(signInVerifyCodeDelegateSpy.result) + XCTAssertNotNil(signInVerifyCodeDelegateSpy.result?.idToken) + XCTAssertEqual(signInVerifyCodeDelegateSpy.result?.account.username, username) + + // Check Account Exists + + let userAccountResult = sut.getNativeAuthUserAccount() + XCTAssertNotNil(userAccountResult) + XCTAssertEqual(userAccountResult?.account.username, username) + } + + // Hero Scenario 1.3.1. Sign out – Local sign out from app on device (no SSO) + + func test_signOutAfterSignInOTPSuccess() async throws { + try XCTSkipIf(!usingMockAPI) + + let signInExpectation = expectation(description: "signing in") + let verifyCodeExpectation = expectation(description: "verifying code") + let signInDelegateSpy = SignInStartDelegateSpy(expectation: signInExpectation) + let signInVerifyCodeDelegateSpy = SignInVerifyCodeDelegateSpy(expectation: verifyCodeExpectation) + + let username = ProcessInfo.processInfo.environment["existingOTPUserEmail"] ?? "" + let otp = "" + + if usingMockAPI { + try await mockResponse(.initiateSuccess, endpoint: .signInInitiate) + try await mockResponse(.challengeTypeOOB, endpoint: .signInChallenge) + } + + sut.signIn(username: username, correlationId: correlationId, delegate: signInDelegateSpy) + + await fulfillment(of: [signInExpectation], timeout: defaultTimeout) + + XCTAssertTrue(signInDelegateSpy.onSignInCodeRequiredCalled) + XCTAssertNotNil(signInDelegateSpy.newStateCodeRequired) + XCTAssertNotNil(signInDelegateSpy.sentTo) + + // Now submit the code.. + + if usingMockAPI { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } else { + // TODO: Replace this with retrieving the OTP from email + XCTAssertNotEqual(otp, "") + } + + signInDelegateSpy.newStateCodeRequired?.submitCode(code: otp, correlationId: correlationId, delegate: signInVerifyCodeDelegateSpy) + + await fulfillment(of: [verifyCodeExpectation], timeout: defaultTimeout) + + XCTAssertTrue(signInVerifyCodeDelegateSpy.onSignInCompletedCalled) + XCTAssertNotNil(signInVerifyCodeDelegateSpy.result) + XCTAssertNotNil(signInVerifyCodeDelegateSpy.result?.idToken) + XCTAssertEqual(signInVerifyCodeDelegateSpy.result?.account.username, username) + + // Sign out + + var userAccountResult = sut.getNativeAuthUserAccount() + userAccountResult?.signOut() + + userAccountResult = sut.getNativeAuthUserAccount() + XCTAssertNil(userAccountResult) + } + + func test_noSignOutAfterSignInPasswordAccountStillPresent() async throws { + try XCTSkipIf(!usingMockAPI) + + let signInExpectation = expectation(description: "signing in") + let signInDelegateSpy = SignInPasswordStartDelegateSpy(expectation: signInExpectation) + + let username = ProcessInfo.processInfo.environment["existingPasswordUserEmail"] ?? "" + let password = ProcessInfo.processInfo.environment["existingUserPassword"] ?? "" + + if usingMockAPI { + try await mockResponse(.initiateSuccess, endpoint: .signInInitiate) + try await mockResponse(.challengeTypePassword, endpoint: .signInChallenge) + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } + + sut.signInUsingPassword(username: username, password: password, correlationId: correlationId, delegate: signInDelegateSpy) + + await fulfillment(of: [signInExpectation], timeout: defaultTimeout) + + XCTAssertTrue(signInDelegateSpy.onSignInCompletedCalled) + XCTAssertNotNil(signInDelegateSpy.result?.idToken) + XCTAssertEqual(signInDelegateSpy.result?.account.username, username) + + // Check Account Exists + + let userAccountResult = sut.getNativeAuthUserAccount() + XCTAssertNotNil(userAccountResult) + XCTAssertEqual(userAccountResult?.account.username, username) + } + + // Hero Scenario 2.4.1. Sign out – Local sign out from app on device (no SSO) + + func test_signOutAfterSignInPasswordSuccess() async throws { + try XCTSkipIf(!usingMockAPI) + + let signInExpectation = expectation(description: "signing in") + let signInDelegateSpy = SignInPasswordStartDelegateSpy(expectation: signInExpectation) + + let username = ProcessInfo.processInfo.environment["existingPasswordUserEmail"] ?? "" + let password = ProcessInfo.processInfo.environment["existingUserPassword"] ?? "" + + if usingMockAPI { + try await mockResponse(.initiateSuccess, endpoint: .signInInitiate) + try await mockResponse(.challengeTypePassword, endpoint: .signInChallenge) + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } + + sut.signInUsingPassword(username: username, password: password, correlationId: correlationId, delegate: signInDelegateSpy) + + await fulfillment(of: [signInExpectation], timeout: defaultTimeout) + + XCTAssertTrue(signInDelegateSpy.onSignInCompletedCalled) + XCTAssertNotNil(signInDelegateSpy.result?.idToken) + XCTAssertEqual(signInDelegateSpy.result?.account.username, username) + + // Sign out + + var userAccountResult = sut.getNativeAuthUserAccount() + userAccountResult?.signOut() + + userAccountResult = sut.getNativeAuthUserAccount() + XCTAssertNil(userAccountResult) + } +} diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift new file mode 100644 index 0000000000..06b9cb5474 --- /dev/null +++ b/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift @@ -0,0 +1,445 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +import MSAL + +final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuthEndToEndBaseTestCase { + private let usernamePassword = ProcessInfo.processInfo.environment["existingPasswordUserEmail"] ?? "" + private let password = ProcessInfo.processInfo.environment["existingUserPassword"] ?? "" + private let attributes = ["age": 40] + + override func setUpWithError() throws { + try super.setUpWithError() + try XCTSkipIf(!usingMockAPI) + } + + // Hero Scenario 2.1.1. Sign up - with Email verification as LAST step (Email & Password) + func test_signUpWithPassword_withEmailVerificationLastStep_succeeds() async throws { + let codeRequiredExp = expectation(description: "code required") + let signUpStartDelegate = SignUpPasswordStartDelegateSpy(expectation: codeRequiredExp) + + if usingMockAPI { + try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) + } + + sut.signUpUsingPassword( + username: usernamePassword, + password: password, + correlationId: correlationId, + delegate: signUpStartDelegate + ) + + await fulfillment(of: [codeRequiredExp], timeout: defaultTimeout) + checkSignUpStartDelegate(signUpStartDelegate) + + // Now submit the code... + + let signUpCompleteExp = expectation(description: "sign-up complete") + let signUpVerifyCodeDelegate = SignUpVerifyCodeDelegateSpy(expectation: signUpCompleteExp) + + if usingMockAPI { + try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) + } + + signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + + await fulfillment(of: [signUpCompleteExp], timeout: defaultTimeout) + XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpCompletedCalled) + + // Now sign in... + + let signInExp = expectation(description: "sign-in after sign-up") + let signInAfterSignUpDelegate = SignInAfterSignUpDelegateSpy(expectation: signInExp) + + if usingMockAPI { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } + + signUpVerifyCodeDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + + await fulfillment(of: [signInExp], timeout: defaultTimeout) + checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) + } + + // Hero Scenario 2.1.2. Sign up - with Email verification as LAST step & Custom Attributes (Email & Password) + func test_signUpWithPassword_withEmailVerificationAsLastStepAndCustomAttributes_succeeds() async throws { + let codeRequiredExp = expectation(description: "code required") + let signUpStartDelegate = SignUpPasswordStartDelegateSpy(expectation: codeRequiredExp) + + if usingMockAPI { + try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) + } + + sut.signUpUsingPassword( + username: usernamePassword, + password: "1234", + attributes: attributes, + correlationId: correlationId, + delegate: signUpStartDelegate + ) + + await fulfillment(of: [codeRequiredExp], timeout: defaultTimeout) + checkSignUpStartDelegate(signUpStartDelegate) + + // Now submit the code... + + let signUpCompleteExp = expectation(description: "sign-up complete") + let signUpVerifyCodeDelegate = SignUpVerifyCodeDelegateSpy(expectation: signUpCompleteExp) + + if usingMockAPI { + try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) + } + + signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + + await fulfillment(of: [signUpCompleteExp], timeout: defaultTimeout) + XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpCompletedCalled) + + // Now sign in... + + let signInExp = expectation(description: "sign-in after sign-up") + let signInAfterSignUpDelegate = SignInAfterSignUpDelegateSpy(expectation: signInExp) + + if usingMockAPI { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } + + signUpVerifyCodeDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + + await fulfillment(of: [signInExp], timeout: defaultTimeout) + checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) + } + + // Hero Scenario 2.1.3. Sign up - with Email verification as FIRST step (Email & Password) + func test_signUpWithPassword_withEmailVerificationAsFirstStep_succeeds() async throws { + let codeRequiredExp = expectation(description: "code required") + let signUpStartDelegate = SignUpPasswordStartDelegateSpy(expectation: codeRequiredExp) + + if usingMockAPI { + try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) + } + + sut.signUpUsingPassword( + username: usernamePassword, + password: password, + correlationId: correlationId, + delegate: signUpStartDelegate + ) + + await fulfillment(of: [codeRequiredExp], timeout: defaultTimeout) + checkSignUpStartDelegate(signUpStartDelegate) + + // Now submit the code... + + let credentialRequiredExp = expectation(description: "credential required") + let signUpVerifyCodeDelegate = SignUpVerifyCodeDelegateSpy(expectation: credentialRequiredExp) + + if usingMockAPI { + try await mockResponse(.credentialRequired, endpoint: .signUpContinue) + try await mockResponse(.challengeTypePassword, endpoint: .signUpChallenge) + } + + signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + + await fulfillment(of: [credentialRequiredExp], timeout: defaultTimeout) + XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpPasswordRequiredCalled) + + // Now submit the password... + + let attributesRequiredExp = expectation(description: "attributes required") + let signUpPasswordDelegate = SignUpPasswordRequiredDelegateSpy(expectation: attributesRequiredExp) + + if usingMockAPI { + try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) + } + + signUpVerifyCodeDelegate.passwordRequiredState?.submitPassword( + password: "1234", + correlationId: correlationId, + delegate: signUpPasswordDelegate + ) + + await fulfillment(of: [attributesRequiredExp], timeout: defaultTimeout) + XCTAssertTrue(signUpPasswordDelegate.onSignUpCompletedCalled) + + // Now sign in... + + let signInExp = expectation(description: "sign-in after sign-up") + let signInAfterSignUpDelegate = SignInAfterSignUpDelegateSpy(expectation: signInExp) + + if usingMockAPI { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } + + signUpPasswordDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + + await fulfillment(of: [signInExp], timeout: defaultTimeout) + checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) + } + + // Hero Scenario 2.1.4. Sign up - with Email verification as FIRST step & Custom Attribute (Email & Password) + func test_signUpWithPasswordWithEmailVerificationAsFirstStepAndCustomAttributes_succeeds() async throws { + let codeRequiredExp = expectation(description: "code required") + let signUpStartDelegate = SignUpPasswordStartDelegateSpy(expectation: codeRequiredExp) + + if usingMockAPI { + try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) + } + + sut.signUpUsingPassword( + username: usernamePassword, + password: password, + correlationId: correlationId, + delegate: signUpStartDelegate + ) + + await fulfillment(of: [codeRequiredExp], timeout: defaultTimeout) + checkSignUpStartDelegate(signUpStartDelegate) + + // Now submit the code... + + let submitCodeExp = expectation(description: "submit code, credential required") + let signUpVerifyCodeDelegate = SignUpVerifyCodeDelegateSpy(expectation: submitCodeExp) + + if usingMockAPI { + try await mockResponse(.credentialRequired, endpoint: .signUpContinue) + try await mockResponse(.challengeTypePassword, endpoint: .signUpChallenge) + } + + signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + + await fulfillment(of: [submitCodeExp], timeout: defaultTimeout) + XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpPasswordRequiredCalled) + + // Now submit the password... + + let passwordRequiredExp = expectation(description: "password required") + let signUpPasswordDelegate = SignUpPasswordRequiredDelegateSpy(expectation: passwordRequiredExp) + + if usingMockAPI { + try await mockResponse(.attributesRequired, endpoint: .signUpContinue) + } + + signUpVerifyCodeDelegate.passwordRequiredState?.submitPassword( + password: "1234", + correlationId: correlationId, + delegate: signUpPasswordDelegate + ) + + await fulfillment(of: [passwordRequiredExp], timeout: defaultTimeout) + XCTAssertTrue(signUpPasswordDelegate.onSignUpAttributesRequiredCalled) + + // Now submit the attributes... + + let attributesRequiredExp = expectation(description: "attributes required, sign-up complete") + let signUpAttributesRequiredDelegate = SignUpAttributesRequiredDelegateSpy(expectation: attributesRequiredExp) + + if usingMockAPI { + try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) + } + + signUpPasswordDelegate.attributesRequiredState?.submitAttributes( + attributes: attributes, + delegate: signUpAttributesRequiredDelegate, + correlationId: correlationId + ) + + await fulfillment(of: [attributesRequiredExp], timeout: defaultTimeout) + XCTAssertTrue(signUpAttributesRequiredDelegate.onSignUpCompletedCalled) + + // Now sign in... + + let signInExp = expectation(description: "sign-in after sign-up") + let signInAfterSignUpDelegate = SignInAfterSignUpDelegateSpy(expectation: signInExp) + + if usingMockAPI { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } + + signUpAttributesRequiredDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + + await fulfillment(of: [signInExp], timeout: defaultTimeout) + checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) + } + + // Hero Scenario 2.1.5. Sign up - with Email verification as FIRST step & Custom Attributes over MULTIPLE screens (Email & Password) + func test_signUpWithPasswordWithEmailVerificationAsFirstStepAndCustomAttributesOverMultipleScreens_succeeds() async throws { + let codeRequiredExp = expectation(description: "code required") + let signUpStartDelegate = SignUpPasswordStartDelegateSpy(expectation: codeRequiredExp) + + if usingMockAPI { + try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) + } + + sut.signUpUsingPassword( + username: usernamePassword, + password: password, + correlationId: correlationId, + delegate: signUpStartDelegate + ) + + await fulfillment(of: [codeRequiredExp], timeout: defaultTimeout) + checkSignUpStartDelegate(signUpStartDelegate) + + // Now submit the code... + + let submitCodeExp = expectation(description: "submit code, credential required") + let signUpVerifyCodeDelegate = SignUpVerifyCodeDelegateSpy(expectation: submitCodeExp) + + if usingMockAPI { + try await mockResponse(.credentialRequired, endpoint: .signUpContinue) + try await mockResponse(.challengeTypePassword, endpoint: .signUpChallenge) + } + + signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + + await fulfillment(of: [submitCodeExp], timeout: defaultTimeout) + XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpPasswordRequiredCalled) + + // Now submit the password... + + let attributesRequiredExp1 = expectation(description: "attributes required 1") + let signUpPasswordDelegate = SignUpPasswordRequiredDelegateSpy(expectation: attributesRequiredExp1) + + if usingMockAPI { + try await mockResponse(.attributesRequired, endpoint: .signUpContinue) + } + + signUpVerifyCodeDelegate.passwordRequiredState?.submitPassword( + password: "1234", + correlationId: correlationId, + delegate: signUpPasswordDelegate + ) + + await fulfillment(of: [attributesRequiredExp1], timeout: defaultTimeout) + XCTAssertTrue(signUpPasswordDelegate.onSignUpAttributesRequiredCalled) + + // Now submit the attributes... + + let attributesRequiredExp2 = expectation(description: "attributes required 2, sign-up complete") + let signUpAttributesRequiredDelegate = SignUpAttributesRequiredDelegateSpy(expectation: attributesRequiredExp2) + + if usingMockAPI { + try await mockResponse(.attributesRequired, endpoint: .signUpContinue) + } + + signUpPasswordDelegate.attributesRequiredState?.submitAttributes( + attributes: attributes, + delegate: signUpAttributesRequiredDelegate, + correlationId: correlationId + ) + + await fulfillment(of: [attributesRequiredExp2], timeout: defaultTimeout) + XCTAssertTrue(signUpAttributesRequiredDelegate.onSignUpAttributesRequiredErrorCalled) + + // Now submit more attributes... + + let signUpCompleteExp = expectation(description: "sign-up complete") + signUpAttributesRequiredDelegate.expectation = signUpCompleteExp + + if usingMockAPI { + try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) + } + + signUpAttributesRequiredDelegate.attributesRequiredState?.submitAttributes( + attributes: attributes, + delegate: signUpAttributesRequiredDelegate, + correlationId: correlationId + ) + + await fulfillment(of: [signUpCompleteExp], timeout: defaultTimeout) + XCTAssertTrue(signUpAttributesRequiredDelegate.onSignUpCompletedCalled) + + // Now sign in... + + let signInExp = expectation(description: "sign-in after sign-up") + let signInAfterSignUpDelegate = SignInAfterSignUpDelegateSpy(expectation: signInExp) + + if usingMockAPI { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } + + signUpAttributesRequiredDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + + await fulfillment(of: [signInExp], timeout: defaultTimeout) + checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) + } + + // Hero Scenario 2.1.6. Sign up – without automatic sign in (Email & Password) + func test_signUpWithPasswordWithoutAutomaticSignIn() async throws { + let codeRequiredExp = expectation(description: "code required") + let signUpStartDelegate = SignUpPasswordStartDelegateSpy(expectation: codeRequiredExp) + + if usingMockAPI { + try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) + } + + sut.signUpUsingPassword( + username: usernamePassword, + password: password, + correlationId: correlationId, + delegate: signUpStartDelegate + ) + + await fulfillment(of: [codeRequiredExp], timeout: defaultTimeout) + checkSignUpStartDelegate(signUpStartDelegate) + + // Now submit the code... + + let signUpCompleteExp = expectation(description: "sign-up complete") + let signUpVerifyCodeDelegate = SignUpVerifyCodeDelegateSpy(expectation: signUpCompleteExp) + + if usingMockAPI { + try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) + } + + signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + + await fulfillment(of: [signUpCompleteExp], timeout: defaultTimeout) + XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpCompletedCalled) + } + + private func checkSignUpStartDelegate(_ delegate: SignUpPasswordStartDelegateSpy) { + XCTAssertTrue(delegate.onSignUpCodeRequiredCalled) + XCTAssertEqual(delegate.channelTargetType, .email) + XCTAssertFalse(delegate.sentTo?.isEmpty ?? true) + XCTAssertNotNil(delegate.codeLength) + } + + private func checkSignInAfterSignUpDelegate(_ delegate: SignInAfterSignUpDelegateSpy) { + XCTAssertTrue(delegate.onSignInCompletedCalled) + XCTAssertEqual(delegate.result?.account.username, usernamePassword) + XCTAssertNotNil(delegate.result?.idToken) + XCTAssertNil(delegate.result?.account.accountClaims) + XCTAssertEqual(delegate.result?.scopes[0], "openid") + XCTAssertEqual(delegate.result?.scopes[1], "offline_access") + } +} diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameEndToEndTests.swift new file mode 100644 index 0000000000..45ca955440 --- /dev/null +++ b/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameEndToEndTests.swift @@ -0,0 +1,313 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +import MSAL + +final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBaseTestCase { + + private let usernameOTP = ProcessInfo.processInfo.environment["existingOTPUserEmail"] ?? "" + private let attributes = ["age": 40] + + override func setUpWithError() throws { + try super.setUpWithError() + try XCTSkipIf(!usingMockAPI) + } + + // Hero Scenario 1.1.1. Sign up – with Email Verification (Email & Email OTP) + func test_signUpWithCode_withEmailVerification_succeeds() async throws { + let codeRequiredExp = expectation(description: "code required") + let signUpStartDelegate = SignUpStartDelegateSpy(expectation: codeRequiredExp) + + if usingMockAPI { + try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) + } + + sut.signUp(username: usernameOTP, correlationId: correlationId, delegate: signUpStartDelegate) + + await fulfillment(of: [codeRequiredExp], timeout: defaultTimeout) + checkSignUpStartDelegate(signUpStartDelegate) + + // Now submit the code... + + let signUpCompleteExp = expectation(description: "sign-up complete") + let signUpVerifyCodeDelegate = SignUpVerifyCodeDelegateSpy(expectation: signUpCompleteExp) + + if usingMockAPI { + try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) + } + + signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + + await fulfillment(of: [signUpCompleteExp], timeout: defaultTimeout) + XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpCompletedCalled) + + // Now sign in... + + let signInExp = expectation(description: "sign-in after sign-up") + let signInAfterSignUpDelegate = SignInAfterSignUpDelegateSpy(expectation: signInExp) + + if usingMockAPI { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } + + signUpVerifyCodeDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + + await fulfillment(of: [signInExp], timeout: defaultTimeout) + checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) + } + + // Hero Scenario 1.1.2. Sign up – with Email Verification as LAST step & Custom Attributes (Email & Email OTP) + func test_signUpWithCode_withEmailVerificationAsLastStepAndCustomAttributes_succeeds() async throws { + let codeRequiredExp = expectation(description: "code required") + let signUpStartDelegate = SignUpStartDelegateSpy(expectation: codeRequiredExp) + + if usingMockAPI { + try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) + } + + sut.signUp(username: usernameOTP, attributes: attributes, correlationId: correlationId, delegate: signUpStartDelegate) + + await fulfillment(of: [codeRequiredExp], timeout: defaultTimeout) + checkSignUpStartDelegate(signUpStartDelegate) + + // Now submit the code... + + let signUpCompleteExp = expectation(description: "sign-up complete") + let signUpVerifyCodeDelegate = SignUpVerifyCodeDelegateSpy(expectation: signUpCompleteExp) + + if usingMockAPI { + try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) + } + + signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + + await fulfillment(of: [signUpCompleteExp], timeout: defaultTimeout) + XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpCompletedCalled) + + // Now sign in... + + let signInExp = expectation(description: "sign-in after sign-up") + let signInAfterSignUpDelegate = SignInAfterSignUpDelegateSpy(expectation: signInExp) + + if usingMockAPI { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } + + signUpVerifyCodeDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + + await fulfillment(of: [signInExp], timeout: defaultTimeout) + checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) + } + + // Hero Scenario 1.1.3. Sign up – with Email Verification as FIRST step & Custom Attributes (Email & Email OTP) + func test_signUpWithCode_withEmailVerificationAsFirstStepAndCustomAttributes_succeeds() async throws { + let codeRequiredExp = expectation(description: "code required") + let signUpStartDelegate = SignUpStartDelegateSpy(expectation: codeRequiredExp) + + if usingMockAPI { + try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) + } + + sut.signUp(username: usernameOTP, attributes: attributes, correlationId: correlationId, delegate: signUpStartDelegate) + + await fulfillment(of: [codeRequiredExp], timeout: defaultTimeout) + checkSignUpStartDelegate(signUpStartDelegate) + + // Now submit the code... + + let submitCodeExp = expectation(description: "submit code") + let signUpVerifyCodeDelegate = SignUpVerifyCodeDelegateSpy(expectation: submitCodeExp) + + if usingMockAPI { + try await mockResponse(.attributesRequired, endpoint: .signUpContinue) + } + + signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + + await fulfillment(of: [submitCodeExp], timeout: defaultTimeout) + XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpAttributesRequiredCalled) + + // Now submit the attributes... + + let attributesExp = expectation(description: "submit attributes, sign-up complete") + let signUpAttributesRequiredDelegate = SignUpAttributesRequiredDelegateSpy(expectation: attributesExp) + + if usingMockAPI { + try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) + } + + signUpVerifyCodeDelegate.attributesRequiredNewState?.submitAttributes( + attributes: attributes, + delegate: signUpAttributesRequiredDelegate, + correlationId: correlationId + ) + + await fulfillment(of: [attributesExp], timeout: defaultTimeout) + XCTAssertTrue(signUpAttributesRequiredDelegate.onSignUpCompletedCalled) + + // Now sign in... + + let signInExp = expectation(description: "sign-in after sign-up") + let signInAfterSignUpDelegate = SignInAfterSignUpDelegateSpy(expectation: signInExp) + + if usingMockAPI { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } + + signUpAttributesRequiredDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + + await fulfillment(of: [signInExp], timeout: defaultTimeout) + checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) + } + + // Hero Scenario 1.1.4. Sign up – with Email Verification as FIRST step & Custom Attributes over MULTIPLE screens (Email & Email OTP) + func test_signUpWithCode_withEmailVerificationAsLastStepAndCustomAttributesOverMultipleScreens_succeeds() async throws { + let codeRequiredExp = expectation(description: "code required") + let signUpStartDelegate = SignUpStartDelegateSpy(expectation: codeRequiredExp) + + if usingMockAPI { + try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) + } + + sut.signUp(username: usernameOTP, attributes: attributes, correlationId: correlationId, delegate: signUpStartDelegate) + + await fulfillment(of: [codeRequiredExp], timeout: defaultTimeout) + checkSignUpStartDelegate(signUpStartDelegate) + + // Now submit the code... + + let submitCodeExp = expectation(description: "submit code") + let signUpVerifyCodeDelegate = SignUpVerifyCodeDelegateSpy(expectation: submitCodeExp) + + if usingMockAPI { + try await mockResponse(.attributesRequired, endpoint: .signUpContinue) + } + + signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + + await fulfillment(of: [submitCodeExp], timeout: defaultTimeout) + XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpAttributesRequiredCalled) + + // Now submit the attributes... + + let submitAttributesExp1 = expectation(description: "submit attributes 1") + let signUpAttributesRequiredDelegate = SignUpAttributesRequiredDelegateSpy(expectation: submitAttributesExp1) + + if usingMockAPI { + try await mockResponse(.attributesRequired, endpoint: .signUpContinue) + } + + signUpVerifyCodeDelegate.attributesRequiredNewState?.submitAttributes( + attributes: attributes, + delegate: signUpAttributesRequiredDelegate, + correlationId: correlationId + ) + + await fulfillment(of: [submitAttributesExp1], timeout: defaultTimeout) + XCTAssertTrue(signUpAttributesRequiredDelegate.onSignUpAttributesRequiredErrorCalled) + + // Now submit more attributes... + + let submitAttributesExp2 = expectation(description: "submit attributes 2, sign-up complete") + signUpAttributesRequiredDelegate.expectation = submitAttributesExp2 + + if usingMockAPI { + try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) + } + + signUpAttributesRequiredDelegate.attributesRequiredState?.submitAttributes( + attributes: attributes, + delegate: signUpAttributesRequiredDelegate, + correlationId: correlationId + ) + + await fulfillment(of: [submitAttributesExp2], timeout: defaultTimeout) + XCTAssertTrue(signUpAttributesRequiredDelegate.onSignUpCompletedCalled) + + // Now sign in... + + let signInExp = expectation(description: "sign-in after sign-up") + let signInAfterSignUpDelegate = SignInAfterSignUpDelegateSpy(expectation: signInExp) + + if usingMockAPI { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } + + signUpAttributesRequiredDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + + await fulfillment(of: [signInExp], timeout: defaultTimeout) + checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) + } + + // Hero Scenario 1.1.5. Sign up – without automatic sign in (Email & Email OTP) + func test_signUpWithoutAutomaticSignIn() async throws { + let codeRequiredExp = expectation(description: "code required") + let signUpStartDelegate = SignUpStartDelegateSpy(expectation: codeRequiredExp) + + if usingMockAPI { + try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) + } + + sut.signUp(username: usernameOTP, correlationId: correlationId, delegate: signUpStartDelegate) + + await fulfillment(of: [codeRequiredExp], timeout: defaultTimeout) + checkSignUpStartDelegate(signUpStartDelegate) + + // Now submit the code... + + let signUpCompleteExp = expectation(description: "sign-up complete") + let signUpVerifyCodeDelegate = SignUpVerifyCodeDelegateSpy(expectation: signUpCompleteExp) + + if usingMockAPI { + try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) + } + + signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + + await fulfillment(of: [signUpCompleteExp], timeout: defaultTimeout) + XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpCompletedCalled) + } + + private func checkSignUpStartDelegate(_ delegate: SignUpStartDelegateSpy) { + XCTAssertTrue(delegate.onSignUpCodeRequiredCalled) + XCTAssertEqual(delegate.channelTargetType, .email) + XCTAssertFalse(delegate.sentTo?.isEmpty ?? true) + XCTAssertNotNil(delegate.codeLength) + } + + private func checkSignInAfterSignUpDelegate(_ delegate: SignInAfterSignUpDelegateSpy) { + XCTAssertTrue(delegate.onSignInCompletedCalled) + XCTAssertEqual(delegate.result?.account.username, usernameOTP) + XCTAssertNotNil(delegate.result?.idToken) + XCTAssertNil(delegate.result?.account.accountClaims) + XCTAssertEqual(delegate.result?.scopes[0], "openid") + XCTAssertEqual(delegate.result?.scopes[1], "offline_access") + } +} diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift b/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift new file mode 100644 index 0000000000..a8806f8a0a --- /dev/null +++ b/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift @@ -0,0 +1,267 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +import XCTest +import MSAL + +class SignUpPasswordStartDelegateSpy: SignUpPasswordStartDelegate { + private let expectation: XCTestExpectation + private(set) var onSignUpPasswordErrorCalled = false + private(set) var error: MSAL.SignUpPasswordStartError? + private(set) var onSignUpCodeRequiredCalled = false + private(set) var newState: SignUpCodeRequiredState? + private(set) var sentTo: String? + private(set) var channelTargetType: MSALNativeAuthChannelType? + private(set) var codeLength: Int? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onSignUpPasswordError(error: SignUpPasswordStartError) { + onSignUpPasswordErrorCalled = true + self.error = error + + expectation.fulfill() + } + + func onSignUpCodeRequired(newState: SignUpCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) { + onSignUpCodeRequiredCalled = true + self.newState = newState + self.sentTo = sentTo + self.channelTargetType = channelTargetType + self.codeLength = codeLength + + expectation.fulfill() + } +} + +class SignUpStartDelegateSpy: SignUpStartDelegate { + private let expectation: XCTestExpectation + private(set) var onSignUpErrorCalled = false + private(set) var error: MSAL.SignUpStartError? + private(set) var onSignUpCodeRequiredCalled = false + private(set) var newState: SignUpCodeRequiredState? + private(set) var sentTo: String? + private(set) var channelTargetType: MSALNativeAuthChannelType? + private(set) var codeLength: Int? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onSignUpError(error: SignUpStartError) { + onSignUpErrorCalled = true + self.error = error + + expectation.fulfill() + } + + func onSignUpCodeRequired(newState: SignUpCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) { + onSignUpCodeRequiredCalled = true + self.newState = newState + self.sentTo = sentTo + self.channelTargetType = channelTargetType + self.codeLength = codeLength + + expectation.fulfill() + } +} + +class SignUpVerifyCodeDelegateSpy: SignUpVerifyCodeDelegate { + private let expectation: XCTestExpectation + private(set) var onSignUpVerifyCodeErrorCalled = false + private(set) var error: VerifyCodeError? + private(set) var onSignUpAttributesRequiredCalled = false + private(set) var attributesRequiredNewState: SignUpAttributesRequiredState? + private(set) var onSignUpPasswordRequiredCalled = false + private(set) var passwordRequiredState: SignUpPasswordRequiredState? + private(set) var onSignUpCompletedCalled = false + private(set) var signInAfterSignUpState: SignInAfterSignUpState? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onSignUpVerifyCodeError(error: VerifyCodeError, newState: SignUpCodeRequiredState?) { + onSignUpVerifyCodeErrorCalled = true + self.error = error + + expectation.fulfill() + } + + func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) { + onSignUpAttributesRequiredCalled = true + attributesRequiredNewState = newState + + expectation.fulfill() + } + + func onSignUpPasswordRequired(newState: SignUpPasswordRequiredState) { + onSignUpPasswordRequiredCalled = true + passwordRequiredState = newState + + expectation.fulfill() + } + + func onSignUpCompleted(newState: SignInAfterSignUpState) { + onSignUpCompletedCalled = true + signInAfterSignUpState = newState + + expectation.fulfill() + } +} + +class SignUpResendCodeDelegateSpy: SignUpResendCodeDelegate { + private let expectation: XCTestExpectation + private(set) var onSignUpResendCodeErrorCalled = false + private(set) var error: ResendCodeError? + private(set) var onSignUpResendCodeCodeRequiredCalled = false + private(set) var signUpCodeRequiredState: SignUpCodeRequiredState? + private(set) var sentTo: String? + private(set) var channelTargetType: MSALNativeAuthChannelType? + private(set) var codeLength: Int? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onSignUpResendCodeError(error: ResendCodeError) { + onSignUpResendCodeErrorCalled = true + self.error = error + } + + func onSignUpResendCodeCodeRequired(newState: SignUpCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) { + onSignUpResendCodeCodeRequiredCalled = true + signUpCodeRequiredState = newState + self.sentTo = sentTo + self.channelTargetType = channelTargetType + self.codeLength = codeLength + + expectation.fulfill() + } +} + +class SignUpPasswordRequiredDelegateSpy: SignUpPasswordRequiredDelegate { + private let expectation: XCTestExpectation + private(set) var onSignUpPasswordRequiredErrorCalled = false + private(set) var error: PasswordRequiredError? + private(set) var passwordRequiredState: SignUpPasswordRequiredState? + private(set) var onSignUpAttributesRequiredCalled = false + private(set) var attributesRequiredState: SignUpAttributesRequiredState? + private(set) var onSignUpCompletedCalled = false + private(set) var signInAfterSignUpState: SignInAfterSignUpState? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onSignUpPasswordRequiredError(error: PasswordRequiredError, newState: SignUpPasswordRequiredState?) { + onSignUpPasswordRequiredErrorCalled = true + self.error = error + passwordRequiredState = newState + + expectation.fulfill() + } + + func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) { + onSignUpAttributesRequiredCalled = true + attributesRequiredState = newState + + expectation.fulfill() + } + + func onSignUpCompleted(newState: SignInAfterSignUpState) { + onSignUpCompletedCalled = true + signInAfterSignUpState = newState + + expectation.fulfill() + } +} + +class SignUpAttributesRequiredDelegateSpy: SignUpAttributesRequiredDelegate { + var expectation: XCTestExpectation + private(set) var onSignUpAttributesRequiredErrorCalled = false + private(set) var error: AttributesRequiredError? + private(set) var attributesRequiredState: SignUpAttributesRequiredState? + private(set) var onSignUpCompletedCalled = false + private(set) var signInAfterSignUpState: SignInAfterSignUpState? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onSignUpAttributesRequiredError(error: AttributesRequiredError) { + onSignUpAttributesRequiredErrorCalled = true + self.error = error + + expectation.fulfill() + } + + func onSignUpCompleted(newState: SignInAfterSignUpState) { + onSignUpCompletedCalled = true + signInAfterSignUpState = newState + + expectation.fulfill() + } + + func onSignUpAttributesRequired(attributes: [MSAL.MSALNativeAuthRequiredAttributes], newState: MSAL.SignUpAttributesRequiredState) { + onSignUpAttributesRequiredErrorCalled = true + attributesRequiredState = newState + expectation.fulfill() + } + + func onSignUpAttributesInvalid(attributeNames: [String], newState: MSAL.SignUpAttributesRequiredState) { + onSignUpAttributesRequiredErrorCalled = true + attributesRequiredState = newState + expectation.fulfill() + } +} + +class SignInAfterSignUpDelegateSpy: SignInAfterSignUpDelegate { + private let expectation: XCTestExpectation + private(set) var onSignInAfterSignUpErrorCalled = false + private(set) var error: SignInAfterSignUpError? + private(set) var onSignInCompletedCalled = false + private(set) var result: MSALNativeAuthUserAccountResult? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onSignInAfterSignUpError(error: SignInAfterSignUpError) { + onSignInAfterSignUpErrorCalled = true + self.error = error + + expectation.fulfill() + } + + func onSignInCompleted(result: MSALNativeAuthUserAccountResult) { + onSignInCompletedCalled = true + self.result = result + + expectation.fulfill() + } +} diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift new file mode 100644 index 0000000000..c6f55c8bff --- /dev/null +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift @@ -0,0 +1,119 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthResetPasswordChallengeIntegrationTests: MSALNativeAuthIntegrationBaseTests { + + private var provider: MSALNativeAuthResetPasswordRequestProvider! + + override func setUpWithError() throws { + try super.setUpWithError() + + provider = MSALNativeAuthResetPasswordRequestProvider( + requestConfigurator: MSALNativeAuthRequestConfigurator(config: config), + telemetryProvider: MSALNativeAuthTelemetryProvider() + ) + + sut = try provider.challenge( + token: "", + context: MSALNativeAuthRequestContext(correlationId: correlationId) + ) + } + + func test_whenResetPasswordChallenge_succeeds() async throws { + try await mockAPIHandler.addResponse( + endpoint: .resetPasswordChallenge, + correlationId: correlationId, + responses: [.challengeTypeOOB] + ) + + let response: MSALNativeAuthResetPasswordChallengeResponse? = try await performTestSucceed() + + XCTAssertNotNil(response?.challengeType) + XCTAssertNotNil(response?.bindingMethod) + XCTAssertNotNil(response?.challengeTargetLabel) + XCTAssertNotNil(response?.challengeChannel) + XCTAssertNotNil(response?.passwordResetToken) + XCTAssertNotNil(response?.codeLength) + } + + func test_whenResetPasswordChallenge_redirects() async throws { + try await mockResponse(.challengeTypeRedirect, endpoint: .resetPasswordChallenge) + let response: MSALNativeAuthResetPasswordChallengeResponse? = try await performTestSucceed() + + + XCTAssertEqual(response?.challengeType, .redirect) + XCTAssertNil(response?.bindingMethod) + XCTAssertNil(response?.challengeTargetLabel) + XCTAssertNil(response?.challengeChannel) + XCTAssertNil(response?.passwordResetToken) + XCTAssertNil(response?.codeLength) + } + + func test_resetPasswordChallenge_invalidClient() async throws { + try await perform_testFail( + endpoint: .resetPasswordChallenge, + response: .invalidClient, + expectedError: createError(.invalidClient) + ) + } + + func test_resetPasswordChallenge_expiredToken() async throws { + try await perform_testFail( + endpoint: .resetPasswordChallenge, + response: .expiredToken, + expectedError: createError(.expiredToken) + ) + } + + func test_resetPasswordChallenge_invalidPasswordResetToken() async throws { + try await perform_testFail( + endpoint: .resetPasswordChallenge, + response: .invalidPasswordResetToken, + expectedError: createError(.invalidRequest) + ) + } + + func test_resetPasswordChallenge_unsupportedChallengeType() async throws { + try await perform_testFail( + endpoint: .resetPasswordChallenge, + response: .unsupportedChallengeType, + expectedError: createError(.unsupportedChallengeType) + ) + } + + private func createError(_ error: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode) -> MSALNativeAuthResetPasswordChallengeResponseError { + .init( + error: error, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + target: nil + ) + } +} diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift new file mode 100644 index 0000000000..f5688cd309 --- /dev/null +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift @@ -0,0 +1,131 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthResetPasswordContinueIntegrationTests: MSALNativeAuthIntegrationBaseTests { + + private var provider: MSALNativeAuthResetPasswordRequestProvider! + + override func setUpWithError() throws { + try super.setUpWithError() + + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + provider = MSALNativeAuthResetPasswordRequestProvider( + requestConfigurator: MSALNativeAuthRequestConfigurator(config: config), + telemetryProvider: MSALNativeAuthTelemetryProvider() + ) + + sut = try provider.continue( + parameters: MSALNativeAuthResetPasswordContinueRequestParameters(context: context, + passwordResetToken: "", + grantType: .oobCode, + oobCode: "0000") + ) + } + + func test_whenResetPasswordContinue_succeeds() async throws { + try await mockAPIHandler.addResponse( + endpoint: .resetPasswordContinue, + correlationId: correlationId, + responses: [.ssprContinueSuccess] + ) + + let response: MSALNativeAuthResetPasswordContinueResponse? = try await performTestSucceed() + + XCTAssertNotNil(response?.passwordSubmitToken) + XCTAssertNotNil(response?.expiresIn) + } + + func test_resetPasswordContinue_invalidClient() async throws { + try await perform_testFail( + endpoint: .resetPasswordContinue, + response: .invalidClient, + expectedError: createResetPasswordContinueError(error: .invalidClient) + ) + } + + func test_resetPasswordContinue_expiredToken() async throws { + try await perform_testFail( + endpoint: .resetPasswordContinue, + response: .expiredToken, + expectedError: createResetPasswordContinueError(error: .expiredToken) + ) + } + + func test_resetPasswordContinue_invalidPasswordResetToken() async throws { + try await perform_testFail( + endpoint: .resetPasswordContinue, + response: .invalidPasswordResetToken, + expectedError: createResetPasswordContinueError(error: .invalidRequest) + ) + } + + func test_resetPasswordContinue_invalidPassword() async throws { + try await perform_testFail( + endpoint: .resetPasswordContinue, + response: .invalidPassword, + expectedError: createResetPasswordContinueError(error: .invalidGrant, errorCodes: [MSALNativeAuthESTSApiErrorCodes.invalidCredentials.rawValue]) + ) + } + + func test_resetPasswordContinue_invalidOOB() async throws { + try await perform_testFail( + endpoint: .resetPasswordContinue, + response: .explicitInvalidOOBValue, + expectedError: createResetPasswordContinueError(error: .invalidOOBValue) + ) + } + + func test_resetPasswordContinue_verificationRequired() async throws { + try await perform_testFail( + endpoint: .resetPasswordContinue, + response: .verificationRequired, + expectedError: createResetPasswordContinueError(error: .verificationRequired) + ) + } + + private func createResetPasswordContinueError( + error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + target: String? = nil, + passwordResetToken: String? = nil + ) -> MSALNativeAuthResetPasswordContinueResponseError { + .init( + error: error, + errorDescription: errorDescription, + errorCodes: errorCodes, + errorURI: errorURI, + innerErrors: innerErrors, + target: target, + passwordResetToken: passwordResetToken + ) + } +} diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift new file mode 100644 index 0000000000..0f513cb326 --- /dev/null +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift @@ -0,0 +1,195 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativeAuthIntegrationBaseTests { + + private var provider: MSALNativeAuthResetPasswordRequestProvider! + + override func setUpWithError() throws { + try super.setUpWithError() + + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + provider = MSALNativeAuthResetPasswordRequestProvider( + requestConfigurator: MSALNativeAuthRequestConfigurator(config: config), + telemetryProvider: MSALNativeAuthTelemetryProvider() + ) + + sut = try provider.pollCompletion( + parameters: MSALNativeAuthResetPasswordPollCompletionRequestParameters(context: context, + passwordResetToken: " MSALNativeAuthResetPasswordPollCompletionResponseError { + .init( + error: error, + errorDescription: errorDescription, + errorCodes: errorCodes, + errorURI: errorURI, + innerErrors: innerErrors, + target: target + ) + } +} diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordStartIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordStartIntegrationTests.swift new file mode 100644 index 0000000000..80c1837440 --- /dev/null +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordStartIntegrationTests.swift @@ -0,0 +1,113 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthResetPasswordStartIntegrationTests: MSALNativeAuthIntegrationBaseTests { + + private var provider: MSALNativeAuthResetPasswordRequestProvider! + + override func setUpWithError() throws { + try super.setUpWithError() + + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + provider = MSALNativeAuthResetPasswordRequestProvider( + requestConfigurator: MSALNativeAuthRequestConfigurator(config: config), + telemetryProvider: MSALNativeAuthTelemetryProvider() + ) + + sut = try provider.start( + parameters: MSALNativeAuthResetPasswordStartRequestProviderParameters( + username: DEFAULT_TEST_ID_TOKEN_USERNAME, + context: context + ) + ) + } + + func test_whenResetPasswordStart_succeeds() async throws { + try await mockAPIHandler.addResponse( + endpoint: .resetPasswordStart, + correlationId: correlationId, + responses: [] + ) + + let response: MSALNativeAuthResetPasswordStartResponse? = try await performTestSucceed() + + XCTAssertNotNil(response?.passwordResetToken) + XCTAssertNil(response?.challengeType) + } + + func test_whenResetPasswordStart_redirects() async throws { + try await mockResponse(.challengeTypeRedirect, endpoint: .resetPasswordStart) + let response: MSALNativeAuthResetPasswordStartResponse? = try await performTestSucceed() + + XCTAssertNil(response?.passwordResetToken) + XCTAssertEqual(response?.challengeType, .redirect) + } + + func test_resetPasswordStart_invalidClient() async throws { + try await perform_testFail( + endpoint: .resetPasswordStart, + response: .invalidClient, + expectedError: createResetPasswordStartError(error: .invalidClient) + ) + } + + func test_resetPasswordStart_userNotFound() async throws { + try await perform_testFail( + endpoint: .resetPasswordStart, + response: .explicityUserNotFound, + expectedError: createResetPasswordStartError(error: .userNotFound) + ) + } + + func test_resetPasswordStart_unsupportedChallengeType() async throws { + try await perform_testFail( + endpoint: .resetPasswordStart, + response: .unsupportedChallengeType, + expectedError: createResetPasswordStartError(error: .unsupportedChallengeType) + ) + } + + private func createResetPasswordStartError( + error: MSALNativeAuthResetPasswordStartOauth2ErrorCode, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + target: String? = nil + ) -> MSALNativeAuthResetPasswordStartResponseError { + .init( + error: error, + errorDescription: errorDescription, + errorCodes: errorCodes, + errorURI: errorURI, + innerErrors: innerErrors, + target: target + ) + } +} diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordSubmitIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordSubmitIntegrationTests.swift new file mode 100644 index 0000000000..fba10607ca --- /dev/null +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordSubmitIntegrationTests.swift @@ -0,0 +1,137 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthResetPasswordSubmitIntegrationTests: MSALNativeAuthIntegrationBaseTests { + + private var provider: MSALNativeAuthResetPasswordRequestProvider! + + override func setUpWithError() throws { + try super.setUpWithError() + + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + provider = MSALNativeAuthResetPasswordRequestProvider( + requestConfigurator: MSALNativeAuthRequestConfigurator(config: config), + telemetryProvider: MSALNativeAuthTelemetryProvider() + ) + + sut = try provider.submit( + parameters: MSALNativeAuthResetPasswordSubmitRequestParameters(context: context, + passwordSubmitToken: "", + newPassword:"new-password") + ) + } + + func test_whenResetPasswordSubmit_succeeds() async throws { + try await mockAPIHandler.addResponse( + endpoint: .resetPasswordSubmit, + correlationId: correlationId, + responses: [.ssprSubmitSuccess] + ) + + let response: MSALNativeAuthResetPasswordSubmitResponse? = try await performTestSucceed() + + XCTAssertNotNil(response?.passwordResetToken) + XCTAssertNotNil(response?.pollInterval) + } + + func test_resetPasswordSubmit_invalidClient() async throws { + try await perform_testFail( + endpoint: .resetPasswordSubmit, + response: .invalidClient, + expectedError: createError(.invalidClient) + ) + } + + func test_resetPasswordSubmit_invalidPasswordResetToken() async throws { + try await perform_testFail( + endpoint: .resetPasswordSubmit, + response: .invalidPasswordResetToken, + expectedError: createError(.invalidRequest) + ) + } + + func test_resetPasswordSubmit_expiredToken() async throws { + try await perform_testFail( + endpoint: .resetPasswordSubmit, + response: .expiredToken, + expectedError: createError(.expiredToken) + ) + } + + func test_resetPasswordSubmit_passwordTooWeak() async throws { + try await perform_testFail( + endpoint: .resetPasswordSubmit, + response: .passwordTooWeak, + expectedError: createError(.passwordTooWeak) + ) + } + + func test_resetPasswordSubmit_passwordTooShort() async throws { + try await perform_testFail( + endpoint: .resetPasswordSubmit, + response: .passwordTooShort, + expectedError: createError(.passwordTooShort) + ) + } + + func test_resetPasswordSubmit_passwordTooLong() async throws { + try await perform_testFail( + endpoint: .resetPasswordSubmit, + response: .passwordTooLong, + expectedError: createError(.passwordTooLong) + ) + } + + func test_resetPasswordSubmit_passwordRecentlyUsed() async throws { + try await perform_testFail( + endpoint: .resetPasswordSubmit, + response: .passwordRecentlyUsed, + expectedError: createError(.passwordRecentlyUsed) + ) + } + + func test_resetPasswordSubmit_passwordBanned() async throws { + try await perform_testFail( + endpoint: .resetPasswordSubmit, + response: .passwordBanned, + expectedError: createError(.passwordBanned) + ) + } + + private func createError(_ error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode) -> MSALNativeAuthResetPasswordSubmitResponseError { + .init( + error: error, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + target: nil + ) + } +} diff --git a/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInChallengeIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInChallengeIntegrationTests.swift new file mode 100644 index 0000000000..e3880ebb2c --- /dev/null +++ b/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInChallengeIntegrationTests.swift @@ -0,0 +1,120 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthSignInChallengeIntegrationTests: MSALNativeAuthIntegrationBaseTests { + private typealias Error = MSALNativeAuthSignInChallengeResponseError + private var provider: MSALNativeAuthSignInRequestProvider! + + override func setUpWithError() throws { + try super.setUpWithError() + + provider = MSALNativeAuthSignInRequestProvider(requestConfigurator: MSALNativeAuthRequestConfigurator(config: config)) + + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + sut = try provider.challenge( + parameters: .init( + context: context, + credentialToken: "Test Credential Token" + ), + context: context + ) + } + + func test_succeedRequest_challengeTypePassword() async throws { + try await mockResponse(.challengeTypePassword, endpoint: .signInChallenge) + let response: MSALNativeAuthSignInChallengeResponse? = try await performTestSucceed() + + XCTAssertTrue(response?.challengeType == .password) + XCTAssertNotNil(response?.credentialToken) + } + + func test_succeedRequest_challengeTypeOOB() async throws { + try await mockResponse(.challengeTypeOOB, endpoint: .signInChallenge) + let response: MSALNativeAuthSignInChallengeResponse? = try await performTestSucceed() + + XCTAssertTrue(response?.challengeType == .oob) + XCTAssertNotNil(response?.credentialToken) + XCTAssertNotNil(response?.bindingMethod) + XCTAssertNotNil(response?.challengeTargetLabel) + XCTAssertNotNil(response?.codeLength) + XCTAssertNotNil(response?.interval) + } + + func test_succeedRequest_challengeTypeRedirect() async throws { + try await mockResponse(.challengeTypeRedirect, endpoint: .signInChallenge) + let response: MSALNativeAuthSignInChallengeResponse? = try await performTestSucceed() + + XCTAssertEqual(response?.challengeType, .redirect) + XCTAssertNil(response?.credentialToken) + } + + + func test_failRequest_unauthorizedClient() async throws { + throw XCTSkip() + + try await perform_testFail( + endpoint: .signInChallenge, + response: .invalidClient, + expectedError: Error(error: .unauthorizedClient, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) + ) + } + + func test_failRequest_invalidPurposeToken() async throws { + throw XCTSkip() + + let response = try await perform_testFail( + endpoint: .signInChallenge, + response: .invalidPurposeToken, + expectedError: Error(error: .invalidRequest, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) + ) + + guard let innerError = response.innerErrors?.first else { + return XCTFail("There should be an inner error") + } + + XCTAssertEqual(innerError.error, "invalid_purpose_token") + XCTAssertNotNil(innerError.errorDescription) + } + + func test_failRequest_expiredToken() async throws { + try await perform_testFail( + endpoint: .signInChallenge, + response: .expiredToken, + expectedError: Error(error: .expiredToken, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) + ) + } + + func test_failRequest_unsupportedChallengeType() async throws { + try await perform_testFail( + endpoint: .signInChallenge, + response: .unsupportedChallengeType, + expectedError: Error(error: .unsupportedChallengeType, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) + ) + } +} diff --git a/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift new file mode 100644 index 0000000000..53a9da5392 --- /dev/null +++ b/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift @@ -0,0 +1,92 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthSignInInitiateIntegrationTests: MSALNativeAuthIntegrationBaseTests { + private typealias Error = MSALNativeAuthSignInInitiateResponseError + private var provider: MSALNativeAuthSignInRequestProvider! + + override func setUpWithError() throws { + try super.setUpWithError() + + provider = MSALNativeAuthSignInRequestProvider(requestConfigurator: MSALNativeAuthRequestConfigurator(config: config)) + + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + sut = try provider.inititate( + parameters: .init( + context: context, + username: "test@contoso.com" + ), + context: context + ) + } + + func test_succeedRequest_initiateSuccess() async throws { + try await mockAPIHandler.addResponse( + endpoint: .signInInitiate, + correlationId: correlationId, + responses: [] + ) + let response: MSALNativeAuthSignInInitiateResponse? = try await performTestSucceed() + XCTAssertNotNil(response?.credentialToken) + } + + func test_succeedRequest_challengeTypeRedirect() async throws { + try await mockResponse(.challengeTypeRedirect, endpoint: .signInInitiate) + let response: MSALNativeAuthSignInInitiateResponse? = try await performTestSucceed() + + XCTAssertNil(response?.credentialToken) + XCTAssertEqual(response?.challengeType, .redirect) + } + + func test_failRequest_unauthorizedClient() async throws { + throw XCTSkip() + + try await perform_testFail( + endpoint: .signInInitiate, + response: .invalidClient, + expectedError: Error(error: .unauthorizedClient, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) + ) + } + + func test_failRequest_userNotFound() async throws { + try await perform_testFail( + endpoint: .signInInitiate, + response: .userNotFound, + expectedError: Error(error: .invalidGrant, errorDescription: nil, errorCodes:[MSALNativeAuthESTSApiErrorCodes.userNotFound.rawValue], errorURI: nil, innerErrors: nil) + ) + } + + func test_failRequest_unsupportedChallengeType() async throws { + try await perform_testFail( + endpoint: .signInInitiate, + response: .unsupportedChallengeType, + expectedError: Error(error: .unsupportedChallengeType, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) + ) + } +} diff --git a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift new file mode 100644 index 0000000000..2c8abdafde --- /dev/null +++ b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift @@ -0,0 +1,112 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthSignUpChallengeIntegrationTests: MSALNativeAuthIntegrationBaseTests { + + private var provider: MSALNativeAuthSignUpRequestProvider! + + override func setUpWithError() throws { + try super.setUpWithError() + + provider = MSALNativeAuthSignUpRequestProvider( + requestConfigurator: MSALNativeAuthRequestConfigurator(config: config), + telemetryProvider: MSALNativeAuthTelemetryProvider() + ) + + sut = try provider.challenge( + token: "", + context: MSALNativeAuthRequestContext(correlationId: correlationId) + ) + } + + func test_whenSignUpChallengePassword_succeeds() async throws { + try await mockResponse(.challengeTypePassword, endpoint: .signUpChallenge) + let response: MSALNativeAuthSignUpChallengeResponse? = try await performTestSucceed() + + XCTAssertEqual(response?.challengeType, .password) + XCTAssertNotNil(response?.signUpToken) + } + + func test_whenSignUpChallengeOOB_succeeds() async throws { + try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) + let response: MSALNativeAuthSignUpChallengeResponse? = try await performTestSucceed() + + XCTAssertEqual(response?.challengeType, .oob) + XCTAssertNotNil(response?.signUpToken) + XCTAssertNotNil(response?.bindingMethod) + XCTAssertNotNil(response?.challengeTargetLabel) + XCTAssertNotNil(response?.codeLength) + XCTAssertNotNil(response?.interval) + } + + func test_whenSignUpChallenge_redirects() async throws { + try await mockResponse(.challengeTypeRedirect, endpoint: .signUpChallenge) + let response: MSALNativeAuthSignUpChallengeResponse? = try await performTestSucceed() + + XCTAssertEqual(response?.challengeType, .redirect) + XCTAssertNil(response?.signUpToken) + } + + func test_signUpChallenge_unauthorizedClient() async throws { + throw XCTSkip() + + try await perform_testFail( + endpoint: .signUpChallenge, + response: .invalidClient, + expectedError: createError(.unauthorizedClient) + ) + } + + func test_signUpChallenge_expiredToken() async throws { + try await perform_testFail( + endpoint: .signUpChallenge, + response: .expiredToken, + expectedError: createError(.expiredToken) + ) + } + + func test_signUpChallenge_unsupportedChallengeType() async throws { + try await perform_testFail( + endpoint: .signUpChallenge, + response: .unsupportedChallengeType, + expectedError: createError(.unsupportedChallengeType) + ) + } + + func test_signUpChallenge_invalidSignUpToken() async throws { + try await perform_testFail( + endpoint: .signUpChallenge, + response: .invalidSignUpToken, + expectedError: createError(.invalidRequest) + ) + } + + private func createError(_ error: MSALNativeAuthSignUpChallengeOauth2ErrorCode) -> MSALNativeAuthSignUpChallengeResponseError { + .init(error: error, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) + } +} diff --git a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift new file mode 100644 index 0000000000..de89ecaa85 --- /dev/null +++ b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift @@ -0,0 +1,241 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrationBaseTests { + + private var provider: MSALNativeAuthSignUpRequestProvider! + private var context: MSIDRequestContext! + + override func setUpWithError() throws { + try super.setUpWithError() + + provider = MSALNativeAuthSignUpRequestProvider( + requestConfigurator: MSALNativeAuthRequestConfigurator(config: config), + telemetryProvider: MSALNativeAuthTelemetryProvider() + ) + + context = MSALNativeAuthRequestContext(correlationId: correlationId) + + let params = MSALNativeAuthSignUpContinueRequestProviderParams( + grantType: .password, + signUpToken: "", + password: "12345", + context: context + ) + + sut = try provider.continue(parameters: params) + } + + func test_signUpContinue_withPassword_succeeds() async throws { + let params = MSALNativeAuthSignUpContinueRequestProviderParams( + grantType: .password, + signUpToken: "", + password: "12345", + context: context + ) + + try await performSuccessfulTestCase(with: params) + } + + func test_signUpContinue_withOOB_succeeds() async throws { + let params = MSALNativeAuthSignUpContinueRequestProviderParams( + grantType: .oobCode, + signUpToken: "", + oobCode: "1234", + context: context + ) + + try await performSuccessfulTestCase(with: params) + } + + func test_signUpContinue_withAttributes_succeeds() async throws { + let params = MSALNativeAuthSignUpContinueRequestProviderParams( + grantType: .attributes, + signUpToken: "", + attributes: ["key": "value"], + context: context + ) + + try await performSuccessfulTestCase(with: params) + } + + func test_signUpContinue_unauthorizedClient() async throws { + throw XCTSkip() + + try await perform_testFail( + endpoint: .signUpContinue, + response: .invalidClient, + expectedError: createError(.unauthorizedClient) + ) + } + + func test_signUpContinue_invalidGrant() async throws { + try await perform_testFail( + endpoint: .signUpContinue, + response: .invalidGrant, + expectedError: createError(.invalidGrant) + ) + } + + func test_signUpContinue_invalidSignUpToken() async throws { + try await perform_testFail( + endpoint: .signUpContinue, + response: .invalidSignUpToken, + expectedError: createError(.invalidRequest) + ) + } + + func test_signUpContinue_expiredToken() async throws { + try await perform_testFail( + endpoint: .signUpContinue, + response: .expiredToken, + expectedError: createError(.expiredToken) + ) + } + + func test_signUpContinue_explicitInvalidOOBValue() async throws { + try await perform_testFail( + endpoint: .signUpContinue, + response: .explicitInvalidOOBValue, + expectedError: createError(.invalidOOBValue) + ) + } + + func test_signUpContinue_passwordTooWeak() async throws { + try await perform_testFail( + endpoint: .signUpContinue, + response: .passwordTooWeak, + expectedError: createError(.passwordTooWeak) + ) + } + + func test_signUpContinue_passwordTooShort() async throws { + try await perform_testFail( + endpoint: .signUpContinue, + response: .passwordTooShort, + expectedError: createError(.passwordTooShort) + ) + } + + func test_signUpContinue_passwordTooLong() async throws { + try await perform_testFail( + endpoint: .signUpContinue, + response: .passwordTooLong, + expectedError: createError(.passwordTooLong) + ) + } + + func test_signUpContinue_passwordRecentlyUsed() async throws { + try await perform_testFail( + endpoint: .signUpContinue, + response: .passwordRecentlyUsed, + expectedError: createError(.passwordRecentlyUsed) + ) + } + + func test_signUpContinue_passwordBanned() async throws { + try await perform_testFail( + endpoint: .signUpContinue, + response: .passwordBanned, + expectedError: createError(.passwordBanned) + ) + } + + func test_signUpContinue_userAlreadyExists() async throws { + try await perform_testFail( + endpoint: .signUpContinue, + response: .userAlreadyExists, + expectedError: createError(.userAlreadyExists) + ) + } + + func test_signUpContinue_attributesRequired() async throws { + let response = try await perform_testFail( + endpoint: .signUpContinue, + response: .attributesRequired, + expectedError: createError(.attributesRequired) + ) + + XCTAssertNotNil(response.signUpToken) + } + + func test_signUpContinue_verificationRequired() async throws { + let response = try await perform_testFail( + endpoint: .signUpContinue, + response: .verificationRequired, + expectedError: createError(.verificationRequired) + ) + + XCTAssertNotNil(response.signUpToken) + XCTAssertNotNil(response.unverifiedAttributes) + } + + func test_signUpContinue_validationFailed() async throws { + let response = try await perform_testFail( + endpoint: .signUpContinue, + response: .attributeValidationFailed, + expectedError: createError(.attributeValidationFailed) + ) + + XCTAssertNotNil(response.signUpToken) + } + + func test_signUpContinue_credentialRequired() async throws { + let response = try await perform_testFail( + endpoint: .signUpContinue, + response: .credentialRequired, + expectedError: createError(.credentialRequired) + ) + + XCTAssertNotNil(response.signUpToken) + } + + func performSuccessfulTestCase(with params: MSALNativeAuthSignUpContinueRequestProviderParams) async throws { + try await mockAPIHandler.addResponse(endpoint: .signUpContinue, correlationId: correlationId, responses: []) + sut = try provider.continue(parameters: params) + + let response: MSALNativeAuthSignUpContinueResponse? = try await performTestSucceed() + + XCTAssertNotNil(response?.signinSLT) + XCTAssertNil(response?.signupToken) + } + + private func createError(_ error: MSALNativeAuthSignUpContinueOauth2ErrorCode) -> MSALNativeAuthSignUpContinueResponseError { + .init( + error: error, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + signUpToken: nil, + requiredAttributes: nil, + unverifiedAttributes: nil, + invalidAttributes: nil + ) + } +} diff --git a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift new file mode 100644 index 0000000000..6beee3c552 --- /dev/null +++ b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift @@ -0,0 +1,188 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegrationBaseTests { + + private var provider: MSALNativeAuthSignUpRequestProvider! + + override func setUpWithError() throws { + try super.setUpWithError() + + provider = MSALNativeAuthSignUpRequestProvider( + requestConfigurator: MSALNativeAuthRequestConfigurator(config: config), + telemetryProvider: MSALNativeAuthTelemetryProvider() + ) + + sut = try provider.start( + parameters: MSALNativeAuthSignUpStartRequestProviderParameters( + username: DEFAULT_TEST_ID_TOKEN_USERNAME, + password: "1234", + attributes: [:], + context: MSALNativeAuthRequestContext(correlationId: correlationId) + ) + ) + } + + func test_whenSignUpStart_redirects() async throws { + try await mockResponse(.challengeTypeRedirect, endpoint: .signUpStart) + let response: MSALNativeAuthSignUpStartResponse? = try await performTestSucceed() + + XCTAssertNil(response?.signupToken) + XCTAssertEqual(response?.challengeType, .redirect) + } + + func test_signUpStart_unauthorizedClient() async throws { + throw XCTSkip() + + try await perform_testFail( + endpoint: .signUpStart, + response: .invalidClient, + expectedError: createError(.unauthorizedClient) + ) + } + + func test_signUpStart_unsupportedChallengeType() async throws { + try await perform_testFail( + endpoint: .signUpStart, + response: .unsupportedChallengeType, + expectedError: createError(.unsupportedChallengeType) + ) + } + + func test_signUpStart_passwordTooWeak() async throws { + try await perform_testFail( + endpoint: .signUpStart, + response: .passwordTooWeak, + expectedError: createError(.passwordTooWeak) + ) + } + + func test_signUpStart_passwordTooShort() async throws { + try await perform_testFail( + endpoint: .signUpStart, + response: .passwordTooShort, + expectedError: createError(.passwordTooShort) + ) + } + + func test_signUpStart_passwordTooLong() async throws { + try await perform_testFail( + endpoint: .signUpStart, + response: .passwordTooLong, + expectedError: createError(.passwordTooLong) + ) + } + + func test_signUpStart_passwordRecentlyUsed() async throws { + try await perform_testFail( + endpoint: .signUpStart, + response: .passwordRecentlyUsed, + expectedError: createError(.passwordRecentlyUsed) + ) + } + + func test_signUpStart_passwordBanned() async throws { + try await perform_testFail( + endpoint: .signUpStart, + response: .passwordBanned, + expectedError: createError(.passwordBanned) + ) + } + + func test_signUpStart_userAlreadyExists() async throws { + try await perform_testFail( + endpoint: .signUpStart, + response: .userAlreadyExists, + expectedError: createError(.userAlreadyExists) + ) + } + + func test_signUpStart_attributesRequired() async throws { + let response = try await perform_testFail( + endpoint: .signUpStart, + response: .attributesRequired, + expectedError: createError(.attributesRequired) + ) + + XCTAssertNotNil(response.signUpToken) + } + + func test_signUpStart_verificationRequired() async throws { + let response = try await perform_testFail( + endpoint: .signUpStart, + response: .verificationRequired, + expectedError: createError(.verificationRequired) + ) + + XCTAssertNotNil(response.signUpToken) + XCTAssertNotNil(response.unverifiedAttributes) + } + + func test_signUpStart_validationFailed() async throws { + let response = try await perform_testFail( + endpoint: .signUpStart, + response: .attributeValidationFailed, + expectedError: createError(.attributeValidationFailed) + ) + + XCTAssertNotNil(response.signUpToken) + } + + func test_signUpStart_unsupportedAuthMethod() async throws { + throw XCTSkip() + + try await perform_testFail( + endpoint: .signUpStart, + response: .unsupportedAuthMethod, + expectedError: createError(.unsupportedAuthMethod) + ) + } + + func test_signUpStart_invalidRequest_withESTSErrorInvalidEmail() async throws { + throw XCTSkip() + + try await perform_testFail( + endpoint: .signUpStart, + response: .invalidUsername, + expectedError: createError(.invalidRequest, errorCodes: [90100]) + ) + } + + private func createError(_ error: MSALNativeAuthSignUpStartOauth2ErrorCode, errorCodes: [Int]? = nil) -> MSALNativeAuthSignUpStartResponseError { + .init( + error: error, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + signUpToken: nil, + unverifiedAttributes: nil, + invalidAttributes: nil + ) + } +} diff --git a/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift new file mode 100644 index 0000000000..8f09632c26 --- /dev/null +++ b/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift @@ -0,0 +1,181 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthTokenIntegrationTests: MSALNativeAuthIntegrationBaseTests { + private typealias Error = MSALNativeAuthTokenResponseError + private var provider: MSALNativeAuthTokenRequestProvider! + + override func setUpWithError() throws { + try super.setUpWithError() + + provider = MSALNativeAuthTokenRequestProvider(requestConfigurator: MSALNativeAuthRequestConfigurator(config: config)) + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + sut = try provider.refreshToken( + parameters: .init( + context: context, + username: "test@contoso.com", + credentialToken: nil, + signInSLT: nil, + grantType: .otp, + scope: nil, + password: nil, + oobCode: nil, + includeChallengeType: false, + refreshToken: nil + ), + context: context + ) + } + + func test_succeedRequest_tokenSuccess() async throws { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + let response: [String: Any]? = try await performTestSucceed() + + XCTAssertNotNil(response?["token_type"]) + XCTAssertNotNil(response?["scope"]) + XCTAssertNotNil(response?["ext_expires_in"]) + XCTAssertNotNil(response?["refresh_token"]) + XCTAssertNotNil(response?["access_token"]) + XCTAssertNotNil(response?["id_token"]) + XCTAssertNotNil(response?["expires_in"]) + } + + func test_succeedRequest_scopesWithAmpersandAndSpaces() async throws { + let expectation = XCTestExpectation() + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + let parameters = MSALNativeAuthTokenRequestParameters(context: context, + username: "test@contoso.com", + credentialToken: nil, + signInSLT: nil, + grantType: .otp, + scope: "test & alt test", + password: nil, + oobCode: nil, + includeChallengeType: false, + refreshToken: nil) + + + let request = try! provider.refreshToken(parameters: parameters, + context: context) + + request.send { result, error in + if let result = result as? [String: Any] { + XCTAssertNotNil(result["token_type"]) + XCTAssertNotNil(result["scope"]) + XCTAssertNotNil(result["ext_expires_in"]) + XCTAssertNotNil(result["refresh_token"]) + XCTAssertNotNil(result["access_token"]) + XCTAssertNotNil(result["id_token"]) + XCTAssertNotNil(result["expires_in"]) + } else { + XCTFail("MSALNativeAuthSignInTokenRequest should return a [String: Any] structure in this test") + } + expectation.fulfill() + } + await fulfillment(of: [expectation], timeout: defaultTimeout) + } + + func test_failRequest_invalidPurposeToken() async throws { + throw XCTSkip() + + let response = try await perform_testFail( + endpoint: .signInToken, + response: .invalidPurposeToken, + expectedError: createError(.invalidRequest) + ) + + guard let innerError = response.innerErrors?.first else { + return XCTFail("There should be an inner error") + } + + XCTAssertEqual(innerError.error, "invalid_purpose_token") + XCTAssertNotNil(innerError.errorDescription) + } + + func test_failRequest_invalidPassword() async throws { + try await perform_testFail( + endpoint: .signInToken, + response: .invalidPassword, + expectedError: Error(error: .invalidGrant, errorDescription: nil, errorCodes: [MSALNativeAuthESTSApiErrorCodes.invalidCredentials.rawValue], errorURI: nil, innerErrors: nil, credentialToken: nil) + ) + } + + func test_failRequest_invalidOOBValue() async throws { + try await perform_testFail( + endpoint: .signInToken, + response: .invalidOOBValue, + expectedError: Error(error: .invalidGrant, errorDescription: nil, errorCodes: [MSALNativeAuthESTSApiErrorCodes.invalidOTP.rawValue], errorURI: nil, innerErrors: nil, credentialToken: nil) + ) + } + + func test_failRequest_invalidGrant() async throws { + try await perform_testFail( + endpoint: .signInToken, + response: .invalidGrant, + expectedError: createError(.invalidGrant) + ) + } + + func test_failRequest_expiredToken() async throws { + try await perform_testFail( + endpoint: .signInToken, + response: .expiredToken, + expectedError: createError(.expiredToken) + ) + } + + func test_failRequest_unsupportedChallengeType() async throws { + try await perform_testFail( + endpoint: .signInToken, + response: .unsupportedChallengeType, + expectedError: createError(.unsupportedChallengeType) + ) + } + + func test_succeedRequest_authorizationPending() async throws { + try await perform_testFail( + endpoint: .signInToken, + response: .authorizationPending, + expectedError: createError(.authorizationPending) + ) + } + + func test_succeedRequest_slowDown() async throws { + try await mockResponse(.slowDown, endpoint: .signInToken) + let result: MSALNativeAuthTokenResponseError = try await perform_uncheckedTestFail() + + let expectedError = createError(.slowDown) + + XCTAssertEqual(result.error.rawValue, expectedError.error.rawValue) + } + + private func createError(_ code: MSALNativeAuthTokenOauth2ErrorCode) -> Error { + .init(error: code, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, credentialToken: nil) + } +} diff --git a/MSAL/test/unit/MSALAccountTests.m b/MSAL/test/unit/MSALAccountTests.m index 7764840c79..6ab09409f0 100644 --- a/MSAL/test/unit/MSALAccountTests.m +++ b/MSAL/test/unit/MSALAccountTests.m @@ -140,6 +140,74 @@ - (void)testInitWithMSIDAccount_whenValidAccountAndCreateTenantProfileNo_shouldI XCTAssertNil(account.tenantProfiles); } +- (void)testInitWithMSIDAccount_whenValidAccountAndValidClaims_shouldInitAndAddClaims +{ + MSIDAccount *msidAccount = [MSIDAccount new]; + msidAccount.accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:@"user@contoso.com" homeAccountId:@"uid.tid"]; + msidAccount.username = @"user@contoso.com"; + msidAccount.name = @"User"; + msidAccount.localAccountId = @"localoid"; + __auto_type authorityUrl = [NSURL URLWithString:@"https://login.microsoftonline.com/tid"]; + __auto_type authority = [[MSIDAADAuthority alloc] initWithURL:authorityUrl context:nil error:nil]; + msidAccount.environment = authority.environment; + msidAccount.realm = authority.realm; + msidAccount.isSSOAccount = YES; + NSDictionary *clientInfoClaims = @{ @"uid" : @"uid", + @"utid" : @"tid" + }; + + + MSIDClientInfo *clientInfo = [[MSIDClientInfo alloc] initWithJSONDictionary:clientInfoClaims error:nil]; + msidAccount.clientInfo = clientInfo; + + NSDictionary *idTokenDictionary = @{ @"aud" : @"b6c69a37", + @"oid" : @"ff9feb5a" + }; + + MSIDIdTokenClaims *idTokenClaims = [[MSIDIdTokenClaims alloc] initWithJSONDictionary:idTokenDictionary error:nil]; + XCTAssertNotNil(idTokenClaims); + msidAccount.idTokenClaims = idTokenClaims; + MSALAccount *account = [[MSALAccount alloc] initWithMSIDAccount:msidAccount createTenantProfile: NO accountClaims:[idTokenClaims jsonDictionary]]; + + XCTAssertNotNil(account); + XCTAssertEqualObjects(account.homeAccountId.objectId, @"uid"); + XCTAssertEqualObjects(account.homeAccountId.tenantId, @"tid"); + XCTAssertEqualObjects(account.username, @"user@contoso.com"); + XCTAssertEqualObjects(account.identifier, @"uid.tid"); + XCTAssertTrue(account.isSSOAccount); + XCTAssertEqualObjects(account.accountClaims, idTokenDictionary); +} + +- (void)testInitWithMSIDAccount_whenValidAccountAndNil_shouldInitAndNotAddClaims +{ + MSIDAccount *msidAccount = [MSIDAccount new]; + msidAccount.accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:@"user@contoso.com" homeAccountId:@"uid.tid"]; + msidAccount.username = @"user@contoso.com"; + msidAccount.name = @"User"; + msidAccount.localAccountId = @"localoid"; + __auto_type authorityUrl = [NSURL URLWithString:@"https://login.microsoftonline.com/tid"]; + __auto_type authority = [[MSIDAADAuthority alloc] initWithURL:authorityUrl context:nil error:nil]; + msidAccount.environment = authority.environment; + msidAccount.realm = authority.realm; + msidAccount.isSSOAccount = YES; + NSDictionary *clientInfoClaims = @{ @"uid" : @"uid", + @"utid" : @"tid" + }; + + + MSIDClientInfo *clientInfo = [[MSIDClientInfo alloc] initWithJSONDictionary:clientInfoClaims error:nil]; + msidAccount.clientInfo = clientInfo; + MSALAccount *account = [[MSALAccount alloc] initWithMSIDAccount:msidAccount createTenantProfile: NO accountClaims:nil]; + + XCTAssertNotNil(account); + XCTAssertEqualObjects(account.homeAccountId.objectId, @"uid"); + XCTAssertEqualObjects(account.homeAccountId.tenantId, @"tid"); + XCTAssertEqualObjects(account.username, @"user@contoso.com"); + XCTAssertEqualObjects(account.identifier, @"uid.tid"); + XCTAssertTrue(account.isSSOAccount); + XCTAssertNil(account.accountClaims); +} + - (void)testAddTenantProfiles_whenAddValidTenantProfiles_shouldAddIt { // Create MSAL account 1 diff --git a/MSAL/test/unit/MSALDeviceInfoProviderTests.m b/MSAL/test/unit/MSALDeviceInfoProviderTests.m index fab33a68fd..e75ba3087b 100644 --- a/MSAL/test/unit/MSALDeviceInfoProviderTests.m +++ b/MSAL/test/unit/MSALDeviceInfoProviderTests.m @@ -90,7 +90,7 @@ - (void)testGetDeviceInfo_whenCurrentSSOExtensionRequestAlreadyPresent_shouldRet dispatch_semaphore_signal(dsem); }]; - [self waitForExpectations:@[expectation, failExpectation] timeout:1]; + [self waitForExpectations:@[expectation, failExpectation] timeout:2]; } - (void)testWPJMetaDataDeviceInfoWithRequestParameters_tenantIdNil API_AVAILABLE(ios(13.0), macos(10.15)) diff --git a/MSAL/test/unit/MSALPublicClientApplicationTests.m b/MSAL/test/unit/MSALPublicClientApplicationTests.m index 731107a187..413ffbc355 100644 --- a/MSAL/test/unit/MSALPublicClientApplicationTests.m +++ b/MSAL/test/unit/MSALPublicClientApplicationTests.m @@ -209,6 +209,7 @@ - (void)testInitWithClientIdAndAuthority_whenValidClientIdAndAuthority_shouldRet - (void)test_non_nil_sdkVersion { + XCTSkip("Skip this test for private preview versioning"); NSString *versionFromInfo = [[NSBundle bundleForClass:MSALPublicClientApplication.class] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; NSString *version = [MSALPublicClientApplication sdkVersion]; XCTAssertNotNil(version); diff --git a/MSAL/test/unit/ios/unit-test-host/Info.plist b/MSAL/test/unit/ios/unit-test-host/Info.plist index 2fe593af20..69ef96173a 100644 --- a/MSAL/test/unit/ios/unit-test-host/Info.plist +++ b/MSAL/test/unit/ios/unit-test-host/Info.plist @@ -43,5 +43,19 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + CFBundleURLTypes + + + CFBundleURLSchemes + + msauth.$(PRODUCT_BUNDLE_IDENTIFIER) + + + + LSApplicationQueriesSchemes + + msauthv2 + msauthv3 + diff --git a/MSAL/test/unit/native_auth/MSALNativeAuthTestCase.swift b/MSAL/test/unit/native_auth/MSALNativeAuthTestCase.swift new file mode 100644 index 0000000000..c175cb322c --- /dev/null +++ b/MSAL/test/unit/native_auth/MSALNativeAuthTestCase.swift @@ -0,0 +1,56 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@_implementationOnly import MSAL_Private + +class MSALNativeAuthTestCase: XCTestCase { + //Do not create more than one instance of this variable, inherit this class instead + static let logger = MSALNativeAuthTestLogger() + var dispatcher: MSALNativeAuthTelemetryTestDispatcher! + var receivedEvents: [[AnyHashable: Any]] = [] + + override func setUpWithError() throws { + // Logger needs to reset so the expectation name and count resets from the previous test + // The previous test could be across class + Self.logger.reset() + + dispatcher = MSALNativeAuthTelemetryTestDispatcher() + + dispatcher.setTestCallback { event in + self.receivedEvents.append(event.propertyMap) + } + + MSIDTelemetry.sharedInstance().add(dispatcher) + } + + override func tearDown() { + // Logger needs to reset so the expectation name and count resets for the next test. + // The next test could be across classes + Self.logger.reset() + + receivedEvents.removeAll() + MSIDTelemetry.sharedInstance().remove(dispatcher) + } +} diff --git a/MSAL/test/unit/native_auth/cache/MSALNativeAuthCacheAccessorTest.swift b/MSAL/test/unit/native_auth/cache/MSALNativeAuthCacheAccessorTest.swift new file mode 100644 index 0000000000..c0b2e83d5a --- /dev/null +++ b/MSAL/test/unit/native_auth/cache/MSALNativeAuthCacheAccessorTest.swift @@ -0,0 +1,286 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthCacheAccessorTest: XCTestCase { + private let cacheAccessor = MSALNativeAuthCacheAccessor() + private lazy var parameters = getParameters() + private lazy var contextStub = ContextStub() + + override func setUp() { + clearCache() + } + + override func tearDown() { + clearCache() + } + + // MARK: happy cases + + func testTokensStore_whenAllInfoPresent_shouldSaveTokensCorrectly() { + let tokenResponse = getTokenResponse() + let parameters = getParameters() + XCTAssertNoThrow(try cacheAccessor.validateAndSaveTokensAndAccount(tokenResponse: tokenResponse, configuration: parameters.msidConfiguration, context: contextStub)) + var tokens: MSALNativeAuthTokens? = nil + + XCTAssertNoThrow(tokens = try cacheAccessor.getTokens(account: parameters.account, configuration: parameters.msidConfiguration, context: contextStub)) + XCTAssertEqual(tokens?.accessToken?.accessToken, tokenResponse.accessToken) + XCTAssertEqual(tokens?.refreshToken?.refreshToken, tokenResponse.refreshToken) + XCTAssertEqual(tokens?.rawIdToken, tokenResponse.idToken) + } + + func testUpdateTokensAndAccount_whenAllInfoPresent_shouldUpdateDataCorrectly() { + let tokenResponse = getTokenResponse() + XCTAssertNoThrow(try cacheAccessor.validateAndSaveTokensAndAccount(tokenResponse: tokenResponse, configuration: parameters.msidConfiguration, context: contextStub)) + var tokens: MSALNativeAuthTokens? = nil + + XCTAssertNoThrow(tokens = try cacheAccessor.getTokens(account: parameters.account, configuration: parameters.msidConfiguration, context: contextStub)) + XCTAssertEqual(tokens?.accessToken?.accessToken, tokenResponse.accessToken) + XCTAssertEqual(tokens?.refreshToken?.refreshToken, tokenResponse.refreshToken) + XCTAssertEqual(tokens?.rawIdToken, tokenResponse.idToken) + + let newAccessToken = "newAccessToken" + let newRefreshToken = "newRefreshToken" + let newIdToken = "newIdToken" + tokenResponse.accessToken = newAccessToken + tokenResponse.refreshToken = newRefreshToken + tokenResponse.idToken = newIdToken + XCTAssertNoThrow(try cacheAccessor.validateAndSaveTokensAndAccount(tokenResponse: tokenResponse, configuration: parameters.msidConfiguration, context: contextStub)) + + XCTAssertNoThrow(tokens = try cacheAccessor.getTokens(account: parameters.account, configuration: parameters.msidConfiguration, context: contextStub)) + XCTAssertEqual(tokens?.accessToken?.accessToken, newAccessToken) + XCTAssertEqual(tokens?.refreshToken?.refreshToken, newRefreshToken) + XCTAssertEqual(tokens?.rawIdToken, newIdToken) + } + + func testGetAllAccounts_whenAllInfoPresent_shouldRetrieveDataCorrectly() { + let tokenResponse = getTokenResponse() + var tokens: MSALNativeAuthTokens? = nil + var account: MSALAccount? = nil + + XCTAssertNoThrow(try cacheAccessor.validateAndSaveTokensAndAccount(tokenResponse: tokenResponse, configuration: parameters.msidConfiguration, context: contextStub)) + XCTAssertNoThrow(account = try cacheAccessor.getAllAccounts(configuration: parameters.msidConfiguration).first) + XCTAssertEqual(account?.username, parameters.accountIdentifier.displayableId) + XCTAssertEqual(account?.identifier, parameters.accountIdentifier.homeAccountId) + XCTAssertEqual(account?.environment, "contoso.com") + XCTAssertNil(account?.accountClaims) + XCTAssertNoThrow(tokens = try cacheAccessor.getTokens(account: account!, configuration: parameters.msidConfiguration, context: contextStub)) + XCTAssertEqual(tokens?.accessToken?.accessToken, tokenResponse.accessToken) + XCTAssertEqual(tokens?.refreshToken?.refreshToken, tokenResponse.refreshToken) + XCTAssertEqual(tokens?.rawIdToken, tokenResponse.idToken) + } + + func testGetAllAccounts_whenAllInfoPresent_shouldRetrieveDataOnlyOnSameAuthority() { + let tokenResponse = getTokenResponse() + var tokens: MSALNativeAuthTokens? = nil + var account: MSALAccount? = nil + + XCTAssertNoThrow(try cacheAccessor.validateAndSaveTokensAndAccount(tokenResponse: tokenResponse, configuration: parameters.msidConfiguration, context: contextStub)) + XCTAssertNoThrow(account = try cacheAccessor.getAllAccounts(configuration: parameters.msidConfiguration).first) + XCTAssertEqual(account?.username, parameters.accountIdentifier.displayableId) + XCTAssertEqual(account?.identifier, parameters.accountIdentifier.homeAccountId) + XCTAssertEqual(account?.environment, "contoso.com") + XCTAssertNil(account?.accountClaims) + parameters.msidConfiguration = getMSIDConfiguration(host: "https://contoso.com/tfp/tenantName") + XCTAssertNoThrow(tokens = try cacheAccessor.getTokens(account: account!, configuration: parameters.msidConfiguration, context: contextStub)) + XCTAssertEqual(tokens?.accessToken?.accessToken, tokenResponse.accessToken) + XCTAssertEqual(tokens?.refreshToken?.refreshToken, tokenResponse.refreshToken) + XCTAssertEqual(tokens?.rawIdToken, tokenResponse.idToken) + } + + func testDataRetrieval_whenAccountIsOverwritten_shouldRetrieveLastAccount() { + let tokenResponse = getTokenResponse() + XCTAssertNoThrow(try cacheAccessor.validateAndSaveTokensAndAccount(tokenResponse: tokenResponse, configuration: parameters.msidConfiguration, context: contextStub)) + var tokens: MSALNativeAuthTokens? = nil + var account: MSALAccount? = nil + + let newDisplayableId = "newDisplayableId" + let newAccessToken = "newAccessToken" + let newRefreshToken = "newRefreshToken" + let newIdToken = "eyJhbGciOiJIUzI1NiJ9.eyJ2ZXIiOiIyLjAiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vdGVzdC92Mi4wIiwic3ViIjoiQUFBQUFBQUFBQUFBQUFBQUFBQUFBUFdLdXZBcTQ3ZWZsc0o3TXdnaW1rVSIsImF1ZCI6IjA5ODRhN2I2LWJjMTMtNDE0MS04YjBkLThmNzY3ZTEzNmJiNyIsImV4cCI6MTY4MTQ2MzAyMywiaWF0IjoxNjgxMzc2MzIzLCJuYmYiOjE2ODEzNzYzMjMsIm5hbWUiOiJOZXcgVXNlciIsInByZWZlcnJlZF91c2VybmFtZSI6Im5ld0Rpc3BsYXlhYmxlSWQiLCJvaWQiOiJuZXdPaWQiLCJ0aWQiOiJuZXdUaWQiLCJhaW8iOiJEVGhGY3dSdFgwT0tqNXBTSEdOZUdVR1NVNGhaNFJoNU83TmhnUjYzMnpldEM5WmgzM3dWRypXeUJqIVFPM0twU0dXRVRla25sMDA1WE8qQWg0bXhRamVuR2VRZXIqakx3Nypkcmh1cDdTc0NJRThraUlsempYMDZuaWNWNFFFTGZxR3BoYkRuemI0RWtOZEZXTHBOTmhJJCJ9.A9K5OQgR3dUaexxosQg6FOMOteC9R96fI0sZtF-KwjU" + tokenResponse.accessToken = newAccessToken + tokenResponse.refreshToken = newRefreshToken + tokenResponse.idToken = newIdToken + XCTAssertNoThrow(try cacheAccessor.validateAndSaveTokensAndAccount(tokenResponse: tokenResponse, configuration: parameters.msidConfiguration, context: contextStub)) + XCTAssertNoThrow(account = try cacheAccessor.getAllAccounts(configuration: parameters.msidConfiguration).first) + XCTAssertEqual(account?.username, newDisplayableId) + XCTAssertEqual(account?.identifier, parameters.accountIdentifier.homeAccountId) + XCTAssertEqual(account?.environment, "contoso.com") + XCTAssertNil(account?.accountClaims) + XCTAssertNoThrow(tokens = try cacheAccessor.getTokens(account: account!, configuration: parameters.msidConfiguration, context: contextStub)) + XCTAssertEqual(tokens?.accessToken?.accessToken, newAccessToken) + XCTAssertEqual(tokens?.refreshToken?.refreshToken, newRefreshToken) + XCTAssertEqual(tokens?.rawIdToken, newIdToken) + } + + func testTokensDeletion_whenAllInfoPresent_shouldRemoveTokensCorrectly() { + var tokens: MSALNativeAuthTokens? = nil + XCTAssertThrowsError(tokens = try cacheAccessor.getTokens(account: parameters.account, configuration: parameters.msidConfiguration, context: contextStub)) + XCTAssertNil(tokens) + + let tokenResponse = getTokenResponse() + let _ = try? cacheAccessor.validateAndSaveTokensAndAccount(tokenResponse: tokenResponse, configuration: parameters.msidConfiguration, context: contextStub) + + tokens = try? cacheAccessor.getTokens(account: parameters.account, configuration: parameters.msidConfiguration, context: contextStub) + XCTAssertNotNil(tokens) + + XCTAssertNoThrow(try cacheAccessor.removeTokens(accountIdentifier: parameters.accountIdentifier, authority: parameters.msidConfiguration.authority, clientId: parameters.msidConfiguration.clientId, context: contextStub)) + + tokens = try? cacheAccessor.getTokens(account: parameters.account, configuration: parameters.msidConfiguration, context: contextStub) + XCTAssertNil(tokens) + } + + // MARK: unhappy cases + + func testDataRetrieval_whenNoDataIsStored_shouldThrowsAnError() { + XCTAssertThrowsError(try cacheAccessor.getTokens(account: parameters.account, configuration: parameters.msidConfiguration, context: contextStub)) + } + + func testDataRetrieval_whenNoAccountStored_ShouldReturnNoAccount() { + var account: MSALAccount? = nil + XCTAssertNoThrow(account = try cacheAccessor.getAllAccounts(configuration: parameters.msidConfiguration).first) + XCTAssertNil(account) + } + + func testContentDeletion_whenNoDataIsStored_shouldNotThrowsAnError() { + XCTAssertNoThrow(try cacheAccessor.removeTokens(accountIdentifier: parameters.accountIdentifier, authority: parameters.msidConfiguration.authority, clientId: parameters.msidConfiguration.clientId, context: contextStub)) + XCTAssertNoThrow(try cacheAccessor.clearCache(accountIdentifier: parameters.accountIdentifier, authority: parameters.msidConfiguration.authority, clientId: parameters.msidConfiguration.clientId, context: contextStub)) + } + + func testRemoveTokens_whenInvalidInputIsUsed_shouldNotThrowsAnError() { + var authority: MSIDAuthority? = nil + XCTAssertNoThrow(authority = try MSIDCIAMAuthority(url: URL(string: "https://www.microsoft.com")!, validateFormat: false, context: nil)) + XCTAssertNoThrow(try cacheAccessor.removeTokens(accountIdentifier: MSIDAccountIdentifier(), authority: authority!, clientId: "" , context: contextStub)) + } + + func testStoreTokens_whenAccessAndRefreshTokensAreMissing_shouldThrowsAnErrorOnGetTokens() { + let tokenResponse = getTokenResponse() + tokenResponse.accessToken = nil + tokenResponse.refreshToken = nil + XCTAssertNoThrow(try cacheAccessor.validateAndSaveTokensAndAccount(tokenResponse: tokenResponse, configuration: parameters.msidConfiguration, context: contextStub)) + + XCTAssertThrowsError(try cacheAccessor.getTokens(account: parameters.account, configuration: parameters.msidConfiguration, context: contextStub)) + } + + func testGetTokens_whenThereIsNoAuthScheme_shouldThrowsAnError() { + let tokenResponse = getTokenResponse() + XCTAssertNoThrow(try cacheAccessor.validateAndSaveTokensAndAccount(tokenResponse: tokenResponse, configuration: parameters.msidConfiguration, context: contextStub)) + + let parameters = getParameters() + parameters.msidConfiguration.authScheme = nil + XCTAssertThrowsError(try cacheAccessor.getTokens(account: parameters.account, configuration: parameters.msidConfiguration, context: contextStub)) + } + + // MARK: private methods + + private func getParameters() -> ParametersStub { + ParametersStub( + account: getAccount(), + accountIdentifier: getAccountIdentifier(), + msidConfiguration: getMSIDConfiguration(host: "https://contoso.com/tfp/tenantName") + ) + } + + private func getAccountIdentifier() -> MSIDAccountIdentifier { + return MSIDAccountIdentifier(displayableId: "1234567890", homeAccountId: "fedcba98-7654-3210-0000-000000000000.00000000-0000-1234-5678-90abcdefffff") + } + + private func getAccount() -> MSALAccount { + let homeAccountId = MSALAccountId(accountIdentifier: "fedcba98-7654-3210-0000-000000000000.00000000-0000-1234-5678-90abcdefffff", objectId: "", tenantId: "https://contoso.com/tfp/tenantName") + let account = MSALAccount(username: "1234567890", homeAccountId: homeAccountId, environment: "contoso.com", tenantProfiles: []) + account?.lookupAccountIdentifier = getAccountIdentifier() + return account! + } + + private func getTokenResponse() -> MSIDCIAMTokenResponse { + let tokenResponse = MSIDCIAMTokenResponse() + tokenResponse.accessToken = "AccessToken" + tokenResponse.refreshToken = "refreshToken" + tokenResponse.idToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" + tokenResponse.scope = "user.read" + let clientInfo = try? MSIDClientInfo(rawClientInfo: "eyAidWlkIiA6ImZlZGNiYTk4LTc2NTQtMzIxMC0wMDAwLTAwMDAwMDAwMDAwMCIsICJ1dGlkIiA6IjAwMDAwMDAwLTAwMDAtMTIzNC01Njc4LTkwYWJjZGVmZmZmZiJ9") + tokenResponse.clientInfo = clientInfo + return tokenResponse + } + + private func getMSIDConfiguration(host: String) -> MSIDConfiguration { + let configuration = MSIDConfiguration(authority: try? MSIDCIAMAuthority(url: URL(string: host)!, validateFormat: false, context: nil), redirectUri: "", clientId: "clientId", target: "user.read") ?? MSIDConfiguration() + let authSchema = MSIDAuthenticationScheme() + configuration.authScheme = authSchema + return configuration + } + + private func clearCache() { + var accounts: [MSALAccount]! + XCTAssertNoThrow(accounts = try cacheAccessor.getAllAccounts(configuration: parameters.msidConfiguration)) + for account in accounts { + let identifier = MSIDAccountIdentifier(displayableId: account.username, homeAccountId: account.homeAccountId.identifier)! + XCTAssertNoThrow(try cacheAccessor.clearCache(accountIdentifier: identifier, + authority: parameters.msidConfiguration.authority, + clientId: parameters.msidConfiguration.clientId, + context: contextStub)) + } + } +} + +private struct ParametersStub { + var account: MSALAccount + var accountIdentifier: MSIDAccountIdentifier + var msidConfiguration: MSIDConfiguration +} + +private class ContextStub: MSIDRequestContext { + + var currentAppRequestMetadata = [AnyHashable : Any]() + var internalCorrelationId = UUID() + var telemetryId = UUID() + + init() { + guard let metadata = Bundle.main.infoDictionary else { return } + let appName = metadata["CFBundleDisplayName"] ?? (metadata["CFBundleName"] ?? "") + let appVer = metadata["CFBundleShortVersionString"] ?? "" + currentAppRequestMetadata[MSID_VERSION_KEY] = MSIDVersion.sdkVersion() + currentAppRequestMetadata[MSID_APP_NAME_KEY] = appName + currentAppRequestMetadata[MSID_APP_VER_KEY] = appVer + } + + func correlationId() -> UUID! { + internalCorrelationId + } + + func logComponent() -> String! { + MSIDVersion.sdkName() + } + + func telemetryRequestId() -> String! { + telemetryId.uuidString + } + + func appRequestMetadata() -> [AnyHashable : Any]! { + currentAppRequestMetadata + } +} diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthBaseControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthBaseControllerTests.swift new file mode 100644 index 0000000000..2f96fa411e --- /dev/null +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthBaseControllerTests.swift @@ -0,0 +1,270 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthBaseControllerTests: MSALNativeAuthTestCase { + + private var sut: MSALNativeAuthBaseController! + private var contextMock: MSALNativeAuthRequestContextMock! + private var clientId: String! + + override func setUp() { + super.setUp() + + contextMock = MSALNativeAuthRequestContextMock() + contextMock.mockTelemetryRequestId = "mock_id" + clientId = DEFAULT_TEST_CLIENT_ID + dispatcher = MSALNativeAuthTelemetryTestDispatcher() + + sut = MSALNativeAuthBaseController( + clientId: clientId + ) + } + + override func tearDown() { + super.tearDown() + MSIDTelemetry.sharedInstance().remove(dispatcher) + } + + func test_makeTelemetryApiEvent() { + + let event = sut.makeLocalTelemetryApiEvent(name: "anEvent", telemetryApiId: .telemetryApiIdSignUp, context: contextMock)! + let properties = event.getProperties()! + + XCTAssertEqual(properties[MSID_TELEMETRY_KEY_EVENT_NAME] as? String, "anEvent") + + let expectedTelemetryApiId = String(MSALNativeAuthTelemetryApiId.telemetryApiIdSignUp.rawValue) + XCTAssertEqual(properties[MSID_TELEMETRY_KEY_API_ID] as? String, expectedTelemetryApiId) + XCTAssertEqual(properties[MSID_TELEMETRY_KEY_CORRELATION_ID] as? String, DEFAULT_TEST_UID.uppercased()) + XCTAssertEqual(properties[MSID_TELEMETRY_KEY_CLIENT_ID] as? String, clientId) + } + + func test_stopTelemetryEvent_with_no_error() { + let event = sut.makeLocalTelemetryApiEvent(name: "anEvent", telemetryApiId: .telemetryApiIdSignInWithPasswordStart, context: contextMock) + let expectation = expectation(description: "Telemetry event test no error") + + dispatcher.setTestCallback { event in + let dict = event.getProperties()! + + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_EVENT_NAME] as? String, "anEvent") + XCTAssertNil(dict[MSID_TELEMETRY_KEY_API_ERROR_CODE]) + XCTAssertNil(dict[MSID_TELEMETRY_KEY_PROTOCOL_CODE]) + XCTAssertNil(dict[MSID_TELEMETRY_KEY_ERROR_DOMAIN]) + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_IS_SUCCESSFUL] as? String, "yes") + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_RESULT_STATUS] as? String, "succeeded") + XCTAssertNotNil(dict[MSID_TELEMETRY_KEY_START_TIME]) + XCTAssertNotNil(dict[MSID_TELEMETRY_KEY_END_TIME]) + + expectation.fulfill() + } + + MSIDTelemetry.sharedInstance().add(dispatcher) + + sut.startTelemetryEvent(event, context: contextMock) + sut.stopTelemetryEvent(event, context: contextMock) + + wait(for: [expectation], timeout: 1) + } + + func test_stopTelemetryEvent_withNegativeErrorCode() { + let event = sut.makeLocalTelemetryApiEvent(name: "anEvent", telemetryApiId: .telemetryApiIdSignInWithPasswordStart, context: contextMock) + let error = NSError(domain: "com.microsoft", code: -1) + + let expectation = expectation(description: "Telemetry event test negative error code") + + dispatcher.setTestCallback { event in + let dict = event.getProperties()! + + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_EVENT_NAME] as? String, "anEvent") + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_API_ERROR_CODE] as? String, "-1") + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_ERROR_DOMAIN] as? String, "com.microsoft") + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_IS_SUCCESSFUL] as? String, "no") + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_RESULT_STATUS] as? String, "failed") + XCTAssertNotNil(dict[MSID_TELEMETRY_KEY_START_TIME]) + XCTAssertNotNil(dict[MSID_TELEMETRY_KEY_END_TIME]) + + expectation.fulfill() + } + + MSIDTelemetry.sharedInstance().add(dispatcher) + + sut.startTelemetryEvent(event, context: contextMock) + sut.stopTelemetryEvent(event, context: contextMock, error: error) + + wait(for: [expectation], timeout: 1) + } + + func test_stopTelemetryEvent_withPositiveErrorCode() { + let event = sut.makeLocalTelemetryApiEvent(name: "anEvent", telemetryApiId: .telemetryApiIdSignInWithPasswordStart, context: contextMock) + let error = NSError(domain: "com.microsoft", code: 12) + + let expectation = expectation(description: "Telemetry event test positive error code") + + dispatcher.setTestCallback { event in + let dict = event.getProperties()! + + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_EVENT_NAME] as? String, "anEvent") + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_API_ERROR_CODE] as? String, "12") + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_ERROR_DOMAIN] as? String, "com.microsoft") + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_IS_SUCCESSFUL] as? String, "no") + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_RESULT_STATUS] as? String, "failed") + XCTAssertNotNil(dict[MSID_TELEMETRY_KEY_START_TIME]) + XCTAssertNotNil(dict[MSID_TELEMETRY_KEY_END_TIME]) + + expectation.fulfill() + } + + MSIDTelemetry.sharedInstance().add(dispatcher) + + sut.startTelemetryEvent(event, context: contextMock) + sut.stopTelemetryEvent(event, context: contextMock, error: error) + + wait(for: [expectation], timeout: 1) + } + + func test_stopTelemetryEvent_with_OAuthErrorKey() { + let event = sut.makeLocalTelemetryApiEvent(name: "anEvent", telemetryApiId: .telemetryApiIdSignInWithPasswordStart, context: contextMock) + let error = NSError(domain: "com.microsoft", code: 12, userInfo: ["MSIDOAuthErrorKey": "oauthErrorCode_mock"]) + + let expectation = expectation(description: "Telemetry event test OAuthErrorKey") + + dispatcher.setTestCallback { event in + let dict = event.getProperties()! + + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_EVENT_NAME] as? String, "anEvent") + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_API_ERROR_CODE] as? String, "12") + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_PROTOCOL_CODE] as? String, "oauthErrorCode_mock") + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_ERROR_DOMAIN] as? String, "com.microsoft") + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_IS_SUCCESSFUL] as? String, "no") + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_RESULT_STATUS] as? String, "failed") + XCTAssertNotNil(dict[MSID_TELEMETRY_KEY_START_TIME]) + XCTAssertNotNil(dict[MSID_TELEMETRY_KEY_END_TIME]) + + expectation.fulfill() + } + + MSIDTelemetry.sharedInstance().add(dispatcher) + + sut.startTelemetryEvent(event, context: contextMock) + sut.stopTelemetryEvent(event, context: contextMock, error: error) + + wait(for: [expectation], timeout: 1) + } + + func test_completeWithTelemetry_withInvalidParameters_shouldComplete() { + let event = sut.makeLocalTelemetryApiEvent(name: "anEvent", telemetryApiId: .telemetryApiIdSignInWithPasswordStart, context: contextMock) + + let exp1 = expectation(description: "Telemetry event") + let exp2 = expectation(description: "Completion event") + + dispatcher.setTestCallback { event in + let dict = event.getProperties()! + + XCTAssertEqual(dict[MSID_TELEMETRY_KEY_EVENT_NAME] as? String, "anEvent") + exp1.fulfill() + } + + MSIDTelemetry.sharedInstance().add(dispatcher) + + sut.startTelemetryEvent(event, context: contextMock) + + let responseNil: String? = nil + + sut.complete(event, response: responseNil, error: nil, context: contextMock) { _, _ in + exp2.fulfill() + } + + wait(for: [exp1, exp2], timeout: 1) + } + + func test_performRequest_withError() async { + let baseUrl = URL(string: "https://www.contoso.com")! + + let parameters = ["p1": "v1"] + + let httpResponse = HTTPURLResponse( + url: baseUrl, + statusCode: 500, + httpVersion: nil, + headerFields: nil + ) + + var urlRequest = URLRequest(url: baseUrl) + urlRequest.httpMethod = "POST" + + let testUrlResponse = MSIDTestURLResponse.request(baseUrl, reponse: httpResponse) + + testUrlResponse?.setError(ErrorMock.error) + + testUrlResponse?.setUrlFormEncodedBody(parameters) + testUrlResponse?.setResponseJSON([""]) + MSIDTestURLSession.add(testUrlResponse) + + let request = MSIDHttpRequest() + + request.urlRequest = urlRequest + request.parameters = parameters + + let result: Result = await sut.performRequest(request, context: contextMock) + + switch result { + case .failure(let error): + XCTAssertEqual(error as? ErrorMock, ErrorMock.error) + case .success: + XCTFail("Unexpected response") + } + } + + func test_performRequest_withSuccess() async { + let request = MSIDHttpRequest() + HttpModuleMockConfigurator.configure(request: request, responseJson: ["response"]) + + let result: Result<[String], Error> = await sut.performRequest(request, context: contextMock) + + switch result { + case .failure: + XCTFail("Unexpected response") + case .success(let response): + XCTAssertEqual(response.first, "response") + } + } + + func test_performRequest_withUnexpectedError() async { + let request = MSIDHttpRequest() + HttpModuleMockConfigurator.configure(request: request, responseJson: [nil] as [Any?]) + + let result: Result<[String], Error> = await sut.performRequest(request, context: contextMock) + + switch result { + case .failure(let error): + XCTAssertEqual(error as? MSALNativeAuthInternalError, .invalidResponse) + case .success: + XCTFail("Unexpected response") + } + } +} diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift new file mode 100644 index 0000000000..001508aa91 --- /dev/null +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift @@ -0,0 +1,215 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase { + + private var sut: MSALNativeAuthCredentialsController! + private var requestProviderMock: MSALNativeAuthTokenRequestProviderMock! + private var cacheAccessorMock: MSALNativeAuthCacheAccessorMock! + private var contextMock: MSALNativeAuthRequestContextMock! + private var factory: MSALNativeAuthResultFactoryMock! + private var responseValidatorMock: MSALNativeAuthTokenResponseValidatorMock! + private var tokenResult = MSIDTokenResult() + private var tokenResponse = MSIDCIAMTokenResponse() + private var defaultUUID = UUID(uuidString: DEFAULT_TEST_UID)! + + override func setUpWithError() throws { + requestProviderMock = .init() + cacheAccessorMock = .init() + contextMock = .init() + contextMock.mockTelemetryRequestId = "telemetry_request_id" + factory = .init() + responseValidatorMock = .init() + sut = .init( + clientId: DEFAULT_TEST_CLIENT_ID, + requestProvider: requestProviderMock, + cacheAccessor: cacheAccessorMock, + factory: factory, + responseValidator: responseValidatorMock + ) + tokenResponse.accessToken = "accessToken" + tokenResponse.scope = "openid profile email" + tokenResponse.idToken = "idToken" + tokenResponse.refreshToken = "refreshToken" + + try super.setUpWithError() + } + + // MARK: get native user account tests + + func test_whenNoAccountPresent_shouldReturnNoAccounts() { + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let accountResult = sut.retrieveUserAccountResult(context: expectedContext) + XCTAssertNil(accountResult) + } + + func test_whenNoTokenPresent_shouldReturnNoAccounts() { + let account = MSALNativeAuthUserAccountResultStub.account + let authTokens = MSALNativeAuthUserAccountResultStub.authTokens + let userAccountResult = MSALNativeAuthUserAccountResult( + account: account, + authTokens: authTokens, + configuration: MSALNativeAuthConfigStubs.configuration, + cacheAccessor: MSALNativeAuthCacheAccessorMock() + ) + factory.mockMakeUserAccountResult(userAccountResult) + cacheAccessorMock.mockUserAccounts = [account] + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let accountResult = sut.retrieveUserAccountResult(context: expectedContext) + XCTAssertNil(accountResult) + } + + func test_whenAccountSet_shouldReturnAccount() async { + let account = MSALNativeAuthUserAccountResultStub.account + let authTokens = MSALNativeAuthUserAccountResultStub.authTokens + + let userAccountResult = MSALNativeAuthUserAccountResult( + account: account, + authTokens: authTokens, + configuration: MSALNativeAuthConfigStubs.configuration, + cacheAccessor: MSALNativeAuthCacheAccessorMock() + ) + + factory.mockMakeUserAccountResult(userAccountResult) + cacheAccessorMock.mockUserAccounts = [account] + cacheAccessorMock.mockAuthTokens = authTokens + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let accountResult = sut.retrieveUserAccountResult(context: expectedContext) + XCTAssertEqual(accountResult?.account.username, account.username) + XCTAssertEqual(accountResult?.idToken, authTokens.rawIdToken) + XCTAssertEqual(accountResult?.scopes, authTokens.accessToken?.scopes.array as? [String]) + XCTAssertEqual(accountResult?.expiresOn, authTokens.accessToken?.expiresOn) + XCTAssertTrue(NSDictionary(dictionary: accountResult?.account.accountClaims ?? [:]).isEqual(to: account.accountClaims ?? [:])) + } + + func test_whenCreateRequestFails_shouldReturnError() async throws { + let expectation = expectation(description: "CredentialsController") + + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let authTokens = MSALNativeAuthUserAccountResultStub.authTokens + + requestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, credentialToken: nil, signInSLT: nil, grantType: MSALNativeAuthGrantType.refreshToken, scope: "" , password: nil, oobCode: nil, includeChallengeType: true, refreshToken: "refreshToken") + requestProviderMock.throwingTokenError = ErrorMock.error + + let helper = CredentialsTestValidatorHelper(expectation: expectation, expectedError: RetrieveAccessTokenError(type: .generalError)) + + let result = await sut.refreshToken(context: expectedContext, authTokens: authTokens) + helper.onAccessTokenRetrieveError(result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdRefreshToken, isSuccessful: false) + } + + func test_whenAccountSet_shouldRefreshToken() async { + let expectation = expectation(description: "CredentialsController") + + let account = MSALNativeAuthUserAccountResultStub.account + let authTokens = MSALNativeAuthUserAccountResultStub.authTokens + let userAccountResult = MSALNativeAuthUserAccountResult(account: account, + authTokens: authTokens, + configuration: MSALNativeAuthConfigStubs.configuration, cacheAccessor: MSALNativeAuthCacheAccessorMock()) + + let request = MSIDHttpRequest() + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + requestProviderMock.result = request + + let expectedAccessToken = "accessToken" + let helper = CredentialsTestValidatorHelper(expectation: expectation, expectedAccessToken: expectedAccessToken) + + factory.mockMakeUserAccountResult(userAccountResult) + tokenResult.accessToken = MSIDAccessToken() + tokenResult.accessToken.accessToken = expectedAccessToken + responseValidatorMock.tokenValidatedResponse = .success(tokenResponse) + cacheAccessorMock.mockUserAccounts = [account] + cacheAccessorMock.mockAuthTokens = authTokens + cacheAccessorMock.expectedMSIDTokenResult = tokenResult + let result = await sut.refreshToken(context: expectedContext, authTokens: authTokens) + helper.onAccessTokenRetrieveCompleted(result) + + await fulfillment(of: [expectation], timeout: 1) + XCTAssertEqual(expectedAccessToken, authTokens.accessToken?.accessToken) + } + + func test_whenErrorIsReturnedFromValidator_itIsCorrectlyTranslatedToDelegateError() async { + await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .generalError) + await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .expiredToken(message: nil)) + await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .authorizationPending(message: nil)) + await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .slowDown(message: nil)) + await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .invalidRequest(message: nil)) + await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: MSALNativeAuthErrorMessage.invalidServerResponse), validatorError: .invalidServerResponse) + await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Invalid Client ID"), validatorError: .invalidClient(message: "Invalid Client ID")) + await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Unsupported challenge type"), validatorError: .unsupportedChallengeType(message: "Unsupported challenge type")) + await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Invalid scope"), validatorError: .invalidScope(message: "Invalid scope")) + await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .refreshTokenExpired), validatorError: .expiredRefreshToken(message: nil)) + await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .browserRequired, message: "MFA currently not supported. Use the browser instead"), validatorError: .strongAuthRequired(message: "MFA currently not supported. Use the browser instead")) + } + + private func checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError, validatorError: MSALNativeAuthTokenValidatedErrorType) async { + let request = MSIDHttpRequest() + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let authTokens = MSALNativeAuthUserAccountResultStub.authTokens + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let expectation = expectation(description: "CredentialsController") + + requestProviderMock.result = request + + let helper = CredentialsTestValidatorHelper(expectation: expectation, expectedError: publicError) + responseValidatorMock.tokenValidatedResponse = .error(validatorError) + + let result = await sut.refreshToken(context: expectedContext, authTokens: authTokens) + helper.onAccessTokenRetrieveError(result) + + checkTelemetryEventResult(id: .telemetryApiIdRefreshToken, isSuccessful: false) + receivedEvents.removeAll() + await fulfillment(of: [expectation], timeout: 1) + } + + private func checkTelemetryEventResult(id: MSALNativeAuthTelemetryApiId, isSuccessful: Bool) { + XCTAssertEqual(receivedEvents.count, 1) + + guard let telemetryEventDict = receivedEvents.first else { + return XCTFail("Telemetry test fail") + } + + let expectedApiId = String(id.rawValue) + XCTAssertEqual(telemetryEventDict["api_id"] as? String, expectedApiId) + XCTAssertEqual(telemetryEventDict["event_name"] as? String, "api_event" ) + XCTAssertEqual(telemetryEventDict["correlation_id" ] as? String, DEFAULT_TEST_UID.uppercased()) + XCTAssertEqual(telemetryEventDict["is_successfull"] as? String, isSuccessful ? "yes" : "no") + XCTAssertEqual(telemetryEventDict["status"] as? String, isSuccessful ? "succeeded" : "failed") + XCTAssertNotNil(telemetryEventDict["start_time"]) + XCTAssertNotNil(telemetryEventDict["stop_time"]) + XCTAssertNotNil(telemetryEventDict["response_time"]) + } +} diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift new file mode 100644 index 0000000000..e94b73e56f --- /dev/null +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift @@ -0,0 +1,923 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { + + private var sut: MSALNativeAuthResetPasswordController! + private var contextMock: MSALNativeAuthRequestContext! + private var requestProviderMock: MSALNativeAuthResetPasswordRequestProviderMock! + private var validatorMock: MSALNativeAuthResetPasswordResponseValidatorMock! + + + private var resetPasswordStartParams: MSALNativeAuthResetPasswordStartRequestProviderParameters { + .init( + username: "user@contoso.com", + context: contextMock + ) + } + + override func setUpWithError() throws { + try super.setUpWithError() + + contextMock = .init(correlationId: .init(uuidString: DEFAULT_TEST_UID)!) + requestProviderMock = .init() + validatorMock = .init() + + sut = .init(config: MSALNativeAuthConfigStubs.configuration, + requestProvider: requestProviderMock, + responseValidator: validatorMock + ) + } + + // MARK: - ResetPasswordStart (/start request) tests + + func test_whenResetPasswordStart_cantCreateRequest_it_returns_unexpectedError() async { + requestProviderMock.mockStartRequestFunc(nil, throwError: true) + requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordStartValidatorHelper(exp) + + let result = await sut.resetPassword(parameters: resetPasswordStartParams) + helper.onResetPasswordError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordStart, isSuccessful: false) + } + + func test_whenResetPasswordStart_returnsSuccess_it_callsChallenge() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams + validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError) + _ = prepareResetPasswordStartValidatorHelper() + + _ = await sut.resetPassword(parameters: resetPasswordStartParams) + + XCTAssertTrue(requestProviderMock.challengeCalled) + } + + func test_whenResetPasswordStartPassword_returns_redirect_it_returnsBrowserRequiredError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams + validatorMock.mockValidateResetPasswordStartFunc(.redirect) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordStartValidatorHelper(exp) + + let result = await sut.resetPassword(parameters: resetPasswordStartParams) + helper.onResetPasswordError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .browserRequired) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordStart, isSuccessful: false) + } + + func test_whenResetPasswordStart_returns_error_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams + validatorMock.mockValidateResetPasswordStartFunc(.error(.userNotFound(message: nil))) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordStartValidatorHelper(exp) + + let result = await sut.resetPassword(parameters: resetPasswordStartParams) + helper.onResetPasswordError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .userNotFound) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordStart, isSuccessful: false) + } + + func test_whenValidatorInResetPasswordStart_returns_unexpectedError_it_returnsGeneralError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams + validatorMock.mockValidateResetPasswordStartFunc(.unexpectedError) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordStartValidatorHelper(exp) + + let result = await sut.resetPassword(parameters: resetPasswordStartParams) + helper.onResetPasswordError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordStart, isSuccessful: false) + } + + // MARK: - ResetPasswordStart (/challenge request) tests + + func test_whenResetPasswordStart_challenge_cantCreateRequest_it_returns_unexpectedError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams + validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) + requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordStartValidatorHelper(exp) + + let result = await sut.resetPassword(parameters: resetPasswordStartParams) + helper.onResetPasswordError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordStart, isSuccessful: false) + } + + func test_whenResetPasswordStart_challenge_succeeds_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams + validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateResetPasswordChallengeFunc(.success("sentTo", .email, 4, "resetPasswordToken")) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordStartValidatorHelper(exp) + + let result = await sut.resetPassword(parameters: resetPasswordStartParams) + helper.onResetPasswordCodeRequired(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordCodeRequiredCalled) + XCTAssertEqual(helper.newState?.flowToken, "resetPasswordToken") + XCTAssertEqual(helper.sentTo, "sentTo") + XCTAssertEqual(helper.channelTargetType, .email) + XCTAssertEqual(helper.codeLength, 4) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordStart, isSuccessful: true) + } + + func test_whenResetPasswordStart_challenge_returns_redirect_it_returnsRedirectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams + validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateResetPasswordChallengeFunc(.redirect) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordStartValidatorHelper(exp) + + let result = await sut.resetPassword(parameters: resetPasswordStartParams) + helper.onResetPasswordError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .browserRequired) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordStart, isSuccessful: false) + } + + func test_whenResetPasswordStart_challenge_returns_error_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams + validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + let error : MSALNativeAuthResetPasswordChallengeValidatedResponse = .error( + MSALNativeAuthResetPasswordChallengeResponseError(error: .expiredToken, + errorDescription: "Expired Token", + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + target: nil)) + validatorMock.mockValidateResetPasswordChallengeFunc(error) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordStartValidatorHelper(exp) + + let result = await sut.resetPassword(parameters: resetPasswordStartParams) + helper.onResetPasswordError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Expired Token") + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordStart, isSuccessful: false) + } + + func test_whenValidatorInResetPasswordStart_challenge_returns_unexpectedError_it_returnsGeneralError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams + validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordStartValidatorHelper(exp) + + let result = await sut.resetPassword(parameters: resetPasswordStartParams) + helper.onResetPasswordError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordStart, isSuccessful: false) + } + + // MARK: - ResendCode tests + + func test_whenResetPasswordResendCode_cantCreateRequest_it_returns_unexpectedError() async { + requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordResendCodeValidatorHelper(exp) + + let result = await sut.resendCode(passwordResetToken: "passwordResetToken", context: contextMock) + helper.onResetPasswordResendCodeError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordResendCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordResendCode, isSuccessful: false) + } + + func test_whenResetPasswordResendCode_succeeds_it_returnsResetPasswordResendCodeRequired() async { + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + + validatorMock.mockValidateResetPasswordChallengeFunc(.success("sentTo", .email, 4, "flowToken response")) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordResendCodeValidatorHelper(exp) + + let result = await sut.resendCode(passwordResetToken: "passwordResetToken", context: contextMock) + helper.onResetPasswordResendCodeRequired(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordResendCodeRequiredCalled) + XCTAssertEqual(helper.newState?.flowToken, "flowToken response") + XCTAssertEqual(helper.sentTo, "sentTo") + XCTAssertEqual(helper.channelTargetType, .email) + XCTAssertEqual(helper.codeLength, 4) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordResendCode, isSuccessful: true) + } + + func test_whenResetPasswordResendCode_returns_error_it_returnsCorrectError() async { + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + let error : MSALNativeAuthResetPasswordChallengeValidatedResponse = .error( + MSALNativeAuthResetPasswordChallengeResponseError(error: .invalidRequest, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + target: nil)) + validatorMock.mockValidateResetPasswordChallengeFunc(error) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordResendCodeValidatorHelper(exp) + + let result = await sut.resendCode(passwordResetToken: "passwordResetToken", context: contextMock) + helper.onResetPasswordResendCodeError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordResendCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordResendCode, isSuccessful: false) + } + + func test_whenResetPasswordResendCode_returns_redirect_it_returnsCorrectError() async { + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateResetPasswordChallengeFunc(.redirect) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordResendCodeValidatorHelper(exp) + + let result = await sut.resendCode(passwordResetToken: "passwordResetToken", context: contextMock) + helper.onResetPasswordResendCodeError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordResendCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordResendCode, isSuccessful: false) + } + + func test_whenResetPasswordResendCode_returns_unexpectedError_it_returnsCorrectError() async { + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordResendCodeValidatorHelper(exp) + + let result = await sut.resendCode(passwordResetToken: "passwordResetToken", context: contextMock) + helper.onResetPasswordResendCodeError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordResendCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordResendCode, isSuccessful: false) + } + + // MARK: - SubmitCode tests + + func test_whenResetPasswordSubmitCode_cantCreateRequest_it_returns_unexpectedError() async { + requestProviderMock.mockContinueRequestFunc(nil, throwError: true) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode(code: "1234", passwordResetToken: "passwordResetToken", context: contextMock) + helper.onResetPasswordVerifyCodeError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordVerifyCodeErrorCalled) + XCTAssertNil(helper.newCodeRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmitCode, isSuccessful: false) + } + + func test_whenResetPasswordSubmitCode_succeeds_it_returnsPasswordRequired() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + validatorMock.mockValidateResetPasswordContinueFunc(.success(passwordSubmitToken: "")) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode(code: "1234", passwordResetToken: "passwordResetToken", context: contextMock) + helper.onPasswordRequired(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onPasswordRequiredCalled) + XCTAssertNotNil(helper.newPasswordRequiredState) + XCTAssertNil(helper.newCodeRequiredState) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmitCode, isSuccessful: true) + } + + func test_whenResetPasswordSubmitCode_returns_invalidOOB_it_returnsInvalidCode() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + validatorMock.mockValidateResetPasswordContinueFunc(.invalidOOB) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode(code: "1234", passwordResetToken: "passwordResetToken", context: contextMock) + helper.onResetPasswordVerifyCodeError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordVerifyCodeErrorCalled) + XCTAssertEqual(helper.newCodeRequiredState?.flowToken, "passwordResetToken") + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .invalidCode) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmitCode, isSuccessful: false) + } + + func test_whenResetPasswordSubmitCode_returns_error_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + let error : MSALNativeAuthResetPasswordContinueValidatedResponse = .error( + MSALNativeAuthResetPasswordContinueResponseError(error: .invalidRequest, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + target: nil, + passwordResetToken: nil)) + validatorMock.mockValidateResetPasswordContinueFunc(error) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode(code: "1234", passwordResetToken: "passwordResetToken", context: contextMock) + helper.onResetPasswordVerifyCodeError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordVerifyCodeErrorCalled) + XCTAssertNil(helper.newCodeRequiredState?.flowToken) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmitCode, isSuccessful: false) + } + + func test_whenResetPasswordSubmitCode_returns_unexpectedError_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + validatorMock.mockValidateResetPasswordContinueFunc(.unexpectedError) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode(code: "1234", passwordResetToken: "passwordResetToken", context: contextMock) + helper.onResetPasswordVerifyCodeError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordVerifyCodeErrorCalled) + XCTAssertNil(helper.newCodeRequiredState?.flowToken) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmitCode, isSuccessful: false) + } + + // MARK: - SubmitPassword tests + + func test_whenResetPasswordSubmitPassword_cantCreateRequest_it_returns_unexpectedError() async { + requestProviderMock.mockSubmitRequestFunc(nil, throwError: true) + requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + helper.onResetPasswordRequiredError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) + } + + func test_whenSubmitPassword_succeeds_it_returnsCompleted() async { + requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() + validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() + validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .succeeded)) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + helper.onResetPasswordCompleted(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordCompletedCalled) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: true) + } + + func test_whenResetPasswordSubmitPassword_returns_passwordError_it_returnsCorrectError() async { + requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() + let error : MSALNativeAuthResetPasswordSubmitValidatedResponse = .passwordError(error: + MSALNativeAuthResetPasswordSubmitResponseError(error: .passwordTooWeak, + errorDescription: "Password too weak", + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + target: nil)) + validatorMock.mockValidateResetPasswordSubmitFunc(error) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + helper.onResetPasswordRequiredError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) + XCTAssertEqual(helper.newPasswordRequiredState?.flowToken, "passwordSubmitToken") + XCTAssertEqual(helper.error?.type, .invalidPassword) + XCTAssertEqual(helper.error?.errorDescription, "Password too weak") + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) + } + + func test_whenResetPasswordSubmitPassword_returns_error_it_returnsCorrectError() async { + requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() + let error : MSALNativeAuthResetPasswordSubmitValidatedResponse = .error( + MSALNativeAuthResetPasswordSubmitResponseError(error: .invalidRequest, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + target: nil)) + validatorMock.mockValidateResetPasswordSubmitFunc(error) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + helper.onResetPasswordRequiredError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) + } + + func test_whenResetPasswordSubmitPassword_returns_unexpectedError_it_returnsCorrectError() async { + requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() + validatorMock.mockValidateResetPasswordSubmitFunc(.unexpectedError) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + helper.onResetPasswordRequiredError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) + } + + // MARK: - SubmitPassword - poll completion tests + + func test_whenSubmitPassword_pollCompletion_returns_failed_it_returnsResetPasswordRequiredError() async { + requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() + validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() + validatorMock.mockValidateResetPasswordPollCompletionFunc(.unexpectedError) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + helper.onResetPasswordRequiredError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) + } + + func test_whenSubmitPassword_pollCompletion_returns_unexpectedError_it_returnsCorrectError() async { + requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() + validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() + validatorMock.mockValidateResetPasswordPollCompletionFunc(.unexpectedError) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + helper.onResetPasswordRequiredError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) + } + + func test_whenSubmitPassword_pollCompletion_returns_passwordError_it_returnsCorrectError() async { + requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() + validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() + let error : MSALNativeAuthResetPasswordPollCompletionValidatedResponse = + .passwordError(error: + MSALNativeAuthResetPasswordPollCompletionResponseError(error: .passwordBanned, + errorDescription: "Password banned", + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + target: nil)) + + validatorMock.mockValidateResetPasswordPollCompletionFunc(error) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + helper.onResetPasswordRequiredError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) + XCTAssertEqual(helper.newPasswordRequiredState?.flowToken, "passwordResetToken") + XCTAssertEqual(helper.error?.type, .invalidPassword) + XCTAssertEqual(helper.error?.errorDescription, "Password banned") + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) + } + + func test_whenSubmitPassword_pollCompletion_returns_error_it_returnsCorrectError() async { + requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() + validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() + let error : MSALNativeAuthResetPasswordPollCompletionValidatedResponse = .error( + MSALNativeAuthResetPasswordPollCompletionResponseError(error: .expiredToken, + errorDescription: "Expired Token", + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + target: nil)) + validatorMock.mockValidateResetPasswordPollCompletionFunc(error) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + helper.onResetPasswordRequiredError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) + XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Expired Token") + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) + } + + func test_whenSubmitPassword_pollCompletion_returns_notStarted_it_returnsCorrectErrorAfterRetries() async { + requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() + validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 1)) + requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() + + validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .notStarted)) + + prepareMockRequestsForPollCompletionRetries(5) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + helper.onResetPasswordRequiredError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) + } + + func test_whenSubmitPassword_pollCompletion_returns_failed_it_returnsError() async { + requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() + validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() + validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .failed)) + + prepareMockRequestsForPollCompletionRetries(5) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + helper.onResetPasswordRequiredError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) + } + + func test_whenSubmitPassword_pollCompletion_returns_inProgress_it_returnsErrorAfterRetries() async { + requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() + validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() + validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .inProgress)) + + prepareMockRequestsForPollCompletionRetries(5) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + helper.onResetPasswordRequiredError(result) + + await fulfillment(of: [exp]) + XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) + } + + + // MARK: - Common Methods + + private func checkTelemetryEventResult(id: MSALNativeAuthTelemetryApiId, isSuccessful: Bool) { + XCTAssertEqual(receivedEvents.count, 1) + + guard let telemetryEventDict = receivedEvents.first else { + return XCTFail("Telemetry test fail") + } + + let expectedApiId = String(id.rawValue) + XCTAssertEqual(telemetryEventDict["api_id"] as? String, expectedApiId) + XCTAssertEqual(telemetryEventDict["event_name"] as? String, "api_event" ) + XCTAssertEqual(telemetryEventDict["correlation_id" ] as? String, DEFAULT_TEST_UID.uppercased()) + XCTAssertEqual(telemetryEventDict["is_successfull"] as? String, isSuccessful ? "yes" : "no") + XCTAssertEqual(telemetryEventDict["status"] as? String, isSuccessful ? "succeeded" : "failed") + XCTAssertNotNil(telemetryEventDict["start_time"]) + XCTAssertNotNil(telemetryEventDict["stop_time"]) + XCTAssertNotNil(telemetryEventDict["response_time"]) + } + + private func prepareResetPasswordStartValidatorHelper(_ expectation: XCTestExpectation? = nil) -> ResetPasswordStartTestsValidatorHelper { + let helper = ResetPasswordStartTestsValidatorHelper(expectation: expectation) + XCTAssertFalse(helper.onResetPasswordErrorCalled) + XCTAssertFalse(helper.onResetPasswordCodeRequiredCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertNil(helper.error) + + return helper + } + + private func prepareResetPasswordResendCodeValidatorHelper(_ expectation: XCTestExpectation? = nil) -> ResetPasswordResendCodeTestsValidatorHelper { + let helper = ResetPasswordResendCodeTestsValidatorHelper(expectation: expectation) + XCTAssertFalse(helper.onResetPasswordResendCodeErrorCalled) + XCTAssertFalse(helper.onResetPasswordResendCodeRequiredCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertNil(helper.error) + + return helper + } + + private func prepareResetPasswordSubmitCodeValidatorHelper(_ expectation: XCTestExpectation? = nil) -> ResetPasswordVerifyCodeTestsValidatorHelper { + let helper = ResetPasswordVerifyCodeTestsValidatorHelper(expectation: expectation) + XCTAssertFalse(helper.onPasswordRequiredCalled) + XCTAssertFalse(helper.onResetPasswordVerifyCodeErrorCalled) + XCTAssertNil(helper.newCodeRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertNil(helper.error) + + return helper + } + + private func prepareResetPasswordSubmitPasswordValidatorHelper(_ expectation: XCTestExpectation? = nil) -> ResetPasswordRequiredTestsValidatorHelper { + let helper = ResetPasswordRequiredTestsValidatorHelper(expectation: expectation) + XCTAssertFalse(helper.onResetPasswordCompletedCalled) + XCTAssertFalse(helper.onResetPasswordRequiredErrorCalled) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertNil(helper.error) + + return helper + } + + private func expectedChallengeParams(token: String = "passwordResetToken") -> (token: String, context: MSIDRequestContext) { + return (token: token, context: contextMock) + } + + private func expectedContinueParams( + grantType: MSALNativeAuthGrantType = .oobCode, + token: String = "passwordResetToken", + oobCode: String? = "1234" + ) -> MSALNativeAuthResetPasswordContinueRequestParameters { + .init( + context: contextMock, + passwordResetToken: token, + grantType: grantType, + oobCode: oobCode + ) + } + + private func expectedSubmitParams( + token: String = "passwordSubmitToken", + password: String = "password" + ) -> MSALNativeAuthResetPasswordSubmitRequestParameters { + .init( + context: contextMock, + passwordSubmitToken: token, + newPassword: password) + } + + private func expectedPollCompletionParameters( + token: String = "passwordResetToken" + ) -> MSALNativeAuthResetPasswordPollCompletionRequestParameters { + .init( + context: contextMock, + passwordResetToken: token) + } + + private func prepareMockRequest() -> MSIDHttpRequest { + let request = MSIDHttpRequest() + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + return request + } + + private func prepareMockRequestsForPollCompletionRetries(_ count: Int) { + for _ in 1...count { + _ = prepareMockRequest() + } + } +} diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift new file mode 100644 index 0000000000..680ff9f9d2 --- /dev/null +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift @@ -0,0 +1,1083 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { + + private var sut: MSALNativeAuthSignInController! + private var signInRequestProviderMock: MSALNativeAuthSignInRequestProviderMock! + private var tokenRequestProviderMock: MSALNativeAuthTokenRequestProviderMock! + private var cacheAccessorMock: MSALNativeAuthCacheAccessorMock! + private var signInResponseValidatorMock: MSALNativeAuthSignInResponseValidatorMock! + private var tokenResponseValidatorMock: MSALNativeAuthTokenResponseValidatorMock! + private var contextMock: MSALNativeAuthRequestContextMock! + private var tokenResult = MSIDTokenResult() + private var tokenResponse = MSIDCIAMTokenResponse() + private var defaultUUID = UUID(uuidString: DEFAULT_TEST_UID)! + private let defaultScopes = "openid profile offline_access" + + override func setUpWithError() throws { + signInRequestProviderMock = .init() + tokenRequestProviderMock = .init() + cacheAccessorMock = .init() + signInResponseValidatorMock = .init() + tokenResponseValidatorMock = .init() + contextMock = .init() + contextMock.mockTelemetryRequestId = "telemetry_request_id" + + sut = .init( + clientId: DEFAULT_TEST_CLIENT_ID, + signInRequestProvider: signInRequestProviderMock, + tokenRequestProvider: tokenRequestProviderMock, + cacheAccessor: cacheAccessorMock, + factory: MSALNativeAuthResultFactoryMock(), + signInResponseValidator: signInResponseValidatorMock, + tokenResponseValidator: tokenResponseValidatorMock + ) + tokenResponse.accessToken = "accessToken" + tokenResponse.scope = "openid profile email" + tokenResponse.idToken = "idToken" + tokenResponse.refreshToken = "refreshToken" + tokenResult.rawIdToken = "idToken" + + try super.setUpWithError() + } + + // MARK: sign in with username and password tests + + func test_whenCreateRequestFails_shouldReturnError() async throws { + let expectation = expectation(description: "SignInController") + + let expectedUsername = "username" + let expectedPassword = "password" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + signInRequestProviderMock.expectedUsername = expectedUsername + signInRequestProviderMock.expectedContext = expectedContext + signInRequestProviderMock.throwingInitError = ErrorMock.error + + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInPasswordStartError(type: .generalError)) + + let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + + helper.onSignInPasswordError(result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithPasswordStart, isSuccessful: false) + } + + func test_whenUserSpecifiesScope_defaultScopesShouldBeIncluded() async throws { + let expectation = expectation(description: "SignInController") + + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedPassword = "password" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let expectedScopes = "scope1 scope2 openid profile offline_access" + let credentialToken = "credentialToken" + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) + + signInRequestProviderMock.result = request + signInRequestProviderMock.expectedUsername = expectedUsername + signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedContext = expectedContext + + tokenRequestProviderMock.result = request + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: expectedScopes, password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) + + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInPasswordStartError(type: .generalError)) + + let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: ["scope1", "scope2"])) + + helper.onSignInPasswordError(result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithPasswordStart, isSuccessful: false) + } + + func test_whenUserSpecifiesScopes_NoDuplicatedScopeShouldBeSent() async throws { + let expectation = expectation(description: "SignInController") + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedPassword = "password" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let expectedScopes = "scope1 openid profile offline_access" + let credentialToken = "credentialToken" + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) + + signInRequestProviderMock.result = request + signInRequestProviderMock.expectedUsername = expectedUsername + signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedContext = expectedContext + + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: expectedScopes, password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.throwingTokenError = ErrorMock.error + + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInPasswordStartError(type: .generalError)) + + let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: ["scope1", "openid", "profile"])) + + helper.onSignInPasswordError(result) + + await fulfillment(of: [expectation], timeout: 1) + } + + func test_successfulResponseAndValidation_shouldCompleteSignIn() async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedPassword = "password" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let credentialToken = "credentialToken" + + let expectation = expectation(description: "SignInController") + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) + + signInRequestProviderMock.result = request + signInRequestProviderMock.expectedUsername = expectedUsername + signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedContext = expectedContext + + tokenRequestProviderMock.result = request + tokenRequestProviderMock.expectedUsername = expectedUsername + tokenRequestProviderMock.expectedContext = expectedContext + + let userAccountResult = MSALNativeAuthUserAccountResultStub.result + + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedUserAccountResult: userAccountResult) + tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) + tokenResponseValidatorMock.expectedTokenResponse = tokenResponse + + cacheAccessorMock.expectedMSIDTokenResult = tokenResult + let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + + helper.onSignInCompleted(result) + + await fulfillment(of: [expectation], timeout: 1) + XCTAssertTrue(cacheAccessorMock.validateAndSaveTokensWasCalled) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithPasswordStart, isSuccessful: true) + } + + func test_successfulResponseAndUnsuccessfulValidation_shouldReturnError() async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedPassword = "password" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let credentialToken = "credentialToken" + + let expectation = expectation(description: "SignInController") + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) + + signInRequestProviderMock.result = request + signInRequestProviderMock.expectedUsername = expectedUsername + signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedContext = expectedContext + + tokenRequestProviderMock.result = request + tokenRequestProviderMock.expectedUsername = expectedUsername + tokenRequestProviderMock.expectedContext = expectedContext + + let userAccountResult = MSALNativeAuthUserAccountResultStub.result + + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedUserAccountResult: userAccountResult) + tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) + tokenResponseValidatorMock.expectedTokenResponse = tokenResponse + + cacheAccessorMock.expectedMSIDTokenResult = nil + let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + + helper.onSignInPasswordError(result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithPasswordStart, isSuccessful: false) + } + + func test_errorResponse_shouldReturnError() async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedPassword = "password" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let credentialToken = "invalid token" + + let expectation = expectation(description: "SignInController") + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .error(.invalidToken(message: nil)) + + signInRequestProviderMock.result = request + signInRequestProviderMock.expectedUsername = expectedUsername + signInRequestProviderMock.expectedContext = expectedContext + + tokenRequestProviderMock.result = request + tokenRequestProviderMock.expectedUsername = expectedUsername + tokenRequestProviderMock.expectedContext = expectedContext + + let userAccountResult = MSALNativeAuthUserAccountResultStub.result + + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedUserAccountResult: userAccountResult) + tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) + tokenResponseValidatorMock.expectedTokenResponse = tokenResponse + + let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + + helper.onSignInPasswordError(result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithPasswordStart, isSuccessful: false) + } + + func test_whenErrorIsReturnedFromValidator_itIsCorrectlyTranslatedToDelegateError() async { + await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError), validatorError: .generalError) + await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError), validatorError: .expiredToken(message: nil)) + await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError), validatorError: .authorizationPending(message: nil)) + await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError), validatorError: .slowDown(message: nil)) + await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError), validatorError: .invalidRequest(message: nil)) + await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError, message: "Invalid server response"), validatorError: .invalidServerResponse) + await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError, message: "Invalid Client ID"), validatorError: .invalidClient(message: "Invalid Client ID")) + await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError, message: "Unsupported challenge type"), validatorError: .unsupportedChallengeType(message: "Unsupported challenge type")) + await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError, message: "Invalid scope"), validatorError: .invalidScope(message: "Invalid scope")) + await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .userNotFound), validatorError: .userNotFound(message: nil)) + await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .invalidPassword), validatorError: .invalidPassword(message: nil)) + } + + func test_whenCredentialsAreRequired_browserRequiredErrorIsReturned() async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedPassword = "password" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let credentialToken = "credentialToken" + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) + + signInRequestProviderMock.result = request + signInRequestProviderMock.expectedUsername = expectedUsername + signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedContext = expectedContext + + tokenRequestProviderMock.result = request + tokenRequestProviderMock.expectedCredentialToken = credentialToken + + let expectation = expectation(description: "SignInController") + + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: .init(type: .browserRequired, message: MSALNativeAuthErrorMessage.unsupportedMFA)) + + tokenResponseValidatorMock.tokenValidatedResponse = .error(.strongAuthRequired(message: "MFA currently not supported. Use the browser instead")) + + let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + + helper.onSignInPasswordError(result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithPasswordStart, isSuccessful: false) + } + + func test_whenSignInUsingPassword_apiReturnsChallengeTypeOOB_codeRequiredShouldBeCalled() async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedPassword = "password" + let expectedSentTo = "sentTo" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let credentialToken = "credentialToken" + + let expectation = expectation(description: "SignInController") + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: expectedSentTo, channelType: expectedChannelTargetType, codeLength: expectedCodeLength) + + signInRequestProviderMock.result = request + signInRequestProviderMock.expectedUsername = expectedUsername + signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedContext = expectedContext + + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation) + helper.expectedSentTo = expectedSentTo + helper.expectedChannelTargetType = expectedChannelTargetType + helper.expectedCodeLength = expectedCodeLength + + let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + result.telemetryUpdate?(.success(())) + + helper.onSignInCodeRequired(result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithPasswordStart, isSuccessful: true) + } + + func test_whenSignInUsingPassword_apiReturnsChallengeTypeOOB__butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedPassword = "password" + let expectedSentTo = "sentTo" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let credentialToken = "credentialToken" + + let expectation = expectation(description: "SignInController") + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: expectedSentTo, channelType: expectedChannelTargetType, codeLength: expectedCodeLength) + + signInRequestProviderMock.result = request + signInRequestProviderMock.expectedUsername = expectedUsername + signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedContext = expectedContext + + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation) + helper.expectedSentTo = expectedSentTo + helper.expectedChannelTargetType = expectedChannelTargetType + helper.expectedCodeLength = expectedCodeLength + + let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + result.telemetryUpdate?(.failure(.init(message: "error"))) + + helper.onSignInCodeRequired(result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithPasswordStart, isSuccessful: false) + } + + // MARK: sign in with username and code + + func test_whenSignInWithCodeStartWithValidInfo_codeRequiredShouldBeCalled() async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let sentTo = "sentTo" + let channelTargetType = MSALNativeAuthChannelType.email + let codeLength = 4 + let credentialToken = "credentialToken" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let expectation = expectation(description: "SignInController") + + signInRequestProviderMock.result = request + signInRequestProviderMock.expectedUsername = expectedUsername + signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedContext = expectedContext + + let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedSentTo: sentTo, expectedChannelTargetType: channelTargetType, expectedCodeLength: codeLength) + + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: sentTo, channelType: channelTargetType, codeLength: codeLength) + + let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + + helper.onSignInCodeRequired(result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithCodeStart, isSuccessful: true) + } + + func test_afterSignInWithCodeSubmitCode_signInShouldCompleteSuccessfully() { + let request = MSIDHttpRequest() + let credentialToken = "credentialToken" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let expectation = expectation(description: "SignInController") + + tokenRequestProviderMock.result = request + tokenRequestProviderMock.expectedContext = expectedContext + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.oobCode, scope: defaultScopes, password: nil, oobCode: "code", includeChallengeType: false, refreshToken: nil) + + let userAccountResult = MSALNativeAuthUserAccountResultStub.result + tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) + cacheAccessorMock.mockUserAccounts = [MSALNativeAuthUserAccountResultStub.account] + cacheAccessorMock.expectedMSIDTokenResult = tokenResult + + let state = SignInCodeRequiredState(scopes: ["openid","profile","offline_access"], controller: sut, inputValidator: MSALNativeAuthInputValidator(), flowToken: credentialToken) + state.submitCode(code: "code", correlationId: defaultUUID, delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedUserAccountResult: userAccountResult)) + + wait(for: [expectation], timeout: 1) + XCTAssertTrue(cacheAccessorMock.clearCacheWasCalled) + XCTAssertTrue(cacheAccessorMock.validateAndSaveTokensWasCalled) + checkTelemetryEventResult(id: .telemetryApiIdSignInSubmitCode, isSuccessful: true) + } + + func test_afterSignInWithCodeSubmitCode_whenTokenCacheIsNotValid_it_shouldReturnCorrectError() { + let request = MSIDHttpRequest() + let credentialToken = "credentialToken" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let expectation = expectation(description: "SignInController") + + tokenRequestProviderMock.result = request + tokenRequestProviderMock.expectedContext = expectedContext + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.oobCode, scope: defaultScopes, password: nil, oobCode: "code", includeChallengeType: false, refreshToken: nil) + + tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) + cacheAccessorMock.expectedMSIDTokenResult = nil + + let state = SignInCodeRequiredState(scopes: ["openid","profile","offline_access"], controller: sut, inputValidator: MSALNativeAuthInputValidator(), flowToken: credentialToken) + state.submitCode(code: "code", correlationId: defaultUUID, delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedError: VerifyCodeError(type: .generalError))) + + wait(for: [expectation], timeout: 1) + + checkTelemetryEventResult(id: .telemetryApiIdSignInSubmitCode, isSuccessful: false) + } + + func test_whenSignInWithCodeStartAndInitiateRequestCreationFail_errorShouldBeReturned() async { + let expectedUsername = "username" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + let expectation = expectation(description: "SignInController") + + signInRequestProviderMock.expectedUsername = expectedUsername + signInRequestProviderMock.expectedContext = expectedContext + signInRequestProviderMock.throwingInitError = MSALNativeAuthError() + + let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError)) + + let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + + helper.onSignInError(result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithCodeStart, isSuccessful: false) + } + + func test_whenSignInWithCodeStartAndInitiateReturnError_properErrorShouldBeReturned() async { + await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .browserRequired), validatorError: .redirect) + await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError, message: nil), validatorError: .invalidClient(message: nil)) + await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .userNotFound), validatorError: .userNotFound(message: nil)) + await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .unsupportedChallengeType(message: nil)) + await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidRequest(message: nil)) + await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidServerResponse) + } + + func test_whenSignInWithCodeChallengeRequestCreationFail_errorShouldBeReturned() async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let expectation = expectation(description: "SignInController") + + signInRequestProviderMock.result = request + signInRequestProviderMock.throwingChallengeError = MSALNativeAuthError() + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: "credentialToken") + + let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError)) + + let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + + helper.onSignInError(result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithCodeStart, isSuccessful: false) + } + + func test_whenSignInWithCodeChallengeReturnsError_properErrorShouldBeReturned() async { + await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .browserRequired), validatorError: .redirect) + await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .expiredToken(message: nil)) + await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidToken(message: nil)) + await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidRequest(message: nil)) + await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidServerResponse) + await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: nil), validatorError: .invalidClient(message: nil)) + await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .userNotFound), validatorError: .userNotFound(message: nil)) + await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: nil), validatorError: .unsupportedChallengeType(message: nil)) + } + + func test_whenSignInWithCodePasswordIsRequired_newStateIsPropagatedToUser() async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedCredentialToken = "credentialToken" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let expectation = expectation(description: "SignInController") + + signInRequestProviderMock.result = request + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: expectedCredentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: expectedCredentialToken) + + let helper = SignInCodeStartWithPasswordRequiredTestsValidatorHelper(expectation: expectation) + + let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + result.telemetryUpdate?(.success(())) + + helper.onSignInPasswordRequired(result.result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithCodeStart, isSuccessful: true) + XCTAssertEqual(helper.passwordRequiredState?.flowToken, expectedCredentialToken) + } + + func test_whenSignInWithCodePasswordIsRequired_newStateIsPropagatedToUser_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedCredentialToken = "credentialToken" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let expectation = expectation(description: "SignInController") + + signInRequestProviderMock.result = request + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: expectedCredentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: expectedCredentialToken) + + let helper = SignInCodeStartWithPasswordRequiredTestsValidatorHelper(expectation: expectation) + + let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + result.telemetryUpdate?(.failure(.init(message: "error"))) + + helper.onSignInPasswordRequired(result.result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithCodeStart, isSuccessful: false) + XCTAssertEqual(helper.passwordRequiredState?.flowToken, expectedCredentialToken) + } + + func test_whenSignInWithCodeSubmitPassword_signInIsCompletedSuccessfully() async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedPassword = "password" + let expectedCredentialToken = "credentialToken" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let exp = expectation(description: "SignInController") + + tokenRequestProviderMock.result = request + tokenRequestProviderMock.expectedContext = expectedContext + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: expectedCredentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: "", password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) + + let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedUserAccountResult: MSALNativeAuthUserAccountResultStub.result) + tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) + tokenResponseValidatorMock.expectedTokenResponse = tokenResponse + cacheAccessorMock.mockUserAccounts = [MSALNativeAuthUserAccountResultStub.account] + cacheAccessorMock.expectedMSIDTokenResult = tokenResult + + let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken) + state.submitPassword(password: expectedPassword, correlationId: defaultUUID, delegate: mockDelegate) + + await fulfillment(of: [exp], timeout: 1) + + XCTAssertTrue(cacheAccessorMock.clearCacheWasCalled) + XCTAssertTrue(cacheAccessorMock.validateAndSaveTokensWasCalled) + checkTelemetryEventResult(id: .telemetryApiIdSignInSubmitPassword, isSuccessful: true) + } + + func test_whenSignInWithCodeSubmitPassword_whenTokenCacheIsNotValid_it_shouldReturnCorrectError() async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedPassword = "password" + let expectedCredentialToken = "credentialToken" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let exp = expectation(description: "SignInController") + + tokenRequestProviderMock.result = request + tokenRequestProviderMock.expectedContext = expectedContext + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: expectedCredentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: "", password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) + + let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: PasswordRequiredError(type: .generalError)) + tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) + tokenResponseValidatorMock.expectedTokenResponse = tokenResponse + cacheAccessorMock.expectedMSIDTokenResult = nil + + let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken) + state.submitPassword(password: expectedPassword, correlationId: defaultUUID, delegate: mockDelegate) + + await fulfillment(of: [exp], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInSubmitPassword, isSuccessful: false) + } + + func test_whenSignInWithCodeSubmitPasswordTokenRequestCreationFail_errorShouldBeReturned() async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedPassword = "password" + let expectedCredentialToken = "credentialToken" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let exp = expectation(description: "SignInController") + + tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError() + signInRequestProviderMock.expectedContext = expectedContext + + let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: PasswordRequiredError(type: .generalError)) + + let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken) + state.submitPassword(password: expectedPassword, correlationId: defaultUUID, delegate: mockDelegate) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertNotNil(mockDelegate.newPasswordRequiredState) + XCTAssertFalse(cacheAccessorMock.validateAndSaveTokensWasCalled) + checkTelemetryEventResult(id: .telemetryApiIdSignInSubmitPassword, isSuccessful: false) + } + + func test_whenSignInWithCodeSubmitPasswordTokenAPIReturnError_correctErrorShouldBeReturned() async { + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .generalError) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .expiredToken(message: nil)) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidClient(message: nil)) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidRequest(message: nil)) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidServerResponse) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .userNotFound(message: nil)) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidOOBCode(message: nil)) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .unsupportedChallengeType(message: nil)) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .browserRequired), validatorError: .strongAuthRequired(message: nil)) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidScope(message: nil)) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .authorizationPending(message: nil)) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .slowDown(message: nil)) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .invalidPassword), validatorError: .invalidPassword(message: nil)) + } + + func test_signInWithCodeSubmitCodeTokenRequestFailCreation_errorShouldBeReturned() { + let credentialToken = "credentialToken" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + let expectation = expectation(description: "SignInController") + + signInRequestProviderMock.expectedContext = expectedContext + tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError() + + let state = SignInCodeRequiredState(scopes: [], controller: sut, flowToken: credentialToken) + state.submitCode(code: "code", correlationId: defaultUUID, delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedError: VerifyCodeError(type: .generalError))) + + wait(for: [expectation], timeout: 1) + XCTAssertFalse(cacheAccessorMock.validateAndSaveTokensWasCalled) + checkTelemetryEventResult(id: .telemetryApiIdSignInSubmitCode, isSuccessful: false) + } + + func test_signInWithCodeSubmitCodeReturnError_correctResultShouldReturned() { + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .generalError) + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .expiredToken(message: nil)) + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidClient(message: nil)) + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidRequest(message: nil)) + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidServerResponse) + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .userNotFound(message: nil)) + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .invalidCode, validatorError: .invalidOOBCode(message: nil)) + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .unsupportedChallengeType(message: nil)) + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .browserRequired, validatorError: .strongAuthRequired(message: nil)) + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidScope(message: nil)) + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .authorizationPending(message: nil)) + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .slowDown(message: nil)) + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidPassword(message: nil)) + } + + func test_signInWithCodeResendCode_shouldSendNewCode() async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let sentTo = "sentTo" + let channelTargetType = MSALNativeAuthChannelType.email + let codeLength = 4 + let credentialToken = "credentialToken" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let expectation = expectation(description: "SignInController") + + signInRequestProviderMock.result = request + signInRequestProviderMock.expectedUsername = expectedUsername + signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedContext = expectedContext + + let helper = SignInResendCodeTestsValidatorHelper(expectation: expectation, expectedSentTo: sentTo, expectedChannelTargetType: channelTargetType, expectedCodeLength: codeLength) + + signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: sentTo, channelType: channelTargetType, codeLength: codeLength) + + let result = await sut.resendCode(credentialToken: credentialToken, context: expectedContext, scopes: []) + + helper.onSignInResendCodeCodeRequired(result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInResendCode, isSuccessful: true) + } + + func test_signInWithCodeResendCodeChallengeCreationFail_errorShouldBeReturned() async { + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + let expectation = expectation(description: "SignInController") + + signInRequestProviderMock.throwingChallengeError = MSALNativeAuthError() + + let helper = SignInResendCodeTestsValidatorHelper(expectation: expectation) + + let result = await sut.resendCode(credentialToken: "credentialToken", context: expectedContext, scopes: []) + + helper.onSignInResendCodeError(result) + + await fulfillment(of: [expectation], timeout: 1) + XCTAssertNotNil(helper.newSignInCodeRequiredState) + checkTelemetryEventResult(id: .telemetryApiIdSignInResendCode, isSuccessful: false) + } + + func test_signInWithCodeResendCodePasswordRequired_shouldReturnAnError() async { + let request = MSIDHttpRequest() + let credentialToken = "credentialToken" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let expectation = expectation(description: "SignInController") + + signInRequestProviderMock.result = request + signInRequestProviderMock.expectedContext = expectedContext + + let helper = SignInResendCodeTestsValidatorHelper(expectation: expectation) + + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) + + let result = await sut.resendCode(credentialToken: credentialToken, context: expectedContext, scopes: []) + + helper.onSignInResendCodeError(result) + + await fulfillment(of: [expectation], timeout: 1) + XCTAssertNil(helper.newSignInCodeRequiredState) + checkTelemetryEventResult(id: .telemetryApiIdSignInResendCode, isSuccessful: false) + } + + func test_signInWithCodeResendCodeChallengeReturnError_shouldReturnAnError() async { + let request = MSIDHttpRequest() + let credentialToken = "credentialToken" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let expectation = expectation(description: "SignInController") + + signInRequestProviderMock.result = request + signInRequestProviderMock.expectedContext = expectedContext + + let helper = SignInResendCodeTestsValidatorHelper(expectation: expectation) + + signInResponseValidatorMock.challengeValidatedResponse = .error(.userNotFound(message: nil)) + + let result = await sut.resendCode(credentialToken: credentialToken, context: expectedContext, scopes: []) + + helper.onSignInResendCodeError(result) + + await fulfillment(of: [expectation], timeout: 1) + XCTAssertNotNil(helper.newSignInCodeRequiredState) + XCTAssertEqual(helper.newSignInCodeRequiredState?.flowToken, credentialToken) + checkTelemetryEventResult(id: .telemetryApiIdSignInResendCode, isSuccessful: false) + } + + // MARK: signIn using SLT + + func test_whenSignInWithSLT_signInIsCompletedSuccessfully() { + let request = MSIDHttpRequest() + let slt = "signInSLT" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let expectation = expectation(description: "SignInController") + + tokenRequestProviderMock.result = request + tokenRequestProviderMock.expectedContext = expectedContext + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: "", credentialToken: nil, signInSLT: slt, grantType: .slt, scope: defaultScopes, password: nil, oobCode: nil, includeChallengeType: false, refreshToken: nil) + + let userAccountResult = MSALNativeAuthUserAccountResultStub.result + let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: expectation, expectedUserAccountResult: userAccountResult) + tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) + tokenResponseValidatorMock.expectedTokenResponse = tokenResponse + + cacheAccessorMock.expectedMSIDTokenResult = tokenResult + + let state = SignInAfterSignUpState(controller: sut, username: "", slt: slt) + state.signIn(correlationId: defaultUUID, delegate: mockDelegate) + + wait(for: [expectation], timeout: 1) + XCTAssertTrue(cacheAccessorMock.validateAndSaveTokensWasCalled) + checkTelemetryEventResult(id: .telemetryApiIdSignInAfterSignUp, isSuccessful: true) + } + + func test_whenSignInWithSLTTokenRequestCreationFail_errorShouldBeReturned() { + let request = MSIDHttpRequest() + let slt = "signInSLT" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let exp = expectation(description: "SignInController") + + tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError() + signInRequestProviderMock.expectedContext = expectedContext + + let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: exp, expectedError: SignInAfterSignUpError()) + + let state = SignInAfterSignUpState(controller: sut, username: "", slt: slt) + state.signIn(correlationId: defaultUUID, delegate: mockDelegate) + + wait(for: [exp], timeout: 1) + XCTAssertFalse(cacheAccessorMock.validateAndSaveTokensWasCalled) + checkTelemetryEventResult(id: .telemetryApiIdSignInAfterSignUp, isSuccessful: false) + } + + func test_whenSignInWithSLTTokenReturnError_shouldReturnAnError() { + let request = MSIDHttpRequest() + let slt = "signInSLT" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let expectation = expectation(description: "SignInController") + + tokenRequestProviderMock.result = request + tokenRequestProviderMock.expectedContext = expectedContext + + let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: expectation, expectedError: SignInAfterSignUpError(message: "Invalid Client ID")) + + tokenResponseValidatorMock.tokenValidatedResponse = .error(.invalidClient(message: "Invalid Client ID")) + + let state = SignInAfterSignUpState(controller: sut, username: "", slt: slt) + state.signIn(correlationId: defaultUUID, delegate: mockDelegate) + + wait(for: [expectation], timeout: 1) + XCTAssertFalse(cacheAccessorMock.validateAndSaveTokensWasCalled) + checkTelemetryEventResult(id: .telemetryApiIdSignInAfterSignUp, isSuccessful: false) + } + + func test_whenSignInWithSLTHaveTokenNil_shouldReturnAnError() { + let expectation = expectation(description: "SignInController") + + let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: expectation, expectedError: SignInAfterSignUpError(message: "Sign In is not available at this point, please use the standalone sign in methods")) + + let state = SignInAfterSignUpState(controller: sut, username: "username", slt: nil) + state.signIn(correlationId: defaultUUID, delegate: mockDelegate) + + wait(for: [expectation], timeout: 1) + XCTAssertFalse(cacheAccessorMock.validateAndSaveTokensWasCalled) + checkTelemetryEventResult(id: .telemetryApiIdSignInAfterSignUp, isSuccessful: false) + } + + + // MARK: private methods + + private func checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: VerifyCodeErrorType, validatorError: MSALNativeAuthTokenValidatedErrorType) { + let request = MSIDHttpRequest() + let expectedCredentialToken = "credentialToken" + let expectedOOBCode = "code" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let exp = expectation(description: "SignInController") + + tokenRequestProviderMock.result = request + tokenRequestProviderMock.expectedContext = expectedContext + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, credentialToken: expectedCredentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.oobCode, scope: "", password: nil, oobCode: expectedOOBCode, includeChallengeType: true, refreshToken: nil) + let mockDelegate = SignInVerifyCodeDelegateSpy(expectation: exp, expectedError: VerifyCodeError(type: delegateError)) + tokenResponseValidatorMock.tokenValidatedResponse = .error(validatorError) + + let state = SignInCodeRequiredState(scopes: [], controller: sut, flowToken: expectedCredentialToken) + state.submitCode(code: expectedOOBCode, correlationId: defaultUUID, delegate: mockDelegate) + + wait(for: [exp], timeout: 1) + XCTAssertFalse(cacheAccessorMock.validateAndSaveTokensWasCalled) + checkTelemetryEventResult(id: .telemetryApiIdSignInSubmitCode, isSuccessful: false) + receivedEvents.removeAll() + } + + private func checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError, validatorError: MSALNativeAuthTokenValidatedErrorType) async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedPassword = "password" + let expectedCredentialToken = "credentialToken" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let exp = expectation(description: "SignInController") + + tokenRequestProviderMock.result = request + tokenRequestProviderMock.expectedContext = expectedContext + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: expectedCredentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: "", password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) + let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: publicError) + tokenResponseValidatorMock.tokenValidatedResponse = .error(validatorError) + + let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken) + state.submitPassword(password: expectedPassword, correlationId: defaultUUID, delegate: mockDelegate) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertFalse(cacheAccessorMock.validateAndSaveTokensWasCalled) + checkTelemetryEventResult(id: .telemetryApiIdSignInSubmitPassword, isSuccessful: false) + receivedEvents.removeAll() + } + + private func checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError, validatorError: MSALNativeAuthSignInChallengeValidatedErrorType) async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let expectation = expectation(description: "SignInController") + + signInRequestProviderMock.result = request + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: "credentialToken") + signInResponseValidatorMock.challengeValidatedResponse = .error(validatorError) + + let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: delegateError) + + let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + + helper.onSignInError(result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithCodeStart, isSuccessful: false) + receivedEvents.removeAll() + } + + private func checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError, validatorError: MSALNativeAuthSignInInitiateValidatedErrorType) async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + let expectation = expectation(description: "SignInController") + + signInRequestProviderMock.expectedUsername = expectedUsername + signInRequestProviderMock.expectedContext = expectedContext + signInRequestProviderMock.result = request + signInResponseValidatorMock.initiateValidatedResponse = .error(validatorError) + + let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: delegateError) + + let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + + helper.onSignInError(result) + + await fulfillment(of: [expectation], timeout: 1) + checkTelemetryEventResult(id: .telemetryApiIdSignInWithCodeStart, isSuccessful: false) + receivedEvents.removeAll() + } + + private func checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError, validatorError: MSALNativeAuthTokenValidatedErrorType) async { + let request = MSIDHttpRequest() + let expectedUsername = "username" + let expectedPassword = "password" + let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let credentialToken = "credentialToken" + + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) + + signInRequestProviderMock.result = request + signInRequestProviderMock.expectedUsername = expectedUsername + signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedContext = expectedContext + + let expectation = expectation(description: "SignInController") + + tokenRequestProviderMock.result = request + + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: delegateError) + tokenResponseValidatorMock.tokenValidatedResponse = .error(validatorError) + + let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + + helper.onSignInPasswordError(result) + + checkTelemetryEventResult(id: .telemetryApiIdSignInWithPasswordStart, isSuccessful: false) + receivedEvents.removeAll() + await fulfillment(of: [expectation], timeout: 1) + } + + private func checkTelemetryEventResult(id: MSALNativeAuthTelemetryApiId, isSuccessful: Bool) { + XCTAssertEqual(receivedEvents.count, 1) + + guard let telemetryEventDict = receivedEvents.first else { + return XCTFail("Telemetry test fail") + } + + let expectedApiId = String(id.rawValue) + XCTAssertEqual(telemetryEventDict["api_id"] as? String, expectedApiId) + XCTAssertEqual(telemetryEventDict["event_name"] as? String, "api_event" ) + XCTAssertEqual(telemetryEventDict["correlation_id" ] as? String, DEFAULT_TEST_UID.uppercased()) + XCTAssertEqual(telemetryEventDict["is_successfull"] as? String, isSuccessful ? "yes" : "no") + XCTAssertEqual(telemetryEventDict["status"] as? String, isSuccessful ? "succeeded" : "failed") + XCTAssertNotNil(telemetryEventDict["start_time"]) + XCTAssertNotNil(telemetryEventDict["stop_time"]) + XCTAssertNotNil(telemetryEventDict["response_time"]) + } + +} diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift new file mode 100644 index 0000000000..2768d78b34 --- /dev/null +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift @@ -0,0 +1,1949 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { + + private var sut: MSALNativeAuthSignUpController! + private var contextMock: MSALNativeAuthRequestContext! + private var requestProviderMock: MSALNativeAuthSignUpRequestProviderMock! + private var validatorMock: MSALNativeAuthSignUpResponseValidatorMock! + private var signInControllerMock: MSALNativeAuthSignInControllerMock! + + private var signUpStartPasswordParams: MSALNativeAuthSignUpStartRequestProviderParameters { + .init( + username: "user@contoso.com", + password: "password", + attributes: ["key": "value"], + context: contextMock + ) + } + + private var signUpStartCodeParams: MSALNativeAuthSignUpStartRequestProviderParameters { + .init( + username: "user@contoso.com", + password: nil, + attributes: ["key": "value"], + context: contextMock + ) + } + + override func setUpWithError() throws { + try super.setUpWithError() + + contextMock = .init(correlationId: .init(uuidString: DEFAULT_TEST_UID)!) + requestProviderMock = .init() + validatorMock = .init() + signInControllerMock = .init() + + sut = MSALNativeAuthSignUpController( + config: MSALNativeAuthConfigStubs.configuration, + requestProvider: requestProviderMock, + responseValidator: validatorMock, + signInController: signInControllerMock + ) + } + + // MARK: - SignUpPasswordStart (/start request) tests + + func test_whenSignUpStartPassword_cantCreateRequest_it_returns_unexpectedError() async { + requestProviderMock.mockStartRequestFunc(nil, throwError: true) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpPasswordStartValidatorHelper(exp) + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + + helper.onSignUpPasswordError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) + } + + func test_whenSignUpStartPassword_returnsVerificationRequired_it_returnsChallenge() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) + + let helper = prepareSignUpPasswordStartValidatorHelper() + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + helper.onSignUpPasswordError(result) + + XCTAssertTrue(requestProviderMock.challengeCalled) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) + } + + func test_whenSignUpStartPassword_returnsAttributeValidationFailed_it_returnsChallenge() async { + let invalidAttributes = ["name"] + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(invalidAttributes: invalidAttributes)) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpPasswordStartValidatorHelper(exp) + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + result.telemetryUpdate?(.success(())) + + helper.onSignUpAttributesInvalid(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpAttributesInvalidCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.attributeNames, invalidAttributes) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) + } + + func test_whenSignUpStartPassword_telemetryUpdateFails_it_updatesTelemetryCorrectly() async { + let invalidAttributes = ["name"] + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(invalidAttributes: invalidAttributes)) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpPasswordStartValidatorHelper(exp) + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + result.telemetryUpdate?(.failure(.init(message: "error"))) + + helper.onSignUpAttributesInvalid(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpAttributesInvalidCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.attributeNames, invalidAttributes) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) + } + + func test_whenSignUpStartPassword_returns_redirect_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + validatorMock.mockValidateSignUpStartFunc(.redirect) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpPasswordStartValidatorHelper(exp) + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + helper.onSignUpPasswordError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .browserRequired) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) + } + + func test_whenSignUpStartPassword_returns_error_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + let error : MSALNativeAuthSignUpStartValidatedResponse = .error( + MSALNativeAuthSignUpStartResponseError(error: .passwordTooLong, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + signUpToken: nil, + unverifiedAttributes: nil, + invalidAttributes: nil)) + validatorMock.mockValidateSignUpStartFunc(error) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpPasswordStartValidatorHelper(exp) + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + helper.onSignUpPasswordError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .invalidPassword) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) + } + + func test_whenSignUpStartPassword_returns_invalidUsername_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + let invalidUsername : MSALNativeAuthSignUpStartValidatedResponse = .invalidUsername( + MSALNativeAuthSignUpStartResponseError(error: .invalidRequest, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + signUpToken: nil, + unverifiedAttributes: nil, + invalidAttributes: nil)) + validatorMock.mockValidateSignUpStartFunc(invalidUsername) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpPasswordStartValidatorHelper(exp) + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + helper.onSignUpPasswordError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .invalidUsername) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) + } + + func test_whenSignUpStartPassword_returns_invalidClientId_it_returnsGeneralError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + let invalidClientId : MSALNativeAuthSignUpStartValidatedResponse = .invalidClientId( + MSALNativeAuthSignUpStartResponseError(error: .invalidRequest, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + signUpToken: nil, + unverifiedAttributes: nil, + invalidAttributes: nil)) + validatorMock.mockValidateSignUpStartFunc(invalidClientId) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpPasswordStartValidatorHelper(exp) + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + helper.onSignUpPasswordError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) + } + + func test_whenValidatorInSignUpStartPassword_returns_unexpectedError_it_returnsGeneralError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + validatorMock.mockValidateSignUpStartFunc(.unexpectedError) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpPasswordStartValidatorHelper(exp) + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + helper.onSignUpPasswordError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) + } + + // MARK: - SignUpPasswordStart (/challenge request) tests + + func test_whenSignUpStartPassword_challenge_cantCreateRequest_it_returns_unexpectedError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpPasswordStartValidatorHelper(exp) + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + helper.onSignUpPasswordError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) + } + + func test_whenSignUpStartPassword_challenge_succeeds_it_continuesTheFlow() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "signUpToken 2")) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpPasswordStartValidatorHelper(exp) + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + helper.onSignUpCodeRequired(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCodeRequiredCalled) + XCTAssertEqual(helper.newState?.flowToken, "signUpToken 2") + XCTAssertEqual(helper.sentTo, "sentTo") + XCTAssertEqual(helper.channelTargetType, .email) + XCTAssertEqual(helper.codeLength, 4) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: true) + } + + func test_whenSignUpStartPassword_challenge_returns_passwordRequired_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("")) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpPasswordStartValidatorHelper(exp) + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + helper.onSignUpPasswordError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) + } + + func test_whenSignUpStartPassword_challenge_returns_redirect_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateSignUpChallengeFunc(.redirect) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpPasswordStartValidatorHelper(exp) + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + helper.onSignUpPasswordError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .browserRequired) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) + } + + func test_whenSignUpStartPassword_challenge_returns_error_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + let error : MSALNativeAuthSignUpChallengeValidatedResponse = .error( + MSALNativeAuthSignUpChallengeResponseError(error: .expiredToken, + errorDescription: "Expired Token", + errorCodes: nil, + errorURI: nil, + innerErrors: nil)) + validatorMock.mockValidateSignUpChallengeFunc(error) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpPasswordStartValidatorHelper(exp) + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + helper.onSignUpPasswordError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Expired Token") + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) + } + + func test_whenValidatorInSignUpStartPassword_challenge_returns_unexpectedError_it_returnsGeneralError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpPasswordStartValidatorHelper(exp) + + let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + helper.onSignUpPasswordError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) + } + + // MARK: - SignUpCodeStart (/start request) tests + + func test_whenSignUpStartCode_cantCreateRequest_returns_it_unexpectedError() async { + requestProviderMock.mockStartRequestFunc(nil, throwError: true) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpCodeStartValidatorHelper(exp) + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + helper.onSignUpError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) + } + + func test_whenSignUpStartCode_returnsVerificationRequired_it_returnsChallenge() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) + + let helper = prepareSignUpCodeStartValidatorHelper() + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + helper.onSignUpError(result) + + XCTAssertTrue(requestProviderMock.challengeCalled) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) + } + + func test_whenSignUpStartCode_returnsAttributeValidationFailed_it_returnsCorrectError() async { + let invalidAttributes = ["name"] + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(invalidAttributes: invalidAttributes)) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpCodeStartValidatorHelper(exp) + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + result.telemetryUpdate?(.success(())) + helper.onSignUpAttributesInvalid(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpAttributesInvalidCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.attributeNames, invalidAttributes) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) + } + + func test_whenSignUpStartCode_telemetryUpdateFails_it_updatesTelemetryCorrectly() async { + let invalidAttributes = ["name"] + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(invalidAttributes: invalidAttributes)) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpCodeStartValidatorHelper(exp) + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + result.telemetryUpdate?(.failure(.init(message: "error"))) + helper.onSignUpAttributesInvalid(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpAttributesInvalidCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.attributeNames, invalidAttributes) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) + } + + func test_whenSignUpStartCode_returns_redirect_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + validatorMock.mockValidateSignUpStartFunc(.redirect) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpCodeStartValidatorHelper(exp) + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + helper.onSignUpError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .browserRequired) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) + } + + func test_whenSignUpStartCode_returns_error_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + let error : MSALNativeAuthSignUpStartValidatedResponse = .error( + MSALNativeAuthSignUpStartResponseError(error: .userAlreadyExists, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + signUpToken: nil, + unverifiedAttributes: nil, + invalidAttributes: nil)) + validatorMock.mockValidateSignUpStartFunc(error) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpCodeStartValidatorHelper(exp) + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + helper.onSignUpError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .userAlreadyExists) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) + } + + func test_whenSignUpStartCode_returns_invalidUsername_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + let invalidUsername : MSALNativeAuthSignUpStartValidatedResponse = .invalidUsername( + MSALNativeAuthSignUpStartResponseError(error: .invalidRequest, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + signUpToken: nil, + unverifiedAttributes: nil, + invalidAttributes: nil)) + validatorMock.mockValidateSignUpStartFunc(invalidUsername) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpCodeStartValidatorHelper(exp) + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + helper.onSignUpError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .invalidUsername) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) + } + + func test_whenSignUpStartCode_returns_invalidClientId_it_returnsGeneralError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + let invalidClientId : MSALNativeAuthSignUpStartValidatedResponse = .invalidClientId( + MSALNativeAuthSignUpStartResponseError(error: .invalidRequest, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + signUpToken: nil, + unverifiedAttributes: nil, + invalidAttributes: nil)) + validatorMock.mockValidateSignUpStartFunc(invalidClientId) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpCodeStartValidatorHelper(exp) + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + helper.onSignUpError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) + } + + func test_whenValidatorInSignUpStartCode_returns_unexpectedError_it_returnsGeneralError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + validatorMock.mockValidateSignUpStartFunc(.unexpectedError) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpCodeStartValidatorHelper(exp) + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + helper.onSignUpError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) + } + + // MARK: - SignUpCodeStart (/challenge request) tests + + func test_whenSignUpStartCode_challenge_cantCreateRequest_it_returns_unexpectedError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpCodeStartValidatorHelper(exp) + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + helper.onSignUpError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) + } + + func test_whenSignUpStartCode_challenge_succeeds_it_continuesTheFlow() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken 1", unverifiedAttributes: [""])) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 1") + validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "signUpToken 2")) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpCodeStartValidatorHelper(exp) + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + helper.onSignUpCodeRequired(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCodeRequiredCalled) + XCTAssertEqual(helper.newState?.flowToken, "signUpToken 2") + XCTAssertEqual(helper.sentTo, "sentTo") + XCTAssertEqual(helper.channelTargetType, .email) + XCTAssertEqual(helper.codeLength, 4) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: true) + } + + func test_whenSignUpStartCode_challenge_succeedsPassword_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("")) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpCodeStartValidatorHelper(exp) + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + helper.onSignUpError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) + } + + func test_whenSignUpStartCode_challenge_returns_redirect_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateSignUpChallengeFunc(.redirect) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpCodeStartValidatorHelper(exp) + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + helper.onSignUpError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .browserRequired) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) + } + + func test_whenSignUpStartCode_challenge_returns_error_it_returnsCorrectError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + let error : MSALNativeAuthSignUpChallengeValidatedResponse = .error( + MSALNativeAuthSignUpChallengeResponseError(error: .expiredToken, + errorDescription: "Expired Token", + errorCodes: nil, + errorURI: nil, + innerErrors: nil)) + validatorMock.mockValidateSignUpChallengeFunc(error) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpCodeStartValidatorHelper(exp) + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + helper.onSignUpError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Expired Token") + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) + } + + func test_whenValidatorInSignUpStartCode_challenge_it_returns_unexpectedError_returnsGeneralError() async { + requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpCodeStartValidatorHelper(exp) + + let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + helper.onSignUpError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) + } + + // MARK: - ResendCode tests + + func test_whenSignUpResendCode_cantCreateRequest_it_returns_unexpectedError() async { + requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpResendCodeValidatorHelper(exp) + + let result = await sut.resendCode(username: "", context: contextMock, signUpToken: "signUpToken") + helper.onSignUpResendCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpResendCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.codeLength) + XCTAssertNotNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpResendCode, isSuccessful: false) + } + + func test_whenSignUpResendCode_succeeds_it_continuesTheFlow() async { + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "signUpToken")) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpResendCodeValidatorHelper(exp) + + let result = await sut.resendCode(username: "", context: contextMock, signUpToken: "signUpToken") + helper.onSignUpResendCodeCodeRequired(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpResendCodeCodeRequiredCalled) + XCTAssertEqual(helper.newState?.flowToken, "signUpToken") + XCTAssertEqual(helper.sentTo, "sentTo") + XCTAssertEqual(helper.channelTargetType, .email) + XCTAssertEqual(helper.codeLength, 4) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpResendCode, isSuccessful: true) + } + + func test_whenSignUpResendCode_succeedsPassword_it_returnsCorrectError() async { + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") + validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("signUpToken 1")) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpResendCodeValidatorHelper(exp) + + let result = await sut.resendCode(username: "", context: contextMock, signUpToken: "signUpToken 2") + helper.onSignUpResendCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpResendCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.codeLength) + XCTAssertNotNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpResendCode, isSuccessful: false) + } + + func test_whenSignUpResendCode_returns_error_it_returnsCorrectError() async { + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + let error : MSALNativeAuthSignUpChallengeValidatedResponse = .error( + MSALNativeAuthSignUpChallengeResponseError(error: .invalidRequest, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil)) + validatorMock.mockValidateSignUpChallengeFunc(error) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpResendCodeValidatorHelper(exp) + + let result = await sut.resendCode(username: "", context: contextMock, signUpToken: "signUpToken") + helper.onSignUpResendCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpResendCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.codeLength) + XCTAssertNotNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpResendCode, isSuccessful: false) + } + + func test_whenSignUpResendCode_returns_redirect_it_returnsCorrectError() async { + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateSignUpChallengeFunc(.redirect) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpResendCodeValidatorHelper(exp) + + let result = await sut.resendCode(username: "", context: contextMock, signUpToken: "signUpToken") + helper.onSignUpResendCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpResendCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.codeLength) + XCTAssertNotNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpResendCode, isSuccessful: false) + } + + func test_whenSignUpResendCode_returns_unexpectedError_it_returnsCorrectError() async { + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() + validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpResendCodeValidatorHelper(exp) + + let result = await sut.resendCode(username: "", context: contextMock, signUpToken: "signUpToken") + helper.onSignUpResendCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpResendCodeErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.codeLength) + XCTAssertNotNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpResendCode, isSuccessful: false) + } + + // MARK: - SubmitCode tests + + func test_whenSignUpSubmitCode_cantCreateRequest_it_returns_unexpectedError() async { + requestProviderMock.mockContinueRequestFunc(nil, throwError: true) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpVerifyCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpVerifyCodeErrorCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newCodeRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) + } + + func test_whenSubmitCode_succeeds_it_continuesTheFlow() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + validatorMock.mockValidateSignUpContinueFunc(.success("")) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpCompleted(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCompletedCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newCodeRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: true) + } + + func test_whenSignUpSubmitCode_returns_invalidUserInput_it_returnsInvalidCode() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + let error : MSALNativeAuthSignUpContinueValidatedResponse = .invalidUserInput( + MSALNativeAuthSignUpContinueResponseError(error: .invalidOOBValue, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + signUpToken: nil, + requiredAttributes: nil, + unverifiedAttributes: nil, + invalidAttributes: nil)) + validatorMock.mockValidateSignUpContinueFunc(error) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpVerifyCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpVerifyCodeErrorCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertEqual(helper.newCodeRequiredState?.flowToken, "signUpToken") + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .invalidCode) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) + } + + func test_whenSignUpSubmitCode_returns_attributesRequired_it_returnsAttributesRequired() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(signUpToken: "signUpToken", requiredAttributes: [])) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + result.telemetryUpdate?(.success(())) + + helper.onSignUpAttributesRequired(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpAttributesRequiredCalled) + XCTAssertEqual(helper.newAttributesRequiredState?.flowToken, "signUpToken") + XCTAssertNil(helper.newCodeRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: true) + } + + func test_whenSignUpSubmitCode_returns_attributesRequired_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(signUpToken: "signUpToken", requiredAttributes: [])) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + result.telemetryUpdate?(.failure(.init(message: "error"))) + + helper.onSignUpAttributesRequired(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpAttributesRequiredCalled) + XCTAssertEqual(helper.newAttributesRequiredState?.flowToken, "signUpToken") + XCTAssertNil(helper.newCodeRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) + } + + func test_whenSignUpSubmitCode_returns_attributeValidationFailed_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(signUpToken: "signUpToken 2", invalidAttributes: ["name"])) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + result.telemetryUpdate?(.success(())) + + helper.onSignUpVerifyCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertTrue(helper.onSignUpVerifyCodeErrorCalled) + XCTAssertNil(helper.newAttributesRequiredState) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) + } + + func test_whenSignUpSubmitCode_returns_error_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + let error : MSALNativeAuthSignUpContinueValidatedResponse = .error( + MSALNativeAuthSignUpContinueResponseError(error: .invalidRequest, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + signUpToken: nil, + requiredAttributes: nil, + unverifiedAttributes: nil, + invalidAttributes: nil)) + validatorMock.mockValidateSignUpContinueFunc(error) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpVerifyCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpVerifyCodeErrorCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newCodeRequiredState?.flowToken) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) + } + + func test_whenSignUpSubmitCode_returns_unexpectedError_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + validatorMock.mockValidateSignUpContinueFunc(.unexpectedError) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpVerifyCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpVerifyCodeErrorCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newCodeRequiredState?.flowToken) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) + } + + // MARK: - SubmitCode + credential_required error tests + + func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") + validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) + + XCTAssertFalse(requestProviderMock.challengeCalled) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpVerifyCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(requestProviderMock.challengeCalled) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) + } + + func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andCantCreateRequest() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpVerifyCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpVerifyCodeErrorCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newCodeRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) + } + + func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andSucceeds() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") + validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("signUpToken 3")) + + XCTAssertFalse(requestProviderMock.challengeCalled) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + result.telemetryUpdate?(.success(())) + + helper.onSignUpPasswordRequired(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(requestProviderMock.challengeCalled) + XCTAssertTrue(helper.onSignUpPasswordRequiredCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newCodeRequiredState) + XCTAssertEqual(helper.newPasswordRequiredState?.flowToken, "signUpToken 3") + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: true) + } + + func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") + validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("signUpToken 3")) + + XCTAssertFalse(requestProviderMock.challengeCalled) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + result.telemetryUpdate?(.failure(.init(message: "error"))) + + helper.onSignUpPasswordRequired(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(requestProviderMock.challengeCalled) + XCTAssertTrue(helper.onSignUpPasswordRequiredCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newCodeRequiredState) + XCTAssertEqual(helper.newPasswordRequiredState?.flowToken, "signUpToken 3") + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) + } + + func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andSucceedOOB_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") + validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("", .email, 4, "signUpToken 3")) + + XCTAssertFalse(requestProviderMock.challengeCalled) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpVerifyCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(requestProviderMock.challengeCalled) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) + } + + func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andRedirects() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") + validatorMock.mockValidateSignUpChallengeFunc(.redirect) + + XCTAssertFalse(requestProviderMock.challengeCalled) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpVerifyCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(requestProviderMock.challengeCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newCodeRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .browserRequired) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) + } + + func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andReturnsError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") + let error : MSALNativeAuthSignUpChallengeValidatedResponse = .error( + MSALNativeAuthSignUpChallengeResponseError(error: .expiredToken, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil)) + validatorMock.mockValidateSignUpChallengeFunc(error) + + XCTAssertFalse(requestProviderMock.challengeCalled) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpVerifyCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(requestProviderMock.challengeCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newCodeRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) + } + + func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andReturnsUnexpectedError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") + validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) + + XCTAssertFalse(requestProviderMock.challengeCalled) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitCodeValidatorHelper(exp) + + let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpVerifyCodeError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(requestProviderMock.challengeCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newCodeRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) + } + + // MARK: - SubmitPassword tests + + func test_whenSignUpSubmitPassword_cantCreateRequest_it_returns_unexpectedError() async { + requestProviderMock.mockContinueRequestFunc(nil, throwError: true) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpPasswordRequiredError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordRequiredErrorCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitPassword, isSuccessful: false) + } + + func test_whenSubmitPassword_succeeds_it_continuesTheFlow() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) + validatorMock.mockValidateSignUpContinueFunc(.success("signInSLT")) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpCompleted(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCompletedCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitPassword, isSuccessful: true) + } + + func test_whenSignUpSubmitPassword_returns_invalidUserInput_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) + let error : MSALNativeAuthSignUpContinueValidatedResponse = .invalidUserInput( + MSALNativeAuthSignUpContinueResponseError(error: .passwordTooWeak, + errorDescription: "Password too weak", + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + signUpToken: nil, + requiredAttributes: nil, + unverifiedAttributes: nil, + invalidAttributes: nil)) + validatorMock.mockValidateSignUpContinueFunc(error) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpPasswordRequiredError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordRequiredErrorCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertEqual(helper.newPasswordRequiredState?.flowToken, "signUpToken") + XCTAssertEqual(helper.error?.type, .invalidPassword) + XCTAssertEqual(helper.error?.errorDescription, "Password too weak") + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitPassword, isSuccessful: false) + } + + func test_whenSignUpSubmitPassword_returns_attributesRequired_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) + validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(signUpToken: "signUpToken 2", requiredAttributes: [])) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + result.telemetryUpdate?(.success(())) + + helper.onSignUpAttributesRequired(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpAttributesRequiredCalled) + XCTAssertEqual(helper.newAttributesRequiredState?.flowToken, "signUpToken 2") + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitPassword, isSuccessful: true) + } + + func test_whenSignUpSubmitPassword_returns_attributesRequired_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) + validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(signUpToken: "signUpToken 2", requiredAttributes: [])) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + result.telemetryUpdate?(.failure(.init(message: "error"))) + + helper.onSignUpAttributesRequired(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpAttributesRequiredCalled) + XCTAssertEqual(helper.newAttributesRequiredState?.flowToken, "signUpToken 2") + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitPassword, isSuccessful: false) + } + + func test_whenSignUpSubmitPassword_returns_error_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) + let error : MSALNativeAuthSignUpContinueValidatedResponse = .error( + MSALNativeAuthSignUpContinueResponseError(error: .invalidRequest, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + signUpToken: nil, + requiredAttributes: nil, + unverifiedAttributes: nil, + invalidAttributes: nil)) + validatorMock.mockValidateSignUpContinueFunc(error) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpPasswordRequiredError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordRequiredErrorCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitPassword, isSuccessful: false) + } + + func test_whenSignUpSubmitPassword_returns_credentialRequired_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpPasswordRequiredError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordRequiredErrorCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitPassword, isSuccessful: false) + } + + func test_whenSignUpSubmitPassword_returns_unexpectedError_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) + validatorMock.mockValidateSignUpContinueFunc(.unexpectedError) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpPasswordRequiredError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpPasswordRequiredErrorCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertEqual(helper.error?.type, .generalError) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitPassword, isSuccessful: false) + } + + func test_whenSignUpSubmitPassword_returns_attributeValidationFailed_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) + validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(signUpToken: "signUpToken 2", invalidAttributes: ["key"])) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + result.telemetryUpdate?(.success(())) + + helper.onSignUpPasswordRequiredError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertTrue(helper.onSignUpPasswordRequiredErrorCalled) + XCTAssertNil(helper.newAttributesRequiredState) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitPassword, isSuccessful: false) + } + + // MARK: - SubmitAttributes tests + + func test_whenSignUpSubmitAttributes_cantCreateRequest_it_returns_unexpectedError() async { + requestProviderMock.mockContinueRequestFunc(nil, throwError: true) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( + grantType: .attributes, + oobCode: nil, + attributes: ["key": "value"] + ) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) + + let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpAttributesRequiredError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpAttributesRequiredErrorCalled) + XCTAssertNil(helper.newState) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitAttributes, isSuccessful: false) + } + + func test_whenSubmitAttributes_succeeds_it_continuesTheFlow() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( + grantType: .attributes, + oobCode: nil, + attributes: ["key": "value"] + ) + validatorMock.mockValidateSignUpContinueFunc(.success("")) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) + + let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpCompleted(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCompletedCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitAttributes, isSuccessful: true) + } + + func test_whenSignUpSubmitAttributes_returns_invalidUserInput_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( + grantType: .attributes, + oobCode: nil, + attributes: ["key": "value"] + ) + let error : MSALNativeAuthSignUpContinueValidatedResponse = .invalidUserInput( + MSALNativeAuthSignUpContinueResponseError(error: .attributeValidationFailed, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + signUpToken: nil, + requiredAttributes: nil, + unverifiedAttributes: nil, + invalidAttributes: nil)) + validatorMock.mockValidateSignUpContinueFunc(error) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) + + let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpAttributesRequiredError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpAttributesRequiredErrorCalled) + XCTAssertNil(helper.newState) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitAttributes, isSuccessful: false) + } + + func test_whenSignUpSubmitAttributes_returns_error_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( + grantType: .attributes, + oobCode: nil, + attributes: ["key": "value"] + ) + let error : MSALNativeAuthSignUpContinueValidatedResponse = .error( + MSALNativeAuthSignUpContinueResponseError(error: .invalidRequest, + errorDescription: nil, + errorCodes: nil, + errorURI: nil, + innerErrors: nil, + signUpToken: nil, + requiredAttributes: nil, + unverifiedAttributes: nil, + invalidAttributes: nil)) + validatorMock.mockValidateSignUpContinueFunc(error) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) + + let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpAttributesRequiredError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpAttributesRequiredErrorCalled) + XCTAssertNil(helper.newState) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitAttributes, isSuccessful: false) + } + + func test_whenSignUpSubmitAttributes_returns_attributesRequired_it_returnsAttributesRequiredError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( + grantType: .attributes, + oobCode: nil, + attributes: ["key": "value"] + ) + validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(signUpToken: "signUpToken 2", requiredAttributes: [])) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) + + let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpAttributesRequired(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpAttributesRequiredCalled) + XCTAssertEqual(helper.newState?.flowToken, "signUpToken 2") + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitAttributes, isSuccessful: false) + } + + func test_whenSignUpSubmitAttributes_returns_credentialRequired_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( + grantType: .attributes, + oobCode: nil, + attributes: ["key": "value"] + ) + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) + + let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpAttributesRequiredError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpAttributesRequiredErrorCalled) + XCTAssertNil(helper.newState) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitAttributes, isSuccessful: false) + } + + func test_whenSignUpSubmitAttributes_returns_unexpectedError_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( + grantType: .attributes, + oobCode: nil, + attributes: ["key": "value"] + ) + validatorMock.mockValidateSignUpContinueFunc(.unexpectedError) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) + + let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpAttributesRequiredError(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpAttributesRequiredErrorCalled) + XCTAssertNil(helper.newState) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitAttributes, isSuccessful: false) + } + + func test_whenSignUpSubmitAttributes_returns_attributeValidationFailed_it_returnsCorrectError() async { + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( + grantType: .attributes, + oobCode: nil, + attributes: ["key": "value"] + ) + validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(signUpToken: "signUpToken 2", invalidAttributes: ["attribute"])) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) + + let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + helper.onSignUpAttributesValidationFailed(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpInvalidAttributesCalled) + XCTAssertEqual(helper.newState?.flowToken, "signUpToken 2") + XCTAssertEqual(helper.invalidAttributes, ["attribute"]) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitAttributes, isSuccessful: false) + } + + // MARK: - Sign-in with SLT (Short-Lived Token) + + func test_whenSignUpSucceeds_and_userCallsSignInWithSLT_signUpControllerPassesCorrectParams() async { + let username = "username" + let slt = "signInSLT" + + class SignInAfterSignUpDelegateStub: SignInAfterSignUpDelegate { + func onSignInAfterSignUpError(error: MSAL.SignInAfterSignUpError) {} + func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) {} + } + + requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) + validatorMock.mockValidateSignUpContinueFunc(.success(slt)) + + let exp = expectation(description: "SignUpController expectation") + let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword("password", username: username, signUpToken: "signUpToken", context: contextMock) + helper.onSignUpCompleted(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onSignUpCompletedCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertNil(helper.error) + + checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitPassword, isSuccessful: true) + + let exp2 = expectation(description: "SignInAfterSignUp expectation") + signInControllerMock.expectation = exp2 + signInControllerMock.signInSLTResult = .failure(.init()) + helper.signInAfterSignUpState?.signIn(delegate: SignInAfterSignUpDelegateStub()) + await fulfillment(of: [exp2], timeout: 1) + + XCTAssertEqual(signInControllerMock.username, username) + XCTAssertEqual(signInControllerMock.slt, slt) + } + + // MARK: - Common Methods + + private func checkTelemetryEventResult(id: MSALNativeAuthTelemetryApiId, isSuccessful: Bool) { + XCTAssertEqual(receivedEvents.count, 1) + + guard let telemetryEventDict = receivedEvents.first else { + return XCTFail("Telemetry test fail") + } + + let expectedApiId = String(id.rawValue) + XCTAssertEqual(telemetryEventDict["api_id"] as? String, expectedApiId) + XCTAssertEqual(telemetryEventDict["event_name"] as? String, "api_event" ) + XCTAssertEqual(telemetryEventDict["correlation_id" ] as? String, DEFAULT_TEST_UID.uppercased()) + XCTAssertEqual(telemetryEventDict["is_successfull"] as? String, isSuccessful ? "yes" : "no") + XCTAssertEqual(telemetryEventDict["status"] as? String, isSuccessful ? "succeeded" : "failed") + XCTAssertNotNil(telemetryEventDict["start_time"]) + XCTAssertNotNil(telemetryEventDict["stop_time"]) + XCTAssertNotNil(telemetryEventDict["response_time"]) + } + + private func prepareSignUpPasswordStartValidatorHelper(_ expectation: XCTestExpectation? = nil) -> SignUpPasswordStartTestsValidatorHelper { + let helper = SignUpPasswordStartTestsValidatorHelper(expectation: expectation) + XCTAssertFalse(helper.onSignUpPasswordErrorCalled) + XCTAssertFalse(helper.onSignUpCodeRequiredCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertNil(helper.error) + + return helper + } + + private func prepareSignUpCodeStartValidatorHelper(_ expectation: XCTestExpectation? = nil) -> SignUpCodeStartTestsValidatorHelper { + let helper = SignUpCodeStartTestsValidatorHelper(expectation: expectation) + XCTAssertFalse(helper.onSignUpCodeErrorCalled) + XCTAssertFalse(helper.onSignUpCodeRequiredCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertNil(helper.error) + + return helper + } + + private func prepareSignUpResendCodeValidatorHelper(_ expectation: XCTestExpectation? = nil) -> SignUpResendCodeTestsValidatorHelper { + let helper = SignUpResendCodeTestsValidatorHelper(expectation: expectation) + XCTAssertFalse(helper.onSignUpResendCodeErrorCalled) + XCTAssertFalse(helper.onSignUpResendCodeCodeRequiredCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.sentTo) + XCTAssertNil(helper.channelTargetType) + XCTAssertNil(helper.codeLength) + XCTAssertNil(helper.error) + + return helper + } + + private func prepareSignUpSubmitCodeValidatorHelper(_ expectation: XCTestExpectation? = nil) -> SignUpVerifyCodeTestsValidatorHelper { + let helper = SignUpVerifyCodeTestsValidatorHelper(expectation: expectation) + XCTAssertFalse(helper.onSignUpCompletedCalled) + XCTAssertFalse(helper.onSignUpPasswordRequiredCalled) + XCTAssertFalse(helper.onSignUpVerifyCodeErrorCalled) + XCTAssertFalse(helper.onSignUpAttributesRequiredCalled) + XCTAssertNil(helper.newCodeRequiredState) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertNil(helper.error) + + return helper + } + + private func prepareSignUpSubmitPasswordValidatorHelper(_ expectation: XCTestExpectation? = nil) -> SignUpPasswordRequiredTestsValidatorHelper { + let helper = SignUpPasswordRequiredTestsValidatorHelper(expectation: expectation) + XCTAssertFalse(helper.onSignUpCompletedCalled) + XCTAssertFalse(helper.onSignUpPasswordRequiredErrorCalled) + XCTAssertFalse(helper.onSignUpAttributesRequiredCalled) + XCTAssertNil(helper.newAttributesRequiredState) + XCTAssertNil(helper.newPasswordRequiredState) + XCTAssertNil(helper.error) + + return helper + } + + private func prepareSignUpSubmitAttributesValidatorHelper(_ expectation: XCTestExpectation? = nil) -> SignUpAttributesRequiredTestsValidatorHelper { + let helper = SignUpAttributesRequiredTestsValidatorHelper(expectation: expectation) + XCTAssertFalse(helper.onSignUpCompletedCalled) + XCTAssertFalse(helper.onSignUpAttributesRequiredErrorCalled) + XCTAssertNil(helper.newState) + XCTAssertNil(helper.error) + + return helper + } + + private func prepareMockRequest() -> MSIDHttpRequest { + let request = MSIDHttpRequest() + HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) + + return request + } + + private func expectedChallengeParams(token: String = "signUpToken") -> (token: String, context: MSIDRequestContext) { + return (token: token, context: contextMock) + } + + private func expectedContinueParams( + grantType: MSALNativeAuthGrantType = .oobCode, + token: String = "signUpToken", + password: String? = nil, + oobCode: String? = "1234", + attributes: [String: Any]? = nil + ) -> MSALNativeAuthSignUpContinueRequestProviderParams { + .init( + grantType: grantType, + signUpToken: token, + password: password, + oobCode: oobCode, + attributes: attributes, + context: contextMock + ) + } +} diff --git a/MSAL/test/unit/native_auth/controllers/factories/MSALNativeAuthResultFactoryTests.swift b/MSAL/test/unit/native_auth/controllers/factories/MSALNativeAuthResultFactoryTests.swift new file mode 100644 index 0000000000..8e82aa8798 --- /dev/null +++ b/MSAL/test/unit/native_auth/controllers/factories/MSALNativeAuthResultFactoryTests.swift @@ -0,0 +1,119 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthResultFactoryTests: XCTestCase { + + private var sut: MSALNativeAuthResultFactory! + + private let tokenResponseDict: [String: Any] = [ + "token_type": "Bearer", + "scope": "openid profile email", + "expires_in": 4141, + "ext_expires_in": 4141, + "access_token": "accessToken", + "refresh_token": "refreshToken", + "id_token": "idToken" + ] + + override func setUpWithError() throws { + sut = .init(config: MSALNativeAuthConfigStubs.configuration) + } + + func test_makeMsidConfiguration() { + let result = sut.makeMSIDConfiguration(scopes: ["", ""]) + + XCTAssertEqual(result.authority, MSALNativeAuthNetworkStubs.msidAuthority) + XCTAssertNil(result.redirectUri) + XCTAssertEqual(result.clientId, DEFAULT_TEST_CLIENT_ID) + XCTAssertEqual(result.target, " ") + } + + func test_makeUserAccount_returnExpectedResult() { + let accessTokenString = "accessToken" + let idToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ii1LSTNROW5OUjdiUm9meG1lWm9YcWJIWkdldyJ9.eyJhdWQiOiJmODdmN2Q2NS1jZjY2LTQzNzAtYTllZi0yNGQzNzBlZDllNjQiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vZmU2MjYwOTYtZWQ5Ny00NTA0LTg4ZTMtNTVhMzNkMmVkNGQ2L3YyLjAiLCJpYXQiOjE2OTUwMzMzMDYsIm5iZiI6MTY5NTAzMzMwNiwiZXhwIjoxNjk1MDM3MjA2LCJhaW8iOiJBVFFBeS84VUFBQUFyeVNpU1Rsa0dHNTl0VHFmcWdHU1ZZRWY4RzRQbldDSnlUZ2hXdzdDU2MvRGZwMWxYRXI0T1JTWFBJbzdzaldnIiwibmFtZSI6InVua25vd24iLCJvaWQiOiIzYzIwZWM4Zi0xNzVkLTQxMjgtODZhMy01MDM5MDRhNDRiMTUiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJkdWFsdGFnaG1zZnQrc2lnbnVwMzFAb3V0bG9vay5jb20iLCJyaCI6IjAuQWM4QWxtQmlfcGZ0QkVXSTQxV2pQUzdVMW1WOWZfaG16M0JEcWU4azAzRHRubVRQQUJJLiIsInN1YiI6ImcwLTc0U3hHUnhSTjBqT19hXzY4bG9adGVsY1EwdTJFX3hyYmNBaGRtWjAiLCJ0aWQiOiJmZTYyNjA5Ni1lZDk3LTQ1MDQtODhlMy01NWEzM2QyZWQ0ZDYiLCJ1dGkiOiJGeWxCbk9nYkwwQy0zX0Z1Ym5VQUFBIiwidmVyIjoiMi4wIiwiZGF0ZU9mQmlydGgiOiIwMS8wMS8yMDAwIiwiY3VzdG9tUm9sZXMiOlsiV3JpdGVyIiwiRWRpdG9yIl0sImFwaVZlcnNpb24iOiIxLjAuMCIsImNvcnJlbGF0aW9uSWQiOiI4ZmM5M2FlYi01ZmMxLTQzOWQtYjM4OC1kYmY0YjM4ZGM3ODUifQ.rBu4Vw3ftWivyNXaDC7fB6HAB7TucGK1BUbSOt_ZW-ivsPLpHK7A4E0i8hu8Qs-zade6Fsp2deSaZNNLLNQCSDav7iMKZukNwQviWOG_Uvz31GVpkh1l26xTs3dlKS-6NjdwpkvccEg1VeIW-pyC_7RLAaCb1uzMoKFn7mA6meFCYBVnEZ3lRSw0_XtoKrcw5hJfvST4MOe7EJw2a2DH-fu1DDh-5FbCP4Y_nn6esre0I_Q0EwuF_4TYTESy_vqHwXZcTKZq34-5x4thRPGE1I_CBEJZkKXIWC6z788zEXSgnHvRfGEH52bRo_ZuPsftV1R1M9os0wPzgBOWwvMzOA" + let username = "username" + let scopes = ["scope1", "scope2"] + let expiresOn = Date() + let accessToken = MSIDAccessToken() + accessToken.accessToken = accessTokenString + accessToken.accountIdentifier = MSIDAccountIdentifier(displayableId: username, homeAccountId: "") + accessToken.expiresOn = expiresOn + accessToken.scopes = NSOrderedSet(array: scopes) + let refreshToken = MSIDRefreshToken() + refreshToken.refreshToken = "refreshToken" + let msidAccount = MSIDAccount() + msidAccount.username = username + guard let tokenResult = MSIDTokenResult(accessToken: accessToken, refreshToken: refreshToken, idToken: idToken, account: msidAccount, authority: MSALNativeAuthNetworkStubs.msidAuthority, correlationId: UUID(), tokenResponse: nil) else { + XCTFail("Unexpected nil token") + return + } + let context = MSALNativeAuthRequestContext(correlationId: .init(uuidString: DEFAULT_TEST_UID)!) + guard let accountResult = sut.makeUserAccountResult(tokenResult: tokenResult, context: context) else { + XCTFail("Unexpected nil account") + return + } + XCTAssertEqual(accountResult.account.username, username) + XCTAssertEqual(accountResult.idToken, idToken) + XCTAssertEqual(accountResult.expiresOn, expiresOn) + XCTAssertEqual(accountResult.scopes, scopes) + XCTAssertNotNil(accountResult.account.accountClaims) + XCTAssertEqual(accountResult.account.accountClaims?.count, 21) + } + + func test_makeUserAccount_withIncorrectIdToken_accountClaimsNotPresent() { + let accessTokenString = "accessToken" + let idToken = "idToken" + let username = "username" + let scopes = ["scope1", "scope2"] + let expiresOn = Date() + let accessToken = MSIDAccessToken() + accessToken.accessToken = accessTokenString + accessToken.accountIdentifier = MSIDAccountIdentifier(displayableId: username, homeAccountId: "") + accessToken.expiresOn = expiresOn + accessToken.scopes = NSOrderedSet(array: scopes) + let refreshToken = MSIDRefreshToken() + refreshToken.refreshToken = "refreshToken" + let msidAccount = MSIDAccount() + msidAccount.username = username + guard let tokenResult = MSIDTokenResult(accessToken: accessToken, refreshToken: refreshToken, idToken: idToken, account: msidAccount, authority: MSALNativeAuthNetworkStubs.msidAuthority, correlationId: UUID(), tokenResponse: nil) else { + XCTFail("Unexpected nil token") + return + } + let context = MSALNativeAuthRequestContext(correlationId: .init(uuidString: DEFAULT_TEST_UID)!) + guard let accountResult = sut.makeUserAccountResult(tokenResult: tokenResult, context: context) else { + XCTFail("Unexpected nil account") + return + } + XCTAssertEqual(accountResult.account.username, username) + XCTAssertEqual(accountResult.idToken, idToken) + XCTAssertEqual(accountResult.expiresOn, expiresOn) + XCTAssertEqual(accountResult.scopes, scopes) + XCTAssertNil(accountResult.account.accountClaims) + } +} diff --git a/MSAL/test/unit/native_auth/input_validator/MSALNativeAuthInputValidatorTest.swift b/MSAL/test/unit/native_auth/input_validator/MSALNativeAuthInputValidatorTest.swift new file mode 100644 index 0000000000..e6e6fc203b --- /dev/null +++ b/MSAL/test/unit/native_auth/input_validator/MSALNativeAuthInputValidatorTest.swift @@ -0,0 +1,42 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthInputValidatorTest: XCTestCase { + + private let validator = MSALNativeAuthInputValidator() + + func testInput_whenValidInputIsUsed_resultShouldBeValid() { + XCTAssertTrue(validator.isInputValid("email@contoso.com")) + XCTAssertTrue(validator.isInputValid("password")) + XCTAssertTrue(validator.isInputValid("1")) + } + + func testInput_whenInvalidStringInputIsUsed_resultShouldBeInvalid() { + XCTAssertFalse(validator.isInputValid("")) + } +} diff --git a/MSAL/test/unit/native_auth/logger/MSALLogMaskTests.m b/MSAL/test/unit/native_auth/logger/MSALLogMaskTests.m new file mode 100644 index 0000000000..1e503e9392 --- /dev/null +++ b/MSAL/test/unit/native_auth/logger/MSALLogMaskTests.m @@ -0,0 +1,167 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "MSALLogMask.h" + +@interface MSALLogMaskTests : XCTestCase + +@end + +@implementation MSALLogMaskTests + +- (void)setUp +{ + // Put setup code here. This method is called before the invocation of each test method in the class. + [super setUp]; + [MSIDLogger sharedLogger].logMaskingLevel = MSIDLogMaskingSettingsMaskAllPII; +} + +- (void)tearDown +{ + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +#pragma mark - Correctness + +- (void)testMaskPII_returnsCorrect_onNotNil +{ + NSString* string = [[MSALLogMask maskPII:@"Test"] description]; + XCTAssertEqualObjects(string, @"Masked(not-null)"); + XCTAssertTrue([string isEqualToString:@"Masked(not-null)"]); +} + +- (void)testMaskPII_returnsCorrect_onNil +{ + NSString* string = [[MSALLogMask maskPII:nil] description]; + XCTAssertEqualObjects(string, @"Masked(null)"); + XCTAssertTrue([string isEqualToString:@"Masked(null)"]); +} + +- (void)testMaskPII_returnsCorrect_onNotNil_andNotMaksed +{ + [MSIDLogger sharedLogger].logMaskingLevel = MSIDLogMaskingSettingsMaskEUIIOnly; + NSString* string = [[MSALLogMask maskPII:@"Test"] description]; + XCTAssertEqualObjects(string, @"Test"); + XCTAssertTrue([string isEqualToString:@"Test"]); +} + +- (void)testMaskEUII_returnsCorrect_onNotNil +{ + NSString* string = [[MSALLogMask maskEUII:@"UserAccountDummy"] description]; + XCTAssertEqualObjects(string, @"Masked(not-null)"); + XCTAssertTrue([string isEqualToString:@"Masked(not-null)"]); +} + +- (void)testMaskEUII_returnsCorrect_onNill +{ + NSString* string = [[MSALLogMask maskEUII:nil] description]; + XCTAssertEqualObjects(string, @"Masked(null)"); + XCTAssertTrue([string isEqualToString:@"Masked(null)"]); +} + +- (void)testMaskEUII_returnsCorrect_onNotNil_andNotMaksed +{ + [MSIDLogger sharedLogger].logMaskingLevel = MSIDLogMaskingSettingsMaskSecretsOnly; + NSString* string = [[MSALLogMask maskEUII:@"Test"] description]; + XCTAssertEqualObjects(string, @"Test"); + XCTAssertTrue([string isEqualToString:@"Test"]); +} + +- (void) testMaskHashable_returnsCorrect_onNotNil +{ + NSString* string = [[MSALLogMask maskTrackablePII:@"HomeAccountId"] description]; + XCTAssertEqualObjects(string, @"d87b613d"); + XCTAssertTrue([string isEqualToString:@"d87b613d"]); +} + +- (void) testMaskHashable_returnsCorrect_onNil +{ + NSString* string = [[MSALLogMask maskTrackablePII:nil] description]; + XCTAssertEqualObjects(string, @"Masked(null)"); + XCTAssertTrue([string isEqualToString:@"Masked(null)"]); +} + +- (void) testMaskHashable_returnsCorrect_onNotNil_andNotMaksed +{ + [MSIDLogger sharedLogger].logMaskingLevel = MSIDLogMaskingSettingsMaskEUIIOnly; + NSString* string = [[MSALLogMask maskTrackablePII:@"HomeAccountId"] description]; + XCTAssertEqualObjects(string, @"HomeAccountId"); + XCTAssertTrue([string isEqualToString:@"HomeAccountId"]); +} + +- (void) testMaskUsername_returnsCorrect_onNotNil +{ + NSString* string = [[MSALLogMask maskUsername:@"user@contoso.com"] description]; + XCTAssertEqualObjects(string, @"auth.placeholder-04f8996d__contoso.com"); + XCTAssertTrue([string isEqualToString:@"auth.placeholder-04f8996d__contoso.com"]); +} + +- (void) testMaskUsername_returnsCorrect_onNil +{ + NSString* string = [[MSALLogMask maskUsername:nil] description]; + XCTAssertEqualObjects(string, @"Masked(null)"); + XCTAssertTrue([string isEqualToString:@"Masked(null)"]); +} + +- (void) testMaskUsernamereturnsCorrect_onNotNil_andNotMaksed +{ + [MSIDLogger sharedLogger].logMaskingLevel = MSIDLogMaskingSettingsMaskSecretsOnly; + NSString* string = [[MSALLogMask maskUsername:@"user@contoso.com"] description]; + XCTAssertEqualObjects(string, @"user@contoso.com"); + XCTAssertTrue([string isEqualToString:@"user@contoso.com"]); +} + +#pragma mark - Macro + +- (void) testMaskPII_returnsSameAsMacro +{ + NSString* string = [[MSALLogMask maskPII:@"Test"] description]; + XCTAssertEqualObjects(string, [MSID_PII_LOG_MASKABLE(@"Test") description]); + XCTAssertTrue([string isEqualToString:[MSID_PII_LOG_MASKABLE(@"Test") description]]); +} + +- (void) testMaskEUII_returnsSameAsMacro +{ + NSString* string = [[MSALLogMask maskEUII:@"Test"] description]; + XCTAssertEqualObjects(string, [MSID_EUII_ONLY_LOG_MASKABLE(@"Test") description]); + XCTAssertTrue([string isEqualToString:[MSID_EUII_ONLY_LOG_MASKABLE(@"Test") description]]); +} + +- (void) testMaskHashable_returnsSameAsMacro +{ + NSString* string = [[MSALLogMask maskTrackablePII:@"HomeAccountId"] description]; + XCTAssertEqualObjects(string, [MSID_PII_LOG_TRACKABLE(@"HomeAccountId") description]); + XCTAssertTrue([string isEqualToString:[MSID_PII_LOG_TRACKABLE(@"HomeAccountId") description]]); +} + +- (void) testMaskUsername_returnsSameAsMacro +{ + NSString* string = [[MSALLogMask maskUsername:@"user@contoso.com"] description]; + XCTAssertEqualObjects(string, [MSID_PII_LOG_EMAIL(@"user@contoso.com") description]); + XCTAssertTrue([string isEqualToString:[MSID_PII_LOG_EMAIL(@"user@contoso.com") description]]); +} + +@end diff --git a/MSAL/test/unit/native_auth/logger/MSALNativeLoggingTests.swift b/MSAL/test/unit/native_auth/logger/MSALNativeLoggingTests.swift new file mode 100644 index 0000000000..e1ef6438d0 --- /dev/null +++ b/MSAL/test/unit/native_auth/logger/MSALNativeLoggingTests.swift @@ -0,0 +1,342 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthTestLogger : NSObject { + static var instanceCreated = false + + @objc dynamic var containsPII = false + @objc dynamic var messages = NSMutableArray() + @objc dynamic var level: MSALLogLevel = .nothing + var expectation = XCTestExpectation() + private var queue = DispatchQueue(label: "test", qos: .default) + + override init () { + super.init() + guard Self.instanceCreated == false else { + fatalError("Only one instance allowed, inherit the MSALNativeAuthTestCase class and use the Self.logger property there") + } + Self.instanceCreated = true + MSALGlobalConfig.loggerConfig.setLogCallback { [weak self] level, message, containsPII in + self?.queue.sync { + self?.messages.add(message as Any) + self?.containsPII = containsPII + self?.level = level + // Making sure expectation has been set in the test case + if self?.expectation.description != "" { + self?.expectation.fulfill() + } + } + } + } + + func reset() { + queue.sync { + expectation = XCTestExpectation(description: "") + containsPII = false + messages.removeAllObjects() + MSALGlobalConfig.loggerConfig.logLevel = .last + } + } +} + +final class MSALNativeLoggingTests: MSALNativeAuthTestCase { + // Used for clarity of code. The static object is needed because MSALGlobalConfig.loggerConfig.setLogCallback + // must be set only once per execution of test + + let context = MSIDBasicContext() + var correlationId = UUID() + let messageRegexFormat = "\\[\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} - %@\\] %@" + + override func setUpWithError() throws { + try super.setUpWithError() + MSALGlobalConfig.loggerConfig.logMaskingLevel = .settingsMaskAllPII + context.correlationId = UUID() + correlationId = UUID() + } + + // MARK: Log With Context + + func testLogWithContext_noMaskNonNil() throws { + Self.logger.expectation = XCTestExpectation(description: "Callback Invoked") + MSALLogger.log(level: .error, context: context, filename: #file, lineNumber: #line, function: #function, format: "Test %@", "String") + XCTWaiter().wait(for: [Self.logger.expectation], timeout: 1) + + XCTAssertNotNil(Self.logger.messages.object(at: 0)); + if let string = Self.logger.messages.object(at: 0) as? String { + let correctString = "Test String" + let correlationId = context.correlationId?.uuidString ?? "Wrong Correlation Id" + if string.range(of: String(format:messageRegexFormat, correlationId, correctString), options: .regularExpression, range: nil, locale: nil) == nil { + XCTFail("Message doesn't contain proper data or has incorrect format") + } + } else { + XCTFail("Message is not string") + } + } + + + func testLogWithContext_andMasked() throws { + Self.logger.expectation = XCTestExpectation(description: "Callback Invoked") + MSALLogger.log(level: .error, context: context, filename: #file, lineNumber: #line, function: #function, format: "Test %@", MSALLogMask.maskPII("String")) + XCTWaiter().wait(for: [Self.logger.expectation], timeout: 1) + + XCTAssertNotNil(Self.logger.messages.object(at: 0)); + if let string = Self.logger.messages.object(at: 0) as? String { + let correctString = "Test Masked\\(not-null\\)" + let correlationId = context.correlationId?.uuidString ?? "Wrong Correlation Id" + if string.range(of: String(format:messageRegexFormat, correlationId, correctString), options: .regularExpression, range: nil, locale: nil) == nil { + XCTFail("Message doesn't contain proper data or has incorrect format") + } + } else { + XCTFail("Message is not string") + } + } + + func testLogWithContext_maskedAndNull() throws { + Self.logger.expectation = XCTestExpectation(description: "Callback Invoked") + MSALLogger.log(level: .error, context: context, filename: #file, lineNumber: #line, function: #function, format: "Test %@", MSALLogMask.maskPII(nil)) + XCTWaiter().wait(for: [Self.logger.expectation], timeout: 1) + + XCTAssertNotNil(Self.logger.messages.object(at: 0)); + if let string = Self.logger.messages.object(at: 0) as? String { + let correctString = "Test Masked\\(null\\)" + let correlationId = context.correlationId?.uuidString ?? "Wrong Correlation Id" + if string.range(of: String(format:messageRegexFormat, correlationId, correctString), options: .regularExpression, range: nil, locale: nil) == nil { + XCTFail("Message doesn't contain proper data or has incorrect format") + } + } else { + XCTFail("Message is not string") + } + } + + // MARK: Log PII With Context + + func testLogPIIWithContext_andMaskAll() throws { + MSALGlobalConfig.loggerConfig.logMaskingLevel = .settingsMaskAllPII + + Self.logger.expectation = XCTestExpectation(description: "Callback Invoked") + MSALLogger.logPII(level: .error, context: context, filename: #file, lineNumber: #line, function: #function, format: "Test %@", MSALLogMask.maskPII("String")) + XCTWaiter().wait(for: [Self.logger.expectation], timeout: 1) + + XCTAssertNotNil(Self.logger.messages.object(at: 0)); + if let string = Self.logger.messages.object(at: 0) as? String { + let correctString = "Test Masked\\(not\\-null\\)" + let correlationId = context.correlationId?.uuidString ?? "Wrong Correlation Id" + if string.range(of: String(format:messageRegexFormat, correlationId, correctString), options: .regularExpression, range: nil, locale: nil) == nil { + XCTFail("Message doesn't contain proper data or has incorrect format") + } + } else { + XCTFail("Message is not string") + } + XCTAssertFalse(Self.logger.containsPII) + } + + func testLogPIIWithContext_andMaskEUII() throws { + MSALGlobalConfig.loggerConfig.logMaskingLevel = .settingsMaskEUIIOnly + + Self.logger.expectation = XCTestExpectation(description: "Callback Invoked") + MSALLogger.logPII(level: .error, context: context, filename: #file, lineNumber: #line, function: #function, format: "Test %@", MSALLogMask.maskPII("String")) + XCTWaiter().wait(for: [Self.logger.expectation], timeout: 1) + + XCTAssertNotNil(Self.logger.messages.object(at: 0)); + if let string = Self.logger.messages.object(at: 0) as? String { + let correctString = "Test String" + let correlationId = context.correlationId?.uuidString ?? "Wrong Correlation Id" + if string.range(of: String(format:messageRegexFormat, correlationId, correctString), options: .regularExpression, range: nil, locale: nil) == nil { + XCTFail("Message doesn't contain proper data or has incorrect format") + } + } else { + XCTFail("Message is not string") + } + XCTAssertTrue(Self.logger.containsPII) + } + + func testLogPIIWithContext_nilString() throws { + + Self.logger.expectation = XCTestExpectation(description: "Callback Invoked") + MSALLogger.logPII(level: .error, context: context, filename: #file, lineNumber: #line, function: #function, format: "Test %@", MSALLogMask.maskPII(nil)) + XCTWaiter().wait(for: [Self.logger.expectation], timeout: 1) + + XCTAssertNotNil(Self.logger.messages.object(at: 0)); + if let string = Self.logger.messages.object(at: 0) as? String { + let correctString = "Test Masked\\(null\\)" + let correlationId = context.correlationId?.uuidString ?? "Wrong Correlation Id" + if string.range(of: String(format:messageRegexFormat, correlationId, correctString), options: .regularExpression, range: nil, locale: nil) == nil { + XCTFail("Message doesn't contain proper data or has incorrect format") + } + } else { + XCTFail("Message is not string") + } + XCTAssertFalse(Self.logger.containsPII) + } + + func testLogPIIWithContext_nilStringNotMasked() throws { + MSALGlobalConfig.loggerConfig.logMaskingLevel = .settingsMaskEUIIOnly + + Self.logger.expectation = XCTestExpectation(description: "Callback Invoked") + MSALLogger.logPII(level: .error, context: context, filename: #file, lineNumber: #line, function: #function, format: "Test %@", MSALLogMask.maskPII(nil)) + XCTWaiter().wait(for: [Self.logger.expectation], timeout: 1) + + XCTAssertNotNil(Self.logger.messages.object(at: 0)); + if let string = Self.logger.messages.object(at: 0) as? String { + let correctString = "Test \\(null\\)" + let correlationId = context.correlationId?.uuidString ?? "Wrong Correlation Id" + if string.range(of: String(format:messageRegexFormat, correlationId, correctString), options: .regularExpression, range: nil, locale: nil) == nil { + XCTFail("Message doesn't contain proper data or has incorrect format") + } + } else { + XCTFail("Message is not string") + } + XCTAssertTrue(Self.logger.containsPII) + } + + // MARK: Log With Correlation Id + + func testLogWithCorrelationId_noMaskNonNil() throws { + Self.logger.expectation = XCTestExpectation(description: "Callback Invoked") + MSALLogger.log(level: .error, correlationId: correlationId, filename: #file, lineNumber: #line, function: #function, format: "Test %@", "String") + XCTWaiter().wait(for: [Self.logger.expectation], timeout: 1) + + XCTAssertNotNil(Self.logger.messages.object(at: 0)); + if let string = Self.logger.messages.object(at: 0) as? String { + let correctString = "Test String" + if string.range(of: String(format:messageRegexFormat, correlationId.uuidString, correctString), options: .regularExpression, range: nil, locale: nil) == nil { + XCTFail("Message doesn't contain proper data or has incorrect format") + } + } else { + XCTFail("Message is not string") + } + } + + func testLogWithCorrelationId_andMasked() throws { + Self.logger.expectation = XCTestExpectation(description: "Callback Invoked") + MSALLogger.log(level: .error, correlationId: correlationId, filename: #file, lineNumber: #line, function: #function, format: "Test %@", MSALLogMask.maskPII("String")) + XCTWaiter().wait(for: [Self.logger.expectation], timeout: 1) + + XCTAssertNotNil(Self.logger.messages.object(at: 0)); + if let string = Self.logger.messages.object(at: 0) as? String { + let correctString = "Test Masked\\(not\\-null\\)" + if string.range(of: String(format:messageRegexFormat, correlationId.uuidString, correctString), options: .regularExpression, range: nil, locale: nil) == nil { + XCTFail("Message doesn't contain proper data or has incorrect format") + } + } else { + XCTFail("Message is not string") + } + } + + func testLogWithCorrelationId_maskedAndNull() throws { + Self.logger.expectation = XCTestExpectation(description: "Callback Invoked") + MSALLogger.log(level: .error, correlationId: correlationId, filename: #file, lineNumber: #line, function: #function, format: "Test %@", MSALLogMask.maskPII(nil)) + XCTWaiter().wait(for: [Self.logger.expectation], timeout: 1) + + XCTAssertNotNil(Self.logger.messages.object(at: 0)); + if let string = Self.logger.messages.object(at: 0) as? String { + let correctString = "Test Masked\\(null\\)" + if string.range(of: String(format:messageRegexFormat, correlationId.uuidString, correctString), options: .regularExpression, range: nil, locale: nil) == nil { + XCTFail("Message doesn't contain proper data or has incorrect format") + } + } else { + XCTFail("Message is not string") + } + } + + // MARK: Log PII With CorrelationId + + func testLogPIIWithCorrelationId_andMaskAll() throws { + MSALGlobalConfig.loggerConfig.logMaskingLevel = .settingsMaskAllPII + + Self.logger.expectation = XCTestExpectation(description: "Callback Invoked") + MSALLogger.logPII(level: .error, correlationId: correlationId, filename: #file, lineNumber: #line, function: #function, format: "Test %@", MSALLogMask.maskPII("String")) + XCTWaiter().wait(for: [Self.logger.expectation], timeout: 1) + + XCTAssertNotNil(Self.logger.messages.object(at: 0)); + if let string = Self.logger.messages.object(at: 0) as? String { + let correctString = "Test Masked\\(not\\-null\\)" + if string.range(of: String(format:messageRegexFormat, correlationId.uuidString, correctString), options: .regularExpression, range: nil, locale: nil) == nil { + XCTFail("Message doesn't contain proper data or has incorrect format") + } + } else { + XCTFail("Message is not string") + } + XCTAssertFalse(Self.logger.containsPII) + } + + func testLogPIIWithCorrelationId_andMaskEUII() throws { + MSALGlobalConfig.loggerConfig.logMaskingLevel = .settingsMaskEUIIOnly + + Self.logger.expectation = XCTestExpectation(description: "Callback Invoked") + MSALLogger.logPII(level: .error, correlationId: correlationId, filename: #file, lineNumber: #line, function: #function, format: "Test %@", MSALLogMask.maskPII("String")) + XCTWaiter().wait(for: [Self.logger.expectation], timeout: 1) + + XCTAssertNotNil(Self.logger.messages.object(at: 0)); + if let string = Self.logger.messages.object(at: 0) as? String { + let correctString = "Test String" + if string.range(of: String(format:messageRegexFormat, correlationId.uuidString, correctString), options: .regularExpression, range: nil, locale: nil) == nil { + XCTFail("Message doesn't contain proper data or has incorrect format") + } + } else { + XCTFail("Message is not string") + } + XCTAssertTrue(Self.logger.containsPII) + } + + func testLogPIIWithCorrelationId_nilString() throws { + Self.logger.expectation = XCTestExpectation(description: "Callback Invoked") + MSALLogger.logPII(level: .error, correlationId: correlationId, filename: #file, lineNumber: #line, function: #function, format: "Test %@", MSALLogMask.maskPII(nil)) + XCTWaiter().wait(for: [Self.logger.expectation], timeout: 1) + + XCTAssertNotNil(Self.logger.messages.object(at: 0)); + if let string = Self.logger.messages.object(at: 0) as? String { + let correctString = "Test Masked\\(null\\)" + if string.range(of: String(format:messageRegexFormat, correlationId.uuidString, correctString), options: .regularExpression, range: nil, locale: nil) == nil { + XCTFail("Message doesn't contain proper data or has incorrect format") + } + } else { + XCTFail("Message is not string") + } + XCTAssertFalse(Self.logger.containsPII) + } + + func testLogPIIWithCorrelationId_nilStringNotMasked() throws { + MSALGlobalConfig.loggerConfig.logMaskingLevel = .settingsMaskEUIIOnly + + Self.logger.expectation = XCTestExpectation(description: "Callback Invoked") + MSALLogger.logPII(level: .error, correlationId: correlationId, filename: #file, lineNumber: #line, function: #function, format: "Test %@", MSALLogMask.maskPII(nil)) + XCTWaiter().wait(for: [Self.logger.expectation], timeout: 1) + + XCTAssertNotNil(Self.logger.messages.object(at: 0)); + if let string = Self.logger.messages.object(at: 0) as? String { + let correctString = "Test \\(null\\)" + if string.range(of: String(format:messageRegexFormat, correlationId.uuidString, correctString), options: .regularExpression, range: nil, locale: nil) == nil { + XCTFail("Message doesn't contain proper data or has incorrect format") + } + } else { + XCTFail("Message is not string") + } + XCTAssertTrue(Self.logger.containsPII) + } +} diff --git a/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift b/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift new file mode 100644 index 0000000000..764d8ffa14 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift @@ -0,0 +1,78 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +open class CredentialsDelegateSpy: CredentialsDelegate { + + private let expectation: XCTestExpectation + var expectedError: RetrieveAccessTokenError? + var expectedAccessToken: String? + + init(expectation: XCTestExpectation, expectedError: RetrieveAccessTokenError? = nil, expectedAccessToken: String? = nil) { + self.expectation = expectation + self.expectedError = expectedError + self.expectedAccessToken = expectedAccessToken + } + + public func onAccessTokenRetrieveCompleted(accessToken: String) { + if let expectedAccessToken = expectedAccessToken { + XCTAssertTrue(Thread.isMainThread) + XCTAssertEqual(expectedAccessToken, accessToken) + } else { + XCTFail("This method should not be called") + } + expectation.fulfill() + } + + public func onAccessTokenRetrieveError(error: MSAL.RetrieveAccessTokenError) { + if let expectedError = expectedError { + XCTAssertTrue(Thread.isMainThread) + XCTAssertEqual(error.type, expectedError.type) + XCTAssertEqual(error.errorDescription, expectedError.errorDescription) + expectation.fulfill() + return + } + } +} + +class CredentialsTestValidatorHelper: CredentialsDelegateSpy { + + func onAccessTokenRetrieveCompleted(_ result: Result) { + guard case let .success(token) = result else { + return XCTFail("wrong result") + } + + Task { await self.onAccessTokenRetrieveCompleted(accessToken: token) } + } + + func onAccessTokenRetrieveError(_ result: Result) { + guard case let .failure(error) = result else { + return XCTFail("wrong result") + } + + Task { await self.onAccessTokenRetrieveError(error: error) } + } +} diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthCacheMocks.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthCacheMocks.swift new file mode 100644 index 0000000000..b94b20b853 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthCacheMocks.swift @@ -0,0 +1,68 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthCacheAccessorMock: MSALNativeAuthCacheInterface { + enum E: Error { + case notImplemented + case noAccount + case noTokens + } + + private(set) var validateAndSaveTokensWasCalled = false + private(set) var clearCacheWasCalled = false + var expectedMSIDTokenResult: MSIDTokenResult? + var mockUserAccounts: [MSALAccount]? + var mockAuthTokens: MSALNativeAuthTokens? + + func getTokens(account: MSALAccount, configuration: MSIDConfiguration, context: MSIDRequestContext) throws -> MSAL.MSALNativeAuthTokens { + guard let mockAuthTokens = mockAuthTokens else { + throw E.noTokens + } + return mockAuthTokens + } + + func getAllAccounts(configuration: MSIDConfiguration) throws -> [MSALAccount] { + guard let mockUserAccounts = mockUserAccounts else { + throw E.noAccount + } + return mockUserAccounts + } + + func validateAndSaveTokensAndAccount(tokenResponse: MSIDTokenResponse, configuration: MSIDConfiguration, context: MSIDRequestContext) throws -> MSIDTokenResult? { + validateAndSaveTokensWasCalled = true + return expectedMSIDTokenResult + } + + func removeTokens(accountIdentifier: MSIDAccountIdentifier, authority: MSIDAuthority, clientId: String, context: MSIDRequestContext) throws { + throw E.notImplemented + } + + func clearCache(accountIdentifier: MSIDAccountIdentifier, authority: MSIDAuthority, clientId: String, context: MSIDRequestContext) throws { + clearCacheWasCalled = true + } +} diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthConfigStubs.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthConfigStubs.swift new file mode 100644 index 0000000000..de85816fbe --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthConfigStubs.swift @@ -0,0 +1,57 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private +@_implementationOnly import MSAL_Unit_Test_Private + +enum ErrorMock: Error { + case error +} + +struct MSALNativeAuthConfigStubs { + + static var configuration: MSALNativeAuthConfiguration { + try! .init( + clientId: DEFAULT_TEST_CLIENT_ID, + authority: try! .init( + url: URL(string: DEFAULT_TEST_AUTHORITY)! + ), + challengeTypes: [.redirect] + ) + } + + static var msidConfiguration: MSIDConfiguration { + .init( + authority: try! .init( + url: URL(string: DEFAULT_TEST_AUTHORITY)!, + context: MSALNativeAuthRequestContext() + ), + redirectUri: "", + clientId: DEFAULT_TEST_CLIENT_ID, + target: "" + ) + } +} diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthCredentialsControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthCredentialsControllerMock.swift new file mode 100644 index 0000000000..3aa6f12a9c --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthCredentialsControllerMock.swift @@ -0,0 +1,41 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthCredentialsControllerMock: MSALNativeAuthCredentialsControlling { + + var refreshTokenResult: Result! + var accountResult: MSALNativeAuthUserAccountResult? + + func refreshToken(context: MSAL.MSALNativeAuthRequestContext, authTokens: MSAL.MSALNativeAuthTokens) async -> Result { + return refreshTokenResult + } + + func retrieveUserAccountResult(context: MSAL.MSALNativeAuthRequestContext) -> MSAL.MSALNativeAuthUserAccountResult? { + return accountResult + } +} diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthFactoriesMocks.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthFactoriesMocks.swift new file mode 100644 index 0000000000..f444b88be1 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthFactoriesMocks.swift @@ -0,0 +1,93 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthResultFactoryMock: MSALNativeAuthResultBuildable { + + var config: MSAL.MSALNativeAuthConfiguration = MSALNativeAuthConfigStubs.configuration + + private(set) var makeMsidConfigurationResult: MSIDConfiguration? + private(set) var makeNativeAuthUserAccountResult: MSALNativeAuthUserAccountResult? + + func mockMakeUserAccountResult(_ result: MSALNativeAuthUserAccountResult) { + self.makeNativeAuthUserAccountResult = result + } + + func makeUserAccountResult(tokenResult: MSIDTokenResult, context: MSIDRequestContext) -> MSAL.MSALNativeAuthUserAccountResult? { + return makeNativeAuthUserAccountResult ?? .init( + account: MSALAccount.init(msidAccount: tokenResult.account, createTenantProfile: false), + authTokens: MSALNativeAuthTokens( + accessToken: tokenResult.accessToken, + refreshToken: tokenResult.refreshToken as? MSIDRefreshToken, + rawIdToken: tokenResult.rawIdToken + ), + configuration: MSALNativeAuthConfigStubs.configuration, + cacheAccessor: MSALNativeAuthCacheAccessorMock() + ) + } + + func makeUserAccountResult(account: MSALAccount, authTokens: MSAL.MSALNativeAuthTokens) -> MSAL.MSALNativeAuthUserAccountResult? { + return makeNativeAuthUserAccountResult ?? .init( + account: account, + authTokens: authTokens, + configuration: MSALNativeAuthConfigStubs.configuration, + cacheAccessor: MSALNativeAuthCacheAccessorMock() + ) + } + + func mockMakeMsidConfigurationFunc(_ result: MSIDConfiguration) { + self.makeMsidConfigurationResult = result + } + + func makeMSIDConfiguration(scopes: [String]) -> MSIDConfiguration { + return makeMsidConfigurationResult ?? MSALNativeAuthConfigStubs.msidConfiguration + } +} + +class MSALNativeAuthControllerFactoryMock: MSALNativeAuthControllerBuildable { + + var signUpController = MSALNativeAuthSignUpControllerMock() + var signInController = MSALNativeAuthSignInControllerMock() + var resetPasswordController = MSALNativeAuthResetPasswordControllerMock() + var credentialsController = MSALNativeAuthCredentialsControllerMock() + + func makeSignUpController() -> MSAL.MSALNativeAuthSignUpControlling { + return signUpController + } + + func makeSignInController() -> MSAL.MSALNativeAuthSignInControlling { + return signInController + } + + func makeResetPasswordController() -> MSAL.MSALNativeAuthResetPasswordControlling { + return resetPasswordController + } + + func makeCredentialsController() -> MSAL.MSALNativeAuthCredentialsControlling { + return credentialsController + } +} diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift new file mode 100644 index 0000000000..d45868031d --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift @@ -0,0 +1,305 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private +@_implementationOnly import MSAL_Unit_Test_Private + +struct MSALNativeAuthNetworkStubs { + + static let tenantSubdomain = "test_tenant" + + static var authority: MSALCIAMAuthority { + try! .init( + url: .init(string: DEFAULT_TEST_AUTHORITY)! + ) + } + + static var msidAuthority: MSIDCIAMAuthority { + try! .init( + url: .init(string: DEFAULT_TEST_AUTHORITY)!, + validateFormat: false, + rawTenant: tenantSubdomain, + context: nil + ) + } +} + +class MSALNativeAuthRequestContextMock: MSIDRequestContext { + + let mockCorrelationId: UUID + var mockTelemetryRequestId = "" + var mockLogComponent = "" + var mockAppRequestMetadata: [AnyHashable: Any] = [:] + + init(correlationId: UUID = .init(uuidString: DEFAULT_TEST_UID)!) { + self.mockCorrelationId = correlationId + } + + func correlationId() -> UUID { + return mockCorrelationId + } + + func logComponent() -> String { + return mockLogComponent + } + + func telemetryRequestId() -> String { + return mockTelemetryRequestId + } + + func appRequestMetadata() -> [AnyHashable: Any] { + return mockAppRequestMetadata + } +} + +class MSALNativeAuthSignInResponseValidatorMock: MSALNativeAuthSignInResponseValidating { + + var expectedRequestContext: MSALNativeAuthRequestContext? + var expectedConfiguration: MSIDConfiguration? + var expectedChallengeResponse: MSALNativeAuthSignInChallengeResponse? + var expectedInitiateResponse: MSALNativeAuthSignInInitiateResponse? + var expectedResponseError: Error? + var initiateValidatedResponse: MSALNativeAuthSignInInitiateValidatedResponse = .error(.userNotFound(message: nil)) + var challengeValidatedResponse: MSALNativeAuthSignInChallengeValidatedResponse = .error(.expiredToken(message: nil)) + + + func validate(context: MSAL.MSALNativeAuthRequestContext, result: Result) -> MSAL.MSALNativeAuthSignInChallengeValidatedResponse { + checkConfAndContext(context) + if case .success(let successChallengeResponse) = result, let expectedChallengeResponse = expectedChallengeResponse { + XCTAssertEqual(successChallengeResponse.challengeType, expectedChallengeResponse.challengeType) + XCTAssertEqual(successChallengeResponse.credentialToken, expectedChallengeResponse.credentialToken) + XCTAssertEqual(successChallengeResponse.challengeTargetLabel, expectedChallengeResponse.challengeTargetLabel) + XCTAssertEqual(successChallengeResponse.challengeChannel, expectedChallengeResponse.challengeChannel) + XCTAssertEqual(successChallengeResponse.codeLength, expectedChallengeResponse.codeLength) + } + if case .failure(let challengeResponseError) = result, let expectedChallengeResponseError = expectedResponseError { + XCTAssertTrue(type(of: challengeResponseError) == type(of: expectedChallengeResponseError)) + XCTAssertEqual(challengeResponseError.localizedDescription, expectedChallengeResponseError.localizedDescription) + } + return challengeValidatedResponse + } + + func validate(context: MSAL.MSALNativeAuthRequestContext, result: Result) -> MSAL.MSALNativeAuthSignInInitiateValidatedResponse { + checkConfAndContext(context) + if case .success(let successInitiateResponse) = result, let expectedInitiateResponse = expectedInitiateResponse { + XCTAssertEqual(successInitiateResponse.challengeType, expectedInitiateResponse.challengeType) + XCTAssertEqual(successInitiateResponse.credentialToken, expectedInitiateResponse.credentialToken) + } + if case .failure(let initiateResponseError) = result, let expectedInitiateResponseError = expectedResponseError { + XCTAssertTrue(type(of: initiateResponseError) == type(of: expectedInitiateResponseError)) + XCTAssertEqual(initiateResponseError.localizedDescription, expectedInitiateResponseError.localizedDescription) + } + return initiateValidatedResponse + } + + private func checkConfAndContext(_ context: MSAL.MSALNativeAuthRequestContext, config: MSIDConfiguration? = nil) { + if let expectedRequestContext = expectedRequestContext { + XCTAssertEqual(expectedRequestContext.correlationId(), context.correlationId()) + XCTAssertEqual(expectedRequestContext.telemetryRequestId(), context.telemetryRequestId()) + } + if let expectedConfiguration = expectedConfiguration { + XCTAssertEqual(expectedConfiguration, config) + } + } +} + +class MSALNativeAuthTokenResponseValidatorMock: MSALNativeAuthTokenResponseValidating { + + var expectedRequestContext: MSALNativeAuthRequestContext? + var expectedConfiguration: MSIDConfiguration? + var expectedTokenResponse: MSIDCIAMTokenResponse? + var expectedResponseError: Error? + var tokenValidatedResponse: MSALNativeAuthTokenValidatedResponse = .error(.generalError) + + func validate(context: MSAL.MSALNativeAuthRequestContext, msidConfiguration: MSIDConfiguration, result: Result) -> MSAL.MSALNativeAuthTokenValidatedResponse { + checkConfAndContext(context, config: msidConfiguration) + if case .success(let successTokenResponse) = result, let expectedTokenResponse = expectedTokenResponse { + XCTAssertEqual(successTokenResponse.accessToken, expectedTokenResponse.accessToken) + XCTAssertEqual(successTokenResponse.refreshToken, expectedTokenResponse.refreshToken) + XCTAssertEqual(successTokenResponse.idToken, expectedTokenResponse.idToken) + XCTAssertEqual(successTokenResponse.scope, expectedTokenResponse.scope) + } + if case .failure(let tokenResponseError) = result, let expectedTokenResponseError = expectedResponseError { + XCTAssertTrue(type(of: tokenResponseError) == type(of: expectedResponseError)) + XCTAssertEqual(tokenResponseError.localizedDescription, expectedTokenResponseError.localizedDescription) + } + return tokenValidatedResponse + } + + func validateAccount(with tokenResult: MSIDTokenResult, context: MSIDRequestContext, accountIdentifier: MSIDAccountIdentifier) throws -> Bool { + true + } + + private func checkConfAndContext(_ context: MSAL.MSALNativeAuthRequestContext, config: MSIDConfiguration? = nil) { + if let expectedRequestContext = expectedRequestContext { + XCTAssertEqual(expectedRequestContext.correlationId(), context.correlationId()) + XCTAssertEqual(expectedRequestContext.telemetryRequestId(), context.telemetryRequestId()) + } + if let expectedConfiguration = expectedConfiguration { + XCTAssertEqual(expectedConfiguration, config) + } + } +} + +class MSALNativeAuthSignInRequestProviderMock: MSALNativeAuthSignInRequestProviding { + + var throwingInitError: Error? + var throwingChallengeError: Error? + var throwingTokenError: Error? + var result: MSIDHttpRequest? + var expectedContext: MSIDRequestContext? + var expectedUsername: String? + var expectedCredentialToken: String? + + func inititate(parameters: MSAL.MSALNativeAuthSignInInitiateRequestParameters, context: MSIDRequestContext) throws -> MSIDHttpRequest { + checkContext(context) + if let expectedUsername = expectedUsername { + XCTAssertEqual(expectedUsername, parameters.username) + } + return try returnMockedResult(throwingInitError) + } + + func challenge(parameters: MSAL.MSALNativeAuthSignInChallengeRequestParameters, context: MSIDRequestContext) throws -> MSIDHttpRequest { + checkContext(context) + if let expectedCredentialToken = expectedCredentialToken { + XCTAssertEqual(expectedCredentialToken, parameters.credentialToken) + } + return try returnMockedResult(throwingChallengeError) + } + + fileprivate func checkContext(_ context: MSIDRequestContext) { + if let expectedContext = expectedContext { + XCTAssertEqual(expectedContext.correlationId(), context.correlationId()) + } + } + + private func returnMockedResult(_ error: Error?) throws -> MSIDHttpRequest { + if let throwingError = error { + throw throwingError + } + if let result = result { + return result + } + XCTFail("Both parameters are nil") + throw ErrorMock.error + } +} + +class MSALNativeAuthTokenRequestProviderMock: MSALNativeAuthTokenRequestProviding { + + var throwingInitError: Error? + var throwingChallengeError: Error? + var throwingTokenError: Error? + var result: MSIDHttpRequest? + var expectedUsername: String? + var expectedCredentialToken: String? + var expectedContext: MSIDRequestContext? + var expectedTokenParams: MSALNativeAuthTokenRequestParameters? + + func signInWithPassword(parameters: MSAL.MSALNativeAuthTokenRequestParameters, context: MSIDRequestContext) throws -> MSIDHttpRequest { + checkContext(context) + if let expectedTokenParams = expectedTokenParams { + XCTAssertEqual(expectedTokenParams.username, parameters.username) + XCTAssertEqual(expectedTokenParams.credentialToken, parameters.credentialToken) + XCTAssertEqual(expectedTokenParams.signInSLT, parameters.signInSLT) + XCTAssertEqual(expectedTokenParams.grantType, parameters.grantType) + XCTAssertEqual(expectedTokenParams.scope, parameters.scope) + XCTAssertEqual(expectedTokenParams.password, parameters.password) + XCTAssertEqual(expectedTokenParams.oobCode, parameters.oobCode) + XCTAssertEqual(expectedTokenParams.context.correlationId(), parameters.context.correlationId()) + } + return try returnMockedResult(throwingTokenError) + } + + func refreshToken(parameters: MSAL.MSALNativeAuthTokenRequestParameters, context: MSIDRequestContext) throws -> MSIDHttpRequest { + checkContext(context) + if let expectedTokenParams = expectedTokenParams { + XCTAssertEqual(expectedTokenParams.username, parameters.username) + XCTAssertEqual(expectedTokenParams.credentialToken, parameters.credentialToken) + XCTAssertEqual(expectedTokenParams.signInSLT, parameters.signInSLT) + XCTAssertEqual(expectedTokenParams.grantType, parameters.grantType) + XCTAssertEqual(expectedTokenParams.scope, parameters.scope) + XCTAssertEqual(expectedTokenParams.password, parameters.password) + XCTAssertEqual(expectedTokenParams.oobCode, parameters.oobCode) + XCTAssertEqual(expectedTokenParams.context.correlationId(), parameters.context.correlationId()) + } + return try returnMockedResult(throwingTokenError) + } + + + + fileprivate func checkContext(_ context: MSIDRequestContext) { + if let expectedContext = expectedContext { + XCTAssertEqual(expectedContext.correlationId(), context.correlationId()) + } + } + + private func returnMockedResult(_ error: Error?) throws -> MSIDHttpRequest { + if let throwingError = error { + throw throwingError + } + if let result = result { + return result + } + XCTFail("Both parameters are nil") + throw ErrorMock.error + } +} + +class HttpModuleMockConfigurator { + + static let baseUrl = URL(string: "https://www.contoso.com")! + + static func configure(request: MSIDHttpRequest, + response: HTTPURLResponse? = nil, + responseJson: Any) { + + let parameters = ["p1": "v1"] + + var httpResponse: HTTPURLResponse! + if response == nil { + httpResponse = HTTPURLResponse( + url: HttpModuleMockConfigurator.baseUrl, + statusCode: 200, + httpVersion: nil, + headerFields: nil + ) + } else { + httpResponse = response + } + + var urlRequest = URLRequest(url: HttpModuleMockConfigurator.baseUrl) + urlRequest.httpMethod = "POST" + + let testUrlResponse = MSIDTestURLResponse.request(HttpModuleMockConfigurator.baseUrl, reponse: httpResponse) + testUrlResponse?.setUrlFormEncodedBody(parameters) + testUrlResponse?.setResponseJSON(responseJson) + MSIDTestURLSession.add(testUrlResponse) + + request.urlRequest = urlRequest + request.parameters = parameters + } +} diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift new file mode 100644 index 0000000000..c08b3e1c35 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift @@ -0,0 +1,51 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthResetPasswordControllerMock: MSALNativeAuthResetPasswordControlling { + + var resetPasswordResult: ResetPasswordStartResult! + var resendCodeResult: ResetPasswordResendCodeResult! + var submitCodeResult: ResetPasswordVerifyCodeResult! + var submitPasswordResult: ResetPasswordRequiredResult! + + func resetPassword(parameters: MSAL.MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartResult { + return resetPasswordResult + } + + func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeResult { + return resendCodeResult + } + + func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordVerifyCodeResult { + return submitCodeResult + } + + func submitPassword(password: String, passwordSubmitToken: String, context: MSIDRequestContext) async -> ResetPasswordRequiredResult { + return submitPasswordResult + } +} diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift new file mode 100644 index 0000000000..1aa8fde4a3 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift @@ -0,0 +1,68 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +class MSALNativeAuthSignInControllerMock: MSALNativeAuthSignInControlling { + + private(set) var username: String? + private(set) var slt: String? + var expectation: XCTestExpectation? + + var signInPasswordStartResult: MSALNativeAuthSignInControlling.SignInPasswordControllerResponse! + var signInStartResult: MSALNativeAuthSignInControlling.SignInCodeControllerResponse! + var signInSLTResult: Result! + var submitCodeResult: SignInVerifyCodeResult! + var submitPasswordResult: SignInPasswordRequiredResult! + var resendCodeResult: SignInResendCodeResult! + + func signIn(params: MSAL.MSALNativeAuthSignInWithPasswordParameters) async -> MSALNativeAuthSignInControlling.SignInPasswordControllerResponse { + return signInPasswordStartResult + } + + func signIn(params: MSAL.MSALNativeAuthSignInWithCodeParameters) async -> MSALNativeAuthSignInControlling.SignInCodeControllerResponse { + return signInStartResult + } + + func signIn(username: String, slt: String?, scopes: [String]?, context: MSAL.MSALNativeAuthRequestContext) async -> Result { + self.username = username + self.slt = slt + expectation?.fulfill() + + return signInSLTResult + } + + func submitCode(_ code: String, credentialToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInVerifyCodeResult { + submitCodeResult + } + + func submitPassword(_ password: String, username: String, credentialToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInPasswordRequiredResult { + return submitPasswordResult + } + + func resendCode(credentialToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInResendCodeResult { + return resendCodeResult + } +} diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift new file mode 100644 index 0000000000..418db74e41 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift @@ -0,0 +1,61 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthSignUpControllerMock: MSALNativeAuthSignUpControlling { + + var startPasswordResult: MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse! + var startResult: MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse! + var resendCodeResult: SignUpResendCodeResult! + var submitCodeResult: MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse! + var submitPasswordResult: MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse! + var submitAttributesResult: SignUpAttributesRequiredResult! + + func signUpStartPassword(parameters: MSAL.MSALNativeAuthSignUpStartRequestProviderParameters) async -> MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse { + return startPasswordResult + } + + func signUpStartCode(parameters: MSAL.MSALNativeAuthSignUpStartRequestProviderParameters) async -> MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse { + return startResult + } + + func resendCode(username: String, context: MSIDRequestContext, signUpToken: String) async -> SignUpResendCodeResult { + return resendCodeResult + } + + func submitCode(_ code: String, username: String, signUpToken: String, context: MSIDRequestContext) async -> MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse { + return submitCodeResult + } + + func submitPassword(_ password: String, username: String, signUpToken: String, context: MSIDRequestContext) async -> MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse { + return submitPasswordResult + } + + func submitAttributes(_ attributes: [String : Any], username: String, signUpToken: String, context: MSIDRequestContext) async -> SignUpAttributesRequiredResult { + return submitAttributesResult + } +} diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift new file mode 100644 index 0000000000..18803d8e37 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift @@ -0,0 +1,107 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthSignUpControllerSpy: MSALNativeAuthSignUpControlling { + private let expectation: XCTestExpectation + private(set) var context: MSIDRequestContext? + private(set) var signUpStartPasswordCalled = false + private(set) var signUpStartCalled = false + private(set) var resendCodeCalled = false + private(set) var submitCodeCalled = false + private(set) var submitPasswordCalled = false + private(set) var submitAttributesCalled = false + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func signUpStartPassword( + parameters: MSAL.MSALNativeAuthSignUpStartRequestProviderParameters + ) async -> MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse { + self.context = parameters.context + signUpStartPasswordCalled = true + expectation.fulfill() + return .init(.error(.init(type: .generalError))) + } + + func signUpStartCode( + parameters: MSAL.MSALNativeAuthSignUpStartRequestProviderParameters + ) async -> MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse { + self.context = parameters.context + signUpStartCalled = true + expectation.fulfill() + return .init(.error(.init(type: .generalError))) + } + + func resendCode( + username: String, + context: MSIDRequestContext, + signUpToken: String + ) async -> SignUpResendCodeResult { + self.context = context + resendCodeCalled = true + expectation.fulfill() + return .error(.init()) + } + + func submitCode( + _ code: String, + username: String, + signUpToken: String, + context: MSIDRequestContext + ) async -> MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse { + self.context = context + submitCodeCalled = true + expectation.fulfill() + return .init(.error(error: .init(type: .generalError), newState: nil)) + } + + func submitPassword( + _ password: String, + username: String, + signUpToken: String, + context: MSIDRequestContext + ) async -> MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse { + self.context = context + submitPasswordCalled = true + expectation.fulfill() + return .init(.error(error: .init(type: .generalError), newState: nil)) + } + + func submitAttributes( + _ attributes: [String: Any], + username: String, + signUpToken: String, + context: MSIDRequestContext + ) async -> SignUpAttributesRequiredResult { + self.context = context + submitAttributesCalled = true + expectation.fulfill() + return .error(error: .init()) + } +} diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift new file mode 100644 index 0000000000..0498377e2d --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift @@ -0,0 +1,117 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthSignUpRequestProviderMock: MSALNativeAuthSignUpRequestProviding { + private var requestStart: MSIDHttpRequest? + private var requestChallenge: MSIDHttpRequest? + private var requestContinue: MSIDHttpRequest? + private var throwErrorStart = false + private var throwErrorChallenge = false + private var throwErrorContinue = false + private(set) var startCalled = false + private(set) var challengeCalled = false + private(set) var continueCalled = false + var expectedStartRequestParameters: MSALNativeAuthSignUpStartRequestProviderParameters! + var expectedChallengeRequestParameters: (token: String, context: MSIDRequestContext)! + var expectedContinueRequestParameters: MSALNativeAuthSignUpContinueRequestProviderParams! + + func mockStartRequestFunc(_ request: MSIDHttpRequest?, throwError: Bool = false) { + self.requestStart = request + self.throwErrorStart = throwError + } + + func start(parameters: MSAL.MSALNativeAuthSignUpStartRequestProviderParameters) throws -> MSIDHttpRequest { + startCalled = true + checkStartParameters(params: parameters) + + if let request = requestStart { + return request + } else if throwErrorStart { + throw ErrorMock.error + } else { + fatalError("Make sure to use mockStartRequestFunc()") + } + } + + private func checkStartParameters(params: MSALNativeAuthSignUpStartRequestProviderParameters) { + XCTAssertEqual(params.username, expectedStartRequestParameters.username) + XCTAssertEqual(params.password, expectedStartRequestParameters.password) + XCTAssertEqual(params.context.correlationId(), expectedStartRequestParameters.context.correlationId()) + XCTAssertEqual(params.attributes["key"] as? String, expectedStartRequestParameters.attributes["key"] as? String) + } + + func mockChallengeRequestFunc(_ request: MSIDHttpRequest?, throwError: Bool = false) { + self.requestChallenge = request + self.throwErrorChallenge = throwError + } + + func challenge(token: String, context: MSIDRequestContext) throws -> MSIDHttpRequest { + challengeCalled = true + checkChallengeParameters(token: token, context: context) + + if let request = requestChallenge { + return request + } else if throwErrorChallenge { + throw ErrorMock.error + } else { + fatalError("Make sure to use mockChallengeRequestFunc()") + } + } + + private func checkChallengeParameters(token: String, context: MSIDRequestContext) { + XCTAssertEqual(token, expectedChallengeRequestParameters.token) + XCTAssertEqual(context.correlationId(), expectedChallengeRequestParameters.context.correlationId()) + } + + func mockContinueRequestFunc(_ request: MSIDHttpRequest?, throwError: Bool = false) { + self.requestContinue = request + self.throwErrorContinue = throwError + } + + func `continue`(parameters: MSAL.MSALNativeAuthSignUpContinueRequestProviderParams) throws -> MSIDHttpRequest { + continueCalled = true + checkContinueParameters(parameters) + + if let request = requestContinue { + return request + } else if throwErrorContinue { + throw ErrorMock.error + } else { + fatalError("Make sure to use mockContinueRequestFunc()") + } + } + + private func checkContinueParameters(_ params: MSALNativeAuthSignUpContinueRequestProviderParams) { + XCTAssertEqual(params.grantType, expectedContinueRequestParameters.grantType) + XCTAssertEqual(params.signUpToken, expectedContinueRequestParameters.signUpToken) + XCTAssertEqual(params.password, expectedContinueRequestParameters.password) + XCTAssertEqual(params.oobCode, expectedContinueRequestParameters.oobCode) + XCTAssertEqual(params.attributes?["key"] as? String, expectedContinueRequestParameters.attributes?["key"] as? String) + XCTAssertEqual(params.context.correlationId(), expectedContinueRequestParameters.context.correlationId()) + } +} diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpResponseValidatorMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpResponseValidatorMock.swift new file mode 100644 index 0000000000..0cfae326d2 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpResponseValidatorMock.swift @@ -0,0 +1,69 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthSignUpResponseValidatorMock: MSALNativeAuthSignUpResponseValidating { + + private var signUpStartValidatedResponse: MSALNativeAuthSignUpStartValidatedResponse? + private var signUpChallengeValidatedResponse: MSALNativeAuthSignUpChallengeValidatedResponse? + private var signUpContinueContinueResponse: MSALNativeAuthSignUpContinueValidatedResponse? + + func mockValidateSignUpStartFunc(_ response: MSALNativeAuthSignUpStartValidatedResponse) { + self.signUpStartValidatedResponse = response + } + + func validate(_ result: Result, with context: MSIDRequestContext) -> MSAL.MSALNativeAuthSignUpStartValidatedResponse { + if let signUpStartValidatedResponse = signUpStartValidatedResponse { + return signUpStartValidatedResponse + } else { + fatalError("Make sure you call mockValidateSignUpStartFunc()") + } + } + + func mockValidateSignUpChallengeFunc(_ response: MSALNativeAuthSignUpChallengeValidatedResponse) { + self.signUpChallengeValidatedResponse = response + } + + func validate(_ result: Result, with context: MSIDRequestContext) -> MSAL.MSALNativeAuthSignUpChallengeValidatedResponse { + if let signUpChallengeValidatedResponse = signUpChallengeValidatedResponse { + return signUpChallengeValidatedResponse + } else { + fatalError("Make sure you call mockValidateSignUpChallengeFunc()") + } + } + + func mockValidateSignUpContinueFunc(_ response: MSALNativeAuthSignUpContinueValidatedResponse) { + self.signUpContinueContinueResponse = response + } + + func validate(_ result: Result, with context: MSIDRequestContext) -> MSAL.MSALNativeAuthSignUpContinueValidatedResponse { + if let signUpContinueContinueResponse = signUpContinueContinueResponse { + return signUpContinueContinueResponse + } else { + fatalError("Make sure you call mockValidateSignUpContinueFunc()") + } + } +} diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthUserAccountResultStub.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthUserAccountResultStub.swift new file mode 100644 index 0000000000..f1a1c67185 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthUserAccountResultStub.swift @@ -0,0 +1,62 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +import Foundation + +struct MSALNativeAuthUserAccountResultStub { + + + static var result : MSALNativeAuthUserAccountResult { + return MSALNativeAuthUserAccountResult( + account: account, + authTokens: authTokens, + configuration: MSALNativeAuthConfigStubs.configuration, + cacheAccessor: MSALNativeAuthCacheAccessorMock() + ) + } + + static var account: MSALAccount { + MSALAccount(username: "username", + homeAccountId: MSALAccountId(), + environment: "", + tenantProfiles: []) + } + + static var authTokens: MSALNativeAuthTokens { + let accessToken = MSIDAccessToken() + accessToken.accessToken = "accessToken" + accessToken.expiresOn = Date() + accessToken.scopes = [] + let refreshToken = MSIDRefreshToken() + refreshToken.refreshToken = "refreshToken" + return MSALNativeAuthTokens(accessToken: accessToken, + refreshToken: refreshToken, + rawIdToken: "idToken") + } + +} diff --git a/MSAL/test/unit/native_auth/mock/ResetPasswordDelegateSpies.swift b/MSAL/test/unit/native_auth/mock/ResetPasswordDelegateSpies.swift new file mode 100644 index 0000000000..c46139d82e --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/ResetPasswordDelegateSpies.swift @@ -0,0 +1,161 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +class ResetPasswordStartDelegateSpy: ResetPasswordStartDelegate { + let expectation: XCTestExpectation? + private(set) var onResetPasswordErrorCalled = false + private(set) var onResetPasswordCodeRequiredCalled = false + private(set) var error: ResetPasswordStartError? + private(set) var newState: ResetPasswordCodeRequiredState? + private(set) var sentTo: String? + private(set) var channelTargetType: MSALNativeAuthChannelType? + private(set) var codeLength: Int? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onResetPasswordError(error: MSAL.ResetPasswordStartError) { + onResetPasswordErrorCalled = true + self.error = error + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onResetPasswordCodeRequired( + newState: ResetPasswordCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int + ) { + onResetPasswordCodeRequiredCalled = true + self.newState = newState + self.sentTo = sentTo + self.channelTargetType = channelTargetType + self.codeLength = codeLength + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } +} + +class ResetPasswordResendCodeDelegateSpy: ResetPasswordResendCodeDelegate { + let expectation: XCTestExpectation? + private(set) var onResetPasswordResendCodeErrorCalled = false + private(set) var onResetPasswordResendCodeRequiredCalled = false + private(set) var error: ResendCodeError? + private(set) var newState: ResetPasswordCodeRequiredState? + private(set) var sentTo: String? + private(set) var channelTargetType: MSALNativeAuthChannelType? + private(set) var codeLength: Int? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onResetPasswordResendCodeError(error: ResendCodeError, newState: ResetPasswordCodeRequiredState?) { + onResetPasswordResendCodeErrorCalled = true + + self.error = error + self.newState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onResetPasswordResendCodeRequired(newState: MSAL.ResetPasswordCodeRequiredState, sentTo: String, channelTargetType: MSAL.MSALNativeAuthChannelType, codeLength: Int) { + onResetPasswordResendCodeRequiredCalled = true + + self.newState = newState + self.sentTo = sentTo + self.channelTargetType = channelTargetType + self.codeLength = codeLength + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } +} + +class ResetPasswordVerifyCodeDelegateSpy: ResetPasswordVerifyCodeDelegate { + let expectation: XCTestExpectation? + private(set) var onResetPasswordVerifyCodeErrorCalled = false + private(set) var onPasswordRequiredCalled = false + private(set) var error: VerifyCodeError? + private(set) var newCodeRequiredState: ResetPasswordCodeRequiredState? + private(set) var newPasswordRequiredState: ResetPasswordRequiredState? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onResetPasswordVerifyCodeError(error: VerifyCodeError, newState: ResetPasswordCodeRequiredState?) { + onResetPasswordVerifyCodeErrorCalled = true + self.error = error + newCodeRequiredState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onPasswordRequired(newState: ResetPasswordRequiredState) { + onPasswordRequiredCalled = true + newPasswordRequiredState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } +} + +class ResetPasswordRequiredDelegateSpy: ResetPasswordRequiredDelegate { + let expectation: XCTestExpectation? + private(set) var onResetPasswordRequiredErrorCalled = false + private(set) var onResetPasswordCompletedCalled = false + private(set) var error: PasswordRequiredError? + private(set) var newPasswordRequiredState: ResetPasswordRequiredState? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onResetPasswordRequiredError(error: PasswordRequiredError, newState: ResetPasswordRequiredState?) { + onResetPasswordRequiredErrorCalled = true + + self.error = error + newPasswordRequiredState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onResetPasswordCompleted() { + onResetPasswordCompletedCalled = true + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } +} diff --git a/MSAL/test/unit/native_auth/mock/ResetPasswordTestValidatorHelpers.swift b/MSAL/test/unit/native_auth/mock/ResetPasswordTestValidatorHelpers.swift new file mode 100644 index 0000000000..472a2bdcb6 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/ResetPasswordTestValidatorHelpers.swift @@ -0,0 +1,114 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +class ResetPasswordStartTestsValidatorHelper: ResetPasswordStartDelegateSpy { + + func onResetPasswordError(_ input: ResetPasswordStartResult) { + guard case let .error(error) = input else { + expectation?.fulfill() + return XCTFail("Should be an .error") + } + + Task { await self.onResetPasswordError(error: error) } + } + + func onResetPasswordCodeRequired(_ input: ResetPasswordStartResult) { + guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input else { + expectation?.fulfill() + return XCTFail("Should be .codeRequired") + } + + Task { + await self.onResetPasswordCodeRequired(newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength) + } + } +} + +class ResetPasswordResendCodeTestsValidatorHelper: ResetPasswordResendCodeDelegateSpy { + + func onResetPasswordResendCodeError(_ input: ResetPasswordResendCodeResult) { + guard case let .error(error, newState) = input else { + expectation?.fulfill() + return XCTFail("should be .error") + } + + Task { await self.onResetPasswordResendCodeError(error: error, newState: newState) } + } + + func onResetPasswordResendCodeRequired(_ input: ResetPasswordResendCodeResult) { + guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input else { + expectation?.fulfill() + return XCTFail("Should be .codeRequired") + } + + Task { + await self.onResetPasswordResendCodeRequired(newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength) + } + } +} + +class ResetPasswordVerifyCodeTestsValidatorHelper: ResetPasswordVerifyCodeDelegateSpy { + + func onResetPasswordVerifyCodeError(_ input: ResetPasswordVerifyCodeResult) { + guard case let .error(error, newState) = input else { + expectation?.fulfill() + return XCTFail("should be .error") + } + + Task { await self.onResetPasswordVerifyCodeError(error: error, newState: newState) } + } + + func onPasswordRequired(_ input: ResetPasswordVerifyCodeResult) { + guard case let .passwordRequired(newState) = input else { + expectation?.fulfill() + return XCTFail("should be .success") + } + + Task { await self.onPasswordRequired(newState: newState) } + } +} + +class ResetPasswordRequiredTestsValidatorHelper: ResetPasswordRequiredDelegateSpy { + + func onResetPasswordRequiredError(_ input: ResetPasswordRequiredResult) { + guard case let .error(error, newState) = input else { + expectation?.fulfill() + return XCTFail("should be .error") + } + + Task { await self.onResetPasswordRequiredError(error: error, newState: newState) } + } + + func onResetPasswordCompleted(_ input: ResetPasswordRequiredResult) { + guard case .completed = input else { + expectation?.fulfill() + return XCTFail("should be .success") + } + + Task { await self.onResetPasswordCompleted() } + } +} diff --git a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift new file mode 100644 index 0000000000..b267df4cef --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift @@ -0,0 +1,311 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +open class SignInPasswordStartDelegateSpy: SignInPasswordStartDelegate { + let expectation: XCTestExpectation + var expectedError: SignInPasswordStartError? + var expectedUserAccountResult: MSALNativeAuthUserAccountResult? + var expectedSentTo: String? + var expectedChannelTargetType: MSALNativeAuthChannelType? + var expectedCodeLength: Int? + + init(expectation: XCTestExpectation, expectedError: SignInPasswordStartError? = nil, expectedUserAccountResult: MSALNativeAuthUserAccountResult? = nil) { + self.expectation = expectation + self.expectedError = expectedError + self.expectedUserAccountResult = expectedUserAccountResult + } + + public func onSignInPasswordError(error: MSAL.SignInPasswordStartError) { + if let expectedError = expectedError { + XCTAssertTrue(Thread.isMainThread) + XCTAssertEqual(error.type, expectedError.type) + XCTAssertEqual(error.errorDescription, expectedError.errorDescription) + expectation.fulfill() + return + } + XCTFail("This method should not be called") + expectation.fulfill() + } + + public func onSignInCodeRequired(newState: MSAL.SignInCodeRequiredState, sentTo: String, channelTargetType: MSAL.MSALNativeAuthChannelType, codeLength: Int) { + XCTAssertTrue(Thread.isMainThread) + expectedSentTo = sentTo + expectedChannelTargetType = channelTargetType + expectedCodeLength = codeLength + + expectation.fulfill() + } + + public func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) { + if let expectedUserAccountResult = expectedUserAccountResult { + XCTAssertTrue(Thread.isMainThread) + XCTAssertEqual(expectedUserAccountResult.idToken, result.idToken) + XCTAssertEqual(expectedUserAccountResult.scopes, result.scopes) + } else { + XCTFail("This method should not be called") + } + expectation.fulfill() + } +} + +class SignInPasswordRequiredDelegateSpy: SignInPasswordRequiredDelegate { + + private(set) var newPasswordRequiredState: SignInPasswordRequiredState? + private(set) var newSignInCodeRequiredState: SignInCodeRequiredState? + let expectation: XCTestExpectation + var expectedError: PasswordRequiredError? + var expectedUserAccountResult: MSALNativeAuthUserAccountResult? + + init(expectation: XCTestExpectation, expectedError: PasswordRequiredError? = nil, expectedUserAccountResult: MSALNativeAuthUserAccountResult? = nil) { + self.expectation = expectation + self.expectedError = expectedError + self.expectedUserAccountResult = expectedUserAccountResult + } + + func onSignInPasswordRequiredError(error: MSAL.PasswordRequiredError, newState: MSAL.SignInPasswordRequiredState?) { + XCTAssertTrue(Thread.isMainThread) + XCTAssertEqual(error.type, expectedError?.type) + newPasswordRequiredState = newState + expectation.fulfill() + } + + func onSignInCodeRequired(newState: SignInCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int) { + XCTAssertTrue(Thread.isMainThread) + newSignInCodeRequiredState = newState + } + + func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) { + XCTAssertTrue(Thread.isMainThread) + if let expectedUserAccountResult = expectedUserAccountResult { + XCTAssertEqual(expectedUserAccountResult.idToken, result.idToken) + XCTAssertEqual(expectedUserAccountResult.scopes, result.scopes) + } else { + XCTFail("This method should not be called") + } + expectation.fulfill() + } +} + +open class SignInPasswordStartDelegateFailureSpy: SignInPasswordStartDelegate { + + public func onSignInPasswordError(error: MSAL.SignInPasswordStartError) { + XCTFail("This method should not be called") + } + + public func onSignInCodeRequired(newState: MSAL.SignInCodeRequiredState, sentTo: String, channelTargetType: MSAL.MSALNativeAuthChannelType, codeLength: Int) { + XCTFail("This method should not be called") + } + + public func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) { + XCTFail("This method should not be called") + } +} + +open class SignInCodeStartDelegateSpy: SignInStartDelegate { + + let expectation: XCTestExpectation + var expectedError: SignInStartError? + var expectedSentTo: String? + var expectedChannelTargetType: MSALNativeAuthChannelType? + var expectedCodeLength: Int? + var verifyCodeDelegate: SignInVerifyCodeDelegate? + var correlationId: UUID? + + init(expectation: XCTestExpectation, correlationId: UUID? = nil, verifyCodeDelegate: SignInVerifyCodeDelegate? = nil, expectedError: SignInStartError? = nil, expectedSentTo: String? = nil, expectedChannelTargetType: MSALNativeAuthChannelType? = nil, expectedCodeLength: Int? = nil) { + self.expectation = expectation + self.verifyCodeDelegate = verifyCodeDelegate + self.expectedSentTo = expectedSentTo + self.expectedChannelTargetType = expectedChannelTargetType + self.expectedCodeLength = expectedCodeLength + self.correlationId = correlationId + self.expectedError = expectedError + } + + public func onSignInError(error: SignInStartError) { + XCTAssertEqual(error.type, expectedError?.type) + XCTAssertEqual(error.localizedDescription, expectedError?.localizedDescription) + XCTAssertTrue(Thread.isMainThread) + expectation.fulfill() + } + + public func onSignInCodeRequired(newState: SignInCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) { + XCTAssertEqual(sentTo, expectedSentTo) + XCTAssertEqual(channelTargetType, expectedChannelTargetType) + XCTAssertEqual(codeLength, expectedCodeLength) + XCTAssertTrue(Thread.isMainThread) + if let verifyCodeDelegate = verifyCodeDelegate { + newState.submitCode(code: "code", correlationId: correlationId, delegate: verifyCodeDelegate) + } else { + expectation.fulfill() + } + } +} + +class SignInResendCodeDelegateSpy: SignInResendCodeDelegate { + + private(set) var newSignInCodeRequiredState: SignInCodeRequiredState? + private(set) var newSignInResendCodeError: ResendCodeError? + let expectation: XCTestExpectation + var expectedSentTo: String? + var expectedChannelTargetType: MSALNativeAuthChannelType? + var expectedCodeLength: Int? + + init(expectation: XCTestExpectation, expectedSentTo: String? = nil, expectedChannelTargetType: MSALNativeAuthChannelType? = nil, expectedCodeLength: Int? = nil) { + self.expectation = expectation + self.expectedSentTo = expectedSentTo + self.expectedChannelTargetType = expectedChannelTargetType + self.expectedCodeLength = expectedCodeLength + } + + func onSignInResendCodeError(error: ResendCodeError, newState: SignInCodeRequiredState?) { + newSignInCodeRequiredState = newState + newSignInResendCodeError = error + expectation.fulfill() + } + + func onSignInResendCodeCodeRequired(newState: SignInCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) { + XCTAssertEqual(sentTo, expectedSentTo) + XCTAssertEqual(channelTargetType, expectedChannelTargetType) + XCTAssertEqual(codeLength, expectedCodeLength) + XCTAssertTrue(Thread.isMainThread) + newSignInCodeRequiredState = newState + expectation.fulfill() + } +} + +class SignInCodeStartDelegateWithPasswordRequiredSpy: SignInCodeStartDelegateSpy { + var passwordRequiredState: SignInPasswordRequiredState? + + public func onSignInPasswordRequired(newState: SignInPasswordRequiredState) { + passwordRequiredState = newState + expectation.fulfill() + } +} + +open class SignInVerifyCodeDelegateSpy: SignInVerifyCodeDelegate { + + private let expectation: XCTestExpectation + var expectedError: VerifyCodeError? + var expectedUserAccountResult: MSALNativeAuthUserAccountResult? + var expectedNewState: SignInCodeRequiredState? + + init(expectation: XCTestExpectation, expectedError: VerifyCodeError? = nil, expectedUserAccountResult: MSALNativeAuthUserAccountResult? = nil) { + self.expectation = expectation + self.expectedError = expectedError + self.expectedUserAccountResult = expectedUserAccountResult + } + + public func onSignInVerifyCodeError(error: VerifyCodeError, newState: SignInCodeRequiredState?) { + XCTAssertEqual(error.type, expectedError?.type) + if let expectedNewState { + XCTAssertEqual(newState, expectedNewState) + } + XCTAssertTrue(Thread.isMainThread) + expectation.fulfill() + } + + public func onSignInCompleted(result: MSALNativeAuthUserAccountResult) { + guard let expectedUserAccountResult = expectedUserAccountResult else { + XCTFail("expectedUserAccountResult expected not nil") + expectation.fulfill() + return + } + XCTAssertEqual(expectedUserAccountResult.idToken, result.idToken) + XCTAssertEqual(expectedUserAccountResult.scopes, result.scopes) + XCTAssertTrue(Thread.isMainThread) + expectation.fulfill() + } +} + +open class SignInAfterSignUpDelegateSpy: SignInAfterSignUpDelegate { + + private let expectation: XCTestExpectation + var expectedError: SignInAfterSignUpError? + var expectedUserAccountResult: MSALNativeAuthUserAccountResult? + + init(expectation: XCTestExpectation, expectedError: SignInAfterSignUpError? = nil, expectedUserAccountResult: MSALNativeAuthUserAccountResult? = nil) { + self.expectation = expectation + self.expectedError = expectedError + self.expectedUserAccountResult = expectedUserAccountResult + } + + public func onSignInAfterSignUpError(error: MSAL.SignInAfterSignUpError) { + XCTAssertEqual(error.errorDescription, expectedError?.errorDescription) + XCTAssertTrue(Thread.isMainThread) + expectation.fulfill() + } + + public func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) { + guard let expectedUserAccountResult = expectedUserAccountResult else { + XCTFail("expectedUserAccount expected not nil") + expectation.fulfill() + return + } + XCTAssertEqual(expectedUserAccountResult.idToken, result.idToken) + XCTAssertEqual(expectedUserAccountResult.scopes, result.scopes) + XCTAssertTrue(Thread.isMainThread) + expectation.fulfill() + } +} + +final class SignInPasswordStartDelegateOptionalMethodNotImplemented: SignInPasswordStartDelegate { + private let expectation: XCTestExpectation + var expectedError: SignInPasswordStartError? + var expectedUserAccountResult: MSALNativeAuthUserAccountResult? + + init(expectation: XCTestExpectation, expectedError: SignInPasswordStartError? = nil, expectedUserAccountResult: MSALNativeAuthUserAccountResult? = nil) { + self.expectation = expectation + self.expectedError = expectedError + self.expectedUserAccountResult = expectedUserAccountResult + } + + func onSignInPasswordError(error: MSAL.SignInPasswordStartError) { + if let expectedError = expectedError { + XCTAssertTrue(Thread.isMainThread) + XCTAssertEqual(error.type, expectedError.type) + XCTAssertEqual(error.errorDescription, expectedError.errorDescription) + expectation.fulfill() + return + } + XCTFail("This method should not be called") + expectation.fulfill() + } + + func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) { + if let expectedUserAccountResult = expectedUserAccountResult { + XCTAssertTrue(Thread.isMainThread) + XCTAssertEqual(expectedUserAccountResult.idToken, result.idToken) + XCTAssertEqual(expectedUserAccountResult.scopes, result.scopes) + } else { + XCTFail("This method should not be called") + } + expectation.fulfill() + } +} diff --git a/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift b/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift new file mode 100644 index 0000000000..cde9b5500b --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift @@ -0,0 +1,134 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +class SignInPasswordStartTestsValidatorHelper: SignInPasswordStartDelegateSpy { + + func onSignInPasswordError(_ input: MSALNativeAuthSignInController.SignInPasswordControllerResponse) { + guard case let .error(error) = input.result else { + expectation.fulfill() + return XCTFail("input should be .error") + } + + self.expectedError = error + Task { await self.onSignInPasswordError(error: error) } + } + + func onSignInCodeRequired(_ input: MSALNativeAuthSignInController.SignInPasswordControllerResponse) { + + guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input.result else { + expectation.fulfill() + return XCTFail("input should be .codeRequired") + } + + Task { await self.onSignInCodeRequired(newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength) } + } + + func onSignInCompleted(_ input: MSALNativeAuthSignInController.SignInPasswordControllerResponse) { + guard case let .completed(result) = input.result else { + expectation.fulfill() + return XCTFail("input should be .success") + } + + Task { await self.onSignInCompleted(result: result) } + } +} + +class SignInPasswordRequiredTestsValidatorHelper: SignInPasswordRequiredDelegateSpy { + + func onSignInPasswordRequiredError(_ input: SignInPasswordRequiredResult) { + guard case let .error(error, newState) = input else { + expectation.fulfill() + return XCTFail("input should be .error") + } + + Task { await self.onSignInPasswordRequiredError(error: error, newState: newState) } + } + + func onSignInCompleted(_ input: SignInPasswordRequiredResult) { + guard case let .completed(result) = input else { + expectation.fulfill() + return XCTFail("input should be .complete") + } + + Task { await self.onSignInCompleted(result: result) } + } +} + +class SignInCodeStartTestsValidatorHelper: SignInCodeStartDelegateSpy { + + func onSignInError(_ input: MSALNativeAuthSignInControlling.SignInCodeControllerResponse) { + guard case let .error(error) = input.result else { + expectation.fulfill() + return XCTFail("input should be .error") + } + + Task { await self.onSignInError(error: error) } + } + + func onSignInCodeRequired(_ input: MSALNativeAuthSignInControlling.SignInCodeControllerResponse) { + guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input.result else { + expectation.fulfill() + return XCTFail("input should be .codeRequired") + } + + Task { await self.onSignInCodeRequired(newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength) } + } +} + +class SignInResendCodeTestsValidatorHelper: SignInResendCodeDelegateSpy { + + func onSignInResendCodeError(_ input: SignInResendCodeResult) { + guard case let .error(error, newState) = input else { + expectation.fulfill() + return XCTFail("input should be .error") + } + + Task { await self.onSignInResendCodeError(error: error, newState: newState) } + } + + func onSignInResendCodeCodeRequired(_ input: SignInResendCodeResult) { + guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input else { + expectation.fulfill() + return XCTFail("input should be .codeRequired") + } + + Task { + await self.onSignInResendCodeCodeRequired(newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength) + } + } +} + +class SignInCodeStartWithPasswordRequiredTestsValidatorHelper: SignInCodeStartDelegateWithPasswordRequiredSpy { + func onSignInPasswordRequired(_ input: SignInStartResult) { + guard case let .passwordRequired(newState) = input else { + expectation.fulfill() + return XCTFail("input should be .passwordRequired") + } + + self.onSignInPasswordRequired(newState: newState) + } +} diff --git a/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift b/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift new file mode 100644 index 0000000000..1585e00961 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift @@ -0,0 +1,370 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +class SignUpPasswordStartDelegateSpy: SignUpPasswordStartDelegate { + let expectation: XCTestExpectation? + private(set) var onSignUpPasswordErrorCalled = false + private(set) var onSignUpCodeRequiredCalled = false + private(set) var onSignUpAttributesInvalidCalled = false + private(set) var error: SignUpPasswordStartError? + private(set) var newState: SignUpCodeRequiredState? + private(set) var sentTo: String? + private(set) var channelTargetType: MSALNativeAuthChannelType? + private(set) var codeLength: Int? + private(set) var attributeNames: [String]? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onSignUpPasswordError(error: MSAL.SignUpPasswordStartError) { + onSignUpPasswordErrorCalled = true + self.error = error + + XCTAssertTrue(Thread.isMainThread) + self.expectation?.fulfill() + } + + func onSignUpCodeRequired(newState: SignUpCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) { + onSignUpCodeRequiredCalled = true + self.newState = newState + self.sentTo = sentTo + self.channelTargetType = channelTargetType + self.codeLength = codeLength + + XCTAssertTrue(Thread.isMainThread) + self.expectation?.fulfill() + } + + func onSignUpAttributesInvalid(attributeNames: [String]) { + self.onSignUpAttributesInvalidCalled = true + self.attributeNames = attributeNames + + XCTAssertTrue(Thread.isMainThread) + self.expectation?.fulfill() + } +} + +class SignUpCodeStartDelegateSpy: SignUpStartDelegate { + let expectation: XCTestExpectation? + private(set) var onSignUpCodeErrorCalled = false + private(set) var onSignUpCodeRequiredCalled = false + private(set) var onSignUpAttributesInvalidCalled = false + private(set) var error: SignUpStartError? + private(set) var newState: SignUpCodeRequiredState? + private(set) var sentTo: String? + private(set) var channelTargetType: MSALNativeAuthChannelType? + private(set) var codeLength: Int? + private(set) var attributeNames: [String]? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onSignUpError(error: MSAL.SignUpStartError) { + onSignUpCodeErrorCalled = true + self.error = error + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onSignUpCodeRequired(newState: MSAL.SignUpCodeRequiredState, sentTo: String, channelTargetType: MSAL.MSALNativeAuthChannelType, codeLength: Int) { + onSignUpCodeRequiredCalled = true + self.newState = newState + self.sentTo = sentTo + self.channelTargetType = channelTargetType + self.codeLength = codeLength + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onSignUpAttributesInvalid(attributeNames: [String]) { + self.onSignUpAttributesInvalidCalled = true + self.attributeNames = attributeNames + + XCTAssertTrue(Thread.isMainThread) + self.expectation?.fulfill() + } +} + +class SignUpResendCodeDelegateSpy: SignUpResendCodeDelegate { + let expectation: XCTestExpectation? + private(set) var onSignUpResendCodeErrorCalled = false + private(set) var onSignUpResendCodeCodeRequiredCalled = false + private(set) var error: ResendCodeError? + private(set) var newState: SignUpCodeRequiredState? + private(set) var sentTo: String? + private(set) var channelTargetType: MSALNativeAuthChannelType? + private(set) var codeLength: Int? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onSignUpResendCodeError(error: ResendCodeError) { + onSignUpResendCodeErrorCalled = true + self.error = error + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onSignUpResendCodeCodeRequired(newState: MSAL.SignUpCodeRequiredState, sentTo: String, channelTargetType: MSAL.MSALNativeAuthChannelType, codeLength: Int) { + onSignUpResendCodeCodeRequiredCalled = true + self.newState = newState + self.sentTo = sentTo + self.codeLength = codeLength + self.channelTargetType = channelTargetType + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } +} + +class SignUpVerifyCodeDelegateSpy: SignUpVerifyCodeDelegate { + let expectation: XCTestExpectation? + private(set) var onSignUpVerifyCodeErrorCalled = false + private(set) var onSignUpAttributesRequiredCalled = false + private(set) var onSignUpPasswordRequiredCalled = false + private(set) var onSignUpCompletedCalled = false + private(set) var error: VerifyCodeError? + private(set) var newCodeRequiredState: SignUpCodeRequiredState? + private(set) var newAttributesRequiredState: SignUpAttributesRequiredState? + private(set) var newPasswordRequiredState: SignUpPasswordRequiredState? + private(set) var newSignInAfterSignUpState: SignInAfterSignUpState? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onSignUpVerifyCodeError(error: MSAL.VerifyCodeError, newState: MSAL.SignUpCodeRequiredState?) { + onSignUpVerifyCodeErrorCalled = true + self.error = error + newCodeRequiredState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: MSAL.SignUpAttributesRequiredState) { + onSignUpAttributesRequiredCalled = true + newAttributesRequiredState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onSignUpPasswordRequired(newState: MSAL.SignUpPasswordRequiredState) { + onSignUpPasswordRequiredCalled = true + newPasswordRequiredState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onSignUpCompleted(newState: SignInAfterSignUpState) { + onSignUpCompletedCalled = true + newSignInAfterSignUpState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } +} + +class SignUpPasswordRequiredDelegateSpy: SignUpPasswordRequiredDelegate { + let expectation: XCTestExpectation? + private(set) var onSignUpPasswordRequiredErrorCalled = false + private(set) var onSignUpAttributesRequiredCalled = false + private(set) var onSignUpCompletedCalled = false + private(set) var error: PasswordRequiredError? + private(set) var newPasswordRequiredState: SignUpPasswordRequiredState? + private(set) var newAttributesRequiredState: SignUpAttributesRequiredState? + private(set) var signInAfterSignUpState: SignInAfterSignUpState? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onSignUpPasswordRequiredError(error: MSAL.PasswordRequiredError, newState: MSAL.SignUpPasswordRequiredState?) { + onSignUpPasswordRequiredErrorCalled = true + self.error = error + newPasswordRequiredState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onSignUpAttributesRequired(attributes: [MSAL.MSALNativeAuthRequiredAttributes], newState: MSAL.SignUpAttributesRequiredState) { + onSignUpAttributesRequiredCalled = true + newAttributesRequiredState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onSignUpCompleted(newState: SignInAfterSignUpState) { + onSignUpCompletedCalled = true + self.signInAfterSignUpState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } +} + +class SignUpAttributesRequiredDelegateSpy: SignUpAttributesRequiredDelegate { + private let expectation: XCTestExpectation? + private(set) var onSignUpAttributesRequiredCalled = false + private(set) var onSignUpAttributesRequiredErrorCalled = false + private(set) var onSignUpCompletedCalled = false + private(set) var error: AttributesRequiredError? + private(set) var newState: SignUpAttributesRequiredState? + private(set) var attributes: [MSAL.MSALNativeAuthRequiredAttributes]? + private(set) var invalidAttributes: [String]? + private(set) var newSignInAfterSignUpState: SignInAfterSignUpState? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onSignUpAttributesRequiredError(error: MSAL.AttributesRequiredError) { + onSignUpAttributesRequiredErrorCalled = true + self.error = error + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onSignUpCompleted(newState: SignInAfterSignUpState) { + onSignUpCompletedCalled = true + newSignInAfterSignUpState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onSignUpAttributesRequired(attributes: [MSAL.MSALNativeAuthRequiredAttributes], newState: MSAL.SignUpAttributesRequiredState) { + self.attributes = attributes + self.newState = newState + onSignUpAttributesRequiredCalled = true + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } + + func onSignUpAttributesInvalid(attributeNames: [String], newState: MSAL.SignUpAttributesRequiredState) { + self.invalidAttributes = attributeNames + self.newState = newState + onSignUpAttributesRequiredCalled = true + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } +} + +class SignUpVerifyCodeDelegateOptionalMethodsNotImplemented: SignUpVerifyCodeDelegate { + private let expectation: XCTestExpectation + private(set) var error: VerifyCodeError? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onSignUpVerifyCodeError(error: MSAL.VerifyCodeError, newState: MSAL.SignUpCodeRequiredState?) { + self.error = error + XCTAssertTrue(Thread.isMainThread) + expectation.fulfill() + } + + func onSignUpCompleted(newState: SignInAfterSignUpState) { + XCTAssertTrue(Thread.isMainThread) + } +} + +class SignUpPasswordStartDelegateOptionalMethodsNotImplemented: SignUpPasswordStartDelegate { + private let expectation: XCTestExpectation? + private(set) var onSignUpPasswordErrorCalled = false + private(set) var error: SignUpPasswordStartError? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onSignUpPasswordError(error: MSAL.SignUpPasswordStartError) { + onSignUpPasswordErrorCalled = true + self.error = error + + XCTAssertTrue(Thread.isMainThread) + self.expectation?.fulfill() + } + + func onSignUpCodeRequired(newState: MSAL.SignUpCodeRequiredState, sentTo: String, channelTargetType: MSAL.MSALNativeAuthChannelType, codeLength: Int) { + XCTFail("This method should not be called") + self.expectation?.fulfill() + } +} + +class SignUpStartDelegateOptionalMethodsNotImplemented: SignUpStartDelegate { + private let expectation: XCTestExpectation? + private(set) var onSignUpStartErrorCalled = false + private(set) var error: SignUpStartError? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onSignUpError(error: MSAL.SignUpStartError) { + onSignUpStartErrorCalled = true + self.error = error + + XCTAssertTrue(Thread.isMainThread) + self.expectation?.fulfill() + } + + func onSignUpCodeRequired(newState: MSAL.SignUpCodeRequiredState, sentTo: String, channelTargetType: MSAL.MSALNativeAuthChannelType, codeLength: Int) { + XCTFail("This method should not be called") + self.expectation?.fulfill() + } +} + +class SignUpPasswordRequiredDelegateOptionalMethodsNotImplemented: SignUpPasswordRequiredDelegate { + private let expectation: XCTestExpectation + private(set) var error: PasswordRequiredError? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onSignUpPasswordRequiredError(error: MSAL.PasswordRequiredError, newState: MSAL.SignUpPasswordRequiredState?) { + self.error = error + XCTAssertTrue(Thread.isMainThread) + expectation.fulfill() + } + + func onSignUpCompleted(newState: SignInAfterSignUpState) { + XCTAssertTrue(Thread.isMainThread) + } +} diff --git a/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift b/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift new file mode 100644 index 0000000000..f4fd6a4595 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift @@ -0,0 +1,272 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +class SignUpPasswordStartTestsValidatorHelper: SignUpPasswordStartDelegateSpy { + + func onSignUpPasswordError(_ input: MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse) { + guard case let .error(error) = input.result else { + expectation?.fulfill() + return XCTFail("Should be an .error") + } + + Task { + await self.onSignUpPasswordError(error: error) + } + } + + func onSignUpCodeRequired(_ input: MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse) { + guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input.result else { + expectation?.fulfill() + return XCTFail("Should be .codeRequired") + } + + Task { + await self.onSignUpCodeRequired(newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength) + } + } + + func onSignUpAttributesInvalid(_ input: MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse) { + guard case let .attributesInvalid(attributes) = input.result else { + expectation?.fulfill() + return XCTFail("Should be .attributeValidationFailed") + } + + Task { + await self.onSignUpAttributesInvalid(attributeNames: attributes) + } + } +} + +class SignUpCodeStartTestsValidatorHelper: SignUpCodeStartDelegateSpy { + + func onSignUpError(_ input: MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse) { + guard case let .error(error) = input.result else { + expectation?.fulfill() + return XCTFail("Should be an .error") + } + + Task { + await self.onSignUpError(error: error) + } + } + + func onSignUpCodeRequired(_ input: MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse) { + guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input.result else { + expectation?.fulfill() + return XCTFail("Should be .codeRequired") + } + + Task { + await self.onSignUpCodeRequired(newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength) + } + } + + func onSignUpAttributesInvalid(_ input: MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse) { + guard case let .attributesInvalid(attributes) = input.result else { + expectation?.fulfill() + return XCTFail("Should be .attributeValidationFailed") + } + + Task { + await self.onSignUpAttributesInvalid(attributeNames: attributes) + } + } +} + +class SignUpResendCodeTestsValidatorHelper: SignUpResendCodeDelegateSpy { + + func onSignUpResendCodeError(_ input: SignUpResendCodeResult) { + guard case let .error(error) = input else { + expectation?.fulfill() + return XCTFail("Should be an .error") + } + + Task { + await self.onSignUpResendCodeError(error: error) + } + } + + func onSignUpResendCodeCodeRequired(_ input: SignUpResendCodeResult) { + guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input else { + expectation?.fulfill() + return XCTFail("Should be .codeRequired") + } + + Task { + await self.onSignUpResendCodeCodeRequired(newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength) + } + } +} + +class SignUpVerifyCodeTestsValidatorHelper: SignUpVerifyCodeDelegateSpy { + + func onSignUpVerifyCodeError(_ input: MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse) { + guard case let .error(error, newState) = input.result else { + expectation?.fulfill() + return XCTFail("Should be an .error") + } + + Task { + await self.onSignUpVerifyCodeError(error: error, newState: newState) + } + } + + func onSignUpAttributesRequired(_ input: MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse) { + guard case let .attributesRequired(attributes, newState) = input.result else { + expectation?.fulfill() + return XCTFail("Should be an .error") + } + + Task { + await self.onSignUpAttributesRequired(attributes: attributes, newState: newState) + } + } + + func onSignUpPasswordRequired(_ input: MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse) { + guard case let .passwordRequired(newState) = input.result else { + expectation?.fulfill() + return XCTFail("Should be an .error") + } + + Task { + await self.onSignUpPasswordRequired(newState: newState) + } + } + + func onSignUpCompleted(_ input: MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse) { + guard case let .completed(newState) = input.result else { + expectation?.fulfill() + return XCTFail("Should be an .error") + } + + Task { + await self.onSignUpCompleted(newState: newState) + } + } +} + +class SignUpPasswordRequiredTestsValidatorHelper: SignUpPasswordRequiredDelegateSpy { + + func onSignUpPasswordRequiredError(_ input: MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse) { + guard case let .error(error, newState) = input.result else { + expectation?.fulfill() + return XCTFail("Should be an .error") + } + + Task { + await self.onSignUpPasswordRequiredError(error: error, newState: newState) + } + } + + func onSignUpAttributesRequired(_ input: MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse) { + guard case let .attributesRequired(attributes, newState) = input.result else { + expectation?.fulfill() + return XCTFail("Should be an .error") + } + + Task { + await self.onSignUpAttributesRequired(attributes: attributes, newState: newState) + } + } + + func onSignUpCompleted(_ input: MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse) { + guard case let .completed(newState) = input.result else { + expectation?.fulfill() + return XCTFail("Should be an .error") + } + + Task { + await self.onSignUpCompleted(newState: newState) + } + } +} + +class SignUpAttributesRequiredTestsValidatorHelper { + private let expectation: XCTestExpectation? + private(set) var onSignUpAttributesRequiredCalled = false + private(set) var onSignUpInvalidAttributesCalled = false + private(set) var onSignUpAttributesRequiredErrorCalled = false + private(set) var onSignUpCompletedCalled = false + private(set) var error: AttributesRequiredError? + private(set) var newState: SignUpAttributesRequiredState? + private(set) var signInAfterSignUpState: SignInAfterSignUpState? + private(set) var attributes: [MSALNativeAuthRequiredAttributes]? + private(set) var invalidAttributes: [String]? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onSignUpAttributesRequired(_ input: SignUpAttributesRequiredResult) { + guard case let .attributesRequired(attributes, state) = input else { + expectation?.fulfill() + return XCTFail("Should be .attributesInvalid") + } + + onSignUpAttributesRequiredCalled = true + self.attributes = attributes + self.newState = state + + expectation?.fulfill() + } + + func onSignUpAttributesRequiredError(_ input: SignUpAttributesRequiredResult) { + guard case let .error(error) = input else { + expectation?.fulfill() + return XCTFail("Should be an .error") + } + + onSignUpAttributesRequiredErrorCalled = true + self.error = error + + expectation?.fulfill() + } + + func onSignUpAttributesValidationFailed(_ input: SignUpAttributesRequiredResult) { + guard case let .attributesInvalid(attributes, state) = input else { + expectation?.fulfill() + return XCTFail("Should be an .error") + } + + self.onSignUpInvalidAttributesCalled = true + self.invalidAttributes = attributes + self.newState = state + + expectation?.fulfill() + } + + func onSignUpCompleted(_ input: SignUpAttributesRequiredResult) { + guard case .completed = input else { + expectation?.fulfill() + return XCTFail("Should be an .error") + } + + onSignUpCompletedCalled = true + + expectation?.fulfill() + } +} diff --git a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift new file mode 100644 index 0000000000..33011dd286 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift @@ -0,0 +1,76 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthResetPasswordControllerSpy: MSALNativeAuthResetPasswordControlling { + private let expectation: XCTestExpectation + private(set) var context: MSIDRequestContext? + private(set) var flowToken: String? + private(set) var resetPasswordCalled = false + private(set) var resendCodeCalled = false + private(set) var submitCodeCalled = false + private(set) var submitPasswordCalled = false + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func resetPassword(parameters: MSAL.MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartResult { + self.context = parameters.context + resetPasswordCalled = true + expectation.fulfill() + + return .error(.init(type: .generalError)) + } + + func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeResult { + self.flowToken = passwordResetToken + self.context = context + resendCodeCalled = true + expectation.fulfill() + + return .error(error: .init(), newState: nil) + } + + func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordVerifyCodeResult { + self.flowToken = passwordResetToken + self.context = context + submitCodeCalled = true + expectation.fulfill() + + return .error(error: .init(type: .generalError), newState: nil) + } + + func submitPassword(password: String, passwordSubmitToken: String, context: MSIDRequestContext) async -> ResetPasswordRequiredResult { + self.flowToken = passwordSubmitToken + self.context = context + submitPasswordCalled = true + expectation.fulfill() + + return .error(error: .init(type: .generalError), newState: nil) + } +} diff --git a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordRequestProviderMock.swift b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordRequestProviderMock.swift new file mode 100644 index 0000000000..4c876637d3 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordRequestProviderMock.swift @@ -0,0 +1,182 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthResetPasswordRequestProviderMock: MSALNativeAuthResetPasswordRequestProviding { + // MARK: Start + + var requestStart: MSIDHttpRequest? + var throwErrorStart = false + private(set) var startCalled = false + var expectedStartRequestParameters: MSALNativeAuthResetPasswordStartRequestProviderParameters! + + func mockStartRequestFunc(_ request: MSIDHttpRequest?, throwError: Bool = false) { + requestStart = request + throwErrorStart = throwError + } + + func start(parameters: MSAL.MSALNativeAuthResetPasswordStartRequestProviderParameters) throws -> MSIDHttpRequest { + startCalled = true + checkParameters(params: parameters) + + if let request = requestStart { + return request + } else if throwErrorStart { + throw ErrorMock.error + } else { + fatalError("Make sure to use mockStartRequestFunc()") + } + } + + private func checkParameters(params: MSALNativeAuthResetPasswordStartRequestProviderParameters) { + XCTAssertEqual(params.username, expectedStartRequestParameters.username) + XCTAssertEqual(params.context.correlationId(), expectedStartRequestParameters.context.correlationId()) + } + + // MARK: Challenge + + var requestChallenge: MSIDHttpRequest? + var throwErrorChallenge = false + private(set) var challengeCalled = false + var expectedChallengeRequestParameters: (token: String, context: MSIDRequestContext)! + + func mockChallengeRequestFunc(_ request: MSIDHttpRequest?, throwError: Bool = false) { + requestChallenge = request + throwErrorChallenge = throwError + } + + func challenge(token: String, context: MSIDRequestContext) throws -> MSIDHttpRequest { + challengeCalled = true + checkParameters(token: token, context: context) + + if let request = requestChallenge { + return request + } else if throwErrorChallenge { + throw ErrorMock.error + } else { + fatalError("Make sure to use mockChallengeRequestFunc()") + } + } + + private func checkParameters(token: String, context: MSIDRequestContext) { + XCTAssertEqual(token, expectedChallengeRequestParameters.token) + XCTAssertEqual(context.correlationId(), expectedChallengeRequestParameters.context.correlationId()) + } + + // MARK: Continue + + var requestContinue: MSIDHttpRequest? + var throwErrorContinue = false + private(set) var continueCalled = false + var expectedContinueRequestParameters: MSALNativeAuthResetPasswordContinueRequestParameters! + + func mockContinueRequestFunc(_ request: MSIDHttpRequest?, throwError: Bool = false) { + requestContinue = request + throwErrorContinue = throwError + } + + func `continue`(parameters: MSAL.MSALNativeAuthResetPasswordContinueRequestParameters) throws -> MSIDHttpRequest { + continueCalled = true + checkParameters(parameters) + + if let request = requestContinue { + return request + } else if throwErrorContinue { + throw ErrorMock.error + } else { + fatalError("Make sure to use mockContinueRequestFunc()") + } + } + + private func checkParameters(_ params: MSALNativeAuthResetPasswordContinueRequestParameters) { + XCTAssertEqual(params.grantType, expectedContinueRequestParameters.grantType) + XCTAssertEqual(params.passwordResetToken, expectedContinueRequestParameters.passwordResetToken) + XCTAssertEqual(params.oobCode, expectedContinueRequestParameters.oobCode) + XCTAssertEqual(params.context.correlationId(), expectedContinueRequestParameters.context.correlationId()) + } + + // MARK: Submit + + var requestSubmit: MSIDHttpRequest? + var throwErrorSubmit = false + private(set) var submitCalled = false + var expectedSubmitRequestParameters: MSALNativeAuthResetPasswordSubmitRequestParameters! + + func mockSubmitRequestFunc(_ request: MSIDHttpRequest?, throwError: Bool = false) { + requestSubmit = request + throwErrorSubmit = throwError + } + + func submit(parameters: MSAL.MSALNativeAuthResetPasswordSubmitRequestParameters) throws -> MSIDHttpRequest { + submitCalled = true + checkParameters(parameters) + + if let request = requestSubmit { + return request + } else if throwErrorSubmit { + throw ErrorMock.error + } else { + fatalError("Make sure to use mockSubmitRequestFunc()") + } + } + + private func checkParameters(_ params: MSALNativeAuthResetPasswordSubmitRequestParameters) { + XCTAssertEqual(params.passwordSubmitToken, expectedSubmitRequestParameters.passwordSubmitToken) + XCTAssertEqual(params.newPassword, expectedSubmitRequestParameters.newPassword) + XCTAssertEqual(params.context.correlationId(), expectedSubmitRequestParameters.context.correlationId()) + } + + // MARK: PollCompletion + + var requestPollCompletion: MSIDHttpRequest? + var throwErrorPollCompletion = false + private(set) var pollCompletionCalled = false + var expectedPollCompletionParameters: MSALNativeAuthResetPasswordPollCompletionRequestParameters! + + func mockPollCompletionRequestFunc(_ request: MSIDHttpRequest?, throwError: Bool = false) { + requestPollCompletion = request + throwErrorPollCompletion = throwError + } + + func pollCompletion(parameters: MSAL.MSALNativeAuthResetPasswordPollCompletionRequestParameters) throws -> MSIDHttpRequest { + pollCompletionCalled = true + checkParameters(parameters) + + if let request = requestPollCompletion { + return request + } else if throwErrorPollCompletion { + throw ErrorMock.error + } else { + fatalError("Make sure to use mockPollCompletionRequestFunc()") + } + } + + private func checkParameters(_ params: MSALNativeAuthResetPasswordPollCompletionRequestParameters) { + XCTAssertEqual(params.passwordResetToken, expectedPollCompletionParameters.passwordResetToken) + XCTAssertEqual(params.context.correlationId(), expectedPollCompletionParameters.context.correlationId()) + } +} diff --git a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordResponseValidatorMock.swift b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordResponseValidatorMock.swift new file mode 100644 index 0000000000..2860c8e399 --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordResponseValidatorMock.swift @@ -0,0 +1,110 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthResetPasswordResponseValidatorMock: MSALNativeAuthResetPasswordResponseValidating { + + // MARK: Start + + private var resetPasswordStartValidatedResponse: MSALNativeAuthResetPasswordStartValidatedResponse? + + func mockValidateResetPasswordStartFunc(_ response: MSALNativeAuthResetPasswordStartValidatedResponse) { + self.resetPasswordStartValidatedResponse = response + } + + func validate(_ result: Result, with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordStartValidatedResponse { + + if let resetPasswordStartValidatedResponse = resetPasswordStartValidatedResponse { + return resetPasswordStartValidatedResponse + } else { + fatalError("Make sure you call mockValidateResetPasswordStartFunc()") + } + } + + // MARK: Challenge + + private var resetPasswordChallengeValidatedResponse: MSALNativeAuthResetPasswordChallengeValidatedResponse? + + func mockValidateResetPasswordChallengeFunc(_ response: MSALNativeAuthResetPasswordChallengeValidatedResponse) { + self.resetPasswordChallengeValidatedResponse = response + } + + func validate(_ result: Result, with context: MSIDRequestContext) -> MSAL.MSALNativeAuthResetPasswordChallengeValidatedResponse { + if let resetPasswordChallengeValidatedResponse = resetPasswordChallengeValidatedResponse { + return resetPasswordChallengeValidatedResponse + } else { + fatalError("Make sure you call mockValidateResetPasswordChallengeFunc()") + } + } + + // MARK: Continue + + private var resetPasswordContinueValidatedResponse: MSALNativeAuthResetPasswordContinueValidatedResponse? + + func mockValidateResetPasswordContinueFunc(_ response: MSALNativeAuthResetPasswordContinueValidatedResponse) { + self.resetPasswordContinueValidatedResponse = response + } + + func validate(_ result: Result, with context: MSIDRequestContext) -> MSAL.MSALNativeAuthResetPasswordContinueValidatedResponse { + if let resetPasswordContinueValidatedResponse = resetPasswordContinueValidatedResponse { + return resetPasswordContinueValidatedResponse + } else { + fatalError("Make sure you call mockValidateResetPasswordContinueFunc()") + } + } + + // MARK: Submit + + private var resetPasswordSubmitValidatedResponse: MSALNativeAuthResetPasswordSubmitValidatedResponse? + + func mockValidateResetPasswordSubmitFunc(_ response: MSALNativeAuthResetPasswordSubmitValidatedResponse) { + self.resetPasswordSubmitValidatedResponse = response + } + + func validate(_ result: Result, with context: MSIDRequestContext) -> MSAL.MSALNativeAuthResetPasswordSubmitValidatedResponse { + if let resetPasswordSubmitValidatedResponse = resetPasswordSubmitValidatedResponse { + return resetPasswordSubmitValidatedResponse + } else { + fatalError("Make sure you call mockValidateResetPasswordSubmitFunc()") + } + } + + // MARK: PollCompletion + + private var resetPasswordPollCompletionValidatedResponse: MSALNativeAuthResetPasswordPollCompletionValidatedResponse? + + func mockValidateResetPasswordPollCompletionFunc(_ response: MSALNativeAuthResetPasswordPollCompletionValidatedResponse) { + self.resetPasswordPollCompletionValidatedResponse = response + } + + func validate(_ result: Result, with context: MSIDRequestContext) -> MSAL.MSALNativeAuthResetPasswordPollCompletionValidatedResponse { + if let resetPasswordPollCompletionValidatedResponse = resetPasswordPollCompletionValidatedResponse { + return resetPasswordPollCompletionValidatedResponse + } else { + fatalError("Make sure you call mockValidateResetPasswordPollCompletionFunc()") + } + } +} diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthEndpointTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthEndpointTests.swift new file mode 100644 index 0000000000..9c79d0094f --- /dev/null +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthEndpointTests.swift @@ -0,0 +1,79 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthEndpointTests: XCTestCase { + + private typealias sut = MSALNativeAuthEndpoint + + func test_allEndpoints_are_tested() { + XCTAssertEqual(sut.allCases.count, 12) + } + + func test_signUp_start() { + XCTAssertEqual(sut.signUpStart.rawValue, "/signup/v1.0/start") + } + + func test_signUp_challenge() { + XCTAssertEqual(sut.signUpChallenge.rawValue, "/signup/v1.0/challenge") + } + + func test_signUp_continue() { + XCTAssertEqual(sut.signUpContinue.rawValue, "/signup/v1.0/continue") + } + + func test_signInInitiate_endpoint() { + XCTAssertEqual(sut.signInInitiate.rawValue, "/oauth2/v2.0/initiate") + } + + func test_signInChallenge_endpoint() { + XCTAssertEqual(sut.signInChallenge.rawValue, "/oauth2/v2.0/challenge") + } + + func test_token_endpoint() { + XCTAssertEqual(sut.token.rawValue, "/oauth2/v2.0/token") + } + + func test_resetPasswordStart_endpoint() { + XCTAssertEqual(sut.resetPasswordStart.rawValue, "/resetpassword/v1.0/start") + } + + func test_resetPasswordChallenge_endpoint() { + XCTAssertEqual(sut.resetPasswordChallenge.rawValue, "/resetpassword/v1.0/challenge") + } + + func test_resetPasswordContinue_endpoint() { + XCTAssertEqual(sut.resetPasswordContinue.rawValue, "/resetpassword/v1.0/continue") + } + + func test_resetPasswordSubmit_endpoint() { + XCTAssertEqual(sut.resetPasswordSubmit.rawValue, "/resetpassword/v1.0/submit") + } + + func test_resetPasswordComplete_endpoint() { + XCTAssertEqual(sut.resetPasswordComplete.rawValue, "/resetpassword/v1.0/complete") + } +} diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift new file mode 100644 index 0000000000..950f058e90 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift @@ -0,0 +1,452 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { + + let telemetryProvider = MSALNativeAuthTelemetryProvider() + let baseUrl = URL(string: DEFAULT_TEST_AUTHORITY)! + var config: MSALNativeAuthConfiguration! = nil + + let context = MSALNativeAuthRequestContext( + correlationId: .init( + UUID(uuidString: DEFAULT_TEST_UID)! + ) + ) + + func test_signInInititate_getsConfiguredSuccessfully() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password])) + let telemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetryProvider.telemetryForSignIn(type: .signInInitiate), + context: context + ) + + let request = MSIDHttpRequest() + let params = MSALNativeAuthSignInInitiateRequestParameters(context: context, + username: DEFAULT_TEST_ID_TOKEN_USERNAME) + let sut = MSALNativeAuthRequestConfigurator(config: config) + try sut.configure(configuratorType: .signIn(.initiate(params)), + request: request, + telemetryProvider: telemetryProvider) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "username": DEFAULT_TEST_ID_TOKEN_USERNAME, + "challenge_type": "password", + ] + + XCTAssertEqual(request.parameters, expectedBodyParams) + checkUrlRequest(request.urlRequest, endpoint: .signInInitiate) + checkHeaders(request: request) + checkTelemetry(request.serverTelemetry, telemetry) + } + + func test_signInChallenge_getsConfiguredSuccessfully() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.otp])) + let telemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetryProvider.telemetryForSignIn(type: .signInChallenge), + context: context + ) + + let request = MSIDHttpRequest() + let params = MSALNativeAuthSignInChallengeRequestParameters(context: context, + credentialToken: "Test Credential Token") + let sut = MSALNativeAuthRequestConfigurator(config: config) + try sut.configure(configuratorType: .signIn(.challenge(params)), + request: request, + telemetryProvider: telemetryProvider) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "credential_token": "Test Credential Token", + "challenge_type": "otp" + ] + + XCTAssertEqual(request.parameters, expectedBodyParams) + checkUrlRequest(request.urlRequest, endpoint: .signInChallenge) + checkHeaders(request: request) + checkTelemetry(request.serverTelemetry, telemetry) + } + + func test_signInToken_getsConfiguredSuccessfully() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password])) + let telemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetryProvider.telemetryForToken(type: .signInWithPassword), + context: context + ) + + let request = MSIDHttpRequest() + let params = MSALNativeAuthTokenRequestParameters(context: context, + username: DEFAULT_TEST_ID_TOKEN_USERNAME, + credentialToken: "Test Credential Token", + signInSLT: "Test SignIn SLT", + grantType: .password, + scope: "", + password: "password", + oobCode: "oob", + includeChallengeType: true, + refreshToken: nil) + + let sut = MSALNativeAuthRequestConfigurator(config: config) + try sut.configure(configuratorType: .token(.signInWithPassword(params)), + request: request, + telemetryProvider: telemetryProvider) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "username": DEFAULT_TEST_ID_TOKEN_USERNAME, + "credential_token": "Test Credential Token", + "signin_slt": "Test SignIn SLT", + "grant_type": "password", + "challenge_type": "password", + "scope": "", + "password": "password", + "oob": "oob", + "client_info" : "true" + ] + + XCTAssertEqual(request.parameters, expectedBodyParams) + checkUrlRequest(request.urlRequest, endpoint: .token) + checkHeaders(request: request) + checkTelemetry(request.serverTelemetry, telemetry) + } + + func test_signUpStartRequest_getsConfiguredSuccessfully() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .oob, .redirect])) + let telemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetryProvider.telemetryForSignUp(type: .signUpStart), + context: context + ) + + let request = MSIDHttpRequest() + let params = MSALNativeAuthSignUpStartRequestParameters(username: DEFAULT_TEST_ID_TOKEN_USERNAME, + password: "strong-password", + attributes: "", + context: context) + + let sut = MSALNativeAuthRequestConfigurator(config: config) + try sut.configure(configuratorType: .signUp(.start(params)), + request: request, + telemetryProvider: telemetryProvider) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "username": DEFAULT_TEST_ID_TOKEN_USERNAME, + "password": "strong-password", + "attributes": "", + "challenge_type": "password oob redirect" + ] + + XCTAssertEqual(request.parameters, expectedBodyParams) + checkUrlRequest(request.urlRequest, endpoint: .signUpStart) + checkHeaders(request: request) + checkTelemetry(request.serverTelemetry, telemetry) + } + + func test_signUpChallengeRequest_getsConfiguredSuccessfully() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .oob, .redirect])) + let telemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetryProvider.telemetryForSignUp(type: .signUpChallenge), + context: context + ) + + let request = MSIDHttpRequest() + let params = MSALNativeAuthSignUpChallengeRequestParameters(signUpToken: "", + context: context) + + let sut = MSALNativeAuthRequestConfigurator(config: config) + try sut.configure(configuratorType: .signUp(.challenge(params)), + request: request, + telemetryProvider: telemetryProvider) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "signup_token": "", + "challenge_type": "password oob redirect" + ] + + XCTAssertEqual(request.parameters, expectedBodyParams) + checkUrlRequest(request.urlRequest, endpoint: .signUpChallenge) + checkHeaders(request: request) + checkTelemetry(request.serverTelemetry, telemetry) + } + + func test_signUpContinueRequest_getsConfiguredSuccessfully() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) + let telemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetryProvider.telemetryForSignUp(type: .signUpContinue), + context: context + ) + + let request = MSIDHttpRequest() + let params = MSALNativeAuthSignUpContinueRequestParameters(grantType: .oobCode, + signUpToken: "", + password: "", + oobCode: "0000", + attributes: "", + context: context) + + let sut = MSALNativeAuthRequestConfigurator(config: config) + try sut.configure(configuratorType: .signUp(.continue(params)), + request: request, + telemetryProvider: telemetryProvider) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "signup_token": "", + "password": "", + "oob": "0000", + "grant_type": "oob", + "attributes": "" + ] + + XCTAssertEqual(request.parameters, expectedBodyParams) + checkUrlRequest(request.urlRequest, endpoint: .signUpContinue) + checkHeaders(request: request) + checkTelemetry(request.serverTelemetry, telemetry) + } + + + func test_resetPasswordStart_getsConfiguredSuccessfully() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .oob, .redirect])) + let telemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetryProvider.telemetryForResetPassword(type: .resetPasswordStart), + context: context + ) + + let request = MSIDHttpRequest() + let params = MSALNativeAuthResetPasswordStartRequestParameters(context: context, + username: DEFAULT_TEST_ID_TOKEN_USERNAME) + + let sut = MSALNativeAuthRequestConfigurator(config: config) + try sut.configure(configuratorType: .resetPassword(.start(params)), + request: request, + telemetryProvider: telemetryProvider) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "username": DEFAULT_TEST_ID_TOKEN_USERNAME, + "challenge_type": "password oob redirect" + ] + + XCTAssertEqual(request.parameters, expectedBodyParams) + checkUrlRequest(request.urlRequest, endpoint: .resetPasswordStart) + checkHeaders(request: request) + checkTelemetry(request.serverTelemetry, telemetry) + } + + func test_resetPasswordChallenge_getsConfiguredSuccessfully() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .oob, .redirect])) + let telemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetryProvider.telemetryForResetPassword(type: .resetPasswordChallenge), + context: context + ) + + let request = MSIDHttpRequest() + let params = MSALNativeAuthResetPasswordChallengeRequestParameters(context: context, + passwordResetToken: "") + + let sut = MSALNativeAuthRequestConfigurator(config: config) + try sut.configure(configuratorType: .resetPassword(.challenge(params)), + request: request, + telemetryProvider: telemetryProvider) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "password_reset_token": "", + "challenge_type": "password oob redirect" + ] + + XCTAssertEqual(request.parameters, expectedBodyParams) + checkUrlRequest(request.urlRequest, endpoint: .resetPasswordChallenge) + checkHeaders(request: request) + checkTelemetry(request.serverTelemetry, telemetry) + } + + func test_resetPasswordContinue_getsConfiguredSuccessfully() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) + let telemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetryProvider.telemetryForResetPassword(type: .resetPasswordContinue), + context: context + ) + + let request = MSIDHttpRequest() + let params = MSALNativeAuthResetPasswordContinueRequestParameters(context: context, + passwordResetToken: "", + grantType: .oobCode, + oobCode: "0000") + + let sut = MSALNativeAuthRequestConfigurator(config: config) + try sut.configure(configuratorType: .resetPassword(.continue(params)), + request: request, + telemetryProvider: telemetryProvider) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "password_reset_token": "", + "grant_type": "oob", + "oob": "0000" + ] + + XCTAssertEqual(request.parameters, expectedBodyParams) + checkUrlRequest(request.urlRequest, endpoint: .resetPasswordContinue) + checkHeaders(request: request) + checkTelemetry(request.serverTelemetry, telemetry) + } + + func test_resetPasswordSubmit_getsConfiguredSuccessfully() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) + let telemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetryProvider.telemetryForResetPassword(type: .resetPasswordSubmit), + context: context + ) + + let request = MSIDHttpRequest() + let params = MSALNativeAuthResetPasswordSubmitRequestParameters(context: context, + passwordSubmitToken: "", + newPassword:"new-password") + + let sut = MSALNativeAuthRequestConfigurator(config: config) + try sut.configure(configuratorType: .resetPassword(.submit(params)), + request: request, + telemetryProvider: telemetryProvider) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "password_submit_token": "", + "new_password": "new-password" + ] + + XCTAssertEqual(request.parameters, expectedBodyParams) + checkUrlRequest(request.urlRequest, endpoint: .resetPasswordSubmit) + checkHeaders(request: request) + checkTelemetry(request.serverTelemetry, telemetry) + } + + func test_resetPasswordPollCompletion_getsConfiguredSuccessfully() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) + let telemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetryProvider.telemetryForResetPassword(type: .resetPasswordPollCompletion), + context: context + ) + + let request = MSIDHttpRequest() + let params = MSALNativeAuthResetPasswordPollCompletionRequestParameters(context: context, + passwordResetToken: "", + password: nil, + oobCode: nil, + includeChallengeType: false, + refreshToken: "refreshToken") + + let sut = MSALNativeAuthRequestConfigurator(config: config) + try sut.configure(configuratorType: .token(.refreshToken(params)), + request: request, + telemetryProvider: telemetryProvider) + + let expectedBodyParams = [ + "client_id" : DEFAULT_TEST_CLIENT_ID, + "grant_type" : "refresh_token", + "scope" : "", + "refresh_token" : "refreshToken", + "client_info" : "true" + ] + + XCTAssertEqual(request.parameters, expectedBodyParams) + checkUrlRequest(request.urlRequest, endpoint: .token) + checkHeaders(request: request) + checkTelemetry(request.serverTelemetry, telemetry) + } + + + private func checkUrlRequest(_ result: URLRequest?, endpoint: MSALNativeAuthEndpoint) { + XCTAssertEqual(result?.httpMethod, MSALParameterStringForHttpMethod(.POST)) + + let expectedUrl = URL(string: MSALNativeAuthNetworkStubs.authority.url.absoluteString + endpoint.rawValue)! + XCTAssertEqual(result?.url, expectedUrl) + } + + private func checkHeaders(request: MSIDHttpRequest) { + let headers = request.urlRequest?.allHTTPHeaderFields! + XCTAssertEqual(headers!["Accept"], "application/json") + XCTAssertEqual(headers!["return-client-request-id"], "true") + XCTAssertEqual(headers!["x-ms-PkeyAuth+"], "1.0") + XCTAssertNotNil("client-request-id") + XCTAssertNotNil("x-client-CPU") + XCTAssertNotNil("x-client-SKU") + XCTAssertNotNil("x-app-name") + XCTAssertNotNil("x-app-ver") + XCTAssertNotNil("x-client-OS") + XCTAssertNotNil("x-client-Ver") +#if TARGET_OS_IPHONE + XCTAssertNotNil("x-client-DM") +#endif + } + + private func checkTelemetry(_ result: MSIDHttpRequestServerTelemetryHandling?, _ expected: MSALNativeAuthServerTelemetry) { + + guard let resultTelemetry = (result as? MSALNativeAuthServerTelemetry)?.currentRequestTelemetry else { + return XCTFail() + } + + let expectedTelemetry = expected.currentRequestTelemetry + + XCTAssertEqual(resultTelemetry.apiId, expectedTelemetry.apiId) + XCTAssertEqual(resultTelemetry.operationType, expectedTelemetry.operationType) + } +} diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift new file mode 100644 index 0000000000..4d1b15f586 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift @@ -0,0 +1,359 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private +@_implementationOnly import MSAL_Unit_Test_Private + +class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { + // MARK: - Variables + + private var sut: MSALNativeAuthResponseErrorHandler! + private let error = NSError(domain:"Test Error Domain", code:400, userInfo:nil) + private var httpRequest: MSIDHttpRequest! + private let context = MSALNativeAuthRequestContextMock(correlationId: .init(uuidString: DEFAULT_TEST_UID)!) + + override func setUpWithError() throws { + sut = MSALNativeAuthResponseErrorHandler() + httpRequest = MSIDHttpRequest() + try super.setUpWithError() + } + + func test_completeWithError_whenBodyMissing() { + let expectation = expectation(description: "Handle Error Body Missing") + sut.handleError( + error, + httpResponse: nil, + data: nil, + httpRequest: nil, + responseSerializer: nil, + externalSSOContext: nil, + context: nil + ) { result, error in + guard let error = error as? NSError else { + XCTFail("Error type not expected, actual error type: \(type(of: error))") + expectation.fulfill() + return + } + XCTAssertEqual(self.error.domain, error.domain) + XCTAssertEqual(self.error.code, error.code) + expectation.fulfill() + } + wait(for: [expectation], timeout: 1) + } + + func test_shouldRetry_whenRetryCountGreaterThanZeroAndRetryStatusCode() { + let expectation = expectation(description: "Handle Error Retry Success") + + let httpResponse = HTTPURLResponse( + url: HttpModuleMockConfigurator.baseUrl, + statusCode: 500, + httpVersion: nil, + headerFields: nil + ) + HttpModuleMockConfigurator.configure(request: httpRequest, response: httpResponse, responseJson: []) + httpRequest.retryCounter = 5 + + sut.handleError( + error, + httpResponse: httpResponse, + data: nil, + httpRequest: httpRequest, + responseSerializer: nil, + externalSSOContext: nil, + context: context + ) { result, error in + XCTAssertEqual(self.httpRequest.retryCounter, 4) + expectation.fulfill() + } + wait(for: [expectation], timeout: 1) + } + + func test_shouldNotRetry_whenRetryCountZeroAndRetryStatusCode() { + let expectation = expectation(description: "Handle Error No Retries Left") + + let httpResponse = HTTPURLResponse( + url: HttpModuleMockConfigurator.baseUrl, + statusCode: 500, + httpVersion: nil, + headerFields: nil + ) + + HttpModuleMockConfigurator.configure(request: httpRequest, response: httpResponse, responseJson: []) + httpRequest.retryCounter = 0 + + sut.handleError( + error, + httpResponse: httpResponse, + data: nil, + httpRequest: httpRequest, + responseSerializer: nil, + externalSSOContext: nil, + context: context + ) { result, error in + guard let error = error as? NSError else { + XCTFail("Error type not expected, actual error type: \(type(of: error))") + expectation.fulfill() + return + } + XCTAssertEqual(error.code, MSIDErrorCode.serverUnhandledResponse.rawValue) + XCTAssertEqual(error.userInfo[MSIDHTTPResponseCodeKey] as! String, "500") + XCTAssertEqual(error.userInfo[MSIDServerUnavailableStatusKey] as! Int, 1) + XCTAssertEqual(error.userInfo[MSIDErrorDescriptionKey] as! String, "internal server error") + XCTAssertEqual((error.userInfo[MSIDHTTPHeadersKey] as! [String: String]).count, 0) + MSIDTestURLSession.clearResponses() + expectation.fulfill() + } + wait(for: [expectation], timeout: 1) + } + + func test_shouldCompleteAndResend_whenResponseContainsPkeyHeader() { + let expectation = expectation(description: "Handle Error Response Pkey Header") + + let httpResponse = HTTPURLResponse( + url: HttpModuleMockConfigurator.baseUrl, + statusCode: 400, + httpVersion: nil, + headerFields: [kMSIDWwwAuthenticateHeader: "PKeyAuth Context=TestContext,Version=1.0"] + ) + + HttpModuleMockConfigurator.configure(request: httpRequest, response: httpResponse, responseJson: []) + + let secondHttpResponse = HTTPURLResponse( + url: HttpModuleMockConfigurator.baseUrl, + statusCode: 200, + httpVersion: nil, + headerFields: ["Authorization": "PKeyAuth Context=\"TestContext\", Version=\"1.0\"", + "Content-Type": "application/x-www-form-urlencoded"] + ) + let testUrlResponse = MSIDTestURLResponse.request(HttpModuleMockConfigurator.baseUrl, reponse: secondHttpResponse) + testUrlResponse?.setRequestHeaders(secondHttpResponse?.allHeaderFields) + testUrlResponse?.setResponseJSON(["Test":"Response"]) + MSIDTestURLSession.add(testUrlResponse) + + sut.handleError( + error, + httpResponse: httpResponse, + data: nil, + httpRequest: httpRequest, + responseSerializer: nil, + externalSSOContext: nil, + context: context + ) { result, error in + guard let result = result as? NSDictionary else { + XCTFail("Result type not expected, actual type: \(type(of: result))") + expectation.fulfill() + return + } + XCTAssertEqual(result["Test"] as! String, "Response") + expectation.fulfill() + } + wait(for: [expectation], timeout: 1) + } + + func test_shouldCompleteWithAPIError_whenStatusCode400() throws { + let expectation = expectation(description: "Handle Error Retry Success") + + let httpResponse = HTTPURLResponse( + url: HttpModuleMockConfigurator.baseUrl, + statusCode: 400, + httpVersion: nil, + headerFields: nil + ) + + var dictionary = [String: Any]() + dictionary["error"] = "invalid_request" + dictionary["error_description"] = "Request parameter validation failed" + dictionary["error_uri"] = HttpModuleMockConfigurator.baseUrl.absoluteString + dictionary["inner_errors"] = [["error": "invalid_username", "error_description":"Username was invalid"]] + + let data = try JSONSerialization.data(withJSONObject: dictionary) + + sut.handleError( + error, + httpResponse: httpResponse, + data: data, + httpRequest: httpRequest, + responseSerializer: nil, + externalSSOContext: nil, + context: context + ) { result, error in + guard let error = error as? MSALNativeAuthSignInInitiateResponseError else { + XCTFail("Error type not expected, actual error type: \(type(of: error))") + expectation.fulfill() + return + } + XCTAssertEqual(error.error, MSALNativeAuthSignInInitiateOauth2ErrorCode.invalidRequest) + XCTAssertEqual(error.errorDescription, "Request parameter validation failed") + XCTAssertEqual(error.errorURI, HttpModuleMockConfigurator.baseUrl.absoluteString) + XCTAssertEqual(error.innerErrors![0].error, "invalid_username") + XCTAssertEqual(error.innerErrors![0].errorDescription, "Username was invalid") + expectation.fulfill() + } + wait(for: [expectation], timeout: 1) + } + + func test_shouldCompleteWithAPIErrorUsingCorrectResponseSerializer_whenStatusCode400AndVerificationRequired() throws { + let expectation = expectation(description: "Handle Error Retry Success") + + let httpResponse = HTTPURLResponse( + url: HttpModuleMockConfigurator.baseUrl, + statusCode: 400, + httpVersion: nil, + headerFields: nil + ) + + var dictionary = [String: Any]() + dictionary["error"] = "verification_required" + dictionary["error_description"] = "AADSTS55102: Verification required." + dictionary["error_uri"] = HttpModuleMockConfigurator.baseUrl.absoluteString + dictionary["signup_token"] = "abcdef" + + let data = try JSONSerialization.data(withJSONObject: dictionary) + + let errorHandler = MSALNativeAuthResponseErrorHandler() + errorHandler.handleError( + error, + httpResponse: httpResponse, + data: data, + httpRequest: httpRequest, + responseSerializer: MSIDHttpResponseSerializer(), // Some transient response serializer + externalSSOContext: nil, + context: context + ) { result, error in + guard let error = error as? MSALNativeAuthSignUpStartResponseError else { + XCTFail("Error type not expected, actual error type: \(type(of: error))") + expectation.fulfill() + return + } + XCTAssertEqual(error.error, MSALNativeAuthSignUpStartOauth2ErrorCode.verificationRequired) + XCTAssertEqual(error.errorDescription, "AADSTS55102: Verification required.") + XCTAssertEqual(error.errorURI, HttpModuleMockConfigurator.baseUrl.absoluteString) + XCTAssertEqual(error.signUpToken, "abcdef") + expectation.fulfill() + } + wait(for: [expectation], timeout: 1) + } + + func test_shouldFailWithDecodeError_whenStatusCode400AndJSONMissing() throws { + let expectation = expectation(description: "Handle Error Retry Success") + + let httpResponse = HTTPURLResponse( + url: HttpModuleMockConfigurator.baseUrl, + statusCode: 400, + httpVersion: nil, + headerFields: nil + ) + + let dictionary = [String: Any]() + let data = try JSONSerialization.data(withJSONObject: dictionary) + + sut.handleError( + error, + httpResponse: httpResponse, + data: data, + httpRequest: httpRequest, + responseSerializer: nil, + externalSSOContext: nil, + context: context + ) { result, error in + guard let error = error as? DecodingError else { + XCTFail("Error type not expected, actual error type: \(type(of: error))") + expectation.fulfill() + return + } + XCTAssertEqual(error.localizedDescription,"The data couldn’t be read because it is missing.") + expectation.fulfill() + } + wait(for: [expectation], timeout: 1) + } + + func test_shouldFailWithDecodeError_whenStatusCode400AndJSONInvalid() throws { + let expectation = expectation(description: "Handle Error Retry Success") + + let httpResponse = HTTPURLResponse( + url: HttpModuleMockConfigurator.baseUrl, + statusCode: 400, + httpVersion: nil, + headerFields: nil + ) + + var dictionary = [String: Any]() + dictionary["error_key_incorrect"] = "invalid_request" + let data = try JSONSerialization.data(withJSONObject: dictionary) + + sut.handleError( + error, + httpResponse: httpResponse, + data: data, + httpRequest: httpRequest, + responseSerializer: nil, + externalSSOContext: nil, + context: context + ) { result, error in + guard let error = error as? DecodingError else { + XCTFail("Error type not expected, actual error type: \(type(of: error))") + expectation.fulfill() + return + } + XCTAssertEqual(error.localizedDescription,"The data couldn’t be read because it is missing.") + expectation.fulfill() + } + wait(for: [expectation], timeout: 1) + } + + func test_shouldCompleteWithHTTPError_whenStatusCodeNotHandled() { + let expectation = expectation(description: "Handle Error Retry Success") + + let httpResponse = HTTPURLResponse( + url: HttpModuleMockConfigurator.baseUrl, + statusCode: 600, + httpVersion: nil, + headerFields: nil + ) + + sut.handleError( + error, + httpResponse: httpResponse, + data: nil, + httpRequest: httpRequest, + responseSerializer: nil, + externalSSOContext: nil, + context: context + ) { result, error in + guard let error = error as? NSError else { + XCTFail("Error type not expected, actual error type: \(type(of: error))") + expectation.fulfill() + return + } + XCTAssertEqual(error.code, MSIDErrorCode.serverUnhandledResponse.rawValue) + XCTAssertEqual(error.userInfo[MSIDHTTPResponseCodeKey] as! String, "600") + XCTAssertEqual(error.userInfo[MSIDErrorDescriptionKey] as! String, "") + XCTAssertEqual((error.userInfo[MSIDHTTPHeadersKey] as! [String: String]).count, 0) + expectation.fulfill() + } + wait(for: [expectation], timeout: 1) + } +} diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestableTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestableTests.swift new file mode 100644 index 0000000000..d1b3ec9838 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestableTests.swift @@ -0,0 +1,79 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthRequestableTests: XCTestCase { + + var request: MSALNativeAuthResetPasswordStartRequestParameters! = nil + + override func setUpWithError() throws { + let context = MSALNativeAuthRequestContext( + correlationId: .init( + UUID(uuidString: DEFAULT_TEST_UID)! + ) + ) + + request = MSALNativeAuthResetPasswordStartRequestParameters(context: context, username: DEFAULT_TEST_ID_TOKEN_USERNAME) + } + + func test_whenSliceConfigIsUsed_CorrectURLIsGenerated() throws { + let sliceDc = "TEST-SLICE-IDENTIFIER" + + guard let authorityUrl = URL(string: DEFAULT_TEST_AUTHORITY) else { + XCTFail() + return + } + + let authority = try MSALCIAMAuthority(url: authorityUrl) + var config = try MSALNativeAuthConfiguration(clientId: DEFAULT_TEST_CLIENT_ID, + authority: authority, + challengeTypes: [.redirect]) + + config.sliceConfig = MSALSliceConfig(slice: nil, dc: sliceDc) + let url = try request.makeEndpointUrl(config: config) + + let expectedUrlString = config.authority.url.absoluteString + request.endpoint.rawValue + "?dc=\(sliceDc)" + XCTAssertEqual(url.absoluteString, expectedUrlString) + } + + func test_whenSliceConfigIsNotUsed_CorrectURLIsGenerated() throws { + guard let authorityUrl = URL(string: DEFAULT_TEST_AUTHORITY) else { + XCTFail() + return + } + + let authority = try MSALCIAMAuthority(url: authorityUrl) + var config = try MSALNativeAuthConfiguration(clientId: DEFAULT_TEST_CLIENT_ID, + authority: authority, + challengeTypes: [.redirect]) + + let url = try request.makeEndpointUrl(config: config) + + let expectedUrlString = config.authority.url.absoluteString + request.endpoint.rawValue + XCTAssertEqual(url.absoluteString, expectedUrlString) + } +} diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthResponseSerializerTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthResponseSerializerTests.swift new file mode 100644 index 0000000000..a896ddb1e4 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthResponseSerializerTests.swift @@ -0,0 +1,80 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthResponseSerializerTests: XCTestCase { + + func testSerialize_correctResponse_shouldReturnSuccess() { + let serializer = MSALNativeAuthResponseSerializer() + let responseString = """ + { + "token_type": "Bearer", + "scope": "scope", + "expires_in": 4141, + "extended_expires_in": 4141, + "access_token": "access", + "refresh_token": "refresh", + "id_token": "id" + } + """ + var response: ResponseStub? = nil + XCTAssertNoThrow(response = try serializer.responseObject(for: nil, data:responseString.data(using: .utf8) , context: nil) as? ResponseStub) + XCTAssertEqual(response?.idToken, "id") + XCTAssertEqual(response?.tokenType, "Bearer") + XCTAssertEqual(response?.scope, "scope") + XCTAssertEqual(response?.expiresIn, 4141) + XCTAssertEqual(response?.extendedExpiresIn, 4141) + XCTAssertEqual(response?.refreshToken, "refresh") + XCTAssertEqual(response?.accessToken, "access") + } + + func testSerialize_wrongResponse_shouldFail() throws { + let serializer = MSALNativeAuthResponseSerializer() + let wrongResponseString = """ + { + "tokenType": "Bearer", + "spe": "scope", + "expiresIn": 4141, + "ext_expires_in": 4141, + "access_token": "access", + "refresh_token": "refresh", + "id_token": "id" + } + """ + XCTAssertThrowsError(try serializer.responseObject(for: nil, data: wrongResponseString.data(using: .utf8) , context: nil)) + } +} + +private struct ResponseStub: Decodable { + let tokenType: String + let scope: String + let expiresIn: Int + let extendedExpiresIn: Int + let accessToken: String + let refreshToken: String + let idToken: String +} diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift new file mode 100644 index 0000000000..6d0c7b0482 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift @@ -0,0 +1,142 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase { + + private var sut: MSALNativeAuthSignUpRequestProvider! + private var telemetryProvider: MSALNativeAuthTelemetryProvider! + private var context: MSIDRequestContext! + + override func setUpWithError() throws { + telemetryProvider = MSALNativeAuthTelemetryProvider() + context = MSALNativeAuthRequestContext(correlationId: .init(uuidString: DEFAULT_TEST_UID)!) + + sut = .init(requestConfigurator: MSALNativeAuthRequestConfigurator(config: MSALNativeAuthConfigStubs.configuration), + telemetryProvider: telemetryProvider) + } + + func test_signUpStartRequest_is_created_successfully() throws { + let parameters = MSALNativeAuthSignUpStartRequestProviderParameters( + username: DEFAULT_TEST_ID_TOKEN_USERNAME, + password: "1234", + attributes: ["city": "dublin"], + context: MSALNativeAuthRequestContext(correlationId: context.correlationId()) + ) + + let request = try sut.start(parameters: parameters) + + checkBodyParams(request.parameters, for: .signUpStart) + checkUrlRequest(request.urlRequest!, for: .signUpStart) + + let expectedTelemetryResult = telemetryProvider.telemetryForSignUp(type: .signUpStart).telemetryString() + checkServerTelemetry(request.serverTelemetry, expectedTelemetryResult: expectedTelemetryResult) + } + + func test_signUpChallengeRequest_is_created_successfully() throws { + let request = try sut.challenge(token: "sign-up-token", context: context) + + checkBodyParams(request.parameters, for: .signUpChallenge) + checkUrlRequest(request.urlRequest!, for: .signUpChallenge) + + let expectedTelemetryResult = telemetryProvider.telemetryForSignUp(type: .signUpChallenge).telemetryString() + checkServerTelemetry(request.serverTelemetry, expectedTelemetryResult: expectedTelemetryResult) + } + + func test_signUpContinueRequest_is_created_successfully() throws { + let parameters = MSALNativeAuthSignUpContinueRequestProviderParams( + grantType: .password, + signUpToken: "sign-up-token", + password: "1234", + oobCode: nil, + attributes: nil, + context: context + ) + + let request = try sut.continue(parameters: parameters) + + checkBodyParams(request.parameters, for: .signUpContinue) + checkUrlRequest(request.urlRequest!, for: .signUpContinue) + + let expectedTelemetryResult = telemetryProvider.telemetryForSignUp(type: .signUpContinue).telemetryString() + checkServerTelemetry(request.serverTelemetry, expectedTelemetryResult: expectedTelemetryResult) + } + + private func checkBodyParams(_ bodyParams: [String: String]?, for endpoint: MSALNativeAuthEndpoint) { + typealias Key = MSALNativeAuthRequestParametersKey + + var expectedBodyParams: [String: String]! + + switch endpoint { + case .signUpStart: + expectedBodyParams = [ + Key.clientId.rawValue: DEFAULT_TEST_CLIENT_ID, + Key.username.rawValue: DEFAULT_TEST_ID_TOKEN_USERNAME, + Key.challengeType.rawValue: "redirect", + Key.attributes.rawValue: "{\"city\":\"dublin\"}", + Key.password.rawValue: "1234" + ] + case .signUpChallenge: + expectedBodyParams = [ + Key.clientId.rawValue: DEFAULT_TEST_CLIENT_ID, + Key.signUpToken.rawValue: "sign-up-token", + Key.challengeType.rawValue: "redirect" + ] + case .signUpContinue: + expectedBodyParams = [ + Key.clientId.rawValue: DEFAULT_TEST_CLIENT_ID, + Key.grantType.rawValue: "password", + Key.signUpToken.rawValue: "sign-up-token", + Key.password.rawValue: "1234" + ] + default: + XCTFail("Case not tested") + } + + XCTAssertEqual(bodyParams, expectedBodyParams) + } + + private func checkUrlRequest(_ result: URLRequest?, for endpoint: MSALNativeAuthEndpoint) { + XCTAssertEqual(result?.httpMethod, MSALParameterStringForHttpMethod(.POST)) + + let expectedUrl = URL(string: MSALNativeAuthNetworkStubs.authority.url.absoluteString + endpoint.rawValue)! + XCTAssertEqual(result?.url, expectedUrl) + + XCTAssertEqual(result?.allHTTPHeaderFields?["return-client-request-id"], "true") + XCTAssertEqual(result?.allHTTPHeaderFields?["Accept"], "application/json") + } + + private func checkServerTelemetry(_ result: MSIDHttpRequestServerTelemetryHandling?, expectedTelemetryResult: String) { + guard let serverTelemetry = result as? MSALNativeAuthServerTelemetry else { + return XCTFail("Server telemetry should be of kind MSALNativeAuthServerTelemetry") + } + + XCTAssertEqual(serverTelemetry.context.correlationId().uuidString, DEFAULT_TEST_UID.uppercased()) + XCTAssertEqual(serverTelemetry.currentRequestTelemetry.telemetryString(), expectedTelemetryResult) + } +} diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthUrlRequestSerializerTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthUrlRequestSerializerTests.swift new file mode 100644 index 0000000000..abba29bd94 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthUrlRequestSerializerTests.swift @@ -0,0 +1,196 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthUrlRequestSerializerTests: MSALNativeAuthTestCase { + + private var sut: MSALNativeAuthUrlRequestSerializer! + private var request: URLRequest! + + override func setUpWithError() throws { + try super.setUpWithError() + + let url = URL(string: DEFAULT_TEST_RESOURCE)! + request = URLRequest(url: url) + + sut = MSALNativeAuthUrlRequestSerializer(context: MSALNativeAuthRequestContext(), encoding: .json) + } + + func test_serialize_successfully() throws { + let parameters = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "grant_type": "passwordless_otp", + "email": DEFAULT_TEST_ID_TOKEN_USERNAME, + "password": "12345", + "scope": DEFAULT_TEST_SCOPE + ] + + let headers = [ + "custom-header": "value" + ] + + let result = sut.serialize(with: request, parameters: parameters, headers: headers) + + let bodyParametersResult = try JSONDecoder().decode([String: String].self, from: result.httpBody!) + + XCTAssertEqual(bodyParametersResult.count, 5) + XCTAssertEqual(bodyParametersResult["client_id"], DEFAULT_TEST_CLIENT_ID) + XCTAssertEqual(bodyParametersResult["grant_type"], "passwordless_otp") + XCTAssertEqual(bodyParametersResult["email"], DEFAULT_TEST_ID_TOKEN_USERNAME) + XCTAssertEqual(bodyParametersResult["password"], "12345") + XCTAssertEqual(bodyParametersResult["scope"], DEFAULT_TEST_SCOPE) + + let httpHeadersResult = result.allHTTPHeaderFields! + + XCTAssertEqual(httpHeadersResult.count, 2) + XCTAssertEqual(httpHeadersResult["Content-Type"], "application/json") + XCTAssertEqual(httpHeadersResult["custom-header"], "value") + } + + func test_serialize_with_dict_in_body() throws { + let customAttributes: [String: Codable] = [ + "name": "John", + "surname": "Smith", + "age": "37" + ] + + let parameters = [ + "customAttributes": customAttributes + ] + + let result = sut.serialize(with: request, parameters: parameters, headers: [:]) + + let bodyParametersResult = try JSONDecoder().decode([String: [String: String]].self, from: result.httpBody!) + + XCTAssertEqual(bodyParametersResult.count, 1) + let resultCustomAttributes = bodyParametersResult["customAttributes"]! + + XCTAssertEqual(resultCustomAttributes["name"], "John") + XCTAssertEqual(resultCustomAttributes["surname"], "Smith") + XCTAssertEqual(resultCustomAttributes["age"], "37") + + let httpHeadersResult = result.allHTTPHeaderFields! + + XCTAssertEqual(httpHeadersResult.count, 1) + XCTAssertEqual(httpHeadersResult["Content-Type"], "application/json") + } + + func test_when_passingEmptyBodyParams_it_still_succeeds() throws { + let expectation = expectation(description: "Body request serialization error") + expectation.isInverted = true + + Self.logger.expectation = expectation + + let result = sut.serialize(with: request, parameters: [:], headers: [:]) + + wait(for: [expectation], timeout: 1) + + let bodyParametersResult = try JSONDecoder().decode([String: [String: String]].self, from: result.httpBody!) + XCTAssertEqual(bodyParametersResult.count, 0) + } + + func test_when_error_happens_in_headerSerialization_it_logs_it() throws { + let expectation = expectation(description: "Header serialization error") + + Self.logger.expectation = expectation + + _ = sut.serialize(with: request, parameters: [:], headers: ["header": 1]) + + wait(for: [expectation], timeout: 1) + + let resultingLog = Self.logger.messages[0] as! String + XCTAssertTrue(resultingLog.contains("Header serialization failed")) + } + + func test_when_error_happens_in_bodySerialization_it_logs_it() throws { + let expectation = expectation(description: "Body request serialization error") + + Self.logger.expectation = expectation + + let impossibleToEncode = [ + "param": UIView() + ] + + _ = sut.serialize(with: request, parameters: impossibleToEncode, headers: [:]) + + wait(for: [expectation], timeout: 1) + + let resultingLog = Self.logger.messages[0] as! String + XCTAssertTrue(resultingLog.contains("HTTP body request serialization failed")) + } + + func test_serializeUrlForm_successfully() { + let parameters = [ + "clientId": DEFAULT_TEST_CLIENT_ID, + "grantType": "oob", + "email": DEFAULT_TEST_ID_TOKEN_USERNAME, + "password": "12345", + "scope": DEFAULT_TEST_SCOPE + ] + + let headers = [ + "custom-header": "value" + ] + + sut = MSALNativeAuthUrlRequestSerializer(context: MSALNativeAuthRequestContext(), encoding: .wwwFormUrlEncoded) + + let result = sut.serialize(with: request, parameters: parameters, headers: headers) + let bodyResultFormUrlEncoded = String(data: result.httpBody!, encoding: .utf8) + + let expectedScope = "scope=https%3A%2F%2Fgraph.microsoft.com%2Fmail.read" + let expectedClientId = "clientId=\(DEFAULT_TEST_CLIENT_ID)" + let expectedGrantType = "grantType=oob" + let expectedEmail = "email=user%40contoso.com" + let expectedPassword = "password=12345" + + let expectedBodyResult = "\(expectedScope)&\(expectedClientId)&\(expectedGrantType)&\(expectedEmail)&\(expectedPassword)" + + XCTAssertEqual(bodyResultFormUrlEncoded?.sorted(), expectedBodyResult.sorted()) + + let httpHeadersResult = result.allHTTPHeaderFields! + + XCTAssertEqual(httpHeadersResult.count, 2) + XCTAssertEqual(httpHeadersResult["Content-Type"], "application/x-www-form-urlencoded") + XCTAssertEqual(httpHeadersResult["custom-header"], "value") + } + + func test_when_passingEmptyBodyParamsUsingUrlForm_it_still_succeeds() throws { + let expectation = expectation(description: "Body request serialization error") + expectation.isInverted = true + + Self.logger.expectation = expectation + + sut = MSALNativeAuthUrlRequestSerializer(context: MSALNativeAuthRequestContext(), encoding: .wwwFormUrlEncoded) + + let result = sut.serialize(with: request, parameters: [:], headers: [:]) + + wait(for: [expectation], timeout: 1) + + let bodyResultFormUrlEncoded = String(data: result.httpBody!, encoding: .utf8)! + XCTAssertTrue(bodyResultFormUrlEncoded.isEmpty) + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/MSALNativeAuthESTSApiErrorDescriptionsTests.swift b/MSAL/test/unit/native_auth/network/errors/MSALNativeAuthESTSApiErrorDescriptionsTests.swift new file mode 100644 index 0000000000..505b313df9 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/MSALNativeAuthESTSApiErrorDescriptionsTests.swift @@ -0,0 +1,43 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthESTSApiErrorDescriptionsTests: XCTestCase { + + private typealias sut = MSALNativeAuthESTSApiErrorDescriptions + + func test_allCases() { + XCTAssertEqual(sut.allCases.count, 2) + } + + func test_usernameParameterIsEmptyOrNotValid() { + XCTAssertEqual(sut.usernameParameterIsEmptyOrNotValid.rawValue, "username parameter is empty or not valid") + } + + func test_clientIdParameterIsEmptyOrNotValid() { + XCTAssertEqual(sut.clientIdParameterIsEmptyOrNotValid.rawValue, "client_id parameter is empty or not valid") + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift new file mode 100644 index 0000000000..6e185a4e71 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift @@ -0,0 +1,51 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests: XCTestCase { + + private typealias sut = MSALNativeAuthResetPasswordChallengeOauth2ErrorCode + + func test_allCases() { + XCTAssertEqual(sut.allCases.count, 4) + } + + func test_invalidRequest() { + XCTAssertEqual(sut.invalidRequest.rawValue, "invalid_request") + } + + func test_invalidClient() { + XCTAssertEqual(sut.invalidClient.rawValue, "invalid_client") + } + + func test_expiredToken() { + XCTAssertEqual(sut.expiredToken.rawValue, "expired_token") + } + + func test_unsupportedChallengeType() { + XCTAssertEqual(sut.unsupportedChallengeType.rawValue, "unsupported_challenge_type") + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift new file mode 100644 index 0000000000..8f06f3adb1 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift @@ -0,0 +1,88 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthResetPasswordChallengeResponseErrorTests: XCTestCase { + + private var sut: MSALNativeAuthResetPasswordChallengeResponseError! + private let testDescription = "testDescription" + + // MARK: - to ResetPasswordStartError tests + + func test_toResetPasswordStartPublicError_invalidClient() { + sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .invalidClient, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) + let error = sut.toResetPasswordStartPublicError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_toResetPasswordStartPublicError_invalidRequest() { + sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .invalidRequest, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) + let error = sut.toResetPasswordStartPublicError() + XCTAssertEqual(error.type, .generalError) + XCTAssertNotNil(error.errorDescription) + } + + func test_toResetPasswordStartPublicError_expiredToken() { + sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .expiredToken, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) + let error = sut.toResetPasswordStartPublicError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_toResetPasswordStartPublicError_unsupportedChallengeType() { + sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .unsupportedChallengeType, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) + let error = sut.toResetPasswordStartPublicError() + XCTAssertEqual(error.type, .generalError) + XCTAssertNotNil(error.errorDescription) + } + + // MARK: - to ResendCodePublicError tests + + func test_toResendCodePublicError_invalidClient() { + sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .invalidClient, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) + let error = sut.toResendCodePublicError() + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_toResendCodePublicError_invalidRequest() { + sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .invalidRequest, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) + let error = sut.toResendCodePublicError() + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_toResendCodePublicError_expiredToken() { + sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .expiredToken, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) + let error = sut.toResendCodePublicError() + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_toResendCodePublicError_unsupportedChallengeType() { + sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .unsupportedChallengeType, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) + let error = sut.toResendCodePublicError() + XCTAssertEqual(error.errorDescription, testDescription) + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift new file mode 100644 index 0000000000..84a4c2080f --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift @@ -0,0 +1,59 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests: XCTestCase { + + private typealias sut = MSALNativeAuthResetPasswordContinueOauth2ErrorCode + + func test_allCases() { + XCTAssertEqual(sut.allCases.count, 6) + } + + func test_invalidRequest() { + XCTAssertEqual(sut.invalidRequest.rawValue, "invalid_request") + } + + func test_invalidClient() { + XCTAssertEqual(sut.invalidClient.rawValue, "invalid_client") + } + + func test_invalidGrant() { + XCTAssertEqual(sut.invalidGrant.rawValue, "invalid_grant") + } + + func test_expiredToken() { + XCTAssertEqual(sut.expiredToken.rawValue, "expired_token") + } + + func test_verificationRequired() { + XCTAssertEqual(sut.verificationRequired.rawValue, "verification_required") + } + + func test_invalidOOBValue() { + XCTAssertEqual(sut.invalidOOBValue.rawValue, "invalid_oob_value") + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift new file mode 100644 index 0000000000..ad627538a5 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift @@ -0,0 +1,76 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthResetPasswordContinueResponseErrorTests: XCTestCase { + + private var sut: MSALNativeAuthResetPasswordContinueResponseError! + private let testDescription = "testDescription" + + // MARK: - to toVerifyCodePublicError tests + + func test_toResetPasswordStartPublicError_invalidRequest() { + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidRequest, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, passwordResetToken: nil) + let error = sut.toVerifyCodePublicError() + XCTAssertEqual(error.type, .generalError) + XCTAssertNotNil(error.errorDescription) + } + + func test_toResetPasswordStartPublicError_invalidClient() { + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidClient, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, passwordResetToken: nil) + let error = sut.toVerifyCodePublicError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_toResetPasswordStartPublicError_invalidGrant() { + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidGrant, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, passwordResetToken: nil) + let error = sut.toVerifyCodePublicError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_toResetPasswordStartPublicError_expiredToken() { + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .expiredToken, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, passwordResetToken: nil) + let error = sut.toVerifyCodePublicError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_toResetPasswordStartPublicError_unsupportedChallengeType() { + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .verificationRequired, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, passwordResetToken: nil) + let error = sut.toVerifyCodePublicError() + XCTAssertEqual(error.type, .generalError) + XCTAssertNotNil(error.errorDescription) + } + + func test_toResetPasswordStartPublicError_invalidOOBValue() { + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidOOBValue, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, passwordResetToken: nil) + let error = sut.toVerifyCodePublicError() + XCTAssertEqual(error.type, .invalidCode) + XCTAssertNotNil(error.errorDescription) + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift new file mode 100644 index 0000000000..08f96846c9 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift @@ -0,0 +1,71 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests: XCTestCase { + + private typealias sut = MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode + + func test_allCases() { + XCTAssertEqual(sut.allCases.count, 9) + } + + func test_invalidRequest() { + XCTAssertEqual(sut.invalidRequest.rawValue, "invalid_request") + } + + func test_invalidClient() { + XCTAssertEqual(sut.invalidClient.rawValue, "invalid_client") + } + + func test_expiredToken() { + XCTAssertEqual(sut.expiredToken.rawValue, "expired_token") + } + + func test_passwordTooWeak() { + XCTAssertEqual(sut.passwordTooWeak.rawValue, "password_too_weak") + } + + func test_passwordTooShort() { + XCTAssertEqual(sut.passwordTooShort.rawValue, "password_too_short") + } + + func test_passwordTooLong() { + XCTAssertEqual(sut.passwordTooLong.rawValue, "password_too_long") + } + + func test_passwordRecentlyUsed() { + XCTAssertEqual(sut.passwordRecentlyUsed.rawValue, "password_recently_used") + } + + func test_passwordBanned() { + XCTAssertEqual(sut.passwordBanned.rawValue, "password_banned") + } + + func test_userNotFound() { + XCTAssertEqual(sut.userNotFound.rawValue, "user_not_found") + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift new file mode 100644 index 0000000000..e522b067c4 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift @@ -0,0 +1,79 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthResetPasswordPollCompletionResponseErrorTests: XCTestCase { + + private var sut: MSALNativeAuthResetPasswordPollCompletionResponseError! + private let testDescription = "testDescription" + + // MARK: - toPasswordRequiredPublicError tests + + func test_toPasswordRequiredPublicError_invalidRequest() { + testPasswordRequiredError(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_invalidClient() { + testPasswordRequiredError(code: .invalidClient, description: "General error", expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_expiredToken() { + testPasswordRequiredError(code: .expiredToken, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_passwordTooWeak() { + testPasswordRequiredError(code: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toPasswordRequiredPublicError_passwordTooShort() { + testPasswordRequiredError(code: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toPasswordRequiredPublicError_passwordTooLong() { + testPasswordRequiredError(code: .passwordTooLong, description: "General error", expectedErrorType: .invalidPassword) + } + + func test_toPasswordRequiredPublicError_passwordRecentlyUsed() { + testPasswordRequiredError(code: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toPasswordRequiredPublicError_passwordBanned() { + testPasswordRequiredError(code: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toPasswordRequiredPublicError_userNotFound() { + testPasswordRequiredError(code: .userNotFound, description: testDescription, expectedErrorType: .generalError) + } + + // MARK: private methods + + private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredErrorType) { + sut = MSALNativeAuthResetPasswordPollCompletionResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) + let error = sut.toPasswordRequiredPublicError() + XCTAssertEqual(error.type, expectedErrorType) + XCTAssertEqual(error.errorDescription, description) + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift new file mode 100644 index 0000000000..9c6eab4e60 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift @@ -0,0 +1,51 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests: XCTestCase { + + private typealias sut = MSALNativeAuthResetPasswordStartOauth2ErrorCode + + func test_allCases() { + XCTAssertEqual(sut.allCases.count, 4) + } + + func test_invalidRequest() { + XCTAssertEqual(sut.invalidRequest.rawValue, "invalid_request") + } + + func test_invalidClient() { + XCTAssertEqual(sut.invalidClient.rawValue, "invalid_client") + } + + func test_userNotFound() { + XCTAssertEqual(sut.userNotFound.rawValue, "user_not_found") + } + + func test_unsupportedChallengeType() { + XCTAssertEqual(sut.unsupportedChallengeType.rawValue, "unsupported_challenge_type") + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift new file mode 100644 index 0000000000..f259c2e515 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift @@ -0,0 +1,67 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests: XCTestCase { + + private typealias sut = MSALNativeAuthResetPasswordSubmitOauth2ErrorCode + + func test_allCases() { + XCTAssertEqual(sut.allCases.count, 8) + } + + func test_invalidRequest() { + XCTAssertEqual(sut.invalidRequest.rawValue, "invalid_request") + } + + func test_invalidClient() { + XCTAssertEqual(sut.invalidClient.rawValue, "invalid_client") + } + + func test_expiredToken() { + XCTAssertEqual(sut.expiredToken.rawValue, "expired_token") + } + + func test_passwordTooWeak() { + XCTAssertEqual(sut.passwordTooWeak.rawValue, "password_too_weak") + } + + func test_passwordTooShort() { + XCTAssertEqual(sut.passwordTooShort.rawValue, "password_too_short") + } + + func test_passwordTooLong() { + XCTAssertEqual(sut.passwordTooLong.rawValue, "password_too_long") + } + + func test_passwordRecentlyUsed() { + XCTAssertEqual(sut.passwordRecentlyUsed.rawValue, "password_recently_used") + } + + func test_passwordBanned() { + XCTAssertEqual(sut.passwordBanned.rawValue, "password_banned") + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift new file mode 100644 index 0000000000..b9aa4f1a0f --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift @@ -0,0 +1,75 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthResetPasswordSubmitResponseErrorTests: XCTestCase { + + private var sut: MSALNativeAuthResetPasswordSubmitResponseError! + private let testDescription = "testDescription" + + // MARK: - toPasswordRequiredPublicError tests + + func test_toPasswordRequiredPublicError_invalidRequest() { + testPasswordRequiredError(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_invalidClient() { + testPasswordRequiredError(code: .invalidClient, description: "General error", expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_expiredToken() { + testPasswordRequiredError(code: .expiredToken, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_passwordTooWeak() { + testPasswordRequiredError(code: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toPasswordRequiredPublicError_passwordTooShort() { + testPasswordRequiredError(code: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toPasswordRequiredPublicError_passwordTooLong() { + testPasswordRequiredError(code: .passwordTooLong, description: "General error", expectedErrorType: .invalidPassword) + } + + func test_toPasswordRequiredPublicError_passwordRecentlyUsed() { + testPasswordRequiredError(code: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toPasswordRequiredPublicError_passwordBanned() { + testPasswordRequiredError(code: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword) + } + + // MARK: private methods + + private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredErrorType) { + sut = MSALNativeAuthResetPasswordSubmitResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) + let error = sut.toPasswordRequiredPublicError() + XCTAssertEqual(error.type, expectedErrorType) + XCTAssertEqual(error.errorDescription, description) + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthErrorRequiredAttributesTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthErrorRequiredAttributesTests.swift new file mode 100644 index 0000000000..41b9c01f48 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthErrorRequiredAttributesTests.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthErrorRequiredAttributesTests: XCTestCase { + + func test_toString_requiredTrue() { + let sut = MSALNativeAuthRequiredAttributesInternal(name: "aName", type: "", required: true) + XCTAssertEqual(sut.description, "aName") + } + + func test_toString_requiredFalse() { + let sut = MSALNativeAuthRequiredAttributesInternal(name: "aName", type: "", required: false) + XCTAssertEqual(sut.description, "aName") + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift new file mode 100644 index 0000000000..22f5c1c901 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift @@ -0,0 +1,51 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests: XCTestCase { + + private typealias sut = MSALNativeAuthSignUpChallengeOauth2ErrorCode + + func test_allCases() { + XCTAssertEqual(sut.allCases.count, 4) + } + + func test_invalidRequest() { + XCTAssertEqual(sut.invalidRequest.rawValue, "invalid_request") + } + + func test_unauthorizedClient() { + XCTAssertEqual(sut.unauthorizedClient.rawValue, "unauthorized_client") + } + + func test_unsupportedChallengeType() { + XCTAssertEqual(sut.unsupportedChallengeType.rawValue, "unsupported_challenge_type") + } + + func test_expiredToken() { + XCTAssertEqual(sut.expiredToken.rawValue, "expired_token") + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift new file mode 100644 index 0000000000..f4c2081f3c --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift @@ -0,0 +1,134 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthSignUpChallengeResponseErrorTests: XCTestCase { + + private var sut: MSALNativeAuthSignUpChallengeResponseError! + private let testDescription = "testDescription" + + // MARK: - to toSignUpPasswordStartPublicError tests + + func test_toSignUpPasswordStartPublicError_unauthorizedClient() { + testSignUpChallengeErrorToSignUpPasswordStart(code: .unauthorizedClient, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpPasswordStartPublicError_unsupportedChallengeType() { + testSignUpChallengeErrorToSignUpPasswordStart(code: .unsupportedChallengeType, description: "General error", expectedErrorType: .generalError) + } + + func test_toSignUpPasswordStartPublicError_expiredToken() { + testSignUpChallengeErrorToSignUpPasswordStart(code: .expiredToken, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpPasswordStartPublicError_invalidRequest() { + testSignUpChallengeErrorToSignUpPasswordStart(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError) + } + + // MARK: - to SignUpCodeStartError tests + + func test_toSignUpCodeStartPublicError_unauthorizedClient() { + testSignUpChallengeErrorToSignUpStart(code: .unauthorizedClient, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpCodeStartPublicError_unsupportedChallengeType() { + testSignUpChallengeErrorToSignUpStart(code: .unsupportedChallengeType, description: "General error", expectedErrorType: .generalError) + } + + func test_toSignUpCodeStartPublicError_expiredToken() { + testSignUpChallengeErrorToSignUpStart(code: .expiredToken, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpCodeStartPublicError_invalidRequest() { + testSignUpChallengeErrorToSignUpStart(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError) + } + + // MARK: - to ResendCodeError tests + + func test_toResendCodePublicError_unauthorizedClient() { + testSignUpChallengeErrorToResendCodePublic(code: .unauthorizedClient, description: testDescription) + } + + func test_toResendCodePublicError_unsupportedChallengeType() { + testSignUpChallengeErrorToResendCodePublic(code: .unsupportedChallengeType, description: "General error") + } + + func test_toResendCodePublicError_expiredToken() { + testSignUpChallengeErrorToResendCodePublic(code: .expiredToken, description: testDescription) + } + + func test_toResendCodePublicError_invalidRequest() { + testSignUpChallengeErrorToResendCodePublic(code: .invalidRequest, description: testDescription) + } + + // MARK: - to PasswordRequiredError tests + + func test_toPasswordRequiredPublicError_unauthorizedClient() { + testSignUpChallengeErrorToPasswordRequired(code: .unauthorizedClient, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_unsupportedChallengeType() { + testSignUpChallengeErrorToPasswordRequired(code: .unsupportedChallengeType, description: "General error", expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_expiredToken() { + testSignUpChallengeErrorToPasswordRequired(code: .expiredToken, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_invalidRequest() { + testSignUpChallengeErrorToPasswordRequired(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError) + } + + // MARK: private methods + + private func testSignUpChallengeErrorToSignUpPasswordStart(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?, expectedErrorType: SignUpPasswordStartErrorType) { + sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil) + let error = sut.toSignUpPasswordStartPublicError() + XCTAssertEqual(error.type, expectedErrorType) + XCTAssertEqual(error.errorDescription, description) + } + + private func testSignUpChallengeErrorToSignUpStart(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?, expectedErrorType: SignUpStartErrorType) { + sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil) + let error = sut.toSignUpStartPublicError() + XCTAssertEqual(error.type, expectedErrorType) + XCTAssertEqual(error.errorDescription, description) + } + + private func testSignUpChallengeErrorToResendCodePublic(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?) { + sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil) + let error = sut.toResendCodePublicError() + XCTAssertEqual(error.errorDescription, description) + } + + private func testSignUpChallengeErrorToPasswordRequired(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredErrorType) { + sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil) + let error = sut.toPasswordRequiredPublicError() + XCTAssertEqual(error.type, expectedErrorType) + XCTAssertEqual(error.errorDescription, description) + } + +} diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift new file mode 100644 index 0000000000..90ee233b4a --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift @@ -0,0 +1,95 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthSignUpContinueOauth2ErrorCodeTests: XCTestCase { + + private typealias sut = MSALNativeAuthSignUpContinueOauth2ErrorCode + + func test_allCases() { + XCTAssertEqual(sut.allCases.count, 15) + } + + func test_invalidRequest() { + XCTAssertEqual(sut.invalidRequest.rawValue, "invalid_request") + } + + func test_unauthorizedClient() { + XCTAssertEqual(sut.unauthorizedClient.rawValue, "unauthorized_client") + } + + func test_invalidGrant() { + XCTAssertEqual(sut.invalidGrant.rawValue, "invalid_grant") + } + + func test_expiredToken() { + XCTAssertEqual(sut.expiredToken.rawValue, "expired_token") + } + + func test_passwordTooWeak() { + XCTAssertEqual(sut.passwordTooWeak.rawValue, "password_too_weak") + } + + func test_passwordTooShort() { + XCTAssertEqual(sut.passwordTooShort.rawValue, "password_too_short") + } + + func test_passwordTooLong() { + XCTAssertEqual(sut.passwordTooLong.rawValue, "password_too_long") + } + + func test_passwordRecentlyUsed() { + XCTAssertEqual(sut.passwordRecentlyUsed.rawValue, "password_recently_used") + } + + func test_passwordBanned() { + XCTAssertEqual(sut.passwordBanned.rawValue, "password_banned") + } + + func test_userAlreadyExists() { + XCTAssertEqual(sut.userAlreadyExists.rawValue, "user_already_exists") + } + + func test_attributesRequired() { + XCTAssertEqual(sut.attributesRequired.rawValue, "attributes_required") + } + + func test_verificationRequired() { + XCTAssertEqual(sut.verificationRequired.rawValue, "verification_required") + } + + func test_attributeValidationFailed() { + XCTAssertEqual(sut.attributeValidationFailed.rawValue, "attribute_validation_failed") + } + + func test_credentialRequired() { + XCTAssertEqual(sut.credentialRequired.rawValue, "credential_required") + } + + func test_invalidOOBValue() { + XCTAssertEqual(sut.invalidOOBValue.rawValue, "invalid_oob_value") + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift new file mode 100644 index 0000000000..db6f5fcfea --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift @@ -0,0 +1,240 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase { + + private var sut: MSALNativeAuthSignUpContinueResponseError! + private let testDescription = "testDescription" + + // MARK: - to toVerifyCodePublicError tests + + func test_toVerifyCodePublicError_invalidRequest() { + testSignUpContinueErrorToVerifyCode(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError) + } + + func test_toVerifyCodePublicError_unauthorizedClient() { + testSignUpContinueErrorToVerifyCode(code: .unauthorizedClient, description: testDescription, expectedErrorType: .generalError) + } + + func test_toVerifyCodePublicError_invalidGrant() { + testSignUpContinueErrorToVerifyCode(code: .invalidGrant, description: testDescription, expectedErrorType: .generalError) + } + + func test_toVerifyCodePublicError_expiredToken() { + testSignUpContinueErrorToVerifyCode(code: .expiredToken, description: testDescription, expectedErrorType: .generalError) + } + + func test_toVerifyCodePublicError_passwordTooWeak() { + testSignUpContinueErrorToVerifyCode(code: .passwordTooWeak, description: testDescription, expectedErrorType: .generalError) + } + + func test_toVerifyCodePublicError_passwordTooShort() { + testSignUpContinueErrorToVerifyCode(code: .passwordTooShort, description: testDescription, expectedErrorType: .generalError) + } + + func test_toVerifyCodePublicError_passwordTooLong() { + testSignUpContinueErrorToVerifyCode(code: .passwordTooLong, description: testDescription, expectedErrorType: .generalError) + } + + func test_toVerifyCodePublicError_passwordRecentlyUsed() { + testSignUpContinueErrorToVerifyCode(code: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .generalError) + } + + func test_toVerifyCodePublicError_passwordBanned() { + testSignUpContinueErrorToVerifyCode(code: .passwordBanned, description: testDescription, expectedErrorType: .generalError) + } + + func test_toVerifyCodePublicError_userAlreadyExists() { + testSignUpContinueErrorToVerifyCode(code: .userAlreadyExists, description: testDescription, expectedErrorType: .generalError) + } + + func test_toVerifyCodePublicError_attributesRequired() { + testSignUpContinueErrorToVerifyCode(code: .attributesRequired, description: testDescription, expectedErrorType: .generalError) + } + + func test_toVerifyCodePublicError_verificationRequired() { + testSignUpContinueErrorToVerifyCode(code: .verificationRequired, description: testDescription, expectedErrorType: .generalError) + } + + func test_toVerifyCodePublicError_attributeValidationFailed() { + testSignUpContinueErrorToVerifyCode(code: .attributeValidationFailed, description: testDescription, expectedErrorType: .generalError) + } + + func test_toVerifyCodePublicError_credentialRequired() { + testSignUpContinueErrorToVerifyCode(code: .credentialRequired, description: testDescription, expectedErrorType: .generalError) + } + + func test_toVerifyCodePublicError_invalidOOBValue() { + testSignUpContinueErrorToVerifyCode(code: .invalidOOBValue, description: testDescription, expectedErrorType: .invalidCode) + } + + // MARK: - toPasswordRequiredPublicError tests + + func test_toPasswordRequiredPublicError_invalidRequest() { + testSignUpContinueErrorToPasswordRequired(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_unauthorizedClient() { + testSignUpContinueErrorToPasswordRequired(code: .unauthorizedClient, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_invalidGrant() { + testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_expiredToken() { + testSignUpContinueErrorToPasswordRequired(code: .expiredToken, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_passwordTooWeak() { + testSignUpContinueErrorToPasswordRequired(code: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toPasswordRequiredPublicError_passwordTooShort() { + testSignUpContinueErrorToPasswordRequired(code: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toPasswordRequiredPublicError_passwordTooLong() { + testSignUpContinueErrorToPasswordRequired(code: .passwordTooLong, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toPasswordRequiredPublicError_passwordRecentlyUsed() { + testSignUpContinueErrorToPasswordRequired(code: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toPasswordRequiredPublicError_passwordBanned() { + testSignUpContinueErrorToPasswordRequired(code: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toPasswordRequiredPublicError_userAlreadyExists() { + testSignUpContinueErrorToPasswordRequired(code: .userAlreadyExists, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_attributesRequired() { + testSignUpContinueErrorToPasswordRequired(code: .attributesRequired, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_verificationRequired() { + testSignUpContinueErrorToPasswordRequired(code: .verificationRequired, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_attributeValidationFailed() { + testSignUpContinueErrorToPasswordRequired(code: .attributeValidationFailed, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_credentialRequired() { + testSignUpContinueErrorToPasswordRequired(code: .credentialRequired, description: testDescription, expectedErrorType: .generalError) + } + + func test_toPasswordRequiredPublicError_invalidOOBValue() { + testSignUpContinueErrorToPasswordRequired(code: .invalidOOBValue, description: testDescription, expectedErrorType: .generalError) + } + + // MARK: - toAttributesRequiredPublicError tests + + func test_toAttributesRequiredPublicError_invalidRequest() { + testSignUpContinueErrorToAttributesRequired(code: .invalidRequest, description: testDescription) + } + + func test_toAttributesRequiredPublicError_unauthorizedClien() { + testSignUpContinueErrorToAttributesRequired(code: .unauthorizedClient, description: testDescription) + } + + func test_toAttributesRequiredPublicError_invalidGrant() { + testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, description: testDescription) + } + + func test_toAttributesRequiredPublicError_expiredToken() { + testSignUpContinueErrorToAttributesRequired(code: .expiredToken, description: testDescription) + } + + func test_toAttributesRequiredPublicError_passwordTooWeak() { + testSignUpContinueErrorToAttributesRequired(code: .passwordTooWeak, description: testDescription) + } + + func test_toAttributesRequiredPublicError_passwordTooShort() { + testSignUpContinueErrorToAttributesRequired(code: .passwordTooShort, description: testDescription) + } + + func test_toAttributesRequiredPublicError_passwordTooLong() { + testSignUpContinueErrorToAttributesRequired(code: .passwordTooLong, description: testDescription) + } + + func test_toAttributesRequiredPublicError_passwordRecentlyUsed() { + testSignUpContinueErrorToAttributesRequired(code: .passwordRecentlyUsed, description: testDescription) + } + + func test_toAttributesRequiredPublicError_passwordBanned() { + testSignUpContinueErrorToAttributesRequired(code: .passwordBanned, description: testDescription) + } + + func test_toAttributesRequiredPublicError_userAlreadyExists() { + testSignUpContinueErrorToAttributesRequired(code: .userAlreadyExists, description: testDescription) + } + + func test_toAttributesRequiredPublicError_attributesRequired() { + testSignUpContinueErrorToAttributesRequired(code: .attributesRequired, description: testDescription) + } + + func test_toAttributesRequiredPublicError_verificationRequired() { + testSignUpContinueErrorToAttributesRequired(code: .verificationRequired, description: testDescription) + } + + func test_toAttributesRequiredPublicError_attributeValidationFailed() { + testSignUpContinueErrorToAttributesRequired(code: .attributeValidationFailed, description: testDescription) + } + + func test_toAttributesRequiredPublicError_credentialRequired() { + testSignUpContinueErrorToAttributesRequired(code: .credentialRequired, description: testDescription) + } + + func test_toAttributesRequiredPublicError_invalidOOBValue() { + testSignUpContinueErrorToAttributesRequired(code: .invalidOOBValue, description: testDescription) + } + + // MARK: private methods + + private func testSignUpContinueErrorToVerifyCode(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, description: String?, expectedErrorType: VerifyCodeErrorType) { + sut = MSALNativeAuthSignUpContinueResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) + let error = sut.toVerifyCodePublicError() + XCTAssertEqual(error.type, expectedErrorType) + XCTAssertEqual(error.errorDescription, description) + } + + private func testSignUpContinueErrorToPasswordRequired(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredErrorType) { + sut = MSALNativeAuthSignUpContinueResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) + let error = sut.toPasswordRequiredPublicError() + XCTAssertEqual(error.type, expectedErrorType) + XCTAssertEqual(error.errorDescription, description) + } + + private func testSignUpContinueErrorToAttributesRequired(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, description: String?) { + sut = MSALNativeAuthSignUpContinueResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) + let error = sut.toAttributesRequiredPublicError() + XCTAssertEqual(error.errorDescription, description) + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift new file mode 100644 index 0000000000..941f799bb6 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift @@ -0,0 +1,87 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthSignUpStartOauth2ErrorCodeTests: XCTestCase { + + private typealias sut = MSALNativeAuthSignUpStartOauth2ErrorCode + + func test_allCases() { + XCTAssertEqual(sut.allCases.count, 13) + } + + func test_invalidRequest() { + XCTAssertEqual(sut.invalidRequest.rawValue, "invalid_request") + } + + func test_unauthorizedClient() { + XCTAssertEqual(sut.unauthorizedClient.rawValue, "unauthorized_client") + } + + func test_unsupportedChallengeType() { + XCTAssertEqual(sut.unsupportedChallengeType.rawValue, "unsupported_challenge_type") + } + + func test_passwordTooWeak() { + XCTAssertEqual(sut.passwordTooWeak.rawValue, "password_too_weak") + } + + func test_passwordTooShort() { + XCTAssertEqual(sut.passwordTooShort.rawValue, "password_too_short") + } + + func test_passwordTooLong() { + XCTAssertEqual(sut.passwordTooLong.rawValue, "password_too_long") + } + + func test_passwordRecentlyUsed() { + XCTAssertEqual(sut.passwordRecentlyUsed.rawValue, "password_recently_used") + } + + func test_passwordBanned() { + XCTAssertEqual(sut.passwordBanned.rawValue, "password_banned") + } + + func test_userAlreadyExists() { + XCTAssertEqual(sut.userAlreadyExists.rawValue, "user_already_exists") + } + + func test_attributesRequired() { + XCTAssertEqual(sut.attributesRequired.rawValue, "attributes_required") + } + + func test_verificationRequired() { + XCTAssertEqual(sut.verificationRequired.rawValue, "verification_required") + } + + func test_unsupportedAuthMethod() { + XCTAssertEqual(sut.unsupportedAuthMethod.rawValue, "unsupported_auth_method") + } + + func test_attributeValidationFailed() { + XCTAssertEqual(sut.attributeValidationFailed.rawValue, "attribute_validation_failed") + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift new file mode 100644 index 0000000000..5b22aca0dd --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift @@ -0,0 +1,156 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthSignUpStartResponseErrorTests: XCTestCase { + + private var sut: MSALNativeAuthSignUpStartResponseError! + private let testDescription = "testDescription" + + // MARK: - to toSignUpStartPasswordPublicError tests + + func test_toSignUpStartPasswordPublicError_invalidRequest() { + testSignUpStartErrorToSignUpStartPassword(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPasswordPublicError_unauthorizedClient() { + testSignUpStartErrorToSignUpStartPassword(code: .unauthorizedClient, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPasswordPublicError_unsupportedChallengeType() { + testSignUpStartErrorToSignUpStartPassword(code: .unsupportedChallengeType, description: "General error", expectedErrorType: .generalError) + } + + func test_toSignUpStartPasswordPublicError_passwordTooWeak() { + testSignUpStartErrorToSignUpStartPassword(code: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toSignUpStartPasswordPublicError_passwordTooShort() { + testSignUpStartErrorToSignUpStartPassword(code: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toSignUpStartPasswordPublicError_passwordTooLong() { + testSignUpStartErrorToSignUpStartPassword(code: .passwordTooLong, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toSignUpStartPasswordPublicError_passwordRecentlyUsed() { + testSignUpStartErrorToSignUpStartPassword(code: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toSignUpStartPasswordPublicError_passwordBanned() { + testSignUpStartErrorToSignUpStartPassword(code: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword) + } + + func test_toSignUpStartPasswordPublicError_userAlreadyExists() { + testSignUpStartErrorToSignUpStartPassword(code: .userAlreadyExists, description: testDescription, expectedErrorType: .userAlreadyExists) + } + + func test_toSignUpStartPasswordPublicError_attributesRequired() { + testSignUpStartErrorToSignUpStartPassword(code: .attributesRequired, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPasswordPublicError_verificationRequired() { + testSignUpStartErrorToSignUpStartPassword(code: .verificationRequired, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPasswordPublicError_unsupportedAuthMethod() { + testSignUpStartErrorToSignUpStartPassword(code: .unsupportedAuthMethod, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPasswordPublicError_attributeValidationFailed() { + testSignUpStartErrorToSignUpStartPassword(code: .attributeValidationFailed, description: testDescription, expectedErrorType: .generalError) + } + + // MARK: - to toSignUpStartPublicError tests + + func test_toSignUpStartPublicError_invalidRequest() { + testSignUpStartErrorToSignUpStart(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPublicError_unauthorizedClient() { + testSignUpStartErrorToSignUpStart(code: .unauthorizedClient, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPublicError_unsupportedChallengeType() { + testSignUpStartErrorToSignUpStart(code: .unsupportedChallengeType, description: "General error", expectedErrorType: .generalError) + } + + func test_toSignUpStartPublicError_passwordTooWeak() { + testSignUpStartErrorToSignUpStart(code: .passwordTooWeak, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPublicError_passwordTooShort() { + testSignUpStartErrorToSignUpStart(code: .passwordTooShort, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPublicError_passwordTooLong() { + testSignUpStartErrorToSignUpStart(code: .passwordTooLong, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPublicError_passwordRecentlyUsed() { + testSignUpStartErrorToSignUpStart(code: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPublicError_passwordBanned() { + testSignUpStartErrorToSignUpStart(code: .passwordBanned, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPublicError_userAlreadyExists() { + testSignUpStartErrorToSignUpStart(code: .userAlreadyExists, description: testDescription, expectedErrorType: .userAlreadyExists) + } + + func test_toSignUpStartPublicError_attributesRequired() { + testSignUpStartErrorToSignUpStart(code: .attributesRequired, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPublicError_verificationRequired() { + testSignUpStartErrorToSignUpStart(code: .verificationRequired, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPublicError_unsupportedAuthMethod() { + testSignUpStartErrorToSignUpStart(code: .unsupportedAuthMethod, description: testDescription, expectedErrorType: .generalError) + } + + func test_toSignUpStartPublicError_attributeValidationFailed() { + testSignUpStartErrorToSignUpStart(code: .attributeValidationFailed, description: testDescription, expectedErrorType: .generalError) + } + + // MARK: private methods + + private func testSignUpStartErrorToSignUpStartPassword(code: MSALNativeAuthSignUpStartOauth2ErrorCode, description: String?, expectedErrorType: SignUpPasswordStartErrorType) { + sut = MSALNativeAuthSignUpStartResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, unverifiedAttributes: nil, invalidAttributes: nil) + let error = sut.toSignUpStartPasswordPublicError() + XCTAssertEqual(error.type, expectedErrorType) + XCTAssertEqual(error.errorDescription, description) + } + + private func testSignUpStartErrorToSignUpStart(code: MSALNativeAuthSignUpStartOauth2ErrorCode, description: String?, expectedErrorType: SignUpStartErrorType) { + sut = MSALNativeAuthSignUpStartResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, unverifiedAttributes: nil, invalidAttributes: nil) + let error = sut.toSignUpStartPublicError() + XCTAssertEqual(error.type, expectedErrorType) + XCTAssertEqual(error.errorDescription, description) + } +} diff --git a/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift new file mode 100644 index 0000000000..a2684f4cb6 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift @@ -0,0 +1,86 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthResetPasswordChallengeRequestParametersTest: XCTestCase { + let baseUrl = URL(string: DEFAULT_TEST_AUTHORITY)! + var config: MSALNativeAuthConfiguration! = nil + + private let context = MSALNativeAuthRequestContextMock( + correlationId: .init(uuidString: DEFAULT_TEST_UID)! + ) + + func testMakeEndpointUrl_whenRightUrlStringIsUsed_noExceptionThrown() { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .oob, .redirect])) + let parameters = MSALNativeAuthResetPasswordChallengeRequestParameters( + context: MSALNativeAuthRequestContextMock(), + passwordResetToken: "" + ) + + var resultUrl: URL? = nil + XCTAssertNoThrow(resultUrl = try parameters.makeEndpointUrl(config: config)) + XCTAssertEqual(resultUrl?.absoluteString, "https://login.microsoftonline.com/common/resetpassword/v1.0/challenge") + } + + func test_allParametersFilled_shouldCreateCorrectBodyRequest() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .oob, .redirect])) + let params = MSALNativeAuthResetPasswordChallengeRequestParameters( + context: MSALNativeAuthRequestContextMock(), + passwordResetToken: "" + ) + + let body = params.makeRequestBody(config: config) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "password_reset_token": "", + "challenge_type": "password oob redirect" + ] + + XCTAssertEqual(body, expectedBodyParams) + } + + func test_allOptionalNil_shouldCreateCorrectBodyRequest() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .redirect])) + let params = MSALNativeAuthResetPasswordChallengeRequestParameters( + context: MSALNativeAuthRequestContextMock(), + passwordResetToken: "" + ) + + let body = params.makeRequestBody(config: config) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "password_reset_token": "", + "challenge_type": "password redirect" + ] + + XCTAssertEqual(body, expectedBodyParams) + } +} diff --git a/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParametersTest.swift new file mode 100644 index 0000000000..f342ed3801 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParametersTest.swift @@ -0,0 +1,93 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthResetPasswordContinueRequestParametersTest: XCTestCase { + let baseUrl = URL(string: DEFAULT_TEST_AUTHORITY)! + var config: MSALNativeAuthConfiguration! = nil + + private let context = MSALNativeAuthRequestContextMock( + correlationId: .init(uuidString: DEFAULT_TEST_UID)! + ) + + func testMakeEndpointUrl_whenRightUrlStringIsUsed_noExceptionThrown() { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) + let parameters = MSALNativeAuthResetPasswordContinueRequestParameters( + context: context, + passwordResetToken: "", + grantType: .oobCode, + oobCode: "0000" + ) + + var resultUrl: URL? = nil + XCTAssertNoThrow(resultUrl = try parameters.makeEndpointUrl(config: config)) + XCTAssertEqual(resultUrl?.absoluteString, "https://login.microsoftonline.com/common/resetpassword/v1.0/continue") + } + + func test_allParametersFilled_shouldCreateCorrectBodyRequest() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) + let params = MSALNativeAuthResetPasswordContinueRequestParameters( + context: context, + passwordResetToken: "", + grantType: .oobCode, + oobCode: "0000" + ) + + let body = params.makeRequestBody(config: config) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "password_reset_token": "", + "grant_type": "oob", + "oob": "0000" + ] + + XCTAssertEqual(body, expectedBodyParams) + } + + func test_allOptionalNil_shouldCreateCorrectBodyRequest() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) + let params = MSALNativeAuthResetPasswordContinueRequestParameters( + context: context, + passwordResetToken: "", + grantType: .oobCode, + oobCode: nil + ) + + let body = params.makeRequestBody(config: config) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "password_reset_token": "", + "grant_type": "oob" + ] + + XCTAssertEqual(body, expectedBodyParams) + } +} diff --git a/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift new file mode 100644 index 0000000000..f8b9daa70a --- /dev/null +++ b/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift @@ -0,0 +1,67 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthResetPasswordPollCompletionRequestParametersTest: XCTestCase { + let baseUrl = URL(string: DEFAULT_TEST_AUTHORITY)! + var config: MSALNativeAuthConfiguration! = nil + + private let context = MSALNativeAuthRequestContextMock( + correlationId: .init(uuidString: DEFAULT_TEST_UID)! + ) + + func testMakeEndpointUrl_whenRightUrlStringIsUsed_noExceptionThrown() { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) + let parameters = MSALNativeAuthResetPasswordPollCompletionRequestParameters( + context: context, + passwordResetToken: "", + newPassword:"new-password" + ) + + var resultUrl: URL? = nil + XCTAssertNoThrow(resultUrl = try parameters.makeEndpointUrl(config: config)) + XCTAssertEqual(resultUrl?.absoluteString, "https://login.microsoftonline.com/common/resetpassword/v1.0/submit") + } + + func test_allParametersFilled_shouldCreateCorrectBodyRequest() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) + let params = MSALNativeAuthResetPasswordSubmitRequestParameters( + context: context, + passwordSubmitToken: "", + newPassword:"new-password" + ) + + let body = params.makeRequestBody(config: config) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "password_submit_token": "", + "new_password": "new-password" + ] + + XCTAssertEqual(body, expectedBodyParams) + } +} diff --git a/MSAL/test/unit/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParametersTest.swift new file mode 100644 index 0000000000..dc833456b6 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParametersTest.swift @@ -0,0 +1,83 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthSignInChallengeRequestParametersTest: XCTestCase { + let baseUrl = URL(string: DEFAULT_TEST_AUTHORITY)! + var config: MSALNativeAuthConfiguration! = nil + + private let context = MSALNativeAuthRequestContextMock( + correlationId: .init(uuidString: DEFAULT_TEST_UID)! + ) + + func testMakeEndpointUrl_whenRightUrlStringIsUsed_noExceptionThrown() { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password])) + let parameters = MSALNativeAuthSignInChallengeRequestParameters(context: MSALNativeAuthRequestContextMock(), + credentialToken: "Test Credential Token") + var resultUrl: URL? = nil + XCTAssertNoThrow(resultUrl = try parameters.makeEndpointUrl(config: config)) + XCTAssertEqual(resultUrl?.absoluteString, "https://login.microsoftonline.com/common/oauth2/v2.0/challenge") + } + + func test_otpParameters_shouldCreateCorrectBodyRequest() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.otp])) + let params = MSALNativeAuthSignInChallengeRequestParameters( + context: context, + credentialToken: "Test Credential Token" + ) + + let body = params.makeRequestBody(config: config) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "credential_token": "Test Credential Token", + "challenge_type": "otp" + ] + + XCTAssertEqual(body, expectedBodyParams) + } + + func test_nilParameters_shouldCreteCorrectBodyRequest() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .redirect])) + let params = MSALNativeAuthSignInChallengeRequestParameters( + context: context, + credentialToken: "Test Credential Token" + ) + + let body = params.makeRequestBody(config: config) + + let expectedBodyParams = [ + "client_id": config.clientId, + "credential_token": params.credentialToken, + "challenge_type": "password redirect", + ] + + XCTAssertEqual(body, expectedBodyParams) + } +} diff --git a/MSAL/test/unit/native_auth/network/parameters/sign_in/MSALNativeAuthSignInInitiateRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/sign_in/MSALNativeAuthSignInInitiateRequestParametersTest.swift new file mode 100644 index 0000000000..d27cc26d3a --- /dev/null +++ b/MSAL/test/unit/native_auth/network/parameters/sign_in/MSALNativeAuthSignInInitiateRequestParametersTest.swift @@ -0,0 +1,83 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthSignInInitiateRequestParametersTest: XCTestCase { + let baseUrl = URL(string: DEFAULT_TEST_AUTHORITY)! + var config: MSALNativeAuthConfiguration! = nil + + private let context = MSALNativeAuthRequestContextMock( + correlationId: .init(uuidString: DEFAULT_TEST_UID)! + ) + + func testMakeEndpointUrl_whenRightUrlStringIsUsed_noExceptionThrown() { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password])) + let parameters = MSALNativeAuthSignInInitiateRequestParameters(context: MSALNativeAuthRequestContextMock(), + username: "username") + var resultUrl: URL? = nil + XCTAssertNoThrow(resultUrl = try parameters.makeEndpointUrl(config: config)) + XCTAssertEqual(resultUrl?.absoluteString, "https://login.microsoftonline.com/common/oauth2/v2.0/initiate") + } + + func test_passwordChallengeType_shouldCreateCorrectBodyRequest() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password])) + let params = MSALNativeAuthSignInInitiateRequestParameters( + context: context, + username: DEFAULT_TEST_ID_TOKEN_USERNAME + ) + + let body = params.makeRequestBody(config: config) + + let expectedBodyParams = [ + "client_id": config.clientId, + "username": params.username, + "challenge_type": "password", + ] + + XCTAssertEqual(body, expectedBodyParams) + } + + func test_otpChallenge_shouldCreateCorrectBodyRequest() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.oob])) + let params = MSALNativeAuthSignInInitiateRequestParameters( + context: context, + username: DEFAULT_TEST_ID_TOKEN_USERNAME + ) + + let body = params.makeRequestBody(config: config) + + let expectedBodyParams = [ + "client_id": config.clientId, + "username": params.username, + "challenge_type": "oob", + ] + + XCTAssertEqual(body, expectedBodyParams) + } +} diff --git a/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParametersTest.swift new file mode 100644 index 0000000000..c1e63091a5 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParametersTest.swift @@ -0,0 +1,67 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthSignUpChallengeRequestParametersTest: XCTestCase { + let baseUrl = URL(string: DEFAULT_TEST_AUTHORITY)! + var config: MSALNativeAuthConfiguration! = nil + + private let context = MSALNativeAuthRequestContextMock( + correlationId: .init(uuidString: DEFAULT_TEST_UID)! + ) + + func testMakeEndpointUrl_whenRightUrlStringIsUsed_noExceptionThrown() { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.redirect])) + let parameters = MSALNativeAuthSignUpChallengeRequestParameters( + signUpToken: "token", + context: MSALNativeAuthRequestContextMock() + ) + var resultUrl: URL? = nil + XCTAssertNoThrow(resultUrl = try parameters.makeEndpointUrl(config: config)) + XCTAssertEqual(resultUrl?.absoluteString, "https://login.microsoftonline.com/common/signup/v1.0/challenge") + } + + func test_allChallengeTypes_shouldCreateCorrectBodyRequest() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .oob, .redirect])) + let params = MSALNativeAuthSignUpChallengeRequestParameters( + signUpToken: "", + context: context + ) + + let body = params.makeRequestBody(config: config) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "signup_token": "", + "challenge_type": "password oob redirect" + ] + + XCTAssertEqual(body, expectedBodyParams) + } +} diff --git a/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParametersTest.swift new file mode 100644 index 0000000000..522a72d330 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParametersTest.swift @@ -0,0 +1,78 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthSignUpContinueRequestParametersTest: XCTestCase { + let baseUrl = URL(string: DEFAULT_TEST_AUTHORITY)! + var config: MSALNativeAuthConfiguration! = nil + + private let context = MSALNativeAuthRequestContextMock( + correlationId: .init(uuidString: DEFAULT_TEST_UID)! + ) + + func testMakeEndpointUrl_whenRightUrlStringIsUsed_noExceptionThrown() { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) + let parameters = MSALNativeAuthSignUpContinueRequestParameters( + grantType: .oobCode, + signUpToken: "token", + password: nil, + oobCode: "1234", + attributes: nil, + context: MSALNativeAuthRequestContextMock() + ) + var resultUrl: URL? = nil + XCTAssertNoThrow(resultUrl = try parameters.makeEndpointUrl(config: config)) + XCTAssertEqual(resultUrl?.absoluteString, "https://login.microsoftonline.com/common/signup/v1.0/continue") + } + + func test_allChallengeTypes_shouldCreateCorrectBodyRequest() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) + let params = MSALNativeAuthSignUpContinueRequestParameters( + grantType: .oobCode, + signUpToken: "", + password: "", + oobCode: "0000", + attributes: "", + context: context + ) + + let body = params.makeRequestBody(config: config) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "signup_token": "", + "password": "", + "oob": "0000", + "grant_type": "oob", + "attributes": "" + ] + + XCTAssertEqual(body, expectedBodyParams) + } +} diff --git a/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpStartRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpStartRequestParametersTest.swift new file mode 100644 index 0000000000..f65c068101 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpStartRequestParametersTest.swift @@ -0,0 +1,73 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthSignUpStartRequestParametersTest: XCTestCase { + let baseUrl = URL(string: DEFAULT_TEST_AUTHORITY)! + var config: MSALNativeAuthConfiguration! = nil + + private let context = MSALNativeAuthRequestContextMock( + correlationId: .init(uuidString: DEFAULT_TEST_UID)! + ) + + func testMakeEndpointUrl_whenRightUrlStringIsUsed_noExceptionThrown() { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.redirect])) + let parameters = MSALNativeAuthSignUpStartRequestParameters( + username: "username", + password: nil, + attributes: nil, + context: MSALNativeAuthRequestContextMock() + ) + var resultUrl: URL? = nil + XCTAssertNoThrow(resultUrl = try parameters.makeEndpointUrl(config: config)) + XCTAssertEqual(resultUrl?.absoluteString, "https://login.microsoftonline.com/common/signup/v1.0/start") + } + + func test_allChallengeTypes_shouldCreateCorrectBodyRequest() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .oob, .redirect])) + let params = MSALNativeAuthSignUpStartRequestParameters( + username: DEFAULT_TEST_ID_TOKEN_USERNAME, + password: "strong-password", + attributes: "", + context: context + ) + + let body = params.makeRequestBody(config: config) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "username": DEFAULT_TEST_ID_TOKEN_USERNAME, + "password": "strong-password", + "attributes": "", + "challenge_type": "password oob redirect" + ] + + XCTAssertEqual(body, expectedBodyParams) + } +} diff --git a/MSAL/test/unit/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParametersTest.swift new file mode 100644 index 0000000000..974589b14a --- /dev/null +++ b/MSAL/test/unit/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParametersTest.swift @@ -0,0 +1,113 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthTokenRequestParametersTest: XCTestCase { + let baseUrl = URL(string: DEFAULT_TEST_AUTHORITY)! + var config: MSALNativeAuthConfiguration! = nil + private let context = MSALNativeAuthRequestContextMock( + correlationId: .init(uuidString: DEFAULT_TEST_UID)! + ) + + func testMakeEndpointUrl_whenRightUrlStringIsUsed_noExceptionThrown() { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password])) + let parameters = MSALNativeAuthTokenRequestParameters(context: MSALNativeAuthRequestContextMock(), + username: "username", + credentialToken: "Test Credential Token", + signInSLT: "Test SignIn SLT", + grantType: .password, + scope: "scope", + password: "password", + oobCode: "Test OTP Code", + includeChallengeType: true, + refreshToken: nil) + var resultUrl: URL? = nil + XCTAssertNoThrow(resultUrl = try parameters.makeEndpointUrl(config: config)) + XCTAssertEqual(resultUrl?.absoluteString, "https://login.microsoftonline.com/common/oauth2/v2.0/token") + } + + func test_passwordParameters_shouldCreateCorrectBodyRequest() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password])) + let params = MSALNativeAuthTokenRequestParameters( + context: context, + username: DEFAULT_TEST_ID_TOKEN_USERNAME, + credentialToken: "Test Credential Token", + signInSLT: "Test SignIn SLT", + grantType: .password, + scope: "", + password: "password", + oobCode: "oob", + includeChallengeType: true, + refreshToken: nil + ) + + let body = params.makeRequestBody(config: config) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "username": DEFAULT_TEST_ID_TOKEN_USERNAME, + "credential_token": "Test Credential Token", + "signin_slt": "Test SignIn SLT", + "grant_type": "password", + "challenge_type": "password", + "scope": "", + "password": "password", + "oob": "oob", + "client_info" : "true" + ] + + XCTAssertEqual(body, expectedBodyParams) + } + + func test_nilParameters_shouldCreateCorrectParameters() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .redirect])) + let params = MSALNativeAuthTokenRequestParameters( + context: context, + username: nil, + credentialToken: nil, + signInSLT: nil, + grantType: .password, + scope: nil, + password: nil, + oobCode: nil, + includeChallengeType: false, + refreshToken: nil + ) + + let body = params.makeRequestBody(config: config) + + let expectedBodyParams = [ + "client_id": config.clientId, + "grant_type": "password", + "client_info" : "true" + ] + + XCTAssertEqual(body, expectedBodyParams) + } +} diff --git a/MSAL/test/unit/native_auth/network/requests/sign_in/MSALNativeAuthSignInChallengeRequestTests.swift b/MSAL/test/unit/native_auth/network/requests/sign_in/MSALNativeAuthSignInChallengeRequestTests.swift new file mode 100644 index 0000000000..26643d1321 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/requests/sign_in/MSALNativeAuthSignInChallengeRequestTests.swift @@ -0,0 +1,137 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthSignInChallengeRequestTests: XCTestCase { + + let context = MSALNativeAuthRequestContext( + correlationId: .init( + UUID(uuidString: DEFAULT_TEST_UID)! + ) + ) + + private var params: MSALNativeAuthSignInChallengeRequestParameters { + .init( + config: MSALNativeAuthConfigStubs.configuration, + context: context, + credentialToken: "Test Credential Token", + challengeTypes: [.otp] + ) + } + + func test_signInChallengeRequest_gets_created_successfully() throws { + + let telemetry = MSIDAADTokenRequestServerTelemetry() + telemetry.currentRequestTelemetry = .init( + appId: 1234, + tokenCacheRefreshType: .proactiveTokenRefresh, + platformFields: ["ios"] + )! + + let sut = try MSALNativeAuthSignInChallengeRequest(params: params) + + XCTAssertEqual(sut.context!.correlationId(), context.correlationId()) + checkBodyParams(sut.parameters) + } + + func test_configure_signInRequest() throws { + let telemetry = MSIDAADTokenRequestServerTelemetry() + telemetry.currentRequestTelemetry = .init( + appId: 1234, + tokenCacheRefreshType: .proactiveTokenRefresh, + platformFields: ["ios"] + )! + + let sut = try MSALNativeAuthSignInChallengeRequest(params: params) + + sut.configure( + requestSerializer: MSALNativeAuthUrlRequestSerializer(context: context, encoding: .wwwFormUrlEncoded), + serverTelemetry: telemetry + ) + + checkTelemetry(sut.serverTelemetry, telemetry) + checkUrlRequest(sut.urlRequest) + } + + func test_configureSignInRequestWithNilParameters_shouldCreateCorrectParameters() throws { + let telemetry = MSIDAADTokenRequestServerTelemetry() + telemetry.currentRequestTelemetry = .init( + appId: 1234, + tokenCacheRefreshType: .proactiveTokenRefresh, + platformFields: ["ios"] + )! + + let sut = try MSALNativeAuthSignInChallengeRequest(params: .init( + config: MSALNativeAuthConfigStubs.configuration, + context: context, + credentialToken: params.credentialToken, + challengeTypes: nil + )) + + sut.configure( + requestSerializer: MSALNativeAuthUrlRequestSerializer(context: context, encoding: .wwwFormUrlEncoded), + serverTelemetry: telemetry + ) + + let expectedBodyParams = [ + "client_id": params.config.clientId, + "credential_token": params.credentialToken + ] + + XCTAssertEqual(sut.parameters, expectedBodyParams) + } + + private func checkTelemetry(_ result: MSIDHttpRequestServerTelemetryHandling?, _ expected: MSIDAADTokenRequestServerTelemetry) { + + guard let resultTelemetry = (result as? MSIDAADTokenRequestServerTelemetry)?.currentRequestTelemetry else { + return XCTFail() + } + + let expectedTelemetry = expected.currentRequestTelemetry + + XCTAssertEqual(resultTelemetry.apiId, expectedTelemetry.apiId) + XCTAssertEqual(resultTelemetry.tokenCacheRefreshType, expectedTelemetry.tokenCacheRefreshType) + XCTAssertEqual(resultTelemetry.platformFields, expectedTelemetry.platformFields) + } + + private func checkBodyParams(_ result: [String: String]?) { + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "credential_token": "Test Credential Token", + "challenge_type": "otp" + ] + + XCTAssertEqual(result, expectedBodyParams) + } + + private func checkUrlRequest(_ result: URLRequest?) { + XCTAssertEqual(result?.httpMethod, MSALParameterStringForHttpMethod(.POST)) + + let expectedUrl = URL(string: MSALNativeAuthNetworkStubs.authority.url.absoluteString + MSALNativeAuthEndpoint.signInChallenge.rawValue)! + XCTAssertEqual(result?.url, expectedUrl) + } +} diff --git a/MSAL/test/unit/native_auth/network/requests/sign_in/MSALNativeAuthSignInTokenRequestTests.swift b/MSAL/test/unit/native_auth/network/requests/sign_in/MSALNativeAuthSignInTokenRequestTests.swift new file mode 100644 index 0000000000..eaba0e483c --- /dev/null +++ b/MSAL/test/unit/native_auth/network/requests/sign_in/MSALNativeAuthSignInTokenRequestTests.swift @@ -0,0 +1,158 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthSignInTokenRequestTests: XCTestCase { + + let context = MSALNativeAuthRequestContext( + correlationId: .init( + UUID(uuidString: DEFAULT_TEST_UID)! + ) + ) + + private var params: MSALNativeAuthSignInTokenRequestParameters { + + .init( + config: MSALNativeAuthConfigStubs.configuration, + context: context, + username: DEFAULT_TEST_ID_TOKEN_USERNAME, + credentialToken: "Test Credential Token", + signInSLT: "Test SignIn SLT", + grantType: .password, + challengeTypes: [.password], + scope: "", + password: "password", + oobCode: "oob" + ) + } + + func test_signInRequest_gets_created_successfully() throws { + + let telemetry = MSIDAADTokenRequestServerTelemetry() + telemetry.currentRequestTelemetry = .init( + appId: 1234, + tokenCacheRefreshType: .proactiveTokenRefresh, + platformFields: ["ios"] + )! + + let sut = try MSALNativeAuthSignInTokenRequest(params: params) + + XCTAssertEqual(sut.context!.correlationId(), context.correlationId()) + checkBodyParams(sut.parameters) + } + + func test_configure_signInRequest() throws { + let telemetry = MSIDAADTokenRequestServerTelemetry() + telemetry.currentRequestTelemetry = .init( + appId: 1234, + tokenCacheRefreshType: .proactiveTokenRefresh, + platformFields: ["ios"] + )! + + let sut = try MSALNativeAuthSignInTokenRequest(params: params) + + sut.configure( + requestSerializer: MSALNativeAuthUrlRequestSerializer(context: context, encoding: .wwwFormUrlEncoded), + serverTelemetry: telemetry + ) + + checkTelemetry(sut.serverTelemetry, telemetry) + checkUrlRequest(sut.urlRequest) + } + + func test_configureSignInRequestWithNilParameters_shouldCreateCorrectParameters() throws { + let telemetry = MSIDAADTokenRequestServerTelemetry() + telemetry.currentRequestTelemetry = .init( + appId: 1234, + tokenCacheRefreshType: .proactiveTokenRefresh, + platformFields: ["ios"] + )! + + let sut = try MSALNativeAuthSignInTokenRequest(params: .init( + config: MSALNativeAuthConfigStubs.configuration, + context: params.context, + username: nil, + credentialToken: nil, + signInSLT: nil, + grantType: .password, + challengeTypes: nil, + scope: nil, + password: nil, + oobCode: nil + )) + + sut.configure( + requestSerializer: MSALNativeAuthUrlRequestSerializer(context: context, encoding: .wwwFormUrlEncoded), + serverTelemetry: telemetry + ) + + let expectedBodyParams = [ + "client_id": params.config.clientId, + "grant_type": "password", + "client_info": "true" + ] + + XCTAssertEqual(sut.parameters, expectedBodyParams) + } + + private func checkTelemetry(_ result: MSIDHttpRequestServerTelemetryHandling?, _ expected: MSIDAADTokenRequestServerTelemetry) { + + guard let resultTelemetry = (result as? MSIDAADTokenRequestServerTelemetry)?.currentRequestTelemetry else { + return XCTFail() + } + + let expectedTelemetry = expected.currentRequestTelemetry + + XCTAssertEqual(resultTelemetry.apiId, expectedTelemetry.apiId) + XCTAssertEqual(resultTelemetry.tokenCacheRefreshType, expectedTelemetry.tokenCacheRefreshType) + XCTAssertEqual(resultTelemetry.platformFields, expectedTelemetry.platformFields) + } + + private func checkBodyParams(_ result: [String: String]?) { + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "username": DEFAULT_TEST_ID_TOKEN_USERNAME, + "credential_token": "Test Credential Token", + "signin_slt": "Test SignIn SLT", + "grant_type": "password", + "challenge_type": "password", + "scope": "", + "password": "password", + "oob": "oob", + "client_info": "true" + ] + + XCTAssertEqual(result, expectedBodyParams) + } + + private func checkUrlRequest(_ result: URLRequest?) { + XCTAssertEqual(result?.httpMethod, MSALParameterStringForHttpMethod(.POST)) + + let expectedUrl = URL(string: MSALNativeAuthNetworkStubs.authority.url.absoluteString + MSALNativeAuthEndpoint.token.rawValue)! + XCTAssertEqual(result?.url, expectedUrl) + } +} diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift new file mode 100644 index 0000000000..8afc007709 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift @@ -0,0 +1,662 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { + + private var sut: MSALNativeAuthResetPasswordResponseValidator! + private var context: MSIDRequestContext! + + override func setUpWithError() throws { + try super.setUpWithError() + + sut = MSALNativeAuthResetPasswordResponseValidator() + context = MSALNativeAuthRequestContextMock() + } + + // MARK: - Start Response + + func test_whenResetPasswordStartSuccessResponseContainsRedirect_itReturnsRedirect() { + let response: Result = .success( + .init(passwordResetToken: nil, challengeType: .redirect) + ) + + let result = sut.validate(response, with: context) + if case .redirect = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenResetPasswordStartSuccessResponseDoesNotContainsTokenOrRedirect_itReturnsUnexpectedError() { + let response: Result = .success( + .init(passwordResetToken: nil, challengeType: .otp) + ) + + let result = sut.validate(response, with: context) + if case .unexpectedError = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenResetPasswordStartSuccessResponseContainsToken_itReturnsSuccess() { + let response: Result = .success( + .init(passwordResetToken: "passwordResetToken", challengeType: .otp) + ) + + let result = sut.validate(response, with: context) + + guard case .success(let passwordResetToken) = result else { + return XCTFail("Unexpected response") + } + + XCTAssertEqual(passwordResetToken, "passwordResetToken") + } + + func test_whenResetPasswordStartErrorResponseIsNotExpected_itReturnsUnexpectedError() { + let response: Result = .failure(NSError()) + + let result = sut.validate(response, with: context) + if case .unexpectedError = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenResetPasswordStartErrorResponseUserNotFound_itReturnsRelatedError() { + let error = createResetPasswordStartError(error: .userNotFound) + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + if case .error(.userNotFound) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenResetPasswordStartErrorResponseInvalidClient_itReturnsRelatedError() { + let error = createResetPasswordStartError(error: .invalidClient) + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + if case .error(.invalidClient) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenResetPasswordStartErrorResponseUnsupportedChallengeType_itReturnsRelatedError() { + let error = createResetPasswordStartError(error: .unsupportedChallengeType) + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + if case .error(.unsupportedChallengeType) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenResetPasswordStartInvalidRequestUserDoesntHaveAPwd_itReturnsRelatedError() { + let error = createResetPasswordStartError(error: .invalidRequest, errorCodes: [500222]) + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + if case .error(.userDoesNotHavePassword) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenResetPasswordStartInvalidRequestGenericErrorCode_itReturnsRelatedError() { + let error = createResetPasswordStartError(error: .invalidRequest, errorCodes: [90023]) + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + if case .error(.invalidRequest) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenResetPasswordStartInvalidRequestNoErrorCode_itReturnsRelatedError() { + let error = createResetPasswordStartError(error: .invalidRequest) + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + if case .error(.invalidRequest) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + // MARK: - Challenge Response + + func test_whenResetPasswordChallengeSuccessResponseContainsRedirect_itReturnsRedirect() { + let response: Result = .success(.init( + challengeType: .redirect, + bindingMethod: nil, + challengeTargetLabel: "challenge-type-label", + challengeChannel: .email, + passwordResetToken: "token", + codeLength: nil) + ) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .redirect) + } + + func test_whenResetPasswordChallengeSuccessResponseContainsValidAttributesAndOOB_itReturnsSuccess() { + let response: Result = .success(.init( + challengeType: .oob, + bindingMethod: nil, + challengeTargetLabel: "challenge-type-label", + challengeChannel: .email, + passwordResetToken: "token", + codeLength: 6) + ) + + let result = sut.validate(response, with: context) + + guard case .success(let sentTo, let channelTargetType, let codeLength, let passwordResetToken) = result else { + return XCTFail("Unexpected response") + } + + XCTAssertEqual(sentTo, "challenge-type-label") + XCTAssertEqual(channelTargetType, .email) + XCTAssertEqual(codeLength, 6) + XCTAssertEqual(passwordResetToken, "token") + } + + func test_whenResetPasswordChallengeSuccessResponseOmitsSomeAttributes_itReturnsUnexpectedError() { + let response: Result = .success(.init( + challengeType: .oob, + bindingMethod: nil, + challengeTargetLabel: "challenge-type-label", + challengeChannel: .email, + passwordResetToken: nil, + codeLength: 6) + ) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenResetPasswordChallengeSuccessResponseHasInvalidChallengeChannel_itReturnsUnexpectedError() { + let response: Result = .success(.init( + challengeType: .otp, + bindingMethod: nil, + challengeTargetLabel: "challenge-type-label", + challengeChannel: .none, + passwordResetToken: nil, + codeLength: 6) + ) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenResetPasswordChallengeErrorResponseIsNotExpected_itReturnsUnexpectedError() { + let response: Result = .failure(NSError()) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenResetPasswordChallengeErrorResponseIsExpected_itReturnsError() { + let error = createResetPasswordChallengeError(error: .expiredToken) + + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .expiredToken = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + // MARK: - Continue Response + + func test_whenResetPasswordContinueSuccessResponseContainsValidAttributesAndOOB_itReturnsSuccess() { + let response: Result = .success(.init(passwordSubmitToken: "passwordSubmitToken", expiresIn: 300)) + + let result = sut.validate(response, with: context) + + guard case .success(let passwordSubmitToken) = result else { + return XCTFail("Unexpected response") + } + + XCTAssertEqual(passwordSubmitToken, "passwordSubmitToken") + } + + func test_whenResetPasswordContinueErrorResponseIsNotExpected_itReturnsUnexpectedError() { + let response: Result = .failure(NSError()) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenResetPasswordContinueErrorResponseIs_invalidOOBValue_itReturnsExpectedError() { + let result = buildContinueErrorResponse(expectedError: .invalidOOBValue) + + XCTAssertEqual(result, .invalidOOB) + } + + func test_whenResetPasswordContinueErrorResponseIs_verificationRequired_itReturnsUnexpectedError() { + let result = buildContinueErrorResponse(expectedError: .verificationRequired) + + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenResetPasswordContinueErrorResponseIs_invalidClient_itReturnsExpectedError() { + let result = buildContinueErrorResponse(expectedError: .invalidClient) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .invalidClient = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordContinueErrorResponseIs_invalidGrant_itReturnsExpectedError() { + let result = buildContinueErrorResponse(expectedError: .invalidGrant) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .invalidGrant = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordContinueErrorResponseIs_expiredToken_itReturnsExpectedError() { + let result = buildContinueErrorResponse(expectedError: .expiredToken) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .expiredToken = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordContinueErrorResponseIs_invalidRequest_itReturnsExpectedError() { + let result = buildContinueErrorResponse(expectedError: .invalidRequest) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .invalidRequest = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + // MARK: - Submit Response + + func test_whenResetPasswordSubmitSuccessResponseContainsToken_itReturnsSuccess() { + let response: Result = .success(.init(passwordResetToken: "passwordResetToken", pollInterval: 1)) + + let result = sut.validate(response, with: context) + + guard case .success(let passwordResetToken, let pollInterval) = result else { + return XCTFail("Unexpected response") + } + + XCTAssertEqual(passwordResetToken, "passwordResetToken") + XCTAssertEqual(pollInterval, 1) + } + + func test_whenResetPasswordSubmitErrorResponseIs_passwordTooWeak_itReturnsExpectedError() { + let result = buildSubmitErrorResponse(expectedError: .passwordTooWeak) + + guard case .passwordError(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordTooWeak = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordSubmitErrorResponseIs_passwordTooShort_itReturnsExpectedError() { + let result = buildSubmitErrorResponse(expectedError: .passwordTooShort) + + guard case .passwordError(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordTooShort = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordSubmitErrorResponseIs_passwordTooLong_itReturnsExpectedError() { + let result = buildSubmitErrorResponse(expectedError: .passwordTooLong) + + guard case .passwordError(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordTooLong = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordSubmitErrorResponseIs_passwordRecentlyUsed_itReturnsExpectedError() { + let result = buildSubmitErrorResponse(expectedError: .passwordRecentlyUsed) + + guard case .passwordError(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordRecentlyUsed = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordSubmitErrorResponseIs_passwordBanned_itReturnsExpectedError() { + let result = buildSubmitErrorResponse(expectedError: .passwordBanned) + + guard case .passwordError(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordBanned = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordSubmitErrorResponseIs_invalidRequest_itReturnsExpectedError() { + let result = buildSubmitErrorResponse(expectedError: .invalidRequest) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .invalidRequest = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordSubmitErrorResponseIs_invalidClient_itReturnsExpectedError() { + let result = buildSubmitErrorResponse(expectedError: .invalidClient) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .invalidClient = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordSubmitErrorResponseIs_expiredToken_itReturnsExpectedError() { + let result = buildSubmitErrorResponse(expectedError: .expiredToken) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .expiredToken = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordSubmitErrorResponseIsNotExpected_itReturnsUnexpectedError() { + let response: Result = .failure(NSError()) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + // MARK: - Poll Completion Response + + func test_whenResetPasswordPollCompletionSuccessResponse_itReturnsSuccess() { + let response: Result = .success(.init(status: .succeeded, signInSLT: nil, expiresIn: nil)) + + let result = sut.validate(response, with: context) + + guard case .success(let status) = result else { + return XCTFail("Unexpected response") + } + + XCTAssertEqual(status, .succeeded) + } + + func test_whenResetPasswordPollCompletionErrorResponseIsPasswordTooWeak_itReturnsExpectedError() { + let result = buildPollCompletionErrorResponse(expectedError: .passwordTooWeak) + + guard case .passwordError(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordTooWeak = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordPollCompletionErrorResponseIsPasswordTooShort_itReturnsExpectedError() { + let result = buildPollCompletionErrorResponse(expectedError: .passwordTooShort) + + guard case .passwordError(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordTooShort = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordPollCompletionErrorResponseIsPasswordTooLong_itReturnsExpectedError() { + let result = buildPollCompletionErrorResponse(expectedError: .passwordTooLong) + + guard case .passwordError(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordTooLong = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordPollCompletionErrorResponseIsPasswordRecentlyUsed_itReturnsExpectedError() { + let result = buildPollCompletionErrorResponse(expectedError: .passwordRecentlyUsed) + + guard case .passwordError(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordRecentlyUsed = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordPollCompletionErrorResponseIsPasswordBanned_itReturnsExpectedError() { + let result = buildPollCompletionErrorResponse(expectedError: .passwordBanned) + + guard case .passwordError(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordBanned = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordPollCompletionErrorResponseIsInvalidRequest_itReturnsExpectedError() { + let result = buildPollCompletionErrorResponse(expectedError: .invalidRequest) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .invalidRequest = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordPollCompletionErrorResponseIsInvalidClient_itReturnsExpectedError() { + let result = buildPollCompletionErrorResponse(expectedError: .invalidClient) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .invalidClient = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordPollCompletionErrorResponseIsExpiredToken_itReturnsExpectedError() { + let result = buildPollCompletionErrorResponse(expectedError: .expiredToken) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .expiredToken = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenResetPasswordPollCompletionErrorResponseIsNotExpected_itReturnsUnexpectedError() { + let response: Result = .failure(NSError()) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + // MARK: - Helper methods + + private func buildContinueErrorResponse( + expectedError: MSALNativeAuthResetPasswordContinueOauth2ErrorCode, + expectedPasswordResetToken: String? = nil + ) -> MSALNativeAuthResetPasswordContinueValidatedResponse { + let response: Result = .failure( + createResetPasswordContinueError( + error: expectedError, + passwordResetToken: expectedPasswordResetToken + ) + ) + + return sut.validate(response, with: context) + } + + private func buildSubmitErrorResponse( + expectedError: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode + ) -> MSALNativeAuthResetPasswordSubmitValidatedResponse { + let response: Result = .failure( + createResetPasswordSubmitError( + error: expectedError + ) + ) + + return sut.validate(response, with: context) + } + + private func buildPollCompletionErrorResponse( + expectedError: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode + ) -> MSALNativeAuthResetPasswordPollCompletionValidatedResponse { + let response: Result = .failure( + createResetPasswordPollCompletionError( + error: expectedError + ) + ) + + return sut.validate(response, with: context) + } + + private func createResetPasswordStartError( + error: MSALNativeAuthResetPasswordStartOauth2ErrorCode, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + target: String? = nil + ) -> MSALNativeAuthResetPasswordStartResponseError { + .init( + error: error, + errorDescription: errorDescription, + errorCodes: errorCodes, + errorURI: errorURI, + innerErrors: innerErrors, + target: target + ) + } + + private func createResetPasswordChallengeError( + error: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + target: String? = nil + ) -> MSALNativeAuthResetPasswordChallengeResponseError { + .init( + error: error, + errorDescription: errorDescription, + errorCodes: errorCodes, + errorURI: errorURI, + innerErrors: innerErrors, + target: target + ) + } + + private func createResetPasswordContinueError( + error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + target: String? = nil, + passwordResetToken: String? = nil + ) -> MSALNativeAuthResetPasswordContinueResponseError { + .init( + error: error, + errorDescription: errorDescription, + errorCodes: errorCodes, + errorURI: errorURI, + innerErrors: innerErrors, + target: target, + passwordResetToken: passwordResetToken + ) + } + + private func createResetPasswordSubmitError( + error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + target: String? = nil + ) -> MSALNativeAuthResetPasswordSubmitResponseError { + .init( + error: error, + errorDescription: errorDescription, + errorCodes: errorCodes, + errorURI: errorURI, + innerErrors: innerErrors, + target: target + ) + } + + private func createResetPasswordPollCompletionError( + error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + target: String? = nil + ) -> MSALNativeAuthResetPasswordPollCompletionResponseError { + .init( + error: error, + errorDescription: errorDescription, + errorCodes: errorCodes, + errorURI: errorURI, + innerErrors: innerErrors, + target: target + ) + } +} diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift new file mode 100644 index 0000000000..328806c000 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift @@ -0,0 +1,64 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthResetPasswordStartValidatedErrorTypeTests: XCTestCase { + + private typealias sut = MSALNativeAuthResetPasswordStartValidatedErrorType + private let testDescription = "testDescription" + + // MARK: - to ResetPasswordStartError tests + + func test_toResetPasswordStartPublicError_invalidClient() { + let error = sut.invalidClient(message: testDescription).toResetPasswordStartPublicError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_toResetPasswordStartPublicError_invalidRequest() { + let error = sut.invalidRequest(message: "General error").toResetPasswordStartPublicError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, "General error") + } + + func test_toResetPasswordStartPublicError_userDoesNotHavePassword() { + let error = sut.userDoesNotHavePassword.toResetPasswordStartPublicError() + XCTAssertEqual(error.type, .userDoesNotHavePassword) + XCTAssertEqual(error.errorDescription, MSALNativeAuthErrorMessage.userDoesNotHavePassword) + } + + func test_toResetPasswordStartPublicError_userNotFound() { + let error = sut.userNotFound(message: testDescription).toResetPasswordStartPublicError() + XCTAssertEqual(error.type, .userNotFound) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_toResetPasswordStartPublicError_unsupportedChallengeType() { + let error = sut.unsupportedChallengeType(message: nil).toResetPasswordStartPublicError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, "General error") + } +} diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift new file mode 100644 index 0000000000..33ca8c9fc1 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift @@ -0,0 +1,110 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +import XCTest +@testable import MSAL + +final class MSALNativeAuthSignInInitiateValidatedErrorTypeTests: XCTestCase { + + private typealias sut = MSALNativeAuthSignInInitiateValidatedErrorType + private let testDescription = "testDescription" + + // MARK: - convertToSignInStartError tests + + func test_convertToSignInStartError_redirect() { + let error = sut.redirect.convertToSignInStartError() + XCTAssertEqual(error.type, .browserRequired) + XCTAssertEqual(error.errorDescription, "Browser required") + } + + func test_convertToSignInStartError_invalidClient() { + let error = sut.invalidClient(message: testDescription).convertToSignInStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInStartError_invalidRequest() { + let error = sut.invalidRequest(message: testDescription).convertToSignInStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInStartError_invalidServerResponse() { + let error = sut.invalidServerResponse.convertToSignInStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, "General error") + } + + func test_convertToSignInStartError_userNotFound() { + let error = sut.userNotFound(message: testDescription).convertToSignInStartError() + XCTAssertEqual(error.type, .userNotFound) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInStartError_unsupportedChallengeType() { + let error = sut.unsupportedChallengeType(message: testDescription).convertToSignInStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + // MARK: - convertToSignInPasswordStartError tests + + func test_convertToSignInPasswordStartError_redirect() { + let error = sut.redirect.convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .browserRequired) + XCTAssertEqual(error.errorDescription, "Browser required") + } + + func test_convertToSignInPasswordStartError_invalidClient() { + let error = sut.invalidClient(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInPasswordStartError_invalidRequest() { + let error = sut.invalidRequest(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInPasswordStartError_invalidServerResponse() { + let error = sut.invalidServerResponse.convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, "General error") + } + + func test_convertToSignInPasswordStartError_userNotFound() { + let error = sut.userNotFound(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .userNotFound) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInPasswordStartError_unsupportedChallengeType() { + let error = sut.unsupportedChallengeType(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + +} diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift new file mode 100644 index 0000000000..7172554a98 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift @@ -0,0 +1,172 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase { + + private let baseUrl = URL(string: DEFAULT_TEST_AUTHORITY)! + private var sut: MSALNativeAuthSignInResponseValidator! + private var defaultUUID = UUID(uuidString: DEFAULT_TEST_UID)! + private var factory: MSALNativeAuthResultFactoryMock! + + + override func setUpWithError() throws { + try super.setUpWithError() + + factory = MSALNativeAuthResultFactoryMock() + sut = MSALNativeAuthSignInResponseValidator() + } + + // MARK: challenge API tests + + func test_whenChallengeTypeRedirect_validationShouldReturnRedirectError() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let challengeResponse = MSALNativeAuthSignInChallengeResponse(credentialToken: nil, challengeType: .redirect, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: nil, codeLength: nil, interval: nil) + let result = sut.validate(context: context, result: .success(challengeResponse)) + if case .error(.redirect) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenChallengeTypePassword_validationShouldReturnPasswordRequired() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let credentialToken = "credentialToken" + let challengeResponse = MSALNativeAuthSignInChallengeResponse(credentialToken: credentialToken, challengeType: .password, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: nil, codeLength: nil, interval: nil) + let result = sut.validate(context: context, result: .success(challengeResponse)) + if case .passwordRequired(credentialToken: credentialToken) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenChallengeTypePasswordAndNoCredentialToken_validationShouldFail() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let challengeResponse = MSALNativeAuthSignInChallengeResponse(credentialToken: nil, challengeType: .password, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: nil, codeLength: nil, interval: nil) + let result = sut.validate(context: context, result: .success(challengeResponse)) + if case .error(.invalidServerResponse) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenChallengeTypeOOB_validationShouldReturnCodeRequired() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let credentialToken = "credentialToken" + let targetLabel = "targetLabel" + let codeLength = 4 + let channelType = MSALNativeAuthInternalChannelType.email + let challengeResponse = MSALNativeAuthSignInChallengeResponse(credentialToken: credentialToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: channelType, codeLength: codeLength, interval: nil) + let result = sut.validate(context: context, result: .success(challengeResponse)) + if case .codeRequired(credentialToken: credentialToken, sentTo: targetLabel, channelType: .email, codeLength: codeLength) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenChallengeTypeOOBButMissingAttributes_validationShouldFail() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let credentialToken = "credentialToken" + let targetLabel = "targetLabel" + let codeLength = 4 + let channelType = MSALNativeAuthInternalChannelType.email + let missingCredentialToken = MSALNativeAuthSignInChallengeResponse(credentialToken: nil, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: channelType, codeLength: codeLength, interval: nil) + var result = sut.validate(context: context, result: .success(missingCredentialToken)) + if case .error(.invalidServerResponse) = result {} else { + XCTFail("Unexpected result: \(result)") + } + let missingTargetLabel = MSALNativeAuthSignInChallengeResponse(credentialToken: credentialToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: channelType, codeLength: codeLength, interval: nil) + result = sut.validate(context: context, result: .success(missingTargetLabel)) + if case .error(.invalidServerResponse) = result {} else { + XCTFail("Unexpected result: \(result)") + } + let missingChannelType = MSALNativeAuthSignInChallengeResponse(credentialToken: credentialToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: nil, codeLength: codeLength, interval: nil) + result = sut.validate(context: context, result: .success(missingChannelType)) + if case .error(.invalidServerResponse) = result {} else { + XCTFail("Unexpected result: \(result)") + } + let missingCodeLength = MSALNativeAuthSignInChallengeResponse(credentialToken: credentialToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: channelType, codeLength: nil, interval: nil) + result = sut.validate(context: context, result: .success(missingCodeLength)) + if case .error(.invalidServerResponse) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenChallengeTypeOTP_validationShouldFail() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let challengeResponse = MSALNativeAuthSignInChallengeResponse(credentialToken: "something", challengeType: .otp, bindingMethod: nil, challengeTargetLabel: "some", challengeChannel: .email, codeLength: 2, interval: nil) + let result = sut.validate(context: context, result: .success(challengeResponse)) + if case .error(.invalidServerResponse) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + // MARK: initiate API tests + + func test_whenInitiateResponseIsValid_validationShouldBeSuccessful() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let credentialToken = "credentialToken" + let initiateResponse = MSALNativeAuthSignInInitiateResponse(credentialToken: credentialToken, challengeType: nil) + let result = sut.validate(context: context, result: .success(initiateResponse)) + if case .success(credentialToken: credentialToken) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenInitiateResponseIsInvalid_validationShouldFail() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let initiateResponse = MSALNativeAuthSignInInitiateResponse(credentialToken: nil, challengeType: nil) + let result = sut.validate(context: context, result: .success(initiateResponse)) + if case .error(.invalidServerResponse) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenInitiateChallengeTypeIsRedirect_validationShouldReturnRedirectError() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let initiateResponse = MSALNativeAuthSignInInitiateResponse(credentialToken: nil, challengeType: .redirect) + let result = sut.validate(context: context, result: .success(initiateResponse)) + if case .error(.redirect) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenInitiateChallengeTypeIsInvalid_validationShouldFail() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + var initiateResponse = MSALNativeAuthSignInInitiateResponse(credentialToken: nil, challengeType: .oob) + var result = sut.validate(context: context, result: .success(initiateResponse)) + if case .error(.invalidServerResponse) = result {} else { + XCTFail("Unexpected result: \(result)") + } + initiateResponse = MSALNativeAuthSignInInitiateResponse(credentialToken: nil, challengeType: .otp) + result = sut.validate(context: context, result: .success(initiateResponse)) + if case .error(.invalidServerResponse) = result {} else { + XCTFail("Unexpected result: \(result)") + } + initiateResponse = MSALNativeAuthSignInInitiateResponse(credentialToken: nil, challengeType: .password) + result = sut.validate(context: context, result: .success(initiateResponse)) + if case .error(.invalidServerResponse) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } +} diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift new file mode 100644 index 0000000000..863d7318a5 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift @@ -0,0 +1,742 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { + + private var sut: MSALNativeAuthSignUpResponseValidator! + private var context: MSIDRequestContext! + + override func setUpWithError() throws { + try super.setUpWithError() + + sut = MSALNativeAuthSignUpResponseValidator() + context = MSALNativeAuthRequestContextMock() + } + + // MARK: - Start Response + + func test_whenSignUpStartSuccessResponseContainsRedirect_it_returns_redirect() { + let response: Result = .success( + .init(signupToken: nil, challengeType: .redirect) + ) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .redirect) + } + + func test_whenSignUpStartSuccessResponseDoesNotContainsTokenOrRedirect_it_returns_unexpectedError() { + let response: Result = .success( + .init(signupToken: nil, challengeType: .otp) + ) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpStartErrorResponseIsNotExpected_it_returns_unexpectedError() { + let response: Result = .failure(NSError()) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpStart_verificationRequiredErrorWithSignUpTokenAndUnverifiedAttributes_it_returns_verificationRequired() { + let error = createSignUpStartError( + error: .verificationRequired, + signUpToken: "sign-up token", + unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes(name: "username")] + ) + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + + guard case .verificationRequired(let signUpToken, let unverifiedAttributes) = result else { + return XCTFail("Unexpected response") + } + + XCTAssertEqual(signUpToken, "sign-up token") + XCTAssertEqual(unverifiedAttributes.first, "username") + } + + func test_whenSignUpStart_verificationRequiredErrorWithSignUpToken_but_unverifiedAttributesIsEmpty_it_returns_unexpectedError() { + let error = createSignUpStartError( + error: .verificationRequired, + signUpToken: "sign-up token", + unverifiedAttributes: [] + ) + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpStart_verificationRequiredErrorWithSignUpToken_but_unverifiedAttributesIsNil_it_returns_unexpectedError() { + let error = createSignUpStartError( + error: .verificationRequired, + signUpToken: "sign-up token", + unverifiedAttributes: nil + ) + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpStart_attributeValidationFailedWithSignUpTokenAndInvalidAttributes_it_returns_attributeValidationFailed() { + let error = createSignUpStartError( + error: .attributeValidationFailed, + invalidAttributes: [MSALNativeAuthErrorBasicAttributes(name: "city")] + ) + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + + guard case .attributeValidationFailed(let invalidAttributes) = result else { + return XCTFail("Unexpected response") + } + + XCTAssertEqual(invalidAttributes.first, "city") + } + + func test_whenSignUpStart_attributeValidationFailedWithSignUpToken_but_invalidAttributesIsEmpty_it_returns_attributeValidationFailed() { + let error = createSignUpStartError( + error: .attributeValidationFailed, + invalidAttributes: [] + ) + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpStart_attributeValidationFailedWithSignUpToken_but_invalidAttributesIsNil_it_returns_attributeValidationFailed() { + let error = createSignUpStartError( + error: .verificationRequired, + invalidAttributes: nil + ) + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpStart_expectedVerificationRequiredErrorWithoutSignUpToken_it_returns_unexpectedError() { + let error = createSignUpStartError(error: .verificationRequired, signUpToken: nil) + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpStartErrorResponseIsExpected_it_returns_error() { + let error = createSignUpStartError(error: .userAlreadyExists) + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .userAlreadyExists = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenSignUpStartErrorResponseIs_invalidRequestWithInvalidUsernameErrorDescription_it_returns_expectedError() { + let attributes = [MSALNativeAuthErrorBasicAttributes(name: "attribute")] + let errorCodes = [MSALNativeAuthESTSApiErrorCodes.invalidRequestParameter.rawValue, Int.max] + + let apiError = createSignUpStartError( + error: .invalidRequest, + errorDescription: "username parameter is empty or not valid", + errorCodes: errorCodes, + errorURI: "aURI", + signUpToken: "aToken", + unverifiedAttributes: attributes, + invalidAttributes: attributes + ) + let response: Result = .failure(apiError) + + let result = sut.validate(response, with: context) + guard case .invalidUsername(let error) = result else { + return XCTFail("Unexpected response") + } + + XCTAssertEqual(error as MSALNativeAuthSignUpStartResponseError, apiError) + } + + func test_whenSignUpStartErrorResponseIs_invalidRequestWithInvalidClientIdErrorDescription_it_returns_expectedError() { + let attributes = [MSALNativeAuthErrorBasicAttributes(name: "attribute")] + let errorCodes = [MSALNativeAuthESTSApiErrorCodes.invalidRequestParameter.rawValue, Int.max] + + let apiError = createSignUpStartError( + error: .invalidRequest, + errorDescription: "client_id parameter is empty or not valid", + errorCodes: errorCodes, + errorURI: "aURI", + signUpToken: "aToken", + unverifiedAttributes: attributes, + invalidAttributes: attributes + ) + let response: Result = .failure(apiError) + + let result = sut.validate(response, with: context) + guard case .invalidClientId(let error) = result else { + return XCTFail("Unexpected response") + } + + XCTAssertEqual(error as MSALNativeAuthSignUpStartResponseError, apiError) + } + + func test_whenSignUpStartErrorResponseIs_invalidRequestWithGenericErrorCode_it_returns_expectedError() { + let attributes = [MSALNativeAuthErrorBasicAttributes(name: "attribute")] + let errorCodes = [Int.max] + + let apiError = createSignUpStartError( + error: .invalidRequest, + errorDescription: "aDescription", + errorCodes: errorCodes, + errorURI: "aURI", + signUpToken: "aToken", + unverifiedAttributes: attributes, + invalidAttributes: attributes + ) + let response: Result = .failure(apiError) + + let result = sut.validate(response, with: context) + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + + let resultError = error as MSALNativeAuthSignUpStartResponseError + XCTAssertEqual(resultError.error, .invalidRequest) + XCTAssertEqual(resultError.errorDescription, "aDescription") + XCTAssertEqual(resultError.errorCodes, errorCodes) + XCTAssertEqual(resultError.errorURI, "aURI") + XCTAssertEqual(resultError.signUpToken, "aToken") + XCTAssertEqual(resultError.unverifiedAttributes, attributes) + XCTAssertEqual(resultError.invalidAttributes, attributes) + } + + // MARK: - Challenge Response + + func test_whenSignUpChallengeSuccessResponseDoesNotContainChallengeType_it_returns_unexpectedError() { + let response: Result = .success(.init( + challengeType: nil, + bindingMethod: nil, + interval: nil, + challengeTargetLabel: "challenge-type-label", + challengeChannel: nil, + signUpToken: "token", + codeLength: nil) + ) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpChallengeSuccessResponseContainsRedirect_it_returns_redirect() { + let response: Result = .success(.init( + challengeType: .redirect, + bindingMethod: nil, + interval: nil, + challengeTargetLabel: "challenge-type-label", + challengeChannel: nil, + signUpToken: "token", + codeLength: nil) + ) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .redirect) + } + + func test_whenSignUpChallengeSuccessResponseContainsValidAttributesAndOOB_it_returns_success() { + let response: Result = .success(.init( + challengeType: .oob, + bindingMethod: nil, + interval: nil, + challengeTargetLabel: "challenge-type-label", + challengeChannel: .email, + signUpToken: "token", + codeLength: 6) + ) + + let result = sut.validate(response, with: context) + + guard case .codeRequired(let displayName, let displayType, let codeLength, let signUpToken) = result else { + return XCTFail("Unexpected response") + } + + XCTAssertEqual(displayName, "challenge-type-label") + XCTAssertEqual(displayType, .email) + XCTAssertEqual(codeLength, 6) + XCTAssertEqual(signUpToken, "token") + } + + func test_whenSignUpChallengeSuccessResponseContainsValidAttributesAndPassword_it_returns_success() { + let response: Result = .success(.init( + challengeType: .password, + bindingMethod: nil, + interval: nil, + challengeTargetLabel: "challenge-type-label", + challengeChannel: .email, + signUpToken: "token", + codeLength: nil) + ) + + let result = sut.validate(response, with: context) + + guard case .passwordRequired(let signUpToken) = result else { + return XCTFail("Unexpected response") + } + + XCTAssertEqual(signUpToken, "token") + } + + func test_whenSignUpChallengeSuccessResponseContainsPassword_but_noToken_it_returns_unexpectedError() { + let response: Result = .success(.init( + challengeType: .password, + bindingMethod: nil, + interval: nil, + challengeTargetLabel: "challenge-type-label", + challengeChannel: .email, + signUpToken: nil, + codeLength: nil) + ) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpChallengeSuccessResponseContainsValidAttributesAndOTP_it_returns_unexpectedError() { + let response: Result = .success(.init( + challengeType: .otp, + bindingMethod: nil, + interval: nil, + challengeTargetLabel: "challenge-type-label", + challengeChannel: nil, + signUpToken: "token", + codeLength: 6) + ) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpChallengeSuccessResponseOmitsSomeAttributes_it_returns_unexpectedError() { + let response: Result = .success(.init( + challengeType: .oob, + bindingMethod: nil, + interval: nil, + challengeTargetLabel: "challenge-type-label", + challengeChannel: nil, + signUpToken: nil, + codeLength: 6) + ) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpChallengeErrorResponseIsNotExpected_it_returns_unexpectedError() { + let response: Result = .failure(NSError()) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpChallengeErrorResponseIsExpected_it_returns_error() { + let error = createSignUpChallengeError(error: .expiredToken) + + let response: Result = .failure(error) + + let result = sut.validate(response, with: context) + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .expiredToken = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + // MARK: - Continue Response + + func test_whenSignUpStartSuccessResponseContainsSLT_it_returns_success() { + let response: Result = .success( + .init(signinSLT: "", expiresIn: nil, signupToken: nil) + ) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .success("")) + } + + func test_whenSignUpStartSuccessResponseButDoesNotContainSLT_it_returns_successWithNoSLT() throws { + let response: Result = .success( + .init(signinSLT: nil, expiresIn: nil, signupToken: nil) + ) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .success(nil)) + } + + func test_whenSignUpContinueErrorResponseIsNotExpected_it_returns_unexpectedError() { + let response: Result = .failure(NSError()) + + let result = sut.validate(response, with: context) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpContinueErrorResponseIs_invalidOOBValue_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .invalidOOBValue, expectedSignUpToken: "sign-up-token") + + guard case .invalidUserInput(let error) = result else { + return XCTFail("Unexpected response") + } + if case .invalidOOBValue = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenSignUpContinueErrorResponseIs_passwordTooWeak_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .passwordTooWeak, expectedSignUpToken: "sign-up-token") + + guard case .invalidUserInput(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordTooWeak = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenSignUpContinueErrorResponseIs_passwordTooShort_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .passwordTooShort, expectedSignUpToken: "sign-up-token") + + guard case .invalidUserInput(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordTooShort = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenSignUpContinueErrorResponseIs_passwordTooLong_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .passwordTooLong, expectedSignUpToken: "sign-up-token") + + guard case .invalidUserInput(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordTooLong = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenSignUpContinueErrorResponseIs_passwordRecentlyUsed_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .passwordRecentlyUsed, expectedSignUpToken: "sign-up-token") + + guard case .invalidUserInput(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordRecentlyUsed = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenSignUpContinueErrorResponseIs_passwordBanned_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .passwordBanned, expectedSignUpToken: "sign-up-token") + + guard case .invalidUserInput(let error) = result else { + return XCTFail("Unexpected response") + } + if case .passwordBanned = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .attributeValidationFailed, expectedSignUpToken: "sign-up-token", invalidAttributes: [MSALNativeAuthErrorBasicAttributes(name: "email")]) + + guard case .attributeValidationFailed(let signUpToken, let invalidAttributes) = result else { + return XCTFail("Unexpected response") + } + + XCTAssertEqual(signUpToken, "sign-up-token") + XCTAssertEqual(invalidAttributes.first, "email") + } + + func test_whenSignUpContinueErrorResponseIs_invalidRequestWithInvalidOTPErrorCode_it_returns_expectedError() { + let signUpToken = "sign-up-token" + var errorCodes = [MSALNativeAuthESTSApiErrorCodes.invalidOTP.rawValue, Int.max] + var result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedSignUpToken: signUpToken, errorCodes: errorCodes) + checkInvalidOOBValue() + errorCodes = [MSALNativeAuthESTSApiErrorCodes.incorrectOTP.rawValue] + result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedSignUpToken: signUpToken, errorCodes: errorCodes) + checkInvalidOOBValue() + errorCodes = [MSALNativeAuthESTSApiErrorCodes.OTPNoCacheEntryForUser.rawValue] + result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedSignUpToken: signUpToken, errorCodes: errorCodes) + checkInvalidOOBValue() + func checkInvalidOOBValue() { + guard case .invalidUserInput(let error) = result else { + return XCTFail("Unexpected response") + } + if case .invalidOOBValue = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + XCTAssertNil(error.errorDescription) + XCTAssertNil(error.errorURI) + XCTAssertNil(error.innerErrors) + XCTAssertEqual(error.signUpToken, signUpToken) + XCTAssertNil(error.requiredAttributes) + XCTAssertNil(error.unverifiedAttributes) + XCTAssertNil(error.invalidAttributes) + XCTAssertEqual(error.errorCodes, errorCodes) + } + } + + func test_whenSignUpContinueErrorResponseIs_invalidRequestWithGenericErrorCode_it_returns_expectedError() { + var result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedSignUpToken: "sign-up-token", errorCodes: [MSALNativeAuthESTSApiErrorCodes.strongAuthRequired.rawValue]) + checkValidatedErrorResult() + result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedSignUpToken: "sign-up-token", errorCodes: [Int.max]) + checkValidatedErrorResult() + result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedSignUpToken: "sign-up-token", errorCodes: [MSALNativeAuthESTSApiErrorCodes.userNotHaveAPassword.rawValue]) + checkValidatedErrorResult() + func checkValidatedErrorResult() { + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .invalidRequest = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + } + + + func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_but_signUpTokenIsNil_it_returns_unexpectedError() { + let result = buildContinueErrorResponse(expectedError: .attributeValidationFailed, expectedSignUpToken: nil, invalidAttributes: [MSALNativeAuthErrorBasicAttributes(name: "email")]) + + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_but_invalidAttributesIsNil_it_returns_unexpectedError() { + let result = buildContinueErrorResponse(expectedError: .attributeValidationFailed, invalidAttributes: nil) + + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_but_invalidAttributesIsEmpty_it_returns_unexpectedError() { + let result = buildContinueErrorResponse(expectedError: .attributeValidationFailed, invalidAttributes: []) + + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpContinueErrorResponseIs_credentialRequired_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .credentialRequired, expectedSignUpToken: "sign-up-token") + + guard case .credentialRequired(let signUpToken) = result else { + return XCTFail("Unexpected response") + } + + XCTAssertEqual(signUpToken, "sign-up-token") + } + + func test_whenSignUpContinueErrorResponseIs_credentialRequired_but_signUpToken_isNil_it_returns_unexpectedError() { + let result = buildContinueErrorResponse(expectedError: .credentialRequired, expectedSignUpToken: nil) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpContinueErrorResponseIs_attributesRequired_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedSignUpToken: "sign-up-token", requiredAttributes: [.init(name: "email", type: "", required: true), .init(name: "city", type: "", required: false)]) + + guard case .attributesRequired(let signUpToken, let requiredAttributes) = result else { + return XCTFail("Unexpected response") + } + + XCTAssertEqual(signUpToken, "sign-up-token") + XCTAssertEqual(requiredAttributes.count, 2) + XCTAssertEqual(requiredAttributes[0].name, "email") + XCTAssertEqual(requiredAttributes[1].name, "city") + } + + func test_whenSignUpContinueErrorResponseIs_attributesRequired_but_signUpToken_IsNil_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedSignUpToken: nil, requiredAttributes: [.init(name: "email", type: "", required: true), .init(name: "city", type: "", required: false)]) + + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpContinueErrorResponseIs_attributesRequired_but_requiredAttributesIsNil_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedSignUpToken: "sign-up-token", requiredAttributes: nil) + + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpContinueErrorResponseIs_attributesRequired_but_requiredAttributes_IsEmpty_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedSignUpToken: "sign-up-token", requiredAttributes: []) + + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpContinueErrorResponseIs_verificationRequired_it_returns_unexpectedError() { + let result = buildContinueErrorResponse(expectedError: .attributesRequired) + XCTAssertEqual(result, .unexpectedError) + } + + func test_whenSignUpContinueErrorResponseIs_unauthorizedClient_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .unauthorizedClient) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .unauthorizedClient = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenSignUpContinueErrorResponseIs_invalidGrant_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .invalidGrant) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .invalidGrant = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenSignUpContinueErrorResponseIs_expiredToken_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .expiredToken) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .expiredToken = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenSignUpContinueErrorResponseIs_invalidRequest_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .invalidRequest) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .invalidRequest = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + func test_whenSignUpContinueErrorResponseIs_userAlreadyExists_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .userAlreadyExists) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") + } + if case .userAlreadyExists = error.error {} else { + XCTFail("Unexpected error: \(error.error)") + } + } + + private func buildContinueErrorResponse( + expectedError: MSALNativeAuthSignUpContinueOauth2ErrorCode, + expectedSignUpToken: String? = nil, + requiredAttributes: [MSALNativeAuthRequiredAttributesInternal]? = nil, + invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil, + errorCodes: [Int]? = nil + ) -> MSALNativeAuthSignUpContinueValidatedResponse { + let response: Result = .failure( + createSignUpContinueError( + error: expectedError, + errorCodes: errorCodes, + signUpToken: expectedSignUpToken, + requiredAttributes: requiredAttributes, + invalidAttributes: invalidAttributes + ) + ) + + return sut.validate(response, with: context) + } + + private func createSignUpStartError( + error: MSALNativeAuthSignUpStartOauth2ErrorCode, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + signUpToken: String? = nil, + unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil, + invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil + ) -> MSALNativeAuthSignUpStartResponseError { + .init( + error: error, + errorDescription: errorDescription, + errorCodes: errorCodes, + errorURI: errorURI, + innerErrors: innerErrors, + signUpToken: signUpToken, + unverifiedAttributes: unverifiedAttributes, + invalidAttributes: invalidAttributes + ) + } + + private func createSignUpChallengeError( + error: MSALNativeAuthSignUpChallengeOauth2ErrorCode, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil + ) -> MSALNativeAuthSignUpChallengeResponseError { + .init( + error: error, + errorDescription: errorDescription, + errorCodes: errorCodes, + errorURI: errorURI, + innerErrors: innerErrors + ) + } + + private func createSignUpContinueError( + error: MSALNativeAuthSignUpContinueOauth2ErrorCode, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + signUpToken: String? = nil, + requiredAttributes: [MSALNativeAuthRequiredAttributesInternal]? = nil, + unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil, + invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil + ) -> MSALNativeAuthSignUpContinueResponseError { + .init( + error: error, + errorDescription: errorDescription, + errorCodes: errorCodes, + errorURI: errorURI, + innerErrors: innerErrors, + signUpToken: signUpToken, + requiredAttributes: requiredAttributes, + unverifiedAttributes: unverifiedAttributes, + invalidAttributes: invalidAttributes + ) + } +} diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift new file mode 100644 index 0000000000..090928c208 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift @@ -0,0 +1,256 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { + + private let baseUrl = URL(string: DEFAULT_TEST_AUTHORITY)! + private var sut: MSALNativeAuthTokenResponseValidator! + private var defaultUUID = UUID(uuidString: DEFAULT_TEST_UID)! + private var tokenResponse = MSIDTokenResponse() + private var factory: MSALNativeAuthResultFactoryMock! + private var context: MSALNativeAuthRequestContext! + + private let accountIdentifier = MSIDAccountIdentifier(displayableId: "aDisplayableId", homeAccountId: "home.account.id")! + private let configuration = MSIDConfiguration() + + + override func setUpWithError() throws { + try super.setUpWithError() + + context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + factory = MSALNativeAuthResultFactoryMock() + sut = MSALNativeAuthTokenResponseValidator(factory: factory, msidValidator: MSIDDefaultTokenResponseValidator()) + tokenResponse.accessToken = "accessToken" + tokenResponse.scope = "openid profile email" + tokenResponse.idToken = "idToken" + tokenResponse.refreshToken = "refreshToken" + } + + // MARK: token API tests + + func test_whenValidTokenResponse_validationIsSuccessful() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let userAccountResult = MSALNativeAuthUserAccountResult(account: + MSALNativeAuthUserAccountResultStub.account, + authTokens: MSALNativeAuthTokens(accessToken: nil, + refreshToken: nil, + rawIdToken: nil), + configuration: MSALNativeAuthConfigStubs.configuration, + cacheAccessor: MSALNativeAuthCacheAccessorMock()) + let refreshToken = MSIDRefreshToken() + refreshToken.familyId = "familyId" + refreshToken.refreshToken = "refreshToken" + let tokenResponse = MSIDCIAMTokenResponse() + factory.mockMakeUserAccountResult(userAccountResult) + let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .success(tokenResponse)) + if case .success(tokenResponse) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenInvalidErrorTokenResponse_anErrorIsReturned() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(MSALNativeAuthInternalError.headerNotSerialized)) + if case .error(.invalidServerResponse) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_invalidGrantTokenResponse_withSeveralUnknownErrorCodes_isProperlyHandled() { + let unknownErrorCode1 = Int.max + let unknownErrorCode2 = unknownErrorCode1 - 1 + + let errorCodes: [Int] = [unknownErrorCode1, unknownErrorCode2] + + let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, errorDescription: nil, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, credentialToken: nil) + + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) + + guard case .error(let innerError) = result else { + return XCTFail("Unexpected response") + } + + if case .generalError = innerError {} else { + XCTFail("Unexpected Error") + } + } + + func test_invalidClient_isProperlyHandled() { + let error = MSALNativeAuthTokenResponseError(error: .invalidClient, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, credentialToken: nil) + + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) + + guard case .error(let innerError) = result else { + return XCTFail("Unexpected response") + } + + if case .invalidClient(message: nil) = innerError {} else { + XCTFail("Unexpected Error") + } + } + + func test_unauthorizedClient_isProperlyHandled() { + let error = MSALNativeAuthTokenResponseError(error: .unauthorizedClient, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, credentialToken: nil) + + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) + + guard case .error(let innerError) = result else { + return XCTFail("Unexpected response") + } + + if case .invalidClient(message: nil) = innerError {} else { + XCTFail("Unexpected Error") + } + } + + + func test_invalidGrantTokenResponse_withKnownError_andSeveralUnknownErrorCodes_isProperlyHandled() { + let description = "description" + let unknownErrorCode1 = Int.max + let unknownErrorCode2 = unknownErrorCode1 - 1 + + var errorCodes: [Int] = [MSALNativeAuthESTSApiErrorCodes.userNotFound.rawValue, unknownErrorCode1, unknownErrorCode2] + guard case .userNotFound(message: description) = checkErrorCodes() else { + return XCTFail("Unexpected Error") + } + errorCodes = [MSALNativeAuthESTSApiErrorCodes.invalidOTP.rawValue, unknownErrorCode1, unknownErrorCode2] + guard case .invalidOOBCode(message: description) = checkErrorCodes() else { + return XCTFail("Unexpected Error") + } + errorCodes = [MSALNativeAuthESTSApiErrorCodes.incorrectOTP.rawValue, unknownErrorCode1, unknownErrorCode2] + guard case .invalidOOBCode(message: description) = checkErrorCodes() else { + return XCTFail("Unexpected Error") + } + errorCodes = [MSALNativeAuthESTSApiErrorCodes.OTPNoCacheEntryForUser.rawValue, unknownErrorCode1, unknownErrorCode2] + guard case .invalidOOBCode(message: description) = checkErrorCodes() else { + return XCTFail("Unexpected Error") + } + errorCodes = [MSALNativeAuthESTSApiErrorCodes.strongAuthRequired.rawValue, unknownErrorCode1, unknownErrorCode2] + guard case .strongAuthRequired(message: description) = checkErrorCodes() else { + return XCTFail("Unexpected Error") + } + errorCodes = [MSALNativeAuthESTSApiErrorCodes.strongAuthRequired.rawValue, unknownErrorCode1, unknownErrorCode2] + guard case .strongAuthRequired(message: description) = checkErrorCodes() else { + return XCTFail("Unexpected Error") + } + errorCodes = [MSALNativeAuthESTSApiErrorCodes.invalidCredentials.rawValue, unknownErrorCode1, unknownErrorCode2] + guard case .invalidPassword(message: description) = checkErrorCodes() else { + return XCTFail("Unexpected Error") + } + errorCodes = [MSALNativeAuthESTSApiErrorCodes.userNotHaveAPassword.rawValue, unknownErrorCode1, unknownErrorCode2] + guard case .generalError = checkErrorCodes() else { + return XCTFail("Unexpected Error") + } + func checkErrorCodes() -> MSALNativeAuthTokenValidatedErrorType? { + let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, credentialToken: nil) + + let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) + + guard case .error(let innerError) = result else { + return nil + } + return innerError + } + } + + func test_invalidGrantTokenResponse_withUnknownErrorCode_andKnownErrorCodes_isProperlyHandled() { + let knownErrorCode = MSALNativeAuthESTSApiErrorCodes.userNotFound.rawValue + let unknownErrorCode1 = Int.max + let unknownErrorCode2 = unknownErrorCode1 - 1 + + // We only check for the first error, if it's unknown, we return .generalError + + let errorCodes: [Int] = [unknownErrorCode1, knownErrorCode, unknownErrorCode2] + + let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, errorDescription: nil, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, credentialToken: nil) + + let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) + + guard case .error(let innerError) = result else { + return XCTFail("Unexpected response") + } + + if case .generalError = innerError {} else { + XCTFail("Unexpected Error") + } + } + + func test_invalidRequesTokenResponse_withOTPErrorCodes_isTranslatedToInvalidCode() { + let unknownErrorCode1 = Int.max + var errorCodes: [Int] = [MSALNativeAuthESTSApiErrorCodes.invalidOTP.rawValue, unknownErrorCode1] + checkErrorCodes() + errorCodes = [MSALNativeAuthESTSApiErrorCodes.incorrectOTP.rawValue, unknownErrorCode1] + checkErrorCodes() + errorCodes = [MSALNativeAuthESTSApiErrorCodes.OTPNoCacheEntryForUser.rawValue, unknownErrorCode1] + checkErrorCodes() + func checkErrorCodes() { + let description = "description" + let error = MSALNativeAuthTokenResponseError(error: .invalidRequest, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, credentialToken: nil) + + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) + + guard case .error(let innerError) = result else { + return XCTFail("Unexpected response") + } + + guard case .invalidOOBCode(message: description) = innerError else { + return XCTFail("Unexpected Error") + } + } + } + + func test_invalidRequesTokenResponse_withGenericErrorCode_isTranslatedToGeneralError() { + let description = "description" + let unknownErrorCode1 = Int.max + var errorCodes: [Int] = [unknownErrorCode1] + checkErrorCodes() + errorCodes = [MSALNativeAuthESTSApiErrorCodes.strongAuthRequired.rawValue] + checkErrorCodes() + errorCodes = [MSALNativeAuthESTSApiErrorCodes.userNotFound.rawValue] + checkErrorCodes() + func checkErrorCodes() { + let error = MSALNativeAuthTokenResponseError(error: .invalidRequest, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, credentialToken: nil) + + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) + + guard case .error(let innerError) = result else { + return XCTFail("Unexpected response") + } + + guard case .invalidRequest(message: description) = innerError else { + return XCTFail("Unexpected Error") + } + } + } +} diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift new file mode 100644 index 0000000000..61043ced6c --- /dev/null +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift @@ -0,0 +1,119 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +import XCTest +@testable import MSAL + +final class MSALNativeAuthTokenValidatedErrorTypeTests: XCTestCase { + + private typealias sut = MSALNativeAuthTokenValidatedErrorType + private let testDescription = "testDescription" + + // MARK: - convertToSignInPasswordStartError tests + + func test_convertToSignInPasswordStartError_generalError() { + let error = sut.generalError.convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, "General error") + } + + func test_convertToSignInPasswordStartError_expiredToken() { + let error = sut.expiredToken(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInPasswordStartError_expiredRefreshToken() { + let error = sut.expiredRefreshToken(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInPasswordStartError_invalidClient() { + let error = sut.invalidClient(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInPasswordStartError_invalidRequest() { + let error = sut.invalidRequest(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInPasswordStartError_invalidServerResponse() { + let error = sut.invalidServerResponse.convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, MSALNativeAuthErrorMessage.invalidServerResponse) + } + + func test_convertToSignInPasswordStartError_userNotFound() { + let error = sut.userNotFound(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .userNotFound) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInPasswordStartError_invalidPassword() { + let error = sut.invalidPassword(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .invalidPassword) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInPasswordStartError_invalidOOBCode() { + let error = sut.invalidOOBCode(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInPasswordStartError_unsupportedChallengeType() { + let error = sut.unsupportedChallengeType(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInPasswordStartError_strongAuthRequired() { + let error = sut.strongAuthRequired(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .browserRequired) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInPasswordStartError_invalidScope() { + let error = sut.invalidScope(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInPasswordStartError_authorizationPending() { + let error = sut.authorizationPending(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } + + func test_convertToSignInPasswordStartError_slowDown() { + let error = sut.slowDown(message: testDescription).convertToSignInPasswordStartError() + XCTAssertEqual(error.type, .generalError) + XCTAssertEqual(error.errorDescription, testDescription) + } +} diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift new file mode 100644 index 0000000000..08a5ca95fd --- /dev/null +++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift @@ -0,0 +1,367 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Unit_Test_Private + +final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { + + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + private var sut: MSALNativeAuthPublicClientApplication! + + override func setUp() { + super.setUp() + + sut = MSALNativeAuthPublicClientApplication( + controllerFactory: controllerFactoryMock, + inputValidator: MSALNativeAuthInputValidator(), + internalChallengeTypes: [] + ) + } + + func testInit_whenPassingB2CAuthority_itShouldThrowError() throws { + let b2cAuthority = try MSALB2CAuthority(url: .init(string: "https://login.contoso.com")!) + let configuration = MSALPublicClientApplicationConfig(clientId: DEFAULT_TEST_CLIENT_ID, redirectUri: nil, authority: b2cAuthority) + + XCTAssertThrowsError(try MSALNativeAuthPublicClientApplication(configuration: configuration, challengeTypes: [.password])) + } + + func testInit_whenPassingNilRedirectUri_itShouldNotThrowError() { + XCTAssertNoThrow(try MSALNativeAuthPublicClientApplication(clientId: "genericClient", tenantSubdomain: "genericTenenat", challengeTypes: [.OOB])) + } + + // MARK: - Delegates + + // Sign Up with password + + func testSignUpPassword_delegate_whenInvalidUsernameUsed_shouldReturnCorrectError() { + let exp = expectation(description: "sign-up public interface") + let delegate = SignUpPasswordStartDelegateSpy(expectation: exp) + sut.signUpUsingPassword(username: "", password: "", delegate: delegate) + wait(for: [exp], timeout: 1) + XCTAssertEqual(delegate.error?.type, .invalidUsername) + } + + func testSignUpPassword_delegate_whenInvalidPasswordUsed_shouldReturnCorrectError() { + let exp = expectation(description: "sign-up public interface") + let delegate = SignUpPasswordStartDelegateSpy(expectation: exp) + sut.signUpUsingPassword(username: "correct", password: "", delegate: delegate) + wait(for: [exp], timeout: 1) + XCTAssertEqual(delegate.error?.type, .invalidPassword) + } + + func testSignUpPassword_delegate_whenValidDataIsPassed_shouldReturnCodeRequired() { + let exp = expectation(description: "sign-up public interface") + let delegate = SignUpPasswordStartDelegateSpy(expectation: exp) + + let expectedResult: SignUpPasswordStartResult = .codeRequired( + newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken"), + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult) + + sut.signUpUsingPassword(username: "correct", password: "correct", delegate: delegate) + + wait(for: [exp]) + + XCTAssertEqual(delegate.newState?.flowToken, "flowToken") + XCTAssertEqual(delegate.sentTo, "sentTo") + XCTAssertEqual(delegate.channelTargetType, .email) + XCTAssertEqual(delegate.codeLength, 1) + } + + func testSignUpPassword_delegate_whenSendAttributes_shouldReturnAttributesInvalid() { + let exp = expectation(description: "sign-up public interface") + let delegate = SignUpPasswordStartDelegateSpy(expectation: exp) + let expectedInvalidAttributes = ["attribute"] + + let expectedResult: SignUpPasswordStartResult = .attributesInvalid(expectedInvalidAttributes) + controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult) + + sut.signUpUsingPassword(username: "correct", password: "correct", delegate: delegate) + + wait(for: [exp]) + + XCTAssertEqual(delegate.attributeNames, expectedInvalidAttributes) + } + + func testSignUpPassword_delegate_whenSendAttributes_butDelegateMethodIsNotImplemented_itShouldReturnAttributesInvalid() { + let exp = expectation(description: "sign-up public interface") + let delegate = SignUpPasswordStartDelegateOptionalMethodsNotImplemented(expectation: exp) + let expectedInvalidAttributes = ["attribute"] + + let expectedResult: SignUpPasswordStartResult = .attributesInvalid(expectedInvalidAttributes) + controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult) + + sut.signUpUsingPassword(username: "correct", password: "correct", delegate: delegate) + + wait(for: [exp]) + + XCTAssertEqual(delegate.error?.type, .generalError) + XCTAssertEqual(delegate.error?.errorDescription, MSALNativeAuthErrorMessage.codeRequiredNotImplemented) + } + + // Sign Up with code + + func testSignUp_delegate_whenInvalidUsernameUsed_shouldReturnCorrectError() { + let exp = expectation(description: "sign-up public interface") + let delegate = SignUpCodeStartDelegateSpy(expectation: exp) + sut.signUp(username: "", delegate: delegate) + wait(for: [exp], timeout: 1) + XCTAssertEqual(delegate.error?.type, .invalidUsername) + } + + func testSignUp_delegate_whenValidDataIsPassed_shouldReturnCodeRequired() { + let exp = expectation(description: "sign-up public interface") + let delegate = SignUpCodeStartDelegateSpy(expectation: exp) + + let expectedResult: SignUpStartResult = .codeRequired( + newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken"), + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + controllerFactoryMock.signUpController.startResult = .init(expectedResult) + + sut.signUp(username: "correct", delegate: delegate) + + wait(for: [exp]) + + XCTAssertEqual(delegate.newState?.flowToken, "flowToken") + XCTAssertEqual(delegate.sentTo, "sentTo") + XCTAssertEqual(delegate.channelTargetType, .email) + XCTAssertEqual(delegate.codeLength, 1) + } + + func testSignUp_delegate_whenSendAttributes_shouldReturnAttributesInvalid() { + let exp = expectation(description: "sign-up public interface") + let delegate = SignUpCodeStartDelegateSpy(expectation: exp) + let expectedInvalidAttributes = ["attribute"] + + let expectedResult: SignUpStartResult = .attributesInvalid(expectedInvalidAttributes) + controllerFactoryMock.signUpController.startResult = .init(expectedResult) + + sut.signUp(username: "correct", delegate: delegate) + + wait(for: [exp]) + + XCTAssertEqual(delegate.attributeNames, expectedInvalidAttributes) + } + + func testSignUp_delegate_whenSendAttributes_butDelegateMethodIsNotImplemented_itShouldReturnAttributesInvalid() { + let exp = expectation(description: "sign-up public interface") + let delegate = SignUpStartDelegateOptionalMethodsNotImplemented(expectation: exp) + let expectedInvalidAttributes = ["attribute"] + + let expectedResult: SignUpStartResult = .attributesInvalid(expectedInvalidAttributes) + controllerFactoryMock.signUpController.startResult = .init(expectedResult) + + sut.signUp(username: "correct", delegate: delegate) + + wait(for: [exp]) + + XCTAssertEqual(delegate.error?.type, .generalError) + XCTAssertEqual(delegate.error?.errorDescription, MSALNativeAuthErrorMessage.codeRequiredNotImplemented) + } + + // Sign in with password + + func testSignInPassword_delegate_whenInvalidUsernameUsed_shouldReturnCorrectError() { + let expectation = expectation(description: "sign-in public interface") + let delegate = SignInPasswordStartDelegateSpy(expectation: expectation, expectedError: .init(type: .invalidUsername)) + sut.signInUsingPassword(username: "", password: "", delegate: delegate) + wait(for: [expectation], timeout: 1) + } + + func testSignInPassword_delegate_whenInvalidPasswordUsed_shouldReturnCorrectError() { + let expectation = expectation(description: "sign-in public interface") + let delegate = SignInPasswordStartDelegateSpy(expectation: expectation, expectedError: .init(type: .invalidPassword)) + sut.signInUsingPassword(username: "correct", password: "", delegate: delegate) + wait(for: [expectation], timeout: 1) + } + + func testSignInPassword_delegate_whenValidUserAndPasswordAreUsed_shouldReturnSuccess() { + let expectation = expectation(description: "sign-in public interface") + let delegate = SignInPasswordStartDelegateSpy(expectation: expectation, expectedUserAccountResult: MSALNativeAuthUserAccountResultStub.result) + + controllerFactoryMock.signInController.signInPasswordStartResult = .init(.init(.completed(MSALNativeAuthUserAccountResultStub.result))) + sut.signInUsingPassword(username: "correct", password: "correct", delegate: delegate) + + wait(for: [expectation], timeout: 1) + } + + func testSignInPassword_delegate_whenCodeIsRequiredAndUserHasImplementedOptionalDelegate_shouldReturnCodeRequired() { + let exp1 = expectation(description: "sign-in public interface") + let exp2 = expectation(description: "expectation Telemetry") + + let delegate = SignInPasswordStartDelegateSpy(expectation: exp1) + delegate.expectedSentTo = "sentTo" + delegate.expectedCodeLength = 1 + delegate.expectedChannelTargetType = .email + + let expectedResult: SignInPasswordStartResult = .codeRequired( + newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: ""), + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + + controllerFactoryMock.signInController.signInPasswordStartResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + sut.signInUsingPassword(username: "correct", password: "correct", delegate: delegate) + + wait(for: [exp1, exp2], timeout: 1) + } + + func testSignInPassword_delegate_whenCodeIsRequiredButUserHasNotImplementedOptionalDelegate_shouldReturnError() { + let exp = expectation(description: "sign-in public interface") + let exp2 = expectation(description: "expectation Telemetry") + + let expectedError = SignInPasswordStartError(type: .generalError, message: MSALNativeAuthErrorMessage.codeRequiredNotImplemented) + let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: exp, expectedError: expectedError) + + let expectedResult: SignInPasswordStartResult = .codeRequired( + newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: ""), + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + + controllerFactoryMock.signInController.signInPasswordStartResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + sut.signInUsingPassword(username: "correct", password: "correct", delegate: delegate) + + wait(for: [exp, exp2], timeout: 1) + } + + // Sign in with code + + func testSignIn_delegate_whenInvalidUser_shouldReturnCorrectError() { + let expectation = expectation(description: "sign-in public interface") + let delegate = SignInCodeStartDelegateSpy(expectation: expectation, expectedError: .init(type: .invalidUsername)) + sut.signIn(username: "", delegate: delegate) + wait(for: [expectation], timeout: 1) + } + + func testSignIn_delegate_whenValidUserIsUsed_shouldReturnCodeRequired() { + let expectation = expectation(description: "sign-in public interface") + let delegate = SignInCodeStartDelegateSpy(expectation: expectation) + delegate.expectedSentTo = "sentTo" + delegate.expectedCodeLength = 1 + delegate.expectedChannelTargetType = .email + + let expectedResult: SignInStartResult = .codeRequired( + newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: ""), + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + + controllerFactoryMock.signInController.signInStartResult = .init(expectedResult) + sut.signIn(username: "correct", delegate: delegate) + + wait(for: [expectation], timeout: 1) + } + + func testSignIn_delegate_whenPasswordIsRequiredAndUserHasImplementedOptionalDelegate_shouldReturnPasswordRequired() { + let exp1 = expectation(description: "sign-in public interface") + let exp2 = expectation(description: "expectation Telemetry") + + let delegate = SignInCodeStartDelegateWithPasswordRequiredSpy(expectation: exp1) + + let expectedState = SignInPasswordRequiredState(scopes: [], username: "", controller: controllerFactoryMock.signInController, flowToken: "flowToken") + let expectedResult: SignInStartResult = .passwordRequired(newState: expectedState) + + controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + sut.signIn(username: "correct", delegate: delegate) + + wait(for: [exp1, exp2], timeout: 1) + + XCTAssertEqual(delegate.passwordRequiredState?.flowToken, expectedState.flowToken) + } + + func testSignIn_delegate_whenPasswordIsRequiredButUserHasNotImplementedOptionalDelegate_shouldReturnError() { + let exp = expectation(description: "sign-in public interface") + let exp2 = expectation(description: "expectation Telemetry") + + let expectedError = SignInStartError(type: .generalError, message: MSALNativeAuthErrorMessage.passwordRequiredNotImplemented) + let delegate = SignInCodeStartDelegateSpy(expectation: exp, expectedError: expectedError) + + let expectedResult: SignInStartResult = .passwordRequired( + newState: SignInPasswordRequiredState(scopes: [], username: "", controller: controllerFactoryMock.signInController, flowToken: "") + ) + + controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + sut.signIn(username: "correct", delegate: delegate) + + wait(for: [exp, exp2], timeout: 1) + } + + // ResetPassword + + func testResetPassword_delegate_whenInvalidUser_shouldReturnCorrectError() { + let exp = expectation(description: "sign-in public interface") + let delegate = ResetPasswordStartDelegateSpy(expectation: exp) + sut.resetPassword(username: "", delegate: delegate) + wait(for: [exp]) + XCTAssertEqual(delegate.error?.type, .invalidUsername) + } + + func testResetPassword_delegate_whenValidUserIsUsed_shouldReturnCodeRequired() { + let expectation = expectation(description: "sign-in public interface") + let delegate = ResetPasswordStartDelegateSpy(expectation: expectation) + + let expectedResult: ResetPasswordStartResult = .codeRequired( + newState: .init(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken"), + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + + controllerFactoryMock.resetPasswordController.resetPasswordResult = .init(expectedResult) + sut.resetPassword(username: "correct", delegate: delegate) + + wait(for: [expectation], timeout: 1) + + XCTAssertEqual(delegate.newState?.flowToken, "flowToken") + XCTAssertEqual(delegate.sentTo, "sentTo") + XCTAssertEqual(delegate.channelTargetType, .email) + XCTAssertEqual(delegate.codeLength, 1) + } +} diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthUserAccountResultTests.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthUserAccountResultTests.swift new file mode 100644 index 0000000000..d0382a0db4 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthUserAccountResultTests.swift @@ -0,0 +1,85 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthUserAccountResultTests: XCTestCase { + var sut: MSALNativeAuthUserAccountResult! + private var cacheAccessorMock: MSALNativeAuthCacheAccessorMock! + private var account: MSALAccount! + + override func setUpWithError() throws { + + account = MSALNativeAuthUserAccountResultStub.account + let accessToken = MSIDAccessToken() + accessToken.accessToken = "accessToken" + let refreshToken = MSIDRefreshToken() + refreshToken.refreshToken = "refreshToken" + let rawIdToken = "rawIdToken" + + cacheAccessorMock = MSALNativeAuthCacheAccessorMock() + + sut = MSALNativeAuthUserAccountResult( + account: account!, + authTokens: MSALNativeAuthTokens(accessToken: accessToken, refreshToken: refreshToken, rawIdToken: rawIdToken), + configuration: MSALNativeAuthConfigStubs.configuration, + cacheAccessor: cacheAccessorMock + ) + try super.setUpWithError() + } + + // MARK: Call delegate properly tests + + func test_whenAccountAndTokenExist_itReturnsCorrectData() { + let expectation = expectation(description: "CredentialsController") + + let mockDelegate = CredentialsDelegateSpy(expectation: expectation, expectedAccessToken: "accessToken") + sut.getAccessToken(delegate: mockDelegate) + wait(for: [expectation], timeout: 1) + } + + func test_whenNoAccessToken_itReturnsCorrectError() { + let expectation = expectation(description: "CredentialsController") + sut = MSALNativeAuthUserAccountResult( + account: account!, + authTokens: MSALNativeAuthTokens(accessToken: nil, refreshToken: nil, rawIdToken: nil), + configuration: MSALNativeAuthConfigStubs.configuration, + cacheAccessor: MSALNativeAuthCacheAccessorMock() + ) + let mockDelegate = CredentialsDelegateSpy(expectation: expectation, expectedError: RetrieveAccessTokenError(type: .tokenNotFound)) + sut.getAccessToken(delegate: mockDelegate) + wait(for: [expectation], timeout: 1) + } + + // MARK: - sign-out tests + + func test_signOut_successfullyCallsCacheAccessor() { + sut.signOut() + XCTAssertTrue(cacheAccessorMock.clearCacheWasCalled) + } +} diff --git a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift new file mode 100644 index 0000000000..060794a567 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift @@ -0,0 +1,118 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class ResetPasswordCodeRequiredStateTests: XCTestCase { + + private var controller: MSALNativeAuthResetPasswordControllerMock! + private var sut: ResetPasswordCodeRequiredState! + + override func setUpWithError() throws { + try super.setUpWithError() + + controller = .init() + sut = ResetPasswordCodeRequiredState(controller: controller, flowToken: "") + } + + // MARK: - Delegates + + // ResendCode + + func test_resendCode_delegate_whenError_shouldReturnCorrectError() { + let expectedError = ResendCodeError(message: "test error") + let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken") + + let expectedResult: ResetPasswordResendCodeResult = .error(error: expectedError, newState: expectedState) + controller.resendCodeResult = .init(expectedResult) + + let exp = expectation(description: "reset password states") + let delegate = ResetPasswordResendCodeDelegateSpy(expectation: exp) + + sut.resendCode(delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.error, expectedError) + XCTAssertEqual(delegate.newState, expectedState) + } + + func test_resendCode_delegate_success_shouldReturnCodeRequired() { + let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken 2") + + let expectedResult: ResetPasswordResendCodeResult = .codeRequired( + newState: expectedState, + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + controller.resendCodeResult = .init(expectedResult) + + let exp = expectation(description: "sign-in states") + let delegate = ResetPasswordResendCodeDelegateSpy(expectation: exp) + + sut.resendCode(delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.newState?.flowToken, expectedState.flowToken) + XCTAssertEqual(delegate.sentTo, "sentTo") + XCTAssertEqual(delegate.channelTargetType, .email) + XCTAssertEqual(delegate.codeLength, 1) + } + + // SubmitCode + + func test_submitCode_delegate_whenError_shouldReturnCorrectError() { + let expectedError = VerifyCodeError(type: .invalidCode) + let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken") + + let expectedResult: ResetPasswordVerifyCodeResult = .error(error: expectedError, newState: expectedState) + controller.submitCodeResult = .init(expectedResult) + + let exp = expectation(description: "reset password states") + let delegate = ResetPasswordVerifyCodeDelegateSpy(expectation: exp) + + sut.submitCode(code: "1234", delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.error, expectedError) + XCTAssertEqual(delegate.newCodeRequiredState, expectedState) + } + + func test_submitCode_delegate_success_shouldReturnPasswordRequired() { + let expectedState = ResetPasswordRequiredState(controller: controller, flowToken: "flowToken 2") + + let expectedResult: ResetPasswordVerifyCodeResult = .passwordRequired(newState: expectedState) + controller.submitCodeResult = .init(expectedResult) + + let exp = expectation(description: "sign-in states") + let delegate = ResetPasswordVerifyCodeDelegateSpy(expectation: exp) + + sut.submitCode(code: "1234", delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.newPasswordRequiredState, expectedState) + } +} diff --git a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift new file mode 100644 index 0000000000..30c832d56f --- /dev/null +++ b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift @@ -0,0 +1,56 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +import XCTest +@testable import MSAL + +final class ResetPasswordRequiredStateTests: XCTestCase { + + private var correlationId: UUID! + private var exp: XCTestExpectation! + private var controller: MSALNativeAuthResetPasswordControllerSpy! + private var sut: ResetPasswordRequiredState! + + override func setUpWithError() throws { + try super.setUpWithError() + + correlationId = UUID() + exp = expectation(description: "ResetPasswordRequiredState expectation") + controller = MSALNativeAuthResetPasswordControllerSpy(expectation: exp) + sut = ResetPasswordRequiredState(controller: controller, flowToken: "") + } + + func test_submitPassword_usesControllerSuccessfully() { + XCTAssertNil(controller.context) + XCTAssertFalse(controller.submitPasswordCalled) + + sut.submitPassword(password: "1234", correlationId: correlationId, delegate: ResetPasswordRequiredDelegateSpy()) + + wait(for: [exp], timeout: 1) + XCTAssertEqual(controller.context?.correlationId(), correlationId) + XCTAssertTrue(controller.submitPasswordCalled) + } +} diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift new file mode 100644 index 0000000000..3784cbd876 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift @@ -0,0 +1,115 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class SignInCodeRequiredStateTests: XCTestCase { + + private var sut: SignInCodeRequiredState! + private var controller: MSALNativeAuthSignInControllerMock! + + override func setUp() { + super.setUp() + + controller = .init() + sut = .init(scopes: [], controller: controller, flowToken: "flowToken") + } + + // MARK: - Delegates + + // ResendCode + + func test_resendCode_delegate_withError_shouldReturnSignInResendCodeError() { + let expectedError = ResendCodeError(message: "test error") + let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2") + + let expectedResult: SignInResendCodeResult = .error( + error: expectedError, + newState: expectedState + ) + controller.resendCodeResult = .init(expectedResult) + + let exp = expectation(description: "sign-in states") + let delegate = SignInResendCodeDelegateSpy(expectation: exp) + + sut.resendCode(delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.newSignInResendCodeError, expectedError) + XCTAssertEqual(delegate.newSignInCodeRequiredState?.flowToken, expectedState.flowToken) + } + + func test_resendCode_delegate_success_shouldReturnSignInResendCodeCodeRequired() { + let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2") + + let expectedResult: SignInResendCodeResult = .codeRequired( + newState: expectedState, + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + controller.resendCodeResult = .init(expectedResult) + + let exp = expectation(description: "sign-in states") + let delegate = SignInResendCodeDelegateSpy(expectation: exp, expectedSentTo: "sentTo", expectedChannelTargetType: .email, expectedCodeLength: 1) + + sut.resendCode(delegate: delegate) + wait(for: [exp]) + XCTAssertEqual(delegate.newSignInCodeRequiredState?.flowToken, expectedState.flowToken) + } + + // SubmitCode + + func test_submitCode_delegate_withError_shouldReturnSignInVerifyCodeError() { + let expectedError = VerifyCodeError(type: .invalidCode) + let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2") + + let expectedResult: SignInVerifyCodeResult = .error( + error: expectedError, + newState: expectedState + ) + controller.submitCodeResult = .init(expectedResult) + + let exp = expectation(description: "sign-in states") + let delegate = SignInVerifyCodeDelegateSpy(expectation: exp, expectedError: expectedError) + delegate.expectedNewState = expectedState + + sut.submitCode(code: "1234", delegate: delegate) + wait(for: [exp]) + } + + func test_submitCode_delegate_success_shouldReturnAccountResult() { + let expectedAccountResult = MSALNativeAuthUserAccountResultStub.result + + let expectedResult: SignInVerifyCodeResult = .completed(expectedAccountResult) + controller.submitCodeResult = .init(expectedResult) + + let exp = expectation(description: "sign-in states") + let delegate = SignInVerifyCodeDelegateSpy(expectation: exp, expectedUserAccountResult: expectedAccountResult) + + sut.submitCode(code: "1234", delegate: delegate) + wait(for: [exp]) + } +} diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift new file mode 100644 index 0000000000..7949fe4775 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift @@ -0,0 +1,73 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class SignInPasswordRequiredStateTests: XCTestCase { + + private var sut: SignInPasswordRequiredState! + private var controller: MSALNativeAuthSignInControllerMock! + + override func setUp() { + super.setUp() + + controller = .init() + sut = .init(scopes: [], username: "username", controller: controller, flowToken: "flowToken") + } + + // MARK: - Delegates + + func test_submitPassword_delegate_withError_shouldReturnError() { + let expectedError = PasswordRequiredError(type: .invalidPassword) + let expectedState = SignInPasswordRequiredState(scopes: [], username: "", controller: controller, flowToken: "flowToken 2") + + let expectedResult: SignInPasswordRequiredResult = .error( + error: expectedError, + newState: expectedState + ) + controller.submitPasswordResult = .init(expectedResult) + + let exp = expectation(description: "sign-in states") + let delegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: expectedError) + + sut.submitPassword(password: "invalid password", delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.newPasswordRequiredState?.flowToken, expectedState.flowToken) + } + + func test_submitPassword_delegate_success_shouldReturnSuccess() { + let expectedAccountResult = MSALNativeAuthUserAccountResultStub.result + + let expectedResult: SignInPasswordRequiredResult = .completed(expectedAccountResult) + controller.submitPasswordResult = .init(expectedResult) + + let exp = expectation(description: "sign-in states") + let delegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedUserAccountResult: expectedAccountResult) + + sut.submitPassword(password: "invalid password", delegate: delegate) + wait(for: [exp]) + } +} diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift new file mode 100644 index 0000000000..ad1e5e7aec --- /dev/null +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift @@ -0,0 +1,109 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +import XCTest +@testable import MSAL + +final class SignUpAttributesRequiredStateTests: XCTestCase { + + private var controller: MSALNativeAuthSignUpControllerMock! + private var sut: SignUpAttributesRequiredState! + + override func setUpWithError() throws { + try super.setUpWithError() + + controller = .init() + sut = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "") + } + + // MARK: - Delegate + + func test_submitPassword_delegate_whenError_shouldReturnAttributesRequiredError() { + let expectedError = AttributesRequiredError() + + let expectedResult: SignUpAttributesRequiredResult = .error(error: expectedError) + controller.submitAttributesResult = .init(expectedResult) + + let exp = expectation(description: "sign-up states") + let delegate = SignUpAttributesRequiredDelegateSpy(expectation: exp) + + sut.submitAttributes(attributes: ["key":"value"], delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.error, expectedError) + } + + func test_submitPassword_delegate_whenSuccess_shouldReturnCompleted() { + let expectedState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt") + + let expectedResult: SignUpAttributesRequiredResult = .completed(expectedState) + controller.submitAttributesResult = .init(expectedResult) + + let exp = expectation(description: "sign-up states") + let delegate = SignUpAttributesRequiredDelegateSpy(expectation: exp) + + sut.submitAttributes(attributes: ["key":"value"], delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.newSignInAfterSignUpState, expectedState) + } + + func test_submitPassword_delegate_whenAttributesRequired_shouldReturnAttributesRequired() { + let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", flowToken: "slt") + let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + .init(name: "anAttribute", type: "aType", required: true) + ] + + let expectedResult: SignUpAttributesRequiredResult = .attributesRequired(attributes: expectedAttributes, state: expectedState) + controller.submitAttributesResult = .init(expectedResult) + + let exp = expectation(description: "sign-up states") + let delegate = SignUpAttributesRequiredDelegateSpy(expectation: exp) + + sut.submitAttributes(attributes: ["key":"value"], delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.attributes, expectedAttributes) + XCTAssertEqual(delegate.newState, expectedState) + } + + func test_submitPassword_delegate_whenAttributesAreInvalud_shouldReturnAttributesInvalid() { + let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", flowToken: "slt") + let expectedAttributes = ["anAttribute"] + + let expectedResult: SignUpAttributesRequiredResult = .attributesInvalid(attributes: expectedAttributes, newState: expectedState) + controller.submitAttributesResult = .init(expectedResult) + + let exp = expectation(description: "sign-up states") + let delegate = SignUpAttributesRequiredDelegateSpy(expectation: exp) + + sut.submitAttributes(attributes: ["key":"value"], delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.invalidAttributes, expectedAttributes) + XCTAssertEqual(delegate.newState, expectedState) + } +} diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift new file mode 100644 index 0000000000..ae79ba1826 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift @@ -0,0 +1,197 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class SignUpCodeRequiredStateTests: XCTestCase { + + private var controller: MSALNativeAuthSignUpControllerMock! + private var sut: SignUpCodeRequiredState! + + override func setUpWithError() throws { + try super.setUpWithError() + + controller = .init() + sut = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "") + } + + // MARK: - Delegates + + // ResendCode + + func test_resendCode_delegate_whenError_shouldReturnCorrectError() { + let expectedError = ResendCodeError(message: "test error") + + let expectedResult: SignUpResendCodeResult = .error(expectedError) + controller.resendCodeResult = .init(expectedResult) + + let exp = expectation(description: "sign-up states") + let delegate = SignUpResendCodeDelegateSpy(expectation: exp) + + sut.resendCode(delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.error, expectedError) + } + + func test_resendCode_delegate_success_shouldReturnCodeRequired() { + let expectedState = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2") + + let expectedResult: SignUpResendCodeResult = .codeRequired( + newState: expectedState, + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + controller.resendCodeResult = .init(expectedResult) + + let exp = expectation(description: "sign-in states") + let delegate = SignUpResendCodeDelegateSpy(expectation: exp) + + sut.resendCode(delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.newState?.flowToken, expectedState.flowToken) + XCTAssertEqual(delegate.sentTo, "sentTo") + XCTAssertEqual(delegate.channelTargetType, .email) + XCTAssertEqual(delegate.codeLength, 1) + } + + // SubmitCode + + func test_submitCode_delegate_whenError_shouldReturnCorrectError() { + let expectedError = VerifyCodeError(type: .invalidCode) + let expectedState = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2") + + let expectedResult: SignUpVerifyCodeResult = .error( + error: expectedError, + newState: expectedState + ) + controller.submitCodeResult = .init(expectedResult) + + let exp = expectation(description: "sign-up states") + let delegate = SignUpVerifyCodeDelegateSpy(expectation: exp) + + sut.submitCode(code: "1234", delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.error, expectedError) + XCTAssertEqual(delegate.newCodeRequiredState?.flowToken, expectedState.flowToken) + } + + func test_submitCode_delegate_whenPasswordRequired_AndUserHasImplementedOptionalDelegate_shouldReturnPasswordRequired() { + let expectedPasswordRequiredState = SignUpPasswordRequiredState(controller: controller, username: "", flowToken: "flowToken 2") + + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "exp telemetry is called") + + let expectedResult: SignUpVerifyCodeResult = .passwordRequired(expectedPasswordRequiredState) + controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignUpVerifyCodeDelegateSpy(expectation: exp) + + sut.submitCode(code: "1234", delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.newPasswordRequiredState, expectedPasswordRequiredState) + } + + func test_submitCode_delegate_whenPasswordRequired_ButUserHasNotImplementedOptionalDelegate_shouldReturnCorrectError() { + let expectedError = VerifyCodeError(type: .generalError, message: MSALNativeAuthErrorMessage.delegateNotImplemented) + + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "exp telemetry is called") + + let expectedResult: SignUpVerifyCodeResult = .passwordRequired(.init(controller: controller, username: "", flowToken: "")) + controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignUpVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: exp) + + sut.submitCode(code: "1234", delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.type, expectedError.type) + XCTAssertEqual(delegate.error?.errorDescription, MSALNativeAuthErrorMessage.delegateNotImplemented) + } + + func test_submitCode_delegate_whenAttributesRequired_AndUserHasImplementedOptionalDelegate_shouldReturnAttributesRequired() { + let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "flowToken 2") + + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "exp telemetry is called") + + let expectedResult: SignUpVerifyCodeResult = .attributesRequired(attributes: [], newState: expectedAttributesRequiredState) + controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignUpVerifyCodeDelegateSpy(expectation: exp) + + sut.submitCode(code: "1234", delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.newAttributesRequiredState, expectedAttributesRequiredState) + } + + func test_submitCode_delegate_whenAttributesRequired_ButUserHasNotImplementedOptionalDelegate_shouldReturnCorrectError() { + let expectedError = VerifyCodeError(type: .generalError, message: MSALNativeAuthErrorMessage.delegateNotImplemented) + + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "exp telemetry is called") + + let expectedResult: SignUpVerifyCodeResult = .attributesRequired(attributes: [], newState: .init(controller: controller, username: "", flowToken: "")) //.attributesRequired(.init(controller: controller, flowToken: "")) + controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignUpVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: exp) + + sut.submitCode(code: "1234", delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.type, expectedError.type) + XCTAssertEqual(delegate.error?.errorDescription, MSALNativeAuthErrorMessage.delegateNotImplemented) + } + + func test_submitCode_delegate_whenSuccess_shouldReturnAccountResult() { + let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt") + + let expectedResult: SignUpVerifyCodeResult = .completed(expectedSignInAfterSignUpState) + controller.submitCodeResult = .init(expectedResult) + + let exp = expectation(description: "sign-up states") + let delegate = SignUpVerifyCodeDelegateSpy(expectation: exp) + + sut.submitCode(code: "1234", delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.newSignInAfterSignUpState, expectedSignInAfterSignUpState) + } +} diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift new file mode 100644 index 0000000000..1ff53b8273 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift @@ -0,0 +1,116 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +import XCTest +@testable import MSAL + +final class SignUpPasswordRequiredStateTests: XCTestCase { + + private var controller: MSALNativeAuthSignUpControllerMock! + private var sut: SignUpPasswordRequiredState! + + override func setUpWithError() throws { + try super.setUpWithError() + + controller = .init() + sut = SignUpPasswordRequiredState(controller: controller, username: "", flowToken: "") + } + + // MARK: - Delegate + + func test_submitPassword_delegate_whenError_shouldReturnPasswordRequiredError() { + let expectedError = PasswordRequiredError(type: .invalidPassword) + let expectedState = SignUpPasswordRequiredState(controller: controller, username: "", flowToken: "flowToken 2") + + let expectedResult: SignUpPasswordRequiredResult = .error(error: expectedError, newState: expectedState) + controller.submitPasswordResult = .init(expectedResult) + + let exp = expectation(description: "sign-up states") + let delegate = SignUpPasswordRequiredDelegateSpy(expectation: exp) + + sut.submitPassword(password: "1234", delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.error, expectedError) + XCTAssertEqual(delegate.newPasswordRequiredState?.flowToken, expectedState.flowToken) + } + + func test_submitCode_delegate_whenAttributesRequired_AndUserHasImplementedOptionalDelegate_shouldReturnAttributesRequired() { + let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "flowToken 2") + + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "exp telemetry is called") + + let expectedResult: SignUpPasswordRequiredResult = .attributesRequired(attributes: [], newState: expectedAttributesRequiredState) + controller.submitPasswordResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignUpPasswordRequiredDelegateSpy(expectation: exp) + + sut.submitPassword(password: "1234", delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.newAttributesRequiredState, expectedAttributesRequiredState) + } + + func test_submitCode_delegate_whenAttributesRequired_ButUserHasNotImplementedOptionalDelegate_shouldReturnPasswordRequiredError() { + let expectedError = PasswordRequiredError(type: .generalError, message: MSALNativeAuthErrorMessage.delegateNotImplemented) + let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "flowToken 2") + + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "exp telemetry is called") + + let expectedResult: SignUpPasswordRequiredResult = .attributesRequired(attributes: [], newState: expectedAttributesRequiredState) + controller.submitPasswordResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignUpPasswordRequiredDelegateOptionalMethodsNotImplemented(expectation: exp) + + sut.submitPassword(password: "1234", delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.type, expectedError.type) + XCTAssertEqual(delegate.error?.errorDescription, MSALNativeAuthErrorMessage.delegateNotImplemented) + } + + func test_submitCode_delegate_whenSuccess_shouldReturnSignUpCompleted() { + let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt") + + let exp = expectation(description: "sign-up states") + + let expectedResult: SignUpPasswordRequiredResult = .completed(expectedSignInAfterSignUpState) + controller.submitPasswordResult = .init(expectedResult) + + let delegate = SignUpPasswordRequiredDelegateSpy(expectation: exp) + + sut.submitPassword(password: "1234", delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.signInAfterSignUpState, expectedSignInAfterSignUpState) + } +} diff --git a/MSAL/test/unit/native_auth/telemetry/MSALNativeAuthCurrentRequestTelemetryTests.swift b/MSAL/test/unit/native_auth/telemetry/MSALNativeAuthCurrentRequestTelemetryTests.swift new file mode 100644 index 0000000000..cd6d791571 --- /dev/null +++ b/MSAL/test/unit/native_auth/telemetry/MSALNativeAuthCurrentRequestTelemetryTests.swift @@ -0,0 +1,62 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthCurrentRequestTelemetryTests: XCTestCase { + + func testSerialization_whenValidProperties_shouldCreateString() { + let telemetry = MSALNativeAuthCurrentRequestTelemetry(apiId: .telemetryApiIdSignUp, + operationType: MSALNativeAuthSignUpType.signUpWithPassword.rawValue, + platformFields: nil) + let result = telemetry.telemetryString() + XCTAssertEqual(result, "4|75001,0|") + } + + func testSerialization_whenSignUpType_SignUpOTP_shouldCreateString() { + let telemetry = MSALNativeAuthCurrentRequestTelemetry(apiId: .telemetryApiIdSignUp, + operationType: MSALNativeAuthSignUpType.signUpWithOTP.rawValue, + platformFields: nil) + let result = telemetry.telemetryString() + XCTAssertEqual(result, "4|75001,1|") + } + + func testSerialization_withOnePlatfomField_shouldCreateString() { + let telemetry = MSALNativeAuthCurrentRequestTelemetry(apiId: .telemetryApiIdSignUp, + operationType: MSALNativeAuthSignUpType.signUpWithPassword.rawValue, + platformFields: ["iPhone14,5"]) + let result = telemetry.telemetryString() + XCTAssertEqual(result, "4|75001,0|iPhone14,5") + } + + func testSerialization_withMultiplePlatfomField_shouldCreateString() { + let telemetry = MSALNativeAuthCurrentRequestTelemetry(apiId: .telemetryApiIdSignUp, + operationType: MSALNativeAuthSignUpType.signUpWithPassword.rawValue, + platformFields: ["iPhone14,5","iOS 16.0"]) + let result = telemetry.telemetryString() + XCTAssertEqual(result, "4|75001,0|iPhone14,5,iOS 16.0") + } +} diff --git a/MSAL/test/unit/native_auth/telemetry/MSALNativeAuthTelemetryProviderTests.swift b/MSAL/test/unit/native_auth/telemetry/MSALNativeAuthTelemetryProviderTests.swift new file mode 100644 index 0000000000..e32b0814e7 --- /dev/null +++ b/MSAL/test/unit/native_auth/telemetry/MSALNativeAuthTelemetryProviderTests.swift @@ -0,0 +1,83 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthTelemetryProviderTests: XCTestCase { + + private var sut : MSALNativeAuthTelemetryProviding! + + override func setUpWithError() throws { + sut = MSALNativeAuthTelemetryProvider() + } + + // MARK: Correct API Id tests + func testTelemetryForSignUp_returnsCorrectApiId() { + let result = sut.telemetryForSignUp(type: MSALNativeAuthSignUpType.signUpWithPassword) + XCTAssertEqual(result.apiId, .telemetryApiIdSignUpCodeStart) + } + + func testTelemetryForSignInWithCode_returnsCorrectApiId() { + let result = sut.telemetryForSignIn(type: MSALNativeAuthSignInType.signInWithOTP) + XCTAssertEqual(result.apiId, .telemetryApiIdSignInWithCodeStart) + } + + func testTelemetryForRefreshToken_returnsCorrectApiId() { + let result = sut.telemetryForToken(type: MSALNativeAuthTokenType.refreshToken) + XCTAssertEqual(result.apiId, .telemetryApiIdToken) + } + + func testTelemetryForResetPasswordStart_returnsCorrectApiId() { + let result = sut.telemetryForResetPasswordStart(type: MSALNativeAuthResetPasswordStartType.resetPasswordStart) + XCTAssertEqual(result.apiId, .telemetryApiIdResetPasswordStart) + } + + func testTelemetryForResendCode_returnsCorrectApiId() { + let result = sut.telemetryForResendCode(type: MSALNativeAuthResendCodeType.resendCode) + XCTAssertEqual(result.apiId, .telemetryApiIdResendCode) + } + + func testTelemetryForVerifyCode_returnsCorrectApiId() { + let result = sut.telemetryForVerifyCode(type: MSALNativeAuthVerifyCodeType.verifyCode) + XCTAssertEqual(result.apiId, .telemetryApiIdVerifyCode) + } + + func testTelemetryForSignOut_returnsCorrectApiId() { + let result = sut.telemetryForSignOut(type: MSALNativeAuthSignOutType.signOutAction) + XCTAssertEqual(result.apiId, .telemetryApiIdSignOut) + } + + // MARK: Correct Operation Type tests + func testTelemetryForSignUp_returnsCorrectOperationType() { + let result = sut.telemetryForSignUp(type: MSALNativeAuthSignUpType.signUpWithOTP) + XCTAssertEqual(result.operationType, MSALNativeAuthSignUpType.signUpWithOTP.rawValue) + } + + func testTelemetryForToken_returnsCorrectOperationType() { + let result = sut.telemetryForToken(type: MSALNativeAuthTokenType.refreshToken) + XCTAssertEqual(result.operationType, MSALNativeAuthTokenType.refreshToken.rawValue) + } +} diff --git a/MSAL/test/unit/native_auth/utils/MSALNativeAuthTelemetryTestDispatcher.swift b/MSAL/test/unit/native_auth/utils/MSALNativeAuthTelemetryTestDispatcher.swift new file mode 100644 index 0000000000..096200b3c8 --- /dev/null +++ b/MSAL/test/unit/native_auth/utils/MSALNativeAuthTelemetryTestDispatcher.swift @@ -0,0 +1,48 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +@_implementationOnly import MSAL_Private + +final class MSALNativeAuthTelemetryTestDispatcher: NSObject, MSIDTelemetryDispatcher { + + typealias TestCallback = (MSIDTelemetryEventInterface) -> Void + + private var testCallback: TestCallback? + + func setTestCallback(_ callback: @escaping TestCallback) { + testCallback = callback + } + + func containsObserver(_ observer: Any!) -> Bool { + return false + } + + func receive(_ requestId: String!, event: MSIDTelemetryEventInterface!) { + testCallback?(event) + } + + func flush(_ requestId: String!) { + } +} diff --git a/Samples/ios/SampleAppiOS-Swift/SampleAppiOS-Swift.xcodeproj/project.pbxproj b/Samples/ios/SampleAppiOS-Swift/SampleAppiOS-Swift.xcodeproj/project.pbxproj index af413dd8d9..196ecf5416 100644 --- a/Samples/ios/SampleAppiOS-Swift/SampleAppiOS-Swift.xcodeproj/project.pbxproj +++ b/Samples/ios/SampleAppiOS-Swift/SampleAppiOS-Swift.xcodeproj/project.pbxproj @@ -25,6 +25,27 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 289E15662948EB5A006104D9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 96672DAB1EC7913D00878AC5 /* MSAL.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 04A6B57B226921890035C7C2; + remoteInfo = "MSAL (iOS Static Library)"; + }; + 289E15682948EB5A006104D9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 96672DAB1EC7913D00878AC5 /* MSAL.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 04A6B59C2269286F0035C7C2; + remoteInfo = "MSAL (Mac Static Library)"; + }; + 289E156A2948EB5A006104D9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 96672DAB1EC7913D00878AC5 /* MSAL.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = B295A16422D0348400FFB313; + remoteInfo = "unit-test-host-mac"; + }; 961E5C301ECA7864001DBA9A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 96672DAB1EC7913D00878AC5 /* MSAL.xcodeproj */; @@ -186,15 +207,18 @@ isa = PBXGroup; children = ( 96672DB71EC7913D00878AC5 /* MSAL.framework */, - 96672DB91EC7913D00878AC5 /* "MSAL-iOS-Unit-Tests".xctest */, + 96672DB91EC7913D00878AC5 /* "MSAL-iOS-UI-Tests".xctest */, 96672DBB1EC7913D00878AC5 /* MSAL.framework */, 96672DBD1EC7913D00878AC5 /* "MSAL-Mac-Unit-Tests".xctest */, 96672DBF1EC7913D00878AC5 /* MSAL Test App.app */, - 96672DC11EC7913D00878AC5 /* MSAL Test App.app */, 96672DC31EC7913D00878AC5 /* MSAL Test Automation (iOS).app */, 96672DC51EC7913D00878AC5 /* unit-test-host.app */, 96595137215180A8009F86DF /* InteractiveiOSTests.xctest */, 96595139215180A8009F86DF /* MultiAppiOSTests.xctest */, + 96672DC11EC7913D00878AC5 /* MSAL Test App (Mac).app */, + 289E15672948EB5A006104D9 /* libMSAL (iOS Static Library).a */, + 289E15692948EB5A006104D9 /* libMSAL (macOS Static Library).a */, + 289E156B2948EB5A006104D9 /* unit-test-host-mac.app */, ); name = Products; sourceTree = ""; @@ -296,6 +320,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -316,6 +341,27 @@ /* End PBXProject section */ /* Begin PBXReferenceProxy section */ + 289E15672948EB5A006104D9 /* libMSAL (iOS Static Library).a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libMSAL (iOS Static Library).a"; + remoteRef = 289E15662948EB5A006104D9 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 289E15692948EB5A006104D9 /* libMSAL (macOS Static Library).a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libMSAL (macOS Static Library).a"; + remoteRef = 289E15682948EB5A006104D9 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 289E156B2948EB5A006104D9 /* unit-test-host-mac.app */ = { + isa = PBXReferenceProxy; + fileType = wrapper.application; + path = "unit-test-host-mac.app"; + remoteRef = 289E156A2948EB5A006104D9 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 96595137215180A8009F86DF /* InteractiveiOSTests.xctest */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; @@ -365,10 +411,10 @@ remoteRef = 96672DBE1EC7913D00878AC5 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 96672DC11EC7913D00878AC5 /* MSAL Test App.app */ = { + 96672DC11EC7913D00878AC5 /* MSAL Test App (Mac).app */ = { isa = PBXReferenceProxy; fileType = wrapper.application; - path = "MSAL Test App.app"; + path = "MSAL Test App (Mac).app"; remoteRef = 96672DC01EC7913D00878AC5 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -551,6 +597,7 @@ CODE_SIGN_ENTITLEMENTS = "SampleAppiOS-Swift/SampleAppiOS-Swift.entitlements"; DEVELOPMENT_TEAM = UBF8T346G9; INFOPLIST_FILE = "SampleAppiOS-Swift/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.microsoft.SampleAppiOS-Swift"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -566,6 +613,7 @@ CODE_SIGN_ENTITLEMENTS = "SampleAppiOS-Swift/SampleAppiOS-Swift.entitlements"; DEVELOPMENT_TEAM = UBF8T346G9; INFOPLIST_FILE = "SampleAppiOS-Swift/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.microsoft.SampleAppiOS-Swift"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/build.py b/build.py index 7c2654b147..e00fc5677b 100755 --- a/build.py +++ b/build.py @@ -35,8 +35,9 @@ script_start_time = timer() -ios_sim_device = "iPhone 14" -ios_sim_dest = "-destination 'platform=iOS Simulator,name=" + ios_sim_device + ",OS=16.4'" +ios_sim_device_type = "iPhone 14" +ios_sim_device_exact_name = ios_sim_device_type + " Simulator \(16.4\)" +ios_sim_dest = "-destination 'platform=iOS Simulator,name=" + ios_sim_device_type + ",OS=16.4'" ios_sim_flags = "-sdk iphonesimulator CODE_SIGN_IDENTITY=\"\" CODE_SIGNING_REQUIRED=NO" default_workspace = "MSAL.xcworkspace" @@ -251,12 +252,25 @@ def print_coverage(self, printname) : def get_device_guid(self) : if (self.platform == "iOS") : - return device_guids.get_ios(ios_sim_device) + return device_guids.get_ios(ios_sim_device_exact_name) if (self.platform == "Mac") : return device_guids.get_mac().decode(sys.stdout.encoding) raise Exception("Unsupported platform: \"" + "\", valid platforms are \"iOS\" and \"Mac\"") + + def do_lint(self) : + if (self.linter != "swiftlint") : + sys.stdout.write("Unknown linter '" + self.linter + "'\n") + return + + command = "swiftlint lint --strict " + self.directory + + result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True ) + + sys.stdout.write(result.stdout.decode(sys.stdout.encoding)) + + return result.returncode def do_codecov(self) : """ @@ -308,6 +322,8 @@ def do_operation(self, operation) : try : if (operation == "codecov") : exit_code = self.do_codecov() + elif (operation == "lint") : + exit_code = self.do_lint() else : command = self.xcodebuild_command(operation, use_xcpretty) if (operation == "build" and self.use_sonarcube == "true" and os.environ.get('TRAVIS') == "true") : @@ -344,7 +360,7 @@ def requires_simulator(targets) : def launch_simulator() : print("Booting simulator...") - command = "xcrun simctl boot " + device_guids.get_ios(ios_sim_device) + command = "xcrun simctl boot " + device_guids.get_ios(ios_sim_device_exact_name) print(command) # This spawns a new process without us having to wait for it diff --git a/cgmanifest.json b/cgmanifest.json new file mode 100644 index 0000000000..1f5115e135 --- /dev/null +++ b/cgmanifest.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://json.schemastore.org/component-detection-manifest.json", + "version": 1, + "registrations":[ + { + "component": { + "type": "other", + "other": { + "name": "SwiftLint", + "version": "0.53.0", + "downloadUrl": "https://github.com/realm/SwiftLint/releases/download/0.53.0/SwiftLint.pkg" + } + }, + "developmentDependency" : true + } + ] +} \ No newline at end of file From d9a122b75a23f6d7c9bfb1f5f77de2552651277e Mon Sep 17 00:00:00 2001 From: Danilo Raspa Date: Tue, 12 Dec 2023 16:36:14 +0000 Subject: [PATCH 14/84] Add co-ownership of MSAL project file --- CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index 0234657fe7..ad6b3a452c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -2,6 +2,8 @@ # Unless a later match takes precedence, these users will be requested # for review whenever someone opens a pull request. * @AzureAD/AppleIdentityTeam +# @AzureAD/AppleIdentityTeam and @AzureAD/MSAL-ObjC-CIAM will be the co-owners of the MSAL.project file +/MSAL/MSAL.xcodeproj/project.pbxproj @AzureAD/AppleIdentityTeam @AzureAD/MSAL-ObjC-CIAM # @AzureAD/MSAL-ObjC-CIAM owns any files in the */native_auth # directories and any of its subdirectories. /MSAL/src/native_auth/ @AzureAD/MSAL-ObjC-CIAM From 16a7d76aabf3b25a51856787108354bbf0a31e73 Mon Sep 17 00:00:00 2001 From: Danilo Raspa Date: Wed, 13 Dec 2023 14:50:33 +0000 Subject: [PATCH 15/84] Check if attributes are parsable to JSON before to parse --- .../MSALNativeAuthSignUpRequestProvider.swift | 3 +++ ...NativeAuthSignUpRequestProviderTests.swift | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift index 64274f246e..7db181cbab 100644 --- a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift +++ b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift @@ -93,6 +93,9 @@ final class MSALNativeAuthSignUpRequestProvider: MSALNativeAuthSignUpRequestProv } private func formatAttributes(_ attributes: [String: Any]) throws -> String? { + guard JSONSerialization.isValidJSONObject(attributes) else { + throw MSALNativeAuthInternalError.invalidAttributes + } let data = try JSONSerialization.data(withJSONObject: attributes) return String(data: data, encoding: .utf8) } diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift index 6d0c7b0482..eff40e49c0 100644 --- a/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift @@ -57,6 +57,17 @@ final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase { let expectedTelemetryResult = telemetryProvider.telemetryForSignUp(type: .signUpStart).telemetryString() checkServerTelemetry(request.serverTelemetry, expectedTelemetryResult: expectedTelemetryResult) } + + func test_signUpStartRequestWithInvalidAttributes_throwAnError() throws { + let parameters = MSALNativeAuthSignUpStartRequestProviderParameters( + username: DEFAULT_TEST_ID_TOKEN_USERNAME, + password: "1234", + attributes: ["invalid attribute": Data()], + context: MSALNativeAuthRequestContext(correlationId: context.correlationId()) + ) + + XCTAssertThrowsError(try sut.start(parameters: parameters)) + } func test_signUpChallengeRequest_is_created_successfully() throws { let request = try sut.challenge(token: "sign-up-token", context: context) @@ -86,6 +97,19 @@ final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase { let expectedTelemetryResult = telemetryProvider.telemetryForSignUp(type: .signUpContinue).telemetryString() checkServerTelemetry(request.serverTelemetry, expectedTelemetryResult: expectedTelemetryResult) } + + func test_signUpContinueRequestWithInvalidAttributes_throwAnError() throws { + let parameters = MSALNativeAuthSignUpContinueRequestProviderParams( + grantType: .password, + signUpToken: "sign-up-token", + password: "1234", + oobCode: nil, + attributes: ["invalid attribute": Data()], + context: context + ) + + XCTAssertThrowsError(try sut.continue(parameters: parameters)) + } private func checkBodyParams(_ bodyParams: [String: String]?, for endpoint: MSALNativeAuthEndpoint) { typealias Key = MSALNativeAuthRequestParametersKey From 031bfdc6477382f732c8d72f4d1a8333fba3d54c Mon Sep 17 00:00:00 2001 From: Marcos Borges <116104275+borgesmb@users.noreply.github.com> Date: Wed, 13 Dec 2023 17:05:21 +0000 Subject: [PATCH 16/84] - Added correlationId to MSALNativeAuthBaseState (#1915) - Removed correlationId from state actions - Adjusted tests accordingly - Removed correlation id from `SignInAfterSignUpState` action method - Fixed SwiftLint warnings - Tidy up Unit tests for correlation ids Renamed MSALNativeAuthControllerFactoryRequestProviderMock to MSALNativeAuthControllerRequestProviderFactoryMock PR comments Made prepareMockRequest more flexible Renamed MSALNativeAuthControllerRequestProviderFactoryMock to MSALNativeAuthControllerProtocolFactoryMock PR Comments Clarified where parameters are checked internally PR comment about signInRequestProviderMock.expectedContext = contextMock Updated end to end tests to not use correlation id's Update submodule Update submodule Update submodule New error message when device is not PSSO registered. Hotfix 1.2.19 (#1909) * Update release config * point to latest main from cc --------- Co-authored-by: Yong Zeng Updating MSAL framework checksum & url for 1.2.19 [skip ci] Merge release 1220 into dev (#1934) * Release MSAL 1.2.20 (#1930) * Update submodule * Update submodule * Get token operation for BrowserCore (#1862) * Update core. * Update msal. * Update core. * update core. * Update core. * Update core. * Update core. * Update core. * Update core. * Update core. * Update submodule * Updated submodule * Updated submodule * Update submodule * update submodule for current key change * New error message when device is not PSSO registered. * Release MSAL 1.2.20 * Align with latest main (#1933) --------- Co-authored-by: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Co-authored-by: Sergei Demchenko Co-authored-by: Swasti Gupta Co-authored-by: Swasti Gupta Co-authored-by: Juan Arias Co-authored-by: Kai * Updating MSAL framework checksum & url for 1.2.20 [skip ci] * Update CommonCore to latest dev --------- Co-authored-by: Veena Soman Co-authored-by: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Co-authored-by: Sergei Demchenko Co-authored-by: Swasti Gupta Co-authored-by: Swasti Gupta Co-authored-by: Juan Arias - Changed submodule --- MSAL/MSAL.xcodeproj/project.pbxproj | 4 + .../MSALNativeAuthResultFactory.swift | 2 +- ...SALNativeAuthResetPasswordController.swift | 18 +- .../MSALNativeAuthSignInController.swift | 28 +- .../MSALNativeAuthSignUpController.swift | 53 +- .../state/MSALNativeAuthBaseState.swift | 4 +- .../state/ResetPasswordStates+Internal.swift | 6 +- .../state/ResetPasswordStates.swift | 23 +- .../SignInAfterSignUpState+Internal.swift | 2 +- .../state/SignInAfterSignUpState.swift | 8 +- .../state/SignInStates+Internal.swift | 7 +- .../state_machine/state/SignInStates.swift | 33 +- .../state/SignUpStates+Internal.swift | 11 +- .../state_machine/state/SignUpStates.swift | 29 +- ...ativeAuthSignInUsernameEndToEndTests.swift | 8 +- .../MSALNativeAuthSignOutEndToEndTests.swift | 4 +- ...gnUpUsernameAndPasswordEndToEndTests.swift | 34 +- ...ativeAuthSignUpUsernameEndToEndTests.swift | 27 +- .../MSALNativeAuthBaseControllerTests.swift | 6 +- ...NativeAuthCredentialsControllerTests.swift | 12 +- ...tiveAuthResetPasswordControllerTests.swift | 91 ++- .../MSALNativeAuthSignInControllerTests.swift | 232 +++----- .../MSALNativeAuthSignUpControllerTests.swift | 173 +++--- .../mock/MSALNativeAuthFactoriesMocks.swift | 34 ++ .../mock/MSALNativeAuthHTTPRequestMock.swift | 38 ++ .../mock/MSALNativeAuthNetworkMocks.swift | 91 +-- .../mock/SignInDelegatesSpies.swift | 18 +- ...ALNativeAuthRequestErrorHandlerTests.swift | 21 +- .../MSALNativeAuthRequestableTests.swift | 2 +- ...ativeAuthPublicClientApplicationTest.swift | 551 +++++++++++++++++- .../ResetPasswordCodeSentStateTests.swift | 11 +- .../ResetPasswordRequiredStateTests.swift | 7 +- .../SignInCodeRequiredStateTests.swift | 9 +- .../SignInPasswordRequiredStateTests.swift | 5 +- .../SignUpAttributesRequiredStateTests.swift | 9 +- .../sign_up/SignUpCodeSentStateTests.swift | 17 +- .../SignUpPasswordRequiredStateTests.swift | 11 +- 37 files changed, 1104 insertions(+), 535 deletions(-) create mode 100644 MSAL/test/unit/native_auth/mock/MSALNativeAuthHTTPRequestMock.swift diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index 0d6a5bd32a..086c674e31 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -1024,6 +1024,7 @@ DE92450E2A38601100C0389F /* MSALNativeAuthCredentialsControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE92450D2A38601100C0389F /* MSALNativeAuthCredentialsControlling.swift */; }; DE9245122A38736600C0389F /* CredentialsDelegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9245112A38736600C0389F /* CredentialsDelegates.swift */; }; DE9245152A3875D700C0389F /* RetrieveAccessTokenError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9245142A3875D700C0389F /* RetrieveAccessTokenError.swift */; }; + DE946FE52B0F713A00978493 /* MSALNativeAuthHTTPRequestMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE946FE42B0F713A00978493 /* MSALNativeAuthHTTPRequestMock.swift */; }; DE94C9E029F198D600C1EC1F /* MSALNativeAuthResetPasswordStartRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94C9DE29F1989600C1EC1F /* MSALNativeAuthResetPasswordStartRequestParametersTest.swift */; }; DE94C9E229F19AA200C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94C9E129F19AA200C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift */; }; DE94C9E429F19C4C00C1EC1F /* MSALNativeAuthResetPasswordContinueRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94C9E329F19C4C00C1EC1F /* MSALNativeAuthResetPasswordContinueRequestParametersTest.swift */; }; @@ -2057,6 +2058,7 @@ DE92450D2A38601100C0389F /* MSALNativeAuthCredentialsControlling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCredentialsControlling.swift; sourceTree = ""; }; DE9245112A38736600C0389F /* CredentialsDelegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialsDelegates.swift; sourceTree = ""; }; DE9245142A3875D700C0389F /* RetrieveAccessTokenError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RetrieveAccessTokenError.swift; sourceTree = ""; }; + DE946FE42B0F713A00978493 /* MSALNativeAuthHTTPRequestMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthHTTPRequestMock.swift; sourceTree = ""; }; DE94C9DE29F1989600C1EC1F /* MSALNativeAuthResetPasswordStartRequestParametersTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordStartRequestParametersTest.swift; sourceTree = ""; }; DE94C9E129F19AA200C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift; sourceTree = ""; }; DE94C9E329F19C4C00C1EC1F /* MSALNativeAuthResetPasswordContinueRequestParametersTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordContinueRequestParametersTest.swift; sourceTree = ""; }; @@ -2435,6 +2437,7 @@ E20C217D2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift */, E20C21742A7A61B600E31598 /* SignUpDelegateSpies.swift */, E2F626B22A781CE300C4A303 /* SignInDelegatesSpies.swift */, + DE946FE42B0F713A00978493 /* MSALNativeAuthHTTPRequestMock.swift */, 9B61C91D2A27E5E200CE9E3A /* reset_password */, ); path = mock; @@ -6040,6 +6043,7 @@ DE94C9E629F19D9B00C1EC1F /* MSALNativeAuthResetPasswordSubmitRequestParametersTest.swift in Sources */, 289747AC2979487900838C80 /* MSALNativeAuthUrlRequestSerializerTests.swift in Sources */, DE14D76129898CF900F37BEF /* MSALNativeAuthTestCase.swift in Sources */, + DE946FE52B0F713A00978493 /* MSALNativeAuthHTTPRequestMock.swift in Sources */, B2725ED222C0469A009B454A /* MSALLegacySharedAccountsProviderTests.m in Sources */, E2BC029A29D766B200041DBC /* MSALNativeAuthSignUpStartRequestParametersTest.swift in Sources */, E2C1D2D429A3992100B26449 /* MSALNativeAuthBaseControllerTests.swift in Sources */, diff --git a/MSAL/src/native_auth/controllers/factories/MSALNativeAuthResultFactory.swift b/MSAL/src/native_auth/controllers/factories/MSALNativeAuthResultFactory.swift index edf1eb337f..7fd3a0c2df 100644 --- a/MSAL/src/native_auth/controllers/factories/MSALNativeAuthResultFactory.swift +++ b/MSAL/src/native_auth/controllers/factories/MSALNativeAuthResultFactory.swift @@ -59,7 +59,7 @@ final class MSALNativeAuthResultFactory: MSALNativeAuthResultBuildable { level: .error, context: context, format: "Claims for account could not be created - \(error)" ) - } + } guard let account = MSALAccount.init(msidAccount: tokenResult.account, createTenantProfile: false, accountClaims: jsonDictionary) else { diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift index 5aa9d939c3..e705c7c483 100644 --- a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift @@ -184,7 +184,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, stopTelemetryEvent(event, context: context) return .codeRequired( - newState: ResetPasswordCodeRequiredState(controller: self, flowToken: challengeToken), + newState: ResetPasswordCodeRequiredState(controller: self, flowToken: challengeToken, correlationId: context.correlationId()), sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength @@ -223,7 +223,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, stopTelemetryEvent(event, context: context) MSALLogger.log(level: .info, context: context, format: "Successful resetpassword/challenge (resend code) request") return .codeRequired( - newState: ResetPasswordCodeRequiredState(controller: self, flowToken: challengeToken), + newState: ResetPasswordCodeRequiredState(controller: self, flowToken: challengeToken, correlationId: context.correlationId()), sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength @@ -276,7 +276,9 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, case .success(let passwordSubmitToken): stopTelemetryEvent(event, context: context) MSALLogger.log(level: .info, context: context, format: "Successful resetpassword/continue request") - return .passwordRequired(newState: ResetPasswordRequiredState(controller: self, flowToken: passwordSubmitToken)) + return .passwordRequired(newState: ResetPasswordRequiredState(controller: self, + flowToken: passwordSubmitToken, + correlationId: context.correlationId())) case .error(let apiError): let error = apiError.toVerifyCodePublicError() stopTelemetryEvent(event, context: context, error: error) @@ -301,7 +303,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context, format: "Invalid code error calling resetpassword/continue \(error.errorDescription ?? "No error description")") - let state = ResetPasswordCodeRequiredState(controller: self, flowToken: passwordResetToken) + let state = ResetPasswordCodeRequiredState(controller: self, flowToken: passwordResetToken, correlationId: context.correlationId()) return .error(error: error, newState: state) } } @@ -351,7 +353,9 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context, format: "Password error calling resetpassword/submit \(error.errorDescription ?? "No error description")") - return .error(error: error, newState: ResetPasswordRequiredState(controller: self, flowToken: passwordSubmitToken)) + return .error(error: error, newState: ResetPasswordRequiredState(controller: self, + flowToken: passwordSubmitToken, + correlationId: context.correlationId())) case .error(let apiError): let error = apiError.toPasswordRequiredPublicError() self.stopTelemetryEvent(event, context: context, error: error) @@ -469,7 +473,9 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context, format: "Password error calling resetpassword/poll_completion \(error.errorDescription ?? "No error description")") - return .error(error: error, newState: ResetPasswordRequiredState(controller: self, flowToken: passwordResetToken)) + return .error(error: error, newState: ResetPasswordRequiredState(controller: self, + flowToken: passwordResetToken, + correlationId: context.correlationId())) case .error(let apiError): let error = apiError.toPasswordRequiredPublicError() self.stopTelemetryEvent(event, context: context, error: error) diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift index c4e0415800..2dc9cd97de 100644 --- a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift @@ -305,9 +305,12 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN let error = ResendCodeError() MSALLogger.log(level: .error, context: context, format: "SignIn ResendCode: received challenge error response: \(challengeError)") stopTelemetryEvent(event, context: context, error: error) - return .error(error: error, newState: SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken)) + return .error(error: error, newState: SignInCodeRequiredState(scopes: scopes, + controller: self, + flowToken: credentialToken, + correlationId: context.correlationId())) case .codeRequired(let credentialToken, let sentTo, let channelType, let codeLength): - let state = SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken) + let state = SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken, correlationId: context.correlationId()) stopTelemetryEvent(event, context: context) return .codeRequired(newState: state, sentTo: sentTo, channelTargetType: channelType, codeLength: codeLength) } @@ -327,7 +330,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN context: context, format: "SignIn completed with errorType: \(errorType)") stopTelemetryEvent(telemetryInfo, error: errorType) - let state = SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken) + let state = SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken, correlationId: context.correlationId()) return .error(error: errorType.convertToVerifyCodeError(), newState: state) } @@ -343,7 +346,11 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN context: telemetryInfo.context, format: "SignIn with username and password completed with errorType: \(errorType)") stopTelemetryEvent(telemetryInfo, error: errorType) - let state = SignInPasswordRequiredState(scopes: scopes, username: username, controller: self, flowToken: credentialToken) + let state = SignInPasswordRequiredState(scopes: scopes, + username: username, + controller: self, + flowToken: credentialToken, + correlationId: telemetryInfo.context.correlationId()) return .error(error: errorType.convertToPasswordRequiredError(), newState: state) } @@ -452,7 +459,8 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN scopes: scopes, username: params.username, controller: self, - flowToken: credentialToken + flowToken: credentialToken, + correlationId: params.context.correlationId() ) return .init(.passwordRequired(newState: state), telemetryUpdate: { [weak self] result in @@ -470,7 +478,10 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN } }) case .codeRequired(let credentialToken, let sentTo, let channelType, let codeLength): - let state = SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken) + let state = SignInCodeRequiredState(scopes: scopes, + controller: self, + flowToken: credentialToken, + correlationId: params.context.correlationId()) stopTelemetryEvent(telemetryInfo) return .init(.codeRequired(newState: state, sentTo: sentTo, channelTargetType: channelType, codeLength: codeLength)) case .error(let challengeError): @@ -495,7 +506,10 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN case .codeRequired(let credentialToken, let sentTo, let channelType, let codeLength): MSALLogger.log(level: .warning, context: telemetryInfo.context, format: MSALNativeAuthErrorMessage.codeRequiredForPasswordUserLog) let result: SignInPasswordStartResult = .codeRequired( - newState: SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken), + newState: SignInCodeRequiredState(scopes: scopes, + controller: self, + flowToken: credentialToken, + correlationId: params.context.correlationId()), sentTo: sentTo, channelTargetType: channelType, codeLength: codeLength diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift index a4291aabcc..ff6a9848b9 100644 --- a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift @@ -323,7 +323,10 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa stopTelemetryEvent(event, context: context) return SignUpStartPasswordControllerResponse( .codeRequired( - newState: SignUpCodeRequiredState(controller: self, username: username, flowToken: signUpToken), + newState: SignUpCodeRequiredState(controller: self, + username: username, + flowToken: signUpToken, + correlationId: context.correlationId()), sentTo: sentTo, channelTargetType: challengeType, codeLength: codeLength @@ -366,7 +369,10 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa stopTelemetryEvent(event, context: context) return SignUpStartCodeControllerResponse( .codeRequired( - newState: SignUpCodeRequiredState(controller: self, username: username, flowToken: signUpToken), + newState: SignUpCodeRequiredState(controller: self, + username: username, + flowToken: signUpToken, + correlationId: context.correlationId()), sentTo: sentTo, channelTargetType: challengeType, codeLength: codeLength @@ -408,7 +414,10 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge resendCode request") stopTelemetryEvent(event, context: context) return .codeRequired( - newState: SignUpCodeRequiredState(controller: self, username: username, flowToken: signUpToken), + newState: SignUpCodeRequiredState(controller: self, + username: username, + flowToken: signUpToken, + correlationId: context.correlationId()), sentTo: sentTo, channelTargetType: challengeType, codeLength: codeLength @@ -443,7 +452,10 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa case .passwordRequired(let signUpToken): MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge request after credential_required") - let state = SignUpPasswordRequiredState(controller: self, username: username, flowToken: signUpToken) + let state = SignUpPasswordRequiredState(controller: self, + username: username, + flowToken: signUpToken, + correlationId: context.correlationId()) return .init(.passwordRequired(state), telemetryUpdate: { [weak self] result in switch result { @@ -509,7 +521,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa let error = VerifyCodeError(type: .invalidCode) stopTelemetryEvent(event, context: context, error: error) - let state = SignUpCodeRequiredState(controller: self, username: username, flowToken: signUpToken) + let state = SignUpCodeRequiredState(controller: self, username: username, flowToken: signUpToken, correlationId: context.correlationId()) return .init(.error(error: error, newState: state)) case .credentialRequired(let signUpToken): MSALLogger.log(level: .verbose, context: context, format: "credential_required received in signup/continue request") @@ -519,7 +531,11 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa case .attributesRequired(let signUpToken, let attributes): MSALLogger.log(level: .verbose, context: context, format: "attributes_required received in signup/continue request: \(attributes)") - let state = SignUpAttributesRequiredState(controller: self, username: username, flowToken: signUpToken) + let state = SignUpAttributesRequiredState(controller: self, + username: username, + flowToken: signUpToken, + correlationId: context.correlationId()) + return .init(.attributesRequired(attributes: attributes, newState: state), telemetryUpdate: { [weak self] result in switch result { case .success: @@ -567,12 +583,19 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa format: "invalid_user_input error in signup/continue submitPassword request \(error.errorDescription ?? "No error description")" ) - let state = SignUpPasswordRequiredState(controller: self, username: username, flowToken: signUpToken) + let state = SignUpPasswordRequiredState(controller: self, + username: username, + flowToken: signUpToken, + correlationId: context.correlationId()) + return .init(.error(error: error, newState: state)) case .attributesRequired(let signUpToken, let attributes): MSALLogger.log(level: .verbose, context: context, format: "attributes_required received in signup/continue request: \(attributes)") - let state = SignUpAttributesRequiredState(controller: self, username: username, flowToken: signUpToken) + let state = SignUpAttributesRequiredState(controller: self, + username: username, + flowToken: signUpToken, + correlationId: context.correlationId()) return .init(.attributesRequired(attributes: attributes, newState: state), telemetryUpdate: { [weak self] result in switch result { @@ -620,7 +643,11 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa context: context, format: "attributes_required received in signup/continue submitAttributes request: \(attributes)") - let state = SignUpAttributesRequiredState(controller: self, username: username, flowToken: signUpToken) + let state = SignUpAttributesRequiredState(controller: self, + username: username, + flowToken: signUpToken, + correlationId: context.correlationId()) + return .attributesRequired(attributes: attributes, state: state) case .attributeValidationFailed(let signUpToken, let invalidAttributes): let message = "attribute_validation_failed from signup/continue submitAttributes request. Make sure these attributes are correct: \(invalidAttributes)" // swiftlint:disable:this line_length @@ -630,7 +657,11 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa let error = AttributesRequiredError(message: errorMessage) stopTelemetryEvent(event, context: context, error: error) - let state = SignUpAttributesRequiredState(controller: self, username: username, flowToken: signUpToken) + let state = SignUpAttributesRequiredState(controller: self, + username: username, + flowToken: signUpToken, + correlationId: context.correlationId()) + return .attributesInvalid(attributes: invalidAttributes, newState: state) case .error(let apiError): let error = apiError.toAttributesRequiredPublicError() @@ -659,6 +690,6 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa ) -> SignInAfterSignUpState { MSALLogger.log(level: .info, context: context, format: "SignUp completed successfully") stopTelemetryEvent(event, context: context) - return SignInAfterSignUpState(controller: signInController, username: username, slt: slt) + return SignInAfterSignUpState(controller: signInController, username: username, slt: slt, correlationId: context.correlationId()) } } diff --git a/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift b/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift index e4e78023b6..f0261cbf08 100644 --- a/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift +++ b/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift @@ -27,8 +27,10 @@ import Foundation @objc public class MSALNativeAuthBaseState: NSObject { let flowToken: String + let correlationId: UUID - init(flowToken: String) { + init(flowToken: String, correlationId: UUID) { self.flowToken = flowToken + self.correlationId = correlationId } } diff --git a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift index 5b0e9ad342..7b8a1bf168 100644 --- a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift +++ b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift @@ -26,12 +26,12 @@ import Foundation extension ResetPasswordCodeRequiredState { - func resendCodeInternal(correlationId: UUID?) async -> ResetPasswordResendCodeResult { + func resendCodeInternal() async -> ResetPasswordResendCodeResult { let context = MSALNativeAuthRequestContext(correlationId: correlationId) return await controller.resendCode(passwordResetToken: flowToken, context: context) } - func submitCodeInternal(code: String, correlationId: UUID?) async -> ResetPasswordVerifyCodeResult { + func submitCodeInternal(code: String) async -> ResetPasswordVerifyCodeResult { let context = MSALNativeAuthRequestContext(correlationId: correlationId) guard inputValidator.isInputValid(code) else { @@ -45,7 +45,7 @@ extension ResetPasswordCodeRequiredState { extension ResetPasswordRequiredState { - func submitPasswordInternal(password: String, correlationId: UUID?) async -> ResetPasswordRequiredResult { + func submitPasswordInternal(password: String) async -> ResetPasswordRequiredResult { let context = MSALNativeAuthRequestContext(correlationId: correlationId) guard inputValidator.isInputValid(password) else { diff --git a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift index 775f3996c7..c9cbf62983 100644 --- a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift +++ b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift @@ -32,23 +32,22 @@ public class ResetPasswordBaseState: MSALNativeAuthBaseState { init( controller: MSALNativeAuthResetPasswordControlling, flowToken: String, - inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator() + inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator(), + correlationId: UUID ) { self.controller = controller self.inputValidator = inputValidator - super.init(flowToken: flowToken) + super.init(flowToken: flowToken, correlationId: correlationId) } } /// An object of this type is created when a user is required to supply a verification code to continue a reset password flow. @objcMembers public class ResetPasswordCodeRequiredState: ResetPasswordBaseState { /// Requests the server to resend the verification code to the user. - /// - Parameters: - /// - correlationId: Optional. UUID to correlate this request with the server for debugging. - /// - delegate: Delegate that receives callbacks for the operation. - public func resendCode(correlationId: UUID? = nil, delegate: ResetPasswordResendCodeDelegate) { + /// - Parameter delegate: Delegate that receives callbacks for the operation. + public func resendCode(delegate: ResetPasswordResendCodeDelegate) { Task { - let result = await resendCodeInternal(correlationId: correlationId) + let result = await resendCodeInternal() switch result { case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): @@ -67,11 +66,10 @@ public class ResetPasswordBaseState: MSALNativeAuthBaseState { /// Submits the code to the server for verification. /// - Parameters: /// - code: Verification code that the user supplied. - /// - correlationId: Optional. UUID to correlate this request with the server for debugging. /// - delegate: Delegate that receives callbacks for the operation. - public func submitCode(code: String, correlationId: UUID? = nil, delegate: ResetPasswordVerifyCodeDelegate) { + public func submitCode(code: String, delegate: ResetPasswordVerifyCodeDelegate) { Task { - let result = await submitCodeInternal(code: code, correlationId: correlationId) + let result = await submitCodeInternal(code: code) switch result { case .passwordRequired(let newState): @@ -88,11 +86,10 @@ public class ResetPasswordBaseState: MSALNativeAuthBaseState { /// Submits the password to the server for verification. /// - Parameters: /// - password: Password that the user supplied. - /// - correlationId: Optional. UUID to correlate this request with the server for debugging. /// - delegate: Delegate that receives callbacks for the operation. - public func submitPassword(password: String, correlationId: UUID? = nil, delegate: ResetPasswordRequiredDelegate) { + public func submitPassword(password: String, delegate: ResetPasswordRequiredDelegate) { Task { - let result = await submitPasswordInternal(password: password, correlationId: correlationId) + let result = await submitPasswordInternal(password: password) switch result { case .completed: diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift index 920d110966..e7e7b145d5 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift @@ -26,7 +26,7 @@ import Foundation extension SignInAfterSignUpState { - func signInInternal(scopes: [String]?, correlationId: UUID?) async -> Result { + func signInInternal(scopes: [String]?) async -> Result { let context = MSALNativeAuthRequestContext(correlationId: correlationId) return await controller.signIn(username: username, slt: slt, scopes: scopes, context: context) } diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift index 6a83a290c6..beed1c2dec 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift @@ -30,25 +30,25 @@ import Foundation let controller: MSALNativeAuthSignInControlling let username: String let slt: String? + let correlationId: UUID - init(controller: MSALNativeAuthSignInControlling, username: String, slt: String?) { + init(controller: MSALNativeAuthSignInControlling, username: String, slt: String?, correlationId: UUID) { self.username = username self.slt = slt self.controller = controller + self.correlationId = correlationId } /// Sign in the user that signed up. /// - Parameters: /// - scopes: Optional. Permissions you want included in the access token received after sign in flow has completed. - /// - correlationId: Optional. UUID to correlate this request with the server for debugging. /// - delegate: Delegate that receives callbacks for the Sign In flow. public func signIn( scopes: [String]? = nil, - correlationId: UUID? = nil, delegate: SignInAfterSignUpDelegate ) { Task { - let controllerResult = await signInInternal(scopes: scopes, correlationId: correlationId) + let controllerResult = await signInInternal(scopes: scopes) switch controllerResult { case .success(let accountResult): diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift index 9a3cfe47bb..7fe582dd03 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift @@ -26,7 +26,7 @@ import Foundation extension SignInCodeRequiredState { - func submitCodeInternal(code: String, correlationId: UUID?) async -> SignInVerifyCodeResult { + func submitCodeInternal(code: String) async -> SignInVerifyCodeResult { let context = MSALNativeAuthRequestContext(correlationId: correlationId) MSALLogger.log(level: .verbose, context: context, format: "SignIn flow, code submitted") guard inputValidator.isInputValid(code) else { @@ -37,7 +37,7 @@ extension SignInCodeRequiredState { return await controller.submitCode(code, credentialToken: flowToken, context: context, scopes: scopes) } - func resendCodeInternal(correlationId: UUID?) async -> SignInResendCodeResult { + func resendCodeInternal() async -> SignInResendCodeResult { let context = MSALNativeAuthRequestContext(correlationId: correlationId) MSALLogger.log(level: .verbose, context: context, format: "SignIn flow, resend code requested") @@ -48,8 +48,7 @@ extension SignInCodeRequiredState { extension SignInPasswordRequiredState { func submitPasswordInternal( - password: String, - correlationId: UUID? + password: String ) async -> SignInPasswordRequiredResult { let context = MSALNativeAuthRequestContext(correlationId: correlationId) MSALLogger.log(level: .info, context: context, format: "SignIn flow, password submitted") diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift b/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift index 876c28fc80..1301c2b81b 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift @@ -31,10 +31,11 @@ import Foundation init( controller: MSALNativeAuthSignInControlling, inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator(), - flowToken: String) { + flowToken: String, + correlationId: UUID) { self.controller = controller self.inputValidator = inputValidator - super.init(flowToken: flowToken) + super.init(flowToken: flowToken, correlationId: correlationId) } } @@ -47,18 +48,17 @@ import Foundation scopes: [String], controller: MSALNativeAuthSignInControlling, inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator(), - flowToken: String) { + flowToken: String, + correlationId: UUID) { self.scopes = scopes - super.init(controller: controller, inputValidator: inputValidator, flowToken: flowToken) + super.init(controller: controller, inputValidator: inputValidator, flowToken: flowToken, correlationId: correlationId) } /// Requests the server to resend the verification code to the user. - /// - Parameters: - /// - correlationId: Optional. UUID to correlate this request with the server for debugging. - /// - delegate: Delegate that receives callbacks for the operation. - public func resendCode(correlationId: UUID? = nil, delegate: SignInResendCodeDelegate) { + /// - Parameter delegate: Delegate that receives callbacks for the operation. + public func resendCode(delegate: SignInResendCodeDelegate) { Task { - let result = await resendCodeInternal(correlationId: correlationId) + let result = await resendCodeInternal() switch result { case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): @@ -77,11 +77,10 @@ import Foundation /// Submits the code to the server for verification. /// - Parameters: /// - code: Verification code that the user supplies. - /// - correlationId: Optional. UUID to correlate this request with the server for debugging. /// - delegate: Delegate that receives callbacks for the operation. - public func submitCode(code: String, correlationId: UUID? = nil, delegate: SignInVerifyCodeDelegate) { + public func submitCode(code: String, delegate: SignInVerifyCodeDelegate) { Task { - let result = await submitCodeInternal(code: code, correlationId: correlationId) + let result = await submitCodeInternal(code: code) switch result { case .completed(let accountResult): @@ -104,20 +103,20 @@ import Foundation username: String, controller: MSALNativeAuthSignInControlling, inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator(), - flowToken: String) { + flowToken: String, + correlationId: UUID) { self.scopes = scopes self.username = username - super.init(controller: controller, inputValidator: inputValidator, flowToken: flowToken) + super.init(controller: controller, inputValidator: inputValidator, flowToken: flowToken, correlationId: correlationId) } /// Submits the password to the server for verification. /// - Parameters: /// - password: Password that the user supplied. - /// - correlationId: Optional. UUID to correlate this request with the server for debugging. /// - delegate: Delegate that receives callbacks for the operation. - public func submitPassword(password: String, correlationId: UUID? = nil, delegate: SignInPasswordRequiredDelegate) { + public func submitPassword(password: String, delegate: SignInPasswordRequiredDelegate) { Task { - let result = await submitPasswordInternal(password: password, correlationId: correlationId) + let result = await submitPasswordInternal(password: password) switch result { case .completed(let accountResult): diff --git a/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift index 0938e599b0..a3c8474076 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift @@ -26,12 +26,12 @@ import Foundation extension SignUpCodeRequiredState { - func resendCodeInternal(correlationId: UUID?) async -> SignUpResendCodeResult { + func resendCodeInternal() async -> SignUpResendCodeResult { let context = MSALNativeAuthRequestContext(correlationId: correlationId) return await controller.resendCode(username: username, context: context, signUpToken: flowToken) } - func submitCodeInternal(code: String, correlationId: UUID?) async -> MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse { + func submitCodeInternal(code: String) async -> MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) guard inputValidator.isInputValid(code) else { @@ -45,10 +45,7 @@ extension SignUpCodeRequiredState { extension SignUpPasswordRequiredState { - func submitPasswordInternal( - password: String, - correlationId: UUID? - ) async -> MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse { + func submitPasswordInternal(password: String) async -> MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) guard inputValidator.isInputValid(password) else { @@ -62,7 +59,7 @@ extension SignUpPasswordRequiredState { extension SignUpAttributesRequiredState { - func submitAttributesInternal(attributes: [String: Any], correlationId: UUID?) async -> SignUpAttributesRequiredResult { + func submitAttributesInternal(attributes: [String: Any]) async -> SignUpAttributesRequiredResult { let context = MSALNativeAuthRequestContext(correlationId: correlationId) return await controller.submitAttributes(attributes, username: username, signUpToken: flowToken, context: context) } diff --git a/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift b/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift index b9823a1fd6..b26451d562 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift @@ -34,24 +34,23 @@ public class SignUpBaseState: MSALNativeAuthBaseState { controller: MSALNativeAuthSignUpControlling, username: String, flowToken: String, - inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator() + inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator(), + correlationId: UUID ) { self.controller = controller self.username = username self.inputValidator = inputValidator - super.init(flowToken: flowToken) + super.init(flowToken: flowToken, correlationId: correlationId) } } /// An object of this type is created when a user is required to supply a verification code to continue a sign up flow. @objcMembers public class SignUpCodeRequiredState: SignUpBaseState { /// Requests the server to resend the verification code to the user. - /// - Parameters: - /// - correlationId: Optional. UUID to correlate this request with the server for debugging. - /// - delegate: Delegate that receives callbacks for the operation. - public func resendCode(correlationId: UUID? = nil, delegate: SignUpResendCodeDelegate) { + /// - Parameter delegate: Delegate that receives callbacks for the operation. + public func resendCode(delegate: SignUpResendCodeDelegate) { Task { - let result = await resendCodeInternal(correlationId: correlationId) + let result = await resendCodeInternal() switch result { case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): @@ -70,11 +69,10 @@ public class SignUpBaseState: MSALNativeAuthBaseState { /// Submits the code to the server for verification. /// - Parameters: /// - code: Verification code that the user supplies. - /// - correlationId: Optional. UUID to correlate this request with the server for debugging. /// - delegate: Delegate that receives callbacks for the operation. - public func submitCode(code: String, correlationId: UUID? = nil, delegate: SignUpVerifyCodeDelegate) { + public func submitCode(code: String, delegate: SignUpVerifyCodeDelegate) { Task { - let controllerResponse = await submitCodeInternal(code: code, correlationId: correlationId) + let controllerResponse = await submitCodeInternal(code: code) switch controllerResponse.result { case .completed(let state): @@ -110,11 +108,10 @@ public class SignUpBaseState: MSALNativeAuthBaseState { /// Submits the password to the server for verification. /// - Parameters: /// - password: Password that the user supplied. - /// - correlationId: Optional. UUID to correlate this request with the server for debugging. /// - delegate: Delegate that receives callbacks for the operation. - public func submitPassword(password: String, correlationId: UUID? = nil, delegate: SignUpPasswordRequiredDelegate) { + public func submitPassword(password: String, delegate: SignUpPasswordRequiredDelegate) { Task { - let controllerResponse = await submitPasswordInternal(password: password, correlationId: correlationId) + let controllerResponse = await submitPasswordInternal(password: password) switch controllerResponse.result { case .completed(let state): @@ -141,14 +138,12 @@ public class SignUpBaseState: MSALNativeAuthBaseState { /// - Parameters: /// - attributes: Dictionary of attributes that the user supplied. /// - delegate: Delegate that receives callbacks for the operation. - /// - correlationId: Optional. UUID to correlate this request with the server for debugging. public func submitAttributes( attributes: [String: Any], - delegate: SignUpAttributesRequiredDelegate, - correlationId: UUID? = nil + delegate: SignUpAttributesRequiredDelegate ) { Task { - let result = await submitAttributesInternal(attributes: attributes, correlationId: correlationId) + let result = await submitAttributesInternal(attributes: attributes) switch result { case .completed(let state): diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUsernameEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUsernameEndToEndTests.swift index f6a0581918..d9907dc5f0 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUsernameEndToEndTests.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUsernameEndToEndTests.swift @@ -97,7 +97,7 @@ final class MSALNativeAuthSignInUsernameEndToEndTests: MSALNativeAuthEndToEndBas try await mockResponse(.invalidOOBValue, endpoint: .signInToken) } - signInDelegateSpy.newStateCodeRequired?.submitCode(code: "badc0d3", correlationId: correlationId, delegate: signInVerifyCodeDelegateSpy) + signInDelegateSpy.newStateCodeRequired?.submitCode(code: "badc0d3", delegate: signInVerifyCodeDelegateSpy) await fulfillment(of: [verifyCodeExpectation], timeout: 2) @@ -140,7 +140,7 @@ final class MSALNativeAuthSignInUsernameEndToEndTests: MSALNativeAuthEndToEndBas XCTAssertNotEqual(otp, "") } - signInDelegateSpy.newStateCodeRequired?.submitCode(code: otp, correlationId: correlationId, delegate: signInVerifyCodeDelegateSpy) + signInDelegateSpy.newStateCodeRequired?.submitCode(code: otp, delegate: signInVerifyCodeDelegateSpy) await fulfillment(of: [verifyCodeExpectation], timeout: 2) @@ -199,7 +199,7 @@ final class MSALNativeAuthSignInUsernameEndToEndTests: MSALNativeAuthEndToEndBas try await mockResponse(.invalidPassword, endpoint: .signInToken) } - signInDelegateSpy.newStatePasswordRequired?.submitPassword(password: "An Invalid Password", correlationId: correlationId, delegate: signInPasswordRequiredDelegateSpy) + signInDelegateSpy.newStatePasswordRequired?.submitPassword(password: "An Invalid Password", delegate: signInPasswordRequiredDelegateSpy) await fulfillment(of: [passwordRequiredExpectation], timeout: 2) @@ -237,7 +237,7 @@ final class MSALNativeAuthSignInUsernameEndToEndTests: MSALNativeAuthEndToEndBas try await mockResponse(.tokenSuccess, endpoint: .signInToken) } - signInDelegateSpy.newStatePasswordRequired?.submitPassword(password: password, correlationId: correlationId, delegate: signInPasswordRequiredDelegateSpy) + signInDelegateSpy.newStatePasswordRequired?.submitPassword(password: password, delegate: signInPasswordRequiredDelegateSpy) await fulfillment(of: [passwordRequiredExpectation], timeout: 2) diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_out/MSALNativeAuthSignOutEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_out/MSALNativeAuthSignOutEndToEndTests.swift index e3404152f9..5d79a7dd1c 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_out/MSALNativeAuthSignOutEndToEndTests.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_out/MSALNativeAuthSignOutEndToEndTests.swift @@ -59,7 +59,7 @@ final class MSALNativeAuthSignOutEndToEndTests: MSALNativeAuthEndToEndBaseTestCa XCTAssertNotEqual(otp, "") } - signInDelegateSpy.newStateCodeRequired?.submitCode(code: otp, correlationId: correlationId, delegate: signInVerifyCodeDelegateSpy) + signInDelegateSpy.newStateCodeRequired?.submitCode(code: otp, delegate: signInVerifyCodeDelegateSpy) await fulfillment(of: [verifyCodeExpectation], timeout: defaultTimeout) @@ -110,7 +110,7 @@ final class MSALNativeAuthSignOutEndToEndTests: MSALNativeAuthEndToEndBaseTestCa XCTAssertNotEqual(otp, "") } - signInDelegateSpy.newStateCodeRequired?.submitCode(code: otp, correlationId: correlationId, delegate: signInVerifyCodeDelegateSpy) + signInDelegateSpy.newStateCodeRequired?.submitCode(code: otp, delegate: signInVerifyCodeDelegateSpy) await fulfillment(of: [verifyCodeExpectation], timeout: defaultTimeout) diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift index 06b9cb5474..1307d4cc75 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift @@ -64,7 +64,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) } - signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + signUpStartDelegate.newState?.submitCode(code: "1234", delegate: signUpVerifyCodeDelegate) await fulfillment(of: [signUpCompleteExp], timeout: defaultTimeout) XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpCompletedCalled) @@ -78,7 +78,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.tokenSuccess, endpoint: .signInToken) } - signUpVerifyCodeDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + signUpVerifyCodeDelegate.signInAfterSignUpState?.signIn(delegate: signInAfterSignUpDelegate) await fulfillment(of: [signInExp], timeout: defaultTimeout) checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) @@ -114,7 +114,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) } - signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + signUpStartDelegate.newState?.submitCode(code: "1234", delegate: signUpVerifyCodeDelegate) await fulfillment(of: [signUpCompleteExp], timeout: defaultTimeout) XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpCompletedCalled) @@ -128,7 +128,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.tokenSuccess, endpoint: .signInToken) } - signUpVerifyCodeDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + signUpVerifyCodeDelegate.signInAfterSignUpState?.signIn(delegate: signInAfterSignUpDelegate) await fulfillment(of: [signInExp], timeout: defaultTimeout) checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) @@ -164,7 +164,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.challengeTypePassword, endpoint: .signUpChallenge) } - signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + signUpStartDelegate.newState?.submitCode(code: "1234", delegate: signUpVerifyCodeDelegate) await fulfillment(of: [credentialRequiredExp], timeout: defaultTimeout) XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpPasswordRequiredCalled) @@ -180,7 +180,6 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth signUpVerifyCodeDelegate.passwordRequiredState?.submitPassword( password: "1234", - correlationId: correlationId, delegate: signUpPasswordDelegate ) @@ -196,7 +195,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.tokenSuccess, endpoint: .signInToken) } - signUpPasswordDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + signUpPasswordDelegate.signInAfterSignUpState?.signIn(delegate: signInAfterSignUpDelegate) await fulfillment(of: [signInExp], timeout: defaultTimeout) checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) @@ -232,7 +231,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.challengeTypePassword, endpoint: .signUpChallenge) } - signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + signUpStartDelegate.newState?.submitCode(code: "1234", delegate: signUpVerifyCodeDelegate) await fulfillment(of: [submitCodeExp], timeout: defaultTimeout) XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpPasswordRequiredCalled) @@ -248,7 +247,6 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth signUpVerifyCodeDelegate.passwordRequiredState?.submitPassword( password: "1234", - correlationId: correlationId, delegate: signUpPasswordDelegate ) @@ -266,8 +264,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth signUpPasswordDelegate.attributesRequiredState?.submitAttributes( attributes: attributes, - delegate: signUpAttributesRequiredDelegate, - correlationId: correlationId + delegate: signUpAttributesRequiredDelegate ) await fulfillment(of: [attributesRequiredExp], timeout: defaultTimeout) @@ -282,7 +279,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.tokenSuccess, endpoint: .signInToken) } - signUpAttributesRequiredDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + signUpAttributesRequiredDelegate.signInAfterSignUpState?.signIn(delegate: signInAfterSignUpDelegate) await fulfillment(of: [signInExp], timeout: defaultTimeout) checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) @@ -318,7 +315,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.challengeTypePassword, endpoint: .signUpChallenge) } - signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + signUpStartDelegate.newState?.submitCode(code: "1234", delegate: signUpVerifyCodeDelegate) await fulfillment(of: [submitCodeExp], timeout: defaultTimeout) XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpPasswordRequiredCalled) @@ -334,7 +331,6 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth signUpVerifyCodeDelegate.passwordRequiredState?.submitPassword( password: "1234", - correlationId: correlationId, delegate: signUpPasswordDelegate ) @@ -352,8 +348,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth signUpPasswordDelegate.attributesRequiredState?.submitAttributes( attributes: attributes, - delegate: signUpAttributesRequiredDelegate, - correlationId: correlationId + delegate: signUpAttributesRequiredDelegate ) await fulfillment(of: [attributesRequiredExp2], timeout: defaultTimeout) @@ -370,8 +365,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth signUpAttributesRequiredDelegate.attributesRequiredState?.submitAttributes( attributes: attributes, - delegate: signUpAttributesRequiredDelegate, - correlationId: correlationId + delegate: signUpAttributesRequiredDelegate ) await fulfillment(of: [signUpCompleteExp], timeout: defaultTimeout) @@ -386,7 +380,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.tokenSuccess, endpoint: .signInToken) } - signUpAttributesRequiredDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + signUpAttributesRequiredDelegate.signInAfterSignUpState?.signIn(delegate: signInAfterSignUpDelegate) await fulfillment(of: [signInExp], timeout: defaultTimeout) checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) @@ -421,7 +415,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) } - signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + signUpStartDelegate.newState?.submitCode(code: "1234", delegate: signUpVerifyCodeDelegate) await fulfillment(of: [signUpCompleteExp], timeout: defaultTimeout) XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpCompletedCalled) diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameEndToEndTests.swift index 45ca955440..a49b951761 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameEndToEndTests.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameEndToEndTests.swift @@ -59,7 +59,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) } - signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + signUpStartDelegate.newState?.submitCode(code: "1234", delegate: signUpVerifyCodeDelegate) await fulfillment(of: [signUpCompleteExp], timeout: defaultTimeout) XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpCompletedCalled) @@ -73,7 +73,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas try await mockResponse(.tokenSuccess, endpoint: .signInToken) } - signUpVerifyCodeDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + signUpVerifyCodeDelegate.signInAfterSignUpState?.signIn(delegate: signInAfterSignUpDelegate) await fulfillment(of: [signInExp], timeout: defaultTimeout) checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) @@ -103,7 +103,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) } - signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + signUpStartDelegate.newState?.submitCode(code: "1234", delegate: signUpVerifyCodeDelegate) await fulfillment(of: [signUpCompleteExp], timeout: defaultTimeout) XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpCompletedCalled) @@ -117,7 +117,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas try await mockResponse(.tokenSuccess, endpoint: .signInToken) } - signUpVerifyCodeDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + signUpVerifyCodeDelegate.signInAfterSignUpState?.signIn(delegate: signInAfterSignUpDelegate) await fulfillment(of: [signInExp], timeout: defaultTimeout) checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) @@ -147,7 +147,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas try await mockResponse(.attributesRequired, endpoint: .signUpContinue) } - signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + signUpStartDelegate.newState?.submitCode(code: "1234", delegate: signUpVerifyCodeDelegate) await fulfillment(of: [submitCodeExp], timeout: defaultTimeout) XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpAttributesRequiredCalled) @@ -163,8 +163,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas signUpVerifyCodeDelegate.attributesRequiredNewState?.submitAttributes( attributes: attributes, - delegate: signUpAttributesRequiredDelegate, - correlationId: correlationId + delegate: signUpAttributesRequiredDelegate ) await fulfillment(of: [attributesExp], timeout: defaultTimeout) @@ -179,7 +178,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas try await mockResponse(.tokenSuccess, endpoint: .signInToken) } - signUpAttributesRequiredDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + signUpAttributesRequiredDelegate.signInAfterSignUpState?.signIn(delegate: signInAfterSignUpDelegate) await fulfillment(of: [signInExp], timeout: defaultTimeout) checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) @@ -209,7 +208,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas try await mockResponse(.attributesRequired, endpoint: .signUpContinue) } - signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + signUpStartDelegate.newState?.submitCode(code: "1234", delegate: signUpVerifyCodeDelegate) await fulfillment(of: [submitCodeExp], timeout: defaultTimeout) XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpAttributesRequiredCalled) @@ -225,8 +224,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas signUpVerifyCodeDelegate.attributesRequiredNewState?.submitAttributes( attributes: attributes, - delegate: signUpAttributesRequiredDelegate, - correlationId: correlationId + delegate: signUpAttributesRequiredDelegate ) await fulfillment(of: [submitAttributesExp1], timeout: defaultTimeout) @@ -243,8 +241,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas signUpAttributesRequiredDelegate.attributesRequiredState?.submitAttributes( attributes: attributes, - delegate: signUpAttributesRequiredDelegate, - correlationId: correlationId + delegate: signUpAttributesRequiredDelegate ) await fulfillment(of: [submitAttributesExp2], timeout: defaultTimeout) @@ -259,7 +256,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas try await mockResponse(.tokenSuccess, endpoint: .signInToken) } - signUpAttributesRequiredDelegate.signInAfterSignUpState?.signIn(correlationId: correlationId, delegate: signInAfterSignUpDelegate) + signUpAttributesRequiredDelegate.signInAfterSignUpState?.signIn(delegate: signInAfterSignUpDelegate) await fulfillment(of: [signInExp], timeout: defaultTimeout) checkSignInAfterSignUpDelegate(signInAfterSignUpDelegate) @@ -289,7 +286,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas try await mockResponse(.signUpContinueSuccess, endpoint: .signUpContinue) } - signUpStartDelegate.newState?.submitCode(code: "1234", correlationId: correlationId, delegate: signUpVerifyCodeDelegate) + signUpStartDelegate.newState?.submitCode(code: "1234", delegate: signUpVerifyCodeDelegate) await fulfillment(of: [signUpCompleteExp], timeout: defaultTimeout) XCTAssertTrue(signUpVerifyCodeDelegate.onSignUpCompletedCalled) diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthBaseControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthBaseControllerTests.swift index 2f96fa411e..ada9c8301d 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthBaseControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthBaseControllerTests.swift @@ -241,8 +241,7 @@ final class MSALNativeAuthBaseControllerTests: MSALNativeAuthTestCase { } func test_performRequest_withSuccess() async { - let request = MSIDHttpRequest() - HttpModuleMockConfigurator.configure(request: request, responseJson: ["response"]) + let request = MSALNativeAuthHTTPRequestMock.prepareMockRequest(responseJson: ["response"]) let result: Result<[String], Error> = await sut.performRequest(request, context: contextMock) @@ -255,8 +254,7 @@ final class MSALNativeAuthBaseControllerTests: MSALNativeAuthTestCase { } func test_performRequest_withUnexpectedError() async { - let request = MSIDHttpRequest() - HttpModuleMockConfigurator.configure(request: request, responseJson: [nil] as [Any?]) + let request = MSALNativeAuthHTTPRequestMock.prepareMockRequest(responseJson: [nil]) let result: Result<[String], Error> = await sut.performRequest(request, context: contextMock) diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift index 001508aa91..30f0614b45 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift @@ -115,7 +115,7 @@ final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase { let authTokens = MSALNativeAuthUserAccountResultStub.authTokens requestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, credentialToken: nil, signInSLT: nil, grantType: MSALNativeAuthGrantType.refreshToken, scope: "" , password: nil, oobCode: nil, includeChallengeType: true, refreshToken: "refreshToken") - requestProviderMock.throwingTokenError = ErrorMock.error + requestProviderMock.throwingRefreshTokenError = ErrorMock.error let helper = CredentialsTestValidatorHelper(expectation: expectation, expectedError: RetrieveAccessTokenError(type: .generalError)) @@ -135,12 +135,9 @@ final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase { authTokens: authTokens, configuration: MSALNativeAuthConfigStubs.configuration, cacheAccessor: MSALNativeAuthCacheAccessorMock()) - let request = MSIDHttpRequest() let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - - requestProviderMock.result = request + requestProviderMock.mockRequestRefreshTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) let expectedAccessToken = "accessToken" let helper = CredentialsTestValidatorHelper(expectation: expectation, expectedAccessToken: expectedAccessToken) @@ -174,15 +171,12 @@ final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase { } private func checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError, validatorError: MSALNativeAuthTokenValidatedErrorType) async { - let request = MSIDHttpRequest() let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let authTokens = MSALNativeAuthUserAccountResultStub.authTokens - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - let expectation = expectation(description: "CredentialsController") - requestProviderMock.result = request + requestProviderMock.mockRequestRefreshTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) let helper = CredentialsTestValidatorHelper(expectation: expectation, expectedError: publicError) responseValidatorMock.tokenValidatedResponse = .error(validatorError) diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift index e94b73e56f..21089c6f77 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift @@ -79,10 +79,10 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordStart_returnsSuccess_it_callsChallenge() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError) _ = prepareResetPasswordStartValidatorHelper() @@ -93,7 +93,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordStartPassword_returns_redirect_it_returnsBrowserRequiredError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams validatorMock.mockValidateResetPasswordStartFunc(.redirect) @@ -115,7 +115,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordStart_returns_error_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams validatorMock.mockValidateResetPasswordStartFunc(.error(.userNotFound(message: nil))) @@ -137,7 +137,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenValidatorInResetPasswordStart_returns_unexpectedError_it_returnsGeneralError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams validatorMock.mockValidateResetPasswordStartFunc(.unexpectedError) @@ -161,7 +161,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { // MARK: - ResetPasswordStart (/challenge request) tests func test_whenResetPasswordStart_challenge_cantCreateRequest_it_returns_unexpectedError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) @@ -185,10 +185,10 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordStart_challenge_succeeds_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateResetPasswordChallengeFunc(.success("sentTo", .email, 4, "resetPasswordToken")) @@ -210,10 +210,10 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordStart_challenge_returns_redirect_it_returnsRedirectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateResetPasswordChallengeFunc(.redirect) @@ -235,10 +235,10 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordStart_challenge_returns_error_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() let error : MSALNativeAuthResetPasswordChallengeValidatedResponse = .error( MSALNativeAuthResetPasswordChallengeResponseError(error: .expiredToken, @@ -268,10 +268,10 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenValidatorInResetPasswordStart_challenge_returns_unexpectedError_it_returnsGeneralError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError) @@ -315,7 +315,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordResendCode_succeeds_it_returnsResetPasswordResendCodeRequired() async { - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateResetPasswordChallengeFunc(.success("sentTo", .email, 4, "flowToken response")) @@ -338,7 +338,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordResendCode_returns_error_it_returnsCorrectError() async { - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() let error : MSALNativeAuthResetPasswordChallengeValidatedResponse = .error( MSALNativeAuthResetPasswordChallengeResponseError(error: .invalidRequest, @@ -366,7 +366,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordResendCode_returns_redirect_it_returnsCorrectError() async { - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateResetPasswordChallengeFunc(.redirect) @@ -387,7 +387,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordResendCode_returns_unexpectedError_it_returnsCorrectError() async { - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError) @@ -429,7 +429,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordSubmitCode_succeeds_it_returnsPasswordRequired() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() validatorMock.mockValidateResetPasswordContinueFunc(.success(passwordSubmitToken: "")) @@ -449,7 +449,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordSubmitCode_returns_invalidOOB_it_returnsInvalidCode() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() validatorMock.mockValidateResetPasswordContinueFunc(.invalidOOB) @@ -469,7 +469,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordSubmitCode_returns_error_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() let error : MSALNativeAuthResetPasswordContinueValidatedResponse = .error( MSALNativeAuthResetPasswordContinueResponseError(error: .invalidRequest, @@ -497,7 +497,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordSubmitCode_returns_unexpectedError_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() validatorMock.mockValidateResetPasswordContinueFunc(.unexpectedError) @@ -537,10 +537,10 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenSubmitPassword_succeeds_it_returnsCompleted() async { - requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) - requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .succeeded)) @@ -559,7 +559,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordSubmitPassword_returns_passwordError_it_returnsCorrectError() async { - requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() let error : MSALNativeAuthResetPasswordSubmitValidatedResponse = .passwordError(error: MSALNativeAuthResetPasswordSubmitResponseError(error: .passwordTooWeak, @@ -586,7 +586,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordSubmitPassword_returns_error_it_returnsCorrectError() async { - requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() let error : MSALNativeAuthResetPasswordSubmitValidatedResponse = .error( MSALNativeAuthResetPasswordSubmitResponseError(error: .invalidRequest, @@ -612,7 +612,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenResetPasswordSubmitPassword_returns_unexpectedError_it_returnsCorrectError() async { - requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() validatorMock.mockValidateResetPasswordSubmitFunc(.unexpectedError) @@ -633,10 +633,10 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { // MARK: - SubmitPassword - poll completion tests func test_whenSubmitPassword_pollCompletion_returns_failed_it_returnsResetPasswordRequiredError() async { - requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) - requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() validatorMock.mockValidateResetPasswordPollCompletionFunc(.unexpectedError) @@ -654,10 +654,10 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenSubmitPassword_pollCompletion_returns_unexpectedError_it_returnsCorrectError() async { - requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) - requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() validatorMock.mockValidateResetPasswordPollCompletionFunc(.unexpectedError) @@ -675,10 +675,10 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenSubmitPassword_pollCompletion_returns_passwordError_it_returnsCorrectError() async { - requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) - requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() let error : MSALNativeAuthResetPasswordPollCompletionValidatedResponse = .passwordError(error: @@ -707,10 +707,10 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenSubmitPassword_pollCompletion_returns_error_it_returnsCorrectError() async { - requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) - requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() let error : MSALNativeAuthResetPasswordPollCompletionValidatedResponse = .error( MSALNativeAuthResetPasswordPollCompletionResponseError(error: .expiredToken, @@ -736,10 +736,10 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenSubmitPassword_pollCompletion_returns_notStarted_it_returnsCorrectErrorAfterRetries() async { - requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 1)) - requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .notStarted)) @@ -760,10 +760,10 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenSubmitPassword_pollCompletion_returns_failed_it_returnsError() async { - requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) - requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .failed)) @@ -783,10 +783,10 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { } func test_whenSubmitPassword_pollCompletion_returns_inProgress_it_returnsErrorAfterRetries() async { - requestProviderMock.mockSubmitRequestFunc(prepareMockRequest()) + requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) - requestProviderMock.mockPollCompletionRequestFunc(prepareMockRequest()) + requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .inProgress)) @@ -908,16 +908,9 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { passwordResetToken: token) } - private func prepareMockRequest() -> MSIDHttpRequest { - let request = MSIDHttpRequest() - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - - return request - } - private func prepareMockRequestsForPollCompletionRetries(_ count: Int) { for _ in 1...count { - _ = prepareMockRequest() + _ = MSALNativeAuthHTTPRequestMock.prepareMockRequest() } } } diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift index 680ff9f9d2..9d337a2465 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift @@ -94,26 +94,21 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { func test_whenUserSpecifiesScope_defaultScopesShouldBeIncluded() async throws { let expectation = expectation(description: "SignInController") - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectedScopes = "scope1 scope2 openid profile offline_access" let credentialToken = "credentialToken" - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) - - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername signInRequestProviderMock.expectedCredentialToken = credentialToken signInRequestProviderMock.expectedContext = expectedContext - tokenRequestProviderMock.result = request + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: expectedScopes, password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInPasswordStartError(type: .generalError)) @@ -128,20 +123,16 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { func test_whenUserSpecifiesScopes_NoDuplicatedScopeShouldBeSent() async throws { let expectation = expectation(description: "SignInController") - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectedScopes = "scope1 openid profile offline_access" let credentialToken = "credentialToken" - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) - - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername signInRequestProviderMock.expectedCredentialToken = credentialToken signInRequestProviderMock.expectedContext = expectedContext @@ -159,7 +150,6 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_successfulResponseAndValidation_shouldCompleteSignIn() async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) @@ -167,19 +157,16 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectation = expectation(description: "SignInController") - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername signInRequestProviderMock.expectedCredentialToken = credentialToken signInRequestProviderMock.expectedContext = expectedContext - tokenRequestProviderMock.result = request + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedUsername = expectedUsername tokenRequestProviderMock.expectedContext = expectedContext @@ -200,7 +187,6 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_successfulResponseAndUnsuccessfulValidation_shouldReturnError() async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) @@ -208,19 +194,16 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectation = expectation(description: "SignInController") - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername signInRequestProviderMock.expectedCredentialToken = credentialToken signInRequestProviderMock.expectedContext = expectedContext - tokenRequestProviderMock.result = request + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedUsername = expectedUsername tokenRequestProviderMock.expectedContext = expectedContext @@ -240,7 +223,6 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_errorResponse_shouldReturnError() async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) @@ -248,18 +230,15 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectation = expectation(description: "SignInController") - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) signInResponseValidatorMock.challengeValidatedResponse = .error(.invalidToken(message: nil)) - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername signInRequestProviderMock.expectedContext = expectedContext - tokenRequestProviderMock.result = request + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedUsername = expectedUsername tokenRequestProviderMock.expectedContext = expectedContext @@ -292,25 +271,21 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_whenCredentialsAreRequired_browserRequiredErrorIsReturned() async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let credentialToken = "credentialToken" - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername signInRequestProviderMock.expectedCredentialToken = credentialToken signInRequestProviderMock.expectedContext = expectedContext - tokenRequestProviderMock.result = request + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedCredentialToken = credentialToken let expectation = expectation(description: "SignInController") @@ -328,7 +303,6 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_whenSignInUsingPassword_apiReturnsChallengeTypeOOB_codeRequiredShouldBeCalled() async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedPassword = "password" let expectedSentTo = "sentTo" @@ -339,13 +313,11 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectation = expectation(description: "SignInController") - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: expectedSentTo, channelType: expectedChannelTargetType, codeLength: expectedCodeLength) - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername signInRequestProviderMock.expectedCredentialToken = credentialToken signInRequestProviderMock.expectedContext = expectedContext @@ -365,7 +337,6 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_whenSignInUsingPassword_apiReturnsChallengeTypeOOB__butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedPassword = "password" let expectedSentTo = "sentTo" @@ -376,13 +347,11 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectation = expectation(description: "SignInController") - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: expectedSentTo, channelType: expectedChannelTargetType, codeLength: expectedCodeLength) - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername signInRequestProviderMock.expectedCredentialToken = credentialToken signInRequestProviderMock.expectedContext = expectedContext @@ -404,7 +373,6 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { // MARK: sign in with username and code func test_whenSignInWithCodeStartWithValidInfo_codeRequiredShouldBeCalled() async { - let request = MSIDHttpRequest() let expectedUsername = "username" let sentTo = "sentTo" let channelTargetType = MSALNativeAuthChannelType.email @@ -412,12 +380,10 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let credentialToken = "credentialToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - let expectation = expectation(description: "SignInController") - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername signInRequestProviderMock.expectedCredentialToken = credentialToken signInRequestProviderMock.expectedContext = expectedContext @@ -436,15 +402,12 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_afterSignInWithCodeSubmitCode_signInShouldCompleteSuccessfully() { - let request = MSIDHttpRequest() let credentialToken = "credentialToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - let expectation = expectation(description: "SignInController") - tokenRequestProviderMock.result = request + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.oobCode, scope: defaultScopes, password: nil, oobCode: "code", includeChallengeType: false, refreshToken: nil) @@ -453,8 +416,8 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { cacheAccessorMock.mockUserAccounts = [MSALNativeAuthUserAccountResultStub.account] cacheAccessorMock.expectedMSIDTokenResult = tokenResult - let state = SignInCodeRequiredState(scopes: ["openid","profile","offline_access"], controller: sut, inputValidator: MSALNativeAuthInputValidator(), flowToken: credentialToken) - state.submitCode(code: "code", correlationId: defaultUUID, delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedUserAccountResult: userAccountResult)) + let state = SignInCodeRequiredState(scopes: ["openid","profile","offline_access"], controller: sut, inputValidator: MSALNativeAuthInputValidator(), flowToken: credentialToken, correlationId: defaultUUID) + state.submitCode(code: "code", delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedUserAccountResult: userAccountResult)) wait(for: [expectation], timeout: 1) XCTAssertTrue(cacheAccessorMock.clearCacheWasCalled) @@ -463,23 +426,20 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_afterSignInWithCodeSubmitCode_whenTokenCacheIsNotValid_it_shouldReturnCorrectError() { - let request = MSIDHttpRequest() let credentialToken = "credentialToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - let expectation = expectation(description: "SignInController") - tokenRequestProviderMock.result = request + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.oobCode, scope: defaultScopes, password: nil, oobCode: "code", includeChallengeType: false, refreshToken: nil) tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) cacheAccessorMock.expectedMSIDTokenResult = nil - let state = SignInCodeRequiredState(scopes: ["openid","profile","offline_access"], controller: sut, inputValidator: MSALNativeAuthInputValidator(), flowToken: credentialToken) - state.submitCode(code: "code", correlationId: defaultUUID, delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedError: VerifyCodeError(type: .generalError))) + let state = SignInCodeRequiredState(scopes: ["openid","profile","offline_access"], controller: sut, inputValidator: MSALNativeAuthInputValidator(), flowToken: credentialToken, correlationId: defaultUUID) + state.submitCode(code: "code", delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedError: VerifyCodeError(type: .generalError))) wait(for: [expectation], timeout: 1) @@ -516,15 +476,12 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_whenSignInWithCodeChallengeRequestCreationFail_errorShouldBeReturned() async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - let expectation = expectation(description: "SignInController") - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.throwingChallengeError = MSALNativeAuthError() signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: "credentialToken") @@ -550,17 +507,14 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_whenSignInWithCodePasswordIsRequired_newStateIsPropagatedToUser() async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedCredentialToken = "credentialToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) let expectation = expectation(description: "SignInController") - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: expectedCredentialToken) signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: expectedCredentialToken) @@ -577,17 +531,14 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_whenSignInWithCodePasswordIsRequired_newStateIsPropagatedToUser_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedCredentialToken = "credentialToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - let expectation = expectation(description: "SignInController") - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: expectedCredentialToken) signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: expectedCredentialToken) @@ -604,17 +555,14 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_whenSignInWithCodeSubmitPassword_signInIsCompletedSuccessfully() async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedPassword = "password" let expectedCredentialToken = "credentialToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - let exp = expectation(description: "SignInController") - tokenRequestProviderMock.result = request + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: expectedCredentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: "", password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) @@ -624,8 +572,8 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { cacheAccessorMock.mockUserAccounts = [MSALNativeAuthUserAccountResultStub.account] cacheAccessorMock.expectedMSIDTokenResult = tokenResult - let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken) - state.submitPassword(password: expectedPassword, correlationId: defaultUUID, delegate: mockDelegate) + let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken, correlationId: defaultUUID) + state.submitPassword(password: expectedPassword, delegate: mockDelegate) await fulfillment(of: [exp], timeout: 1) @@ -635,17 +583,14 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_whenSignInWithCodeSubmitPassword_whenTokenCacheIsNotValid_it_shouldReturnCorrectError() async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedPassword = "password" let expectedCredentialToken = "credentialToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - let exp = expectation(description: "SignInController") - tokenRequestProviderMock.result = request + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: expectedCredentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: "", password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) @@ -654,22 +599,19 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { tokenResponseValidatorMock.expectedTokenResponse = tokenResponse cacheAccessorMock.expectedMSIDTokenResult = nil - let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken) - state.submitPassword(password: expectedPassword, correlationId: defaultUUID, delegate: mockDelegate) + let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken, correlationId: defaultUUID) + state.submitPassword(password: expectedPassword, delegate: mockDelegate) await fulfillment(of: [exp], timeout: 1) checkTelemetryEventResult(id: .telemetryApiIdSignInSubmitPassword, isSuccessful: false) } func test_whenSignInWithCodeSubmitPasswordTokenRequestCreationFail_errorShouldBeReturned() async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedPassword = "password" let expectedCredentialToken = "credentialToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - let exp = expectation(description: "SignInController") tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError() @@ -677,8 +619,8 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: PasswordRequiredError(type: .generalError)) - let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken) - state.submitPassword(password: expectedPassword, correlationId: defaultUUID, delegate: mockDelegate) + let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken, correlationId: defaultUUID) + state.submitPassword(password: expectedPassword, delegate: mockDelegate) await fulfillment(of: [exp], timeout: 1) XCTAssertNotNil(mockDelegate.newPasswordRequiredState) @@ -711,8 +653,8 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { signInRequestProviderMock.expectedContext = expectedContext tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError() - let state = SignInCodeRequiredState(scopes: [], controller: sut, flowToken: credentialToken) - state.submitCode(code: "code", correlationId: defaultUUID, delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedError: VerifyCodeError(type: .generalError))) + let state = SignInCodeRequiredState(scopes: [], controller: sut, flowToken: credentialToken, correlationId: defaultUUID) + state.submitCode(code: "code", delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedError: VerifyCodeError(type: .generalError))) wait(for: [expectation], timeout: 1) XCTAssertFalse(cacheAccessorMock.validateAndSaveTokensWasCalled) @@ -736,19 +678,16 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_signInWithCodeResendCode_shouldSendNewCode() async { - let request = MSIDHttpRequest() let expectedUsername = "username" let sentTo = "sentTo" let channelTargetType = MSALNativeAuthChannelType.email let codeLength = 4 let credentialToken = "credentialToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) let expectation = expectation(description: "SignInController") - signInRequestProviderMock.result = request + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername signInRequestProviderMock.expectedCredentialToken = credentialToken signInRequestProviderMock.expectedContext = expectedContext @@ -784,15 +723,12 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_signInWithCodeResendCodePasswordRequired_shouldReturnAnError() async { - let request = MSIDHttpRequest() let credentialToken = "credentialToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) let expectation = expectation(description: "SignInController") - signInRequestProviderMock.result = request + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedContext = expectedContext let helper = SignInResendCodeTestsValidatorHelper(expectation: expectation) @@ -809,15 +745,12 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_signInWithCodeResendCodeChallengeReturnError_shouldReturnAnError() async { - let request = MSIDHttpRequest() let credentialToken = "credentialToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) let expectation = expectation(description: "SignInController") - signInRequestProviderMock.result = request + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedContext = expectedContext let helper = SignInResendCodeTestsValidatorHelper(expectation: expectation) @@ -837,15 +770,12 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { // MARK: signIn using SLT func test_whenSignInWithSLT_signInIsCompletedSuccessfully() { - let request = MSIDHttpRequest() let slt = "signInSLT" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - let expectation = expectation(description: "SignInController") - tokenRequestProviderMock.result = request + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: "", credentialToken: nil, signInSLT: slt, grantType: .slt, scope: defaultScopes, password: nil, oobCode: nil, includeChallengeType: false, refreshToken: nil) @@ -856,8 +786,8 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { cacheAccessorMock.expectedMSIDTokenResult = tokenResult - let state = SignInAfterSignUpState(controller: sut, username: "", slt: slt) - state.signIn(correlationId: defaultUUID, delegate: mockDelegate) + let state = SignInAfterSignUpState(controller: sut, username: "", slt: slt, correlationId: defaultUUID) + state.signIn(delegate: mockDelegate) wait(for: [expectation], timeout: 1) XCTAssertTrue(cacheAccessorMock.validateAndSaveTokensWasCalled) @@ -865,12 +795,9 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_whenSignInWithSLTTokenRequestCreationFail_errorShouldBeReturned() { - let request = MSIDHttpRequest() let slt = "signInSLT" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - let exp = expectation(description: "SignInController") tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError() @@ -878,8 +805,8 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: exp, expectedError: SignInAfterSignUpError()) - let state = SignInAfterSignUpState(controller: sut, username: "", slt: slt) - state.signIn(correlationId: defaultUUID, delegate: mockDelegate) + let state = SignInAfterSignUpState(controller: sut, username: "", slt: slt, correlationId: defaultUUID) + state.signIn(delegate: mockDelegate) wait(for: [exp], timeout: 1) XCTAssertFalse(cacheAccessorMock.validateAndSaveTokensWasCalled) @@ -887,23 +814,20 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_whenSignInWithSLTTokenReturnError_shouldReturnAnError() { - let request = MSIDHttpRequest() let slt = "signInSLT" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) let expectation = expectation(description: "SignInController") - tokenRequestProviderMock.result = request + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: expectation, expectedError: SignInAfterSignUpError(message: "Invalid Client ID")) tokenResponseValidatorMock.tokenValidatedResponse = .error(.invalidClient(message: "Invalid Client ID")) - let state = SignInAfterSignUpState(controller: sut, username: "", slt: slt) - state.signIn(correlationId: defaultUUID, delegate: mockDelegate) + let state = SignInAfterSignUpState(controller: sut, username: "", slt: slt, correlationId: defaultUUID) + state.signIn(delegate: mockDelegate) wait(for: [expectation], timeout: 1) XCTAssertFalse(cacheAccessorMock.validateAndSaveTokensWasCalled) @@ -915,8 +839,8 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: expectation, expectedError: SignInAfterSignUpError(message: "Sign In is not available at this point, please use the standalone sign in methods")) - let state = SignInAfterSignUpState(controller: sut, username: "username", slt: nil) - state.signIn(correlationId: defaultUUID, delegate: mockDelegate) + let state = SignInAfterSignUpState(controller: sut, username: "username", slt: nil, correlationId: defaultUUID) + state.signIn(delegate: mockDelegate) wait(for: [expectation], timeout: 1) XCTAssertFalse(cacheAccessorMock.validateAndSaveTokensWasCalled) @@ -927,23 +851,20 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { // MARK: private methods private func checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: VerifyCodeErrorType, validatorError: MSALNativeAuthTokenValidatedErrorType) { - let request = MSIDHttpRequest() let expectedCredentialToken = "credentialToken" let expectedOOBCode = "code" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - let exp = expectation(description: "SignInController") - tokenRequestProviderMock.result = request + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, credentialToken: expectedCredentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.oobCode, scope: "", password: nil, oobCode: expectedOOBCode, includeChallengeType: true, refreshToken: nil) let mockDelegate = SignInVerifyCodeDelegateSpy(expectation: exp, expectedError: VerifyCodeError(type: delegateError)) tokenResponseValidatorMock.tokenValidatedResponse = .error(validatorError) - let state = SignInCodeRequiredState(scopes: [], controller: sut, flowToken: expectedCredentialToken) - state.submitCode(code: expectedOOBCode, correlationId: defaultUUID, delegate: mockDelegate) + let state = SignInCodeRequiredState(scopes: [], controller: sut, flowToken: expectedCredentialToken, correlationId: defaultUUID) + state.submitCode(code: expectedOOBCode, delegate: mockDelegate) wait(for: [exp], timeout: 1) XCTAssertFalse(cacheAccessorMock.validateAndSaveTokensWasCalled) @@ -952,24 +873,21 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } private func checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError, validatorError: MSALNativeAuthTokenValidatedErrorType) async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedPassword = "password" let expectedCredentialToken = "credentialToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - let exp = expectation(description: "SignInController") - tokenRequestProviderMock.result = request + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: expectedCredentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: "", password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: publicError) tokenResponseValidatorMock.tokenValidatedResponse = .error(validatorError) - let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken) - state.submitPassword(password: expectedPassword, correlationId: defaultUUID, delegate: mockDelegate) + let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken, correlationId: defaultUUID) + state.submitPassword(password: expectedPassword, delegate: mockDelegate) await fulfillment(of: [exp], timeout: 1) XCTAssertFalse(cacheAccessorMock.validateAndSaveTokensWasCalled) @@ -978,16 +896,13 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } private func checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError, validatorError: MSALNativeAuthSignInChallengeValidatedErrorType) async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) let expectation = expectation(description: "SignInController") - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc((MSALNativeAuthHTTPRequestMock.prepareMockRequest())) + signInRequestProviderMock.mockChallengeRequestFunc((MSALNativeAuthHTTPRequestMock.prepareMockRequest())) signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: "credentialToken") signInResponseValidatorMock.challengeValidatedResponse = .error(validatorError) @@ -1003,17 +918,14 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } private func checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError, validatorError: MSALNativeAuthSignInInitiateValidatedErrorType) async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - let expectation = expectation(description: "SignInController") signInRequestProviderMock.expectedUsername = expectedUsername signInRequestProviderMock.expectedContext = expectedContext - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInResponseValidatorMock.initiateValidatedResponse = .error(validatorError) let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: delegateError) @@ -1028,27 +940,23 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } private func checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError, validatorError: MSALNativeAuthTokenValidatedErrorType) async { - let request = MSIDHttpRequest() let expectedUsername = "username" let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let credentialToken = "credentialToken" - - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) - signInRequestProviderMock.result = request + signInRequestProviderMock.mockInitiateRequestFunc((MSALNativeAuthHTTPRequestMock.prepareMockRequest())) + signInRequestProviderMock.mockChallengeRequestFunc((MSALNativeAuthHTTPRequestMock.prepareMockRequest())) signInRequestProviderMock.expectedUsername = expectedUsername signInRequestProviderMock.expectedCredentialToken = credentialToken signInRequestProviderMock.expectedContext = expectedContext let expectation = expectation(description: "SignInController") - tokenRequestProviderMock.result = request + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: delegateError) tokenResponseValidatorMock.tokenValidatedResponse = .error(validatorError) diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift index 2768d78b34..0e601d7d06 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift @@ -94,10 +94,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartPassword_returnsVerificationRequired_it_returnsChallenge() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -113,7 +113,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartPassword_returnsAttributeValidationFailed_it_returnsChallenge() async { let invalidAttributes = ["name"] - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(invalidAttributes: invalidAttributes)) @@ -138,7 +138,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartPassword_telemetryUpdateFails_it_updatesTelemetryCorrectly() async { let invalidAttributes = ["name"] - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(invalidAttributes: invalidAttributes)) @@ -162,7 +162,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartPassword_returns_redirect_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams validatorMock.mockValidateSignUpStartFunc(.redirect) @@ -184,7 +184,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartPassword_returns_error_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams let error : MSALNativeAuthSignUpStartValidatedResponse = .error( MSALNativeAuthSignUpStartResponseError(error: .passwordTooLong, @@ -215,7 +215,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartPassword_returns_invalidUsername_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams let invalidUsername : MSALNativeAuthSignUpStartValidatedResponse = .invalidUsername( MSALNativeAuthSignUpStartResponseError(error: .invalidRequest, @@ -246,7 +246,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartPassword_returns_invalidClientId_it_returnsGeneralError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams let invalidClientId : MSALNativeAuthSignUpStartValidatedResponse = .invalidClientId( MSALNativeAuthSignUpStartResponseError(error: .invalidRequest, @@ -277,7 +277,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenValidatorInSignUpStartPassword_returns_unexpectedError_it_returnsGeneralError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams validatorMock.mockValidateSignUpStartFunc(.unexpectedError) @@ -301,7 +301,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { // MARK: - SignUpPasswordStart (/challenge request) tests func test_whenSignUpStartPassword_challenge_cantCreateRequest_it_returns_unexpectedError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) @@ -325,10 +325,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartPassword_challenge_succeeds_it_continuesTheFlow() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "signUpToken 2")) @@ -350,10 +350,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartPassword_challenge_returns_passwordRequired_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("")) @@ -375,10 +375,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartPassword_challenge_returns_redirect_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.redirect) @@ -400,10 +400,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartPassword_challenge_returns_error_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() let error : MSALNativeAuthSignUpChallengeValidatedResponse = .error( MSALNativeAuthSignUpChallengeResponseError(error: .expiredToken, @@ -432,10 +432,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenValidatorInSignUpStartPassword_challenge_returns_unexpectedError_it_returnsGeneralError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -480,10 +480,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartCode_returnsVerificationRequired_it_returnsChallenge() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -499,7 +499,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartCode_returnsAttributeValidationFailed_it_returnsCorrectError() async { let invalidAttributes = ["name"] - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(invalidAttributes: invalidAttributes)) @@ -523,7 +523,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartCode_telemetryUpdateFails_it_updatesTelemetryCorrectly() async { let invalidAttributes = ["name"] - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(invalidAttributes: invalidAttributes)) @@ -546,7 +546,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartCode_returns_redirect_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams validatorMock.mockValidateSignUpStartFunc(.redirect) @@ -568,7 +568,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartCode_returns_error_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams let error : MSALNativeAuthSignUpStartValidatedResponse = .error( MSALNativeAuthSignUpStartResponseError(error: .userAlreadyExists, @@ -599,7 +599,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartCode_returns_invalidUsername_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams let invalidUsername : MSALNativeAuthSignUpStartValidatedResponse = .invalidUsername( MSALNativeAuthSignUpStartResponseError(error: .invalidRequest, @@ -630,7 +630,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartCode_returns_invalidClientId_it_returnsGeneralError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams let invalidClientId : MSALNativeAuthSignUpStartValidatedResponse = .invalidClientId( MSALNativeAuthSignUpStartResponseError(error: .invalidRequest, @@ -661,7 +661,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenValidatorInSignUpStartCode_returns_unexpectedError_it_returnsGeneralError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams validatorMock.mockValidateSignUpStartFunc(.unexpectedError) @@ -685,7 +685,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { // MARK: - SignUpCodeStart (/challenge request) tests func test_whenSignUpStartCode_challenge_cantCreateRequest_it_returns_unexpectedError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) @@ -709,10 +709,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartCode_challenge_succeeds_it_continuesTheFlow() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken 1", unverifiedAttributes: [""])) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 1") validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "signUpToken 2")) @@ -734,10 +734,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartCode_challenge_succeedsPassword_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("")) @@ -759,10 +759,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartCode_challenge_returns_redirect_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.redirect) @@ -784,10 +784,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpStartCode_challenge_returns_error_it_returnsCorrectError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() let error : MSALNativeAuthSignUpChallengeValidatedResponse = .error( MSALNativeAuthSignUpChallengeResponseError(error: .expiredToken, @@ -816,10 +816,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenValidatorInSignUpStartCode_challenge_it_returns_unexpectedError_returnsGeneralError() async { - requestProviderMock.mockStartRequestFunc(prepareMockRequest()) + requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -863,7 +863,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpResendCode_succeeds_it_continuesTheFlow() async { - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "signUpToken")) @@ -885,7 +885,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpResendCode_succeedsPassword_it_returnsCorrectError() async { - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("signUpToken 1")) @@ -906,7 +906,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpResendCode_returns_error_it_returnsCorrectError() async { - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() let error : MSALNativeAuthSignUpChallengeValidatedResponse = .error( MSALNativeAuthSignUpChallengeResponseError(error: .invalidRequest, @@ -933,7 +933,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpResendCode_returns_redirect_it_returnsCorrectError() async { - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.redirect) @@ -954,7 +954,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpResendCode_returns_unexpectedError_it_returnsCorrectError() async { - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -997,7 +997,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSubmitCode_succeeds_it_continuesTheFlow() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) validatorMock.mockValidateSignUpContinueFunc(.success("")) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() @@ -1018,7 +1018,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitCode_returns_invalidUserInput_it_returnsInvalidCode() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) let error : MSALNativeAuthSignUpContinueValidatedResponse = .invalidUserInput( MSALNativeAuthSignUpContinueResponseError(error: .invalidOOBValue, errorDescription: nil, @@ -1049,7 +1049,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitCode_returns_attributesRequired_it_returnsAttributesRequired() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(signUpToken: "signUpToken", requiredAttributes: [])) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() @@ -1072,7 +1072,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitCode_returns_attributesRequired_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(signUpToken: "signUpToken", requiredAttributes: [])) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() @@ -1095,7 +1095,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitCode_returns_attributeValidationFailed_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(signUpToken: "signUpToken 2", invalidAttributes: ["name"])) @@ -1116,7 +1116,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitCode_returns_error_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() let error : MSALNativeAuthSignUpContinueValidatedResponse = .error( MSALNativeAuthSignUpContinueResponseError(error: .invalidRequest, @@ -1147,7 +1147,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitCode_returns_unexpectedError_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() validatorMock.mockValidateSignUpContinueFunc(.unexpectedError) @@ -1170,10 +1170,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { // MARK: - SubmitCode + credential_required error tests func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -1192,7 +1192,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andCantCreateRequest() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) @@ -1215,10 +1215,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andSucceeds() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("signUpToken 3")) @@ -1244,10 +1244,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("signUpToken 3")) @@ -1273,10 +1273,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andSucceedOOB_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("", .email, 4, "signUpToken 3")) @@ -1296,10 +1296,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andRedirects() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") validatorMock.mockValidateSignUpChallengeFunc(.redirect) @@ -1322,10 +1322,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andReturnsError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") let error : MSALNativeAuthSignUpChallengeValidatedResponse = .error( MSALNativeAuthSignUpChallengeResponseError(error: .expiredToken, @@ -1354,10 +1354,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andReturnsUnexpectedError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) - requestProviderMock.mockChallengeRequestFunc(prepareMockRequest()) + requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -1401,7 +1401,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSubmitPassword_succeeds_it_continuesTheFlow() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) validatorMock.mockValidateSignUpContinueFunc(.success("signInSLT")) @@ -1421,7 +1421,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitPassword_returns_invalidUserInput_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) let error : MSALNativeAuthSignUpContinueValidatedResponse = .invalidUserInput( MSALNativeAuthSignUpContinueResponseError(error: .passwordTooWeak, @@ -1452,7 +1452,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitPassword_returns_attributesRequired_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(signUpToken: "signUpToken 2", requiredAttributes: [])) @@ -1474,7 +1474,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitPassword_returns_attributesRequired_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(signUpToken: "signUpToken 2", requiredAttributes: [])) @@ -1496,7 +1496,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitPassword_returns_error_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) let error : MSALNativeAuthSignUpContinueValidatedResponse = .error( MSALNativeAuthSignUpContinueResponseError(error: .invalidRequest, @@ -1526,7 +1526,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitPassword_returns_credentialRequired_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) @@ -1546,7 +1546,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitPassword_returns_unexpectedError_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) validatorMock.mockValidateSignUpContinueFunc(.unexpectedError) @@ -1566,7 +1566,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitPassword_returns_attributeValidationFailed_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(signUpToken: "signUpToken 2", invalidAttributes: ["key"])) @@ -1610,7 +1610,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSubmitAttributes_succeeds_it_continuesTheFlow() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( grantType: .attributes, oobCode: nil, @@ -1633,7 +1633,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitAttributes_returns_invalidUserInput_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( grantType: .attributes, oobCode: nil, @@ -1665,7 +1665,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitAttributes_returns_error_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( grantType: .attributes, oobCode: nil, @@ -1697,7 +1697,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitAttributes_returns_attributesRequired_it_returnsAttributesRequiredError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( grantType: .attributes, oobCode: nil, @@ -1719,7 +1719,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitAttributes_returns_credentialRequired_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( grantType: .attributes, oobCode: nil, @@ -1741,7 +1741,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitAttributes_returns_unexpectedError_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( grantType: .attributes, oobCode: nil, @@ -1763,7 +1763,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { } func test_whenSignUpSubmitAttributes_returns_attributeValidationFailed_it_returnsCorrectError() async { - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams( grantType: .attributes, oobCode: nil, @@ -1796,7 +1796,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) {} } - requestProviderMock.mockContinueRequestFunc(prepareMockRequest()) + requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) validatorMock.mockValidateSignUpContinueFunc(.success(slt)) @@ -1919,13 +1919,6 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { return helper } - private func prepareMockRequest() -> MSIDHttpRequest { - let request = MSIDHttpRequest() - HttpModuleMockConfigurator.configure(request: request, responseJson: [""]) - - return request - } - private func expectedChallengeParams(token: String = "signUpToken") -> (token: String, context: MSIDRequestContext) { return (token: token, context: contextMock) } diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthFactoriesMocks.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthFactoriesMocks.swift index f444b88be1..4c7e36d511 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthFactoriesMocks.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthFactoriesMocks.swift @@ -91,3 +91,37 @@ class MSALNativeAuthControllerFactoryMock: MSALNativeAuthControllerBuildable { return credentialsController } } + +class MSALNativeAuthControllerProtocolFactoryMock: MSALNativeAuthControllerBuildable { + + var signUpController: MSALNativeAuthSignUpControlling! + var signInController: MSALNativeAuthSignInControlling! + var resetPasswordController: MSALNativeAuthResetPasswordControlling! + var credentialsController: MSALNativeAuthCredentialsControlling! + + init (signUpController: MSALNativeAuthSignUpControlling = MSALNativeAuthSignUpControllerMock(), + signInController: MSALNativeAuthSignInControlling = MSALNativeAuthSignInControllerMock(), + resetPasswordController: MSALNativeAuthResetPasswordControlling = MSALNativeAuthResetPasswordControllerMock(), + credentialsController: MSALNativeAuthCredentialsControlling = MSALNativeAuthCredentialsControllerMock()) { + self.signUpController = signUpController + self.signInController = signInController + self.resetPasswordController = resetPasswordController + self.credentialsController = credentialsController + } + + func makeSignUpController() -> MSAL.MSALNativeAuthSignUpControlling { + return signUpController + } + + func makeSignInController() -> MSAL.MSALNativeAuthSignInControlling { + return signInController + } + + func makeResetPasswordController() -> MSAL.MSALNativeAuthResetPasswordControlling { + return resetPasswordController + } + + func makeCredentialsController() -> MSAL.MSALNativeAuthCredentialsControlling { + return credentialsController + } +} diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthHTTPRequestMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthHTTPRequestMock.swift new file mode 100644 index 0000000000..94b7c56e9c --- /dev/null +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthHTTPRequestMock.swift @@ -0,0 +1,38 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthHTTPRequestMock { + static func prepareMockRequest(request: MSIDHttpRequest = MSIDHttpRequest(), + response: HTTPURLResponse? = nil, + responseJson: [Any?] = [""]) -> MSIDHttpRequest { + HttpModuleMockConfigurator.configure(request: request, response: response, responseJson: responseJson) + return request + } +} + diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift index d45868031d..21ce6dd4d7 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift @@ -168,18 +168,35 @@ class MSALNativeAuthSignInRequestProviderMock: MSALNativeAuthSignInRequestProvid var throwingInitError: Error? var throwingChallengeError: Error? - var throwingTokenError: Error? - var result: MSIDHttpRequest? + private var requestInitiate: MSIDHttpRequest? + private var requestChallenge: MSIDHttpRequest? + var expectedContext: MSIDRequestContext? var expectedUsername: String? var expectedCredentialToken: String? + func mockInitiateRequestFunc(_ request: MSIDHttpRequest?, throwError: Error? = nil) { + self.requestInitiate = request + self.throwingInitError = throwError + } + func inititate(parameters: MSAL.MSALNativeAuthSignInInitiateRequestParameters, context: MSIDRequestContext) throws -> MSIDHttpRequest { checkContext(context) if let expectedUsername = expectedUsername { XCTAssertEqual(expectedUsername, parameters.username) } - return try returnMockedResult(throwingInitError) + if let request = requestInitiate { + return request + } else if throwingInitError != nil { + throw throwingInitError! + } else { + fatalError("Make sure to use mockInitiateRequestFunc()") + } + } + + func mockChallengeRequestFunc(_ request: MSIDHttpRequest?, throwError: Error? = nil) { + self.requestChallenge = request + self.throwingChallengeError = throwError } func challenge(parameters: MSAL.MSALNativeAuthSignInChallengeRequestParameters, context: MSIDRequestContext) throws -> MSIDHttpRequest { @@ -187,7 +204,13 @@ class MSALNativeAuthSignInRequestProviderMock: MSALNativeAuthSignInRequestProvid if let expectedCredentialToken = expectedCredentialToken { XCTAssertEqual(expectedCredentialToken, parameters.credentialToken) } - return try returnMockedResult(throwingChallengeError) + if let request = requestChallenge { + return request + } else if throwingChallengeError != nil { + throw throwingChallengeError! + } else { + fatalError("Make sure to use mockChallengeRequestFunc()") + } } fileprivate func checkContext(_ context: MSIDRequestContext) { @@ -195,30 +218,24 @@ class MSALNativeAuthSignInRequestProviderMock: MSALNativeAuthSignInRequestProvid XCTAssertEqual(expectedContext.correlationId(), context.correlationId()) } } - - private func returnMockedResult(_ error: Error?) throws -> MSIDHttpRequest { - if let throwingError = error { - throw throwingError - } - if let result = result { - return result - } - XCTFail("Both parameters are nil") - throw ErrorMock.error - } } -class MSALNativeAuthTokenRequestProviderMock: MSALNativeAuthTokenRequestProviding { - - var throwingInitError: Error? - var throwingChallengeError: Error? +class MSALNativeAuthTokenRequestProviderMock: MSALNativeAuthTokenRequestProviding { + + var requestToken: MSIDHttpRequest? + var requestRefreshToken: MSIDHttpRequest? var throwingTokenError: Error? - var result: MSIDHttpRequest? + var throwingRefreshTokenError: Error? var expectedUsername: String? var expectedCredentialToken: String? var expectedContext: MSIDRequestContext? var expectedTokenParams: MSALNativeAuthTokenRequestParameters? + func mockRequestTokenFunc(_ request: MSIDHttpRequest?, throwError: Error? = nil) { + self.requestToken = request + self.throwingTokenError = throwError + } + func signInWithPassword(parameters: MSAL.MSALNativeAuthTokenRequestParameters, context: MSIDRequestContext) throws -> MSIDHttpRequest { checkContext(context) if let expectedTokenParams = expectedTokenParams { @@ -231,7 +248,18 @@ class MSALNativeAuthTokenRequestProviderMock: MSALNativeAuthTokenRequestProvidin XCTAssertEqual(expectedTokenParams.oobCode, parameters.oobCode) XCTAssertEqual(expectedTokenParams.context.correlationId(), parameters.context.correlationId()) } - return try returnMockedResult(throwingTokenError) + if let request = requestToken { + return request + } else if throwingTokenError != nil { + throw throwingTokenError! + } else { + fatalError("Make sure to use mockRequestTokenFunc()") + } + } + + func mockRequestRefreshTokenFunc(_ request: MSIDHttpRequest?, throwError: Error? = nil) { + self.requestRefreshToken = request + self.throwingRefreshTokenError = throwError } func refreshToken(parameters: MSAL.MSALNativeAuthTokenRequestParameters, context: MSIDRequestContext) throws -> MSIDHttpRequest { @@ -246,27 +274,20 @@ class MSALNativeAuthTokenRequestProviderMock: MSALNativeAuthTokenRequestProvidin XCTAssertEqual(expectedTokenParams.oobCode, parameters.oobCode) XCTAssertEqual(expectedTokenParams.context.correlationId(), parameters.context.correlationId()) } - return try returnMockedResult(throwingTokenError) + if let request = requestRefreshToken { + return request + } else if throwingRefreshTokenError != nil { + throw throwingRefreshTokenError! + } else { + fatalError("Make sure to use mockRequestRefreshTokenFunc()") + } } - - fileprivate func checkContext(_ context: MSIDRequestContext) { if let expectedContext = expectedContext { XCTAssertEqual(expectedContext.correlationId(), context.correlationId()) } } - - private func returnMockedResult(_ error: Error?) throws -> MSIDHttpRequest { - if let throwingError = error { - throw throwingError - } - if let result = result { - return result - } - XCTFail("Both parameters are nil") - throw ErrorMock.error - } } class HttpModuleMockConfigurator { diff --git a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift index b267df4cef..1da5af64aa 100644 --- a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift +++ b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift @@ -32,7 +32,8 @@ open class SignInPasswordStartDelegateSpy: SignInPasswordStartDelegate { var expectedSentTo: String? var expectedChannelTargetType: MSALNativeAuthChannelType? var expectedCodeLength: Int? - + private(set) var newSignInCodeRequiredState: SignInCodeRequiredState? + init(expectation: XCTestExpectation, expectedError: SignInPasswordStartError? = nil, expectedUserAccountResult: MSALNativeAuthUserAccountResult? = nil) { self.expectation = expectation self.expectedError = expectedError @@ -53,6 +54,7 @@ open class SignInPasswordStartDelegateSpy: SignInPasswordStartDelegate { public func onSignInCodeRequired(newState: MSAL.SignInCodeRequiredState, sentTo: String, channelTargetType: MSAL.MSALNativeAuthChannelType, codeLength: Int) { XCTAssertTrue(Thread.isMainThread) + newSignInCodeRequiredState = newState expectedSentTo = sentTo expectedChannelTargetType = channelTargetType expectedCodeLength = codeLength @@ -137,7 +139,8 @@ open class SignInCodeStartDelegateSpy: SignInStartDelegate { var expectedCodeLength: Int? var verifyCodeDelegate: SignInVerifyCodeDelegate? var correlationId: UUID? - + private(set) var newSignInCodeRequiredState: SignInCodeRequiredState? + init(expectation: XCTestExpectation, correlationId: UUID? = nil, verifyCodeDelegate: SignInVerifyCodeDelegate? = nil, expectedError: SignInStartError? = nil, expectedSentTo: String? = nil, expectedChannelTargetType: MSALNativeAuthChannelType? = nil, expectedCodeLength: Int? = nil) { self.expectation = expectation self.verifyCodeDelegate = verifyCodeDelegate @@ -156,12 +159,13 @@ open class SignInCodeStartDelegateSpy: SignInStartDelegate { } public func onSignInCodeRequired(newState: SignInCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) { + newSignInCodeRequiredState = newState XCTAssertEqual(sentTo, expectedSentTo) XCTAssertEqual(channelTargetType, expectedChannelTargetType) XCTAssertEqual(codeLength, expectedCodeLength) XCTAssertTrue(Thread.isMainThread) if let verifyCodeDelegate = verifyCodeDelegate { - newState.submitCode(code: "code", correlationId: correlationId, delegate: verifyCodeDelegate) + newState.submitCode(code: "code", delegate: verifyCodeDelegate) } else { expectation.fulfill() } @@ -215,7 +219,8 @@ open class SignInVerifyCodeDelegateSpy: SignInVerifyCodeDelegate { var expectedError: VerifyCodeError? var expectedUserAccountResult: MSALNativeAuthUserAccountResult? var expectedNewState: SignInCodeRequiredState? - + private(set) var onSignInCompletedCalled: Bool = false + init(expectation: XCTestExpectation, expectedError: VerifyCodeError? = nil, expectedUserAccountResult: MSALNativeAuthUserAccountResult? = nil) { self.expectation = expectation self.expectedError = expectedError @@ -232,6 +237,7 @@ open class SignInVerifyCodeDelegateSpy: SignInVerifyCodeDelegate { } public func onSignInCompleted(result: MSALNativeAuthUserAccountResult) { + onSignInCompletedCalled = true guard let expectedUserAccountResult = expectedUserAccountResult else { XCTFail("expectedUserAccountResult expected not nil") expectation.fulfill() @@ -249,7 +255,8 @@ open class SignInAfterSignUpDelegateSpy: SignInAfterSignUpDelegate { private let expectation: XCTestExpectation var expectedError: SignInAfterSignUpError? var expectedUserAccountResult: MSALNativeAuthUserAccountResult? - + private(set) var onSignInCompletedCalled = false + init(expectation: XCTestExpectation, expectedError: SignInAfterSignUpError? = nil, expectedUserAccountResult: MSALNativeAuthUserAccountResult? = nil) { self.expectation = expectation self.expectedError = expectedError @@ -263,6 +270,7 @@ open class SignInAfterSignUpDelegateSpy: SignInAfterSignUpDelegate { } public func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) { + onSignInCompletedCalled = true guard let expectedUserAccountResult = expectedUserAccountResult else { XCTFail("expectedUserAccount expected not nil") expectation.fulfill() diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift index 4d1b15f586..85e7051d9c 100644 --- a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift @@ -32,12 +32,10 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { private var sut: MSALNativeAuthResponseErrorHandler! private let error = NSError(domain:"Test Error Domain", code:400, userInfo:nil) - private var httpRequest: MSIDHttpRequest! private let context = MSALNativeAuthRequestContextMock(correlationId: .init(uuidString: DEFAULT_TEST_UID)!) override func setUpWithError() throws { sut = MSALNativeAuthResponseErrorHandler() - httpRequest = MSIDHttpRequest() try super.setUpWithError() } @@ -73,7 +71,7 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { httpVersion: nil, headerFields: nil ) - HttpModuleMockConfigurator.configure(request: httpRequest, response: httpResponse, responseJson: []) + let httpRequest = MSALNativeAuthHTTPRequestMock.prepareMockRequest(response: httpResponse, responseJson: []) httpRequest.retryCounter = 5 sut.handleError( @@ -85,7 +83,7 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { externalSSOContext: nil, context: context ) { result, error in - XCTAssertEqual(self.httpRequest.retryCounter, 4) + XCTAssertEqual(httpRequest.retryCounter, 4) expectation.fulfill() } wait(for: [expectation], timeout: 1) @@ -101,7 +99,7 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { headerFields: nil ) - HttpModuleMockConfigurator.configure(request: httpRequest, response: httpResponse, responseJson: []) + let httpRequest = MSALNativeAuthHTTPRequestMock.prepareMockRequest(response: httpResponse, responseJson: []) httpRequest.retryCounter = 0 sut.handleError( @@ -138,8 +136,7 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { httpVersion: nil, headerFields: [kMSIDWwwAuthenticateHeader: "PKeyAuth Context=TestContext,Version=1.0"] ) - - HttpModuleMockConfigurator.configure(request: httpRequest, response: httpResponse, responseJson: []) + let httpRequest = MSALNativeAuthHTTPRequestMock.prepareMockRequest(response: httpResponse, responseJson: []) let secondHttpResponse = HTTPURLResponse( url: HttpModuleMockConfigurator.baseUrl, @@ -183,6 +180,8 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { headerFields: nil ) + let httpRequest = MSALNativeAuthHTTPRequestMock.prepareMockRequest() + var dictionary = [String: Any]() dictionary["error"] = "invalid_request" dictionary["error_description"] = "Request parameter validation failed" @@ -225,6 +224,8 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { headerFields: nil ) + let httpRequest = MSALNativeAuthHTTPRequestMock.prepareMockRequest() + var dictionary = [String: Any]() dictionary["error"] = "verification_required" dictionary["error_description"] = "AADSTS55102: Verification required." @@ -266,6 +267,8 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { httpVersion: nil, headerFields: nil ) + + let httpRequest = MSALNativeAuthHTTPRequestMock.prepareMockRequest() let dictionary = [String: Any]() let data = try JSONSerialization.data(withJSONObject: dictionary) @@ -300,6 +303,8 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { headerFields: nil ) + let httpRequest = MSALNativeAuthHTTPRequestMock.prepareMockRequest() + var dictionary = [String: Any]() dictionary["error_key_incorrect"] = "invalid_request" let data = try JSONSerialization.data(withJSONObject: dictionary) @@ -333,6 +338,8 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { httpVersion: nil, headerFields: nil ) + + let httpRequest = MSALNativeAuthHTTPRequestMock.prepareMockRequest() sut.handleError( error, diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestableTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestableTests.swift index d1b3ec9838..5be2a8782c 100644 --- a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestableTests.swift +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestableTests.swift @@ -67,7 +67,7 @@ final class MSALNativeAuthRequestableTests: XCTestCase { } let authority = try MSALCIAMAuthority(url: authorityUrl) - var config = try MSALNativeAuthConfiguration(clientId: DEFAULT_TEST_CLIENT_ID, + let config = try MSALNativeAuthConfiguration(clientId: DEFAULT_TEST_CLIENT_ID, authority: authority, challengeTypes: [.redirect]) diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift index 08a5ca95fd..d371cf31ff 100644 --- a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift +++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift @@ -26,13 +26,22 @@ import Foundation import XCTest @testable import MSAL +@_implementationOnly import MSAL_Private @_implementationOnly import MSAL_Unit_Test_Private final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() private var sut: MSALNativeAuthPublicClientApplication! + private var correlationId: UUID = UUID() + private let clientId = "clientId" + private let authorityURL = URL(string: "https://microsoft.com") + + private var authority: MSALCIAMAuthority! + private var configuration : MSALNativeAuthConfiguration! + private var contextMock: MSALNativeAuthRequestContext! + override func setUp() { super.setUp() @@ -41,6 +50,10 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { inputValidator: MSALNativeAuthInputValidator(), internalChallengeTypes: [] ) + + authority = try! MSALCIAMAuthority(url: authorityURL!) + configuration = try! MSALNativeAuthConfiguration(clientId: clientId, authority: authority!, challengeTypes: [.oob, .password]) + contextMock = .init(correlationId: .init(uuidString: correlationId.uuidString)!) } func testInit_whenPassingB2CAuthority_itShouldThrowError() throws { @@ -79,7 +92,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignUpPasswordStartDelegateSpy(expectation: exp) let expectedResult: SignUpPasswordStartResult = .codeRequired( - newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken"), + newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -142,7 +155,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignUpCodeStartDelegateSpy(expectation: exp) let expectedResult: SignUpStartResult = .codeRequired( - newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken"), + newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -226,7 +239,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { delegate.expectedChannelTargetType = .email let expectedResult: SignInPasswordStartResult = .codeRequired( - newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: ""), + newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -249,7 +262,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: exp, expectedError: expectedError) let expectedResult: SignInPasswordStartResult = .codeRequired( - newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: ""), + newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -281,7 +294,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { delegate.expectedChannelTargetType = .email let expectedResult: SignInStartResult = .codeRequired( - newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: ""), + newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -299,7 +312,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignInCodeStartDelegateWithPasswordRequiredSpy(expectation: exp1) - let expectedState = SignInPasswordRequiredState(scopes: [], username: "", controller: controllerFactoryMock.signInController, flowToken: "flowToken") + let expectedState = SignInPasswordRequiredState(scopes: [], username: "", controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) let expectedResult: SignInStartResult = .passwordRequired(newState: expectedState) controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in @@ -321,7 +334,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignInCodeStartDelegateSpy(expectation: exp, expectedError: expectedError) let expectedResult: SignInStartResult = .passwordRequired( - newState: SignInPasswordRequiredState(scopes: [], username: "", controller: controllerFactoryMock.signInController, flowToken: "") + newState: SignInPasswordRequiredState(scopes: [], username: "", controller: controllerFactoryMock.signInController, flowToken: "", correlationId: correlationId) ) controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in @@ -348,7 +361,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = ResetPasswordStartDelegateSpy(expectation: expectation) let expectedResult: ResetPasswordStartResult = .codeRequired( - newState: .init(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken"), + newState: .init(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -364,4 +377,526 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { XCTAssertEqual(delegate.channelTargetType, .email) XCTAssertEqual(delegate.codeLength, 1) } + + // MARK: - CorrelationId + + // SignUp Password + // Testing SingUpStart -> SingUpChallenge -> SingUpContinue -> SignInToken with Password + + func testSignUpPassword_correlationId_whenSetOnStart_itCascadesToAll() { + let expectationPasswordStart = expectation(description: "Sign Up Password Start") + let delegatePasswordStart = SignUpPasswordStartDelegateSpy(expectation: expectationPasswordStart) + let expectationVerifyCode = expectation(description: "Sign Up Verify Code") + let delegateVerifyCode = SignUpVerifyCodeDelegateSpy(expectation: expectationVerifyCode) + let expectationSignInAfterSingUp = expectation(description: "Sign In After Sign Up") + let delegateSignInAfterSignUp = SignInAfterSignUpDelegateSpy(expectation: expectationSignInAfterSingUp) + + let signUpRequestProviderMock = MSALNativeAuthSignUpRequestProviderMock() + signUpRequestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signUpRequestProviderMock.expectedStartRequestParameters = expectedSignUpStartPasswordParams + signUpRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signUpRequestProviderMock.expectedChallengeRequestParameters = expectedSignUpChallengeParams() + signUpRequestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signUpRequestProviderMock.expectedContinueRequestParameters = expectedSignUpContinueParams(token: "signUpToken 2") + + let signUpResponseValidatorMock = MSALNativeAuthSignUpResponseValidatorMock() + signUpResponseValidatorMock.mockValidateSignUpStartFunc((.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""]))) + signUpResponseValidatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "signUpToken 2")) + signUpResponseValidatorMock.mockValidateSignUpContinueFunc(.success("signInSLT")) + + let signInRequestProviderMock = MSALNativeAuthSignInRequestProviderMock() + + let expectedUsername = "username" + let expectedScopes = "scope1 scope2 openid profile offline_access" + + let tokenResponse = MSIDCIAMTokenResponse() + tokenResponse.accessToken = "accessToken" + tokenResponse.scope = "openid profile email" + tokenResponse.idToken = "idToken" + tokenResponse.refreshToken = "refreshToken" + + let tokenRequestProviderMock = MSALNativeAuthTokenRequestProviderMock() + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: expectedUsername, credentialToken: nil, signInSLT: "signInSLT", grantType: MSALNativeAuthGrantType.slt, scope: expectedScopes, password: nil, oobCode: nil, includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedContext = contextMock + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + + let tokenResponseValidatorMock = MSALNativeAuthTokenResponseValidatorMock() + tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) + + let authResultFactoryMock = MSALNativeAuthResultFactoryMock() + let userAccountResult = MSALNativeAuthUserAccountResult(account: MSALNativeAuthUserAccountResultStub.account, + authTokens: MSALNativeAuthTokens(accessToken: nil, + refreshToken: nil, + rawIdToken: nil), + configuration: MSALNativeAuthConfigStubs.configuration, + cacheAccessor: MSALNativeAuthCacheAccessorMock()) + authResultFactoryMock.mockMakeUserAccountResult(userAccountResult) + + let tokenResult = MSIDTokenResult() + tokenResult.rawIdToken = "idToken" + let cacheAccessorMock = MSALNativeAuthCacheAccessorMock() + cacheAccessorMock.expectedMSIDTokenResult = tokenResult + + delegateSignInAfterSignUp.expectedUserAccountResult = userAccountResult + let signInAfterSignUpController = MSALNativeAuthSignInController(clientId: clientId, + signInRequestProvider: signInRequestProviderMock, + tokenRequestProvider: tokenRequestProviderMock, + cacheAccessor: cacheAccessorMock, + factory: authResultFactoryMock, + signInResponseValidator: MSALNativeAuthSignInResponseValidatorMock(), + tokenResponseValidator: tokenResponseValidatorMock) + let signUpController = MSALNativeAuthSignUpController(config: configuration, + requestProvider: signUpRequestProviderMock, + responseValidator: signUpResponseValidatorMock, + signInController: signInAfterSignUpController) + + let controllerFactory = MSALNativeAuthControllerProtocolFactoryMock(signUpController: signUpController) + + sut = MSALNativeAuthPublicClientApplication( + controllerFactory: controllerFactory, + inputValidator: MSALNativeAuthInputValidator(), + internalChallengeTypes: [] + ) + + // Correlation Id is validated internally against expectedStartRequestParameters and expectedChallengeRequestParameters in the + // MSALNativeAuthSignUpRequestProviderMock class - checkStartParameters and checkChallengeParameters functions + sut.signUpUsingPassword(username: "username", password: "password", attributes: ["key": "value"], correlationId: correlationId, delegate: delegatePasswordStart) + + wait(for: [expectationPasswordStart]) + + // Correlation Id is validated internally against expectedContinueRequestParameters in the + // MSALNativeAuthSignUpRequestProviderMock class - checkContinueParameters function + delegatePasswordStart.newState?.submitCode(code: "1234", delegate: delegateVerifyCode) + + wait(for: [expectationVerifyCode]) + + // Correlation Id is validated internally against expectedTokenParams in the + // MSALNativeAuthTokenRequestProviderMock class - checkContext function + delegateVerifyCode.newSignInAfterSignUpState?.signIn(scopes: ["scope1", "scope2"], delegate: delegateSignInAfterSignUp) + + wait(for: [expectationSignInAfterSingUp]) + + // User account result is validated internally against expectedUserAccountResult in the + // SignInAfterSignUpDelegateSpy class - onSignInCompleted function + XCTAssertTrue(delegateSignInAfterSignUp.onSignInCompletedCalled) + } + + // SignUp Code + // Testing SingUpStart -> SingUpChallenge -> SingUpContinue -> SignInToken with Code + + func testSignUpCode_correlationId_whenSetOnStart_itCascadesToAll() { + let expectationCodeStart = expectation(description: "Sign Up Code Start") + let delegateCodeStart = SignUpCodeStartDelegateSpy(expectation: expectationCodeStart) + let expectationVerifyCode = expectation(description: "Sign Up Verify Code") + let delegateVerifyCode = SignUpVerifyCodeDelegateSpy(expectation: expectationVerifyCode) + let expectationSignInAfterSingUp = expectation(description: "Sign In After Sign Up") + let delegateSignInAfterSignUp = SignInAfterSignUpDelegateSpy(expectation: expectationSignInAfterSingUp) + + let signUpRequestProviderMock = MSALNativeAuthSignUpRequestProviderMock() + signUpRequestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signUpRequestProviderMock.expectedStartRequestParameters = expectedSignUpStartCodeParams + signUpRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signUpRequestProviderMock.expectedChallengeRequestParameters = expectedSignUpChallengeParams() + signUpRequestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signUpRequestProviderMock.expectedContinueRequestParameters = expectedSignUpContinueParams(token: "signUpToken 2") + + let signUpResponseValidatorMock = MSALNativeAuthSignUpResponseValidatorMock() + signUpResponseValidatorMock.mockValidateSignUpStartFunc((.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""]))) + signUpResponseValidatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "signUpToken 2")) + signUpResponseValidatorMock.mockValidateSignUpContinueFunc(.success("signInSLT")) + + let signInRequestProviderMock = MSALNativeAuthSignInRequestProviderMock() + + let expectedUsername = "username" + let expectedScopes = "scope1 scope2 openid profile offline_access" + + let tokenResponse = MSIDCIAMTokenResponse() + tokenResponse.accessToken = "accessToken" + tokenResponse.scope = "openid profile email" + tokenResponse.idToken = "idToken" + tokenResponse.refreshToken = "refreshToken" + + let tokenRequestProviderMock = MSALNativeAuthTokenRequestProviderMock() + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: expectedUsername, credentialToken: nil, signInSLT: "signInSLT", grantType: MSALNativeAuthGrantType.slt, scope: expectedScopes, password: nil, oobCode: nil, includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedContext = contextMock + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + + let tokenResponseValidatorMock = MSALNativeAuthTokenResponseValidatorMock() + tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) + + let authResultFactoryMock = MSALNativeAuthResultFactoryMock() + let userAccountResult = MSALNativeAuthUserAccountResult(account: MSALNativeAuthUserAccountResultStub.account, + authTokens: MSALNativeAuthTokens(accessToken: nil, + refreshToken: nil, + rawIdToken: nil), + configuration: MSALNativeAuthConfigStubs.configuration, + cacheAccessor: MSALNativeAuthCacheAccessorMock()) + authResultFactoryMock.mockMakeUserAccountResult(userAccountResult) + + let tokenResult = MSIDTokenResult() + tokenResult.rawIdToken = "idToken" + let cacheAccessorMock = MSALNativeAuthCacheAccessorMock() + cacheAccessorMock.expectedMSIDTokenResult = tokenResult + + delegateSignInAfterSignUp.expectedUserAccountResult = userAccountResult + let signInAfterSignUpController = MSALNativeAuthSignInController(clientId: clientId, + signInRequestProvider: signInRequestProviderMock, + tokenRequestProvider: tokenRequestProviderMock, + cacheAccessor: cacheAccessorMock, + factory: authResultFactoryMock, + signInResponseValidator: MSALNativeAuthSignInResponseValidatorMock(), + tokenResponseValidator: tokenResponseValidatorMock) + let signUpController = MSALNativeAuthSignUpController(config: configuration, + requestProvider: signUpRequestProviderMock, + responseValidator: signUpResponseValidatorMock, + signInController: signInAfterSignUpController) + + let controllerFactory = MSALNativeAuthControllerProtocolFactoryMock(signUpController: signUpController) + + sut = MSALNativeAuthPublicClientApplication( + controllerFactory: controllerFactory, + inputValidator: MSALNativeAuthInputValidator(), + internalChallengeTypes: [] + ) + + // Correlation Id is validated internally against expectedStartRequestParameters and expectedChallengeRequestParameters in the + // MSALNativeAuthSignUpRequestProviderMock class - checkStartParameters and checkChallengeParameters functions + sut.signUp(username: "username", attributes: ["key": "value"], correlationId: correlationId, delegate: delegateCodeStart) + + wait(for: [expectationCodeStart]) + + // Correlation Id is validated internally against expectedContinueRequestParameters in the + // MSALNativeAuthSignUpRequestProviderMock class - checkContinueParameters function + delegateCodeStart.newState?.submitCode(code: "1234", delegate: delegateVerifyCode) + + wait(for: [expectationVerifyCode]) + + // Correlation Id is validated internally against expectedTokenParams in the + // MSALNativeAuthTokenRequestProviderMock class - checkContext function + delegateVerifyCode.newSignInAfterSignUpState?.signIn(scopes: ["scope1", "scope2"], delegate: delegateSignInAfterSignUp) + wait(for: [expectationSignInAfterSingUp]) + + // User account result is validated internally against expectedUserAccountResult in the + // SignInAfterSignUpDelegateSpy class - onSignInCompleted function + XCTAssertTrue(delegateSignInAfterSignUp.onSignInCompletedCalled) + } + + // SignIn Password + // Testing SignInInitiate -> SignInChallenge -> SignInToken with Password + + func testSignInPassword_correlationId_whenSetOnStart_itCascadesToAll() { + let expectationPasswordStart = expectation(description: "Sign In Password Start") + let delegatePasswordStart = SignInPasswordStartDelegateSpy(expectation: expectationPasswordStart) + let expectationVerifyCode = expectation(description: "Sign In Verify Code") + let delegateVerifyCode = SignInVerifyCodeDelegateSpy(expectation: expectationVerifyCode) + + let signInRequestProviderMock = MSALNativeAuthSignInRequestProviderMock() + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.expectedUsername = "username" + + signInRequestProviderMock.expectedContext = contextMock + let credentialToken = "" + let expectedSentTo = "sentTo" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + let signInResponseValidatorMock = MSALNativeAuthSignInResponseValidatorMock() + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: expectedSentTo, channelType: expectedChannelTargetType, codeLength: expectedCodeLength) + + let expectedScopes = "scope1 scope2 openid profile offline_access" + + let tokenResponse = MSIDCIAMTokenResponse() + tokenResponse.accessToken = "accessToken" + tokenResponse.scope = "openid profile email" + tokenResponse.idToken = "idToken" + tokenResponse.refreshToken = "refreshToken" + + let tokenRequestProviderMock = MSALNativeAuthTokenRequestProviderMock() + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: nil, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.oobCode, scope: expectedScopes, password: nil, oobCode: "1234", includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedContext = contextMock + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + + let tokenResponseValidatorMock = MSALNativeAuthTokenResponseValidatorMock() + tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) + + let authResultFactoryMock = MSALNativeAuthResultFactoryMock() + let userAccountResult = MSALNativeAuthUserAccountResult(account: MSALNativeAuthUserAccountResultStub.account, + authTokens: MSALNativeAuthTokens(accessToken: nil, + refreshToken: nil, + rawIdToken: nil), + configuration: MSALNativeAuthConfigStubs.configuration, + cacheAccessor: MSALNativeAuthCacheAccessorMock()) + authResultFactoryMock.mockMakeUserAccountResult(userAccountResult) + + let tokenResult = MSIDTokenResult() + tokenResult.rawIdToken = "idToken" + let cacheAccessorMock = MSALNativeAuthCacheAccessorMock() + cacheAccessorMock.expectedMSIDTokenResult = tokenResult + + delegateVerifyCode.expectedUserAccountResult = userAccountResult + let signInController = MSALNativeAuthSignInController(clientId: clientId, + signInRequestProvider: signInRequestProviderMock, + tokenRequestProvider: tokenRequestProviderMock, + cacheAccessor: cacheAccessorMock, + factory: authResultFactoryMock, + signInResponseValidator: signInResponseValidatorMock, + tokenResponseValidator: tokenResponseValidatorMock) + let controllerFactory = MSALNativeAuthControllerProtocolFactoryMock(signInController: signInController) + + sut = MSALNativeAuthPublicClientApplication( + controllerFactory: controllerFactory, + inputValidator: MSALNativeAuthInputValidator(), + internalChallengeTypes: [] + ) + + // Correlation Id is validated internally against contextMock on both initiate and challenge in the + // MSALNativeAuthSignInRequestProviderMock class - checkContext function + sut.signInUsingPassword(username: "username", password: "password", scopes: ["scope1", "scope2"], correlationId: correlationId, delegate: delegatePasswordStart) + + wait(for: [expectationPasswordStart]) + + // Correlation Id is validated internally against expectedTokenParams + // MSALNativeAuthTokenRequestProviderMock class - checkContext function + delegatePasswordStart.newSignInCodeRequiredState?.submitCode(code: "1234", delegate: delegateVerifyCode) + wait(for: [expectationVerifyCode]) + + // User account result is validated internally against expectedUserAccountResult in the + // SignInVerifyCodeDelegateSpy class - onSignInCompleted function + XCTAssertTrue(delegateVerifyCode.onSignInCompletedCalled) + } + + // SignIn Code + // Testing SignInInitiate -> SignInChallenge -> SignInToken with Code + + func testSignInCode_correlationId_whenSetOnStart_itCascadesToAll() { + let expectationCodeStart = expectation(description: "Sign In Code Start") + let delegateCodeStart = SignInCodeStartDelegateSpy(expectation: expectationCodeStart) + let expectationVerifyCode = expectation(description: "Sign In Verify Code") + let delegateVerifyCode = SignInVerifyCodeDelegateSpy(expectation: expectationVerifyCode) + + let signInRequestProviderMock = MSALNativeAuthSignInRequestProviderMock() + signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + signInRequestProviderMock.expectedUsername = "username" + signInRequestProviderMock.expectedContext = contextMock + + let credentialToken = "" + let expectedSentTo = "sentTo" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + delegateCodeStart.expectedSentTo = expectedSentTo + delegateCodeStart.expectedChannelTargetType = expectedChannelTargetType + delegateCodeStart.expectedCodeLength = expectedCodeLength + + let signInResponseValidatorMock = MSALNativeAuthSignInResponseValidatorMock() + signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: expectedSentTo, channelType: expectedChannelTargetType, codeLength: expectedCodeLength) + + let expectedScopes = "scope1 scope2 openid profile offline_access" + + let tokenResponse = MSIDCIAMTokenResponse() + tokenResponse.accessToken = "accessToken" + tokenResponse.scope = "openid profile email" + tokenResponse.idToken = "idToken" + tokenResponse.refreshToken = "refreshToken" + + let tokenRequestProviderMock = MSALNativeAuthTokenRequestProviderMock() + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: nil, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.oobCode, scope: expectedScopes, password: nil, oobCode: "1234", includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedContext = contextMock + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + + let tokenResponseValidatorMock = MSALNativeAuthTokenResponseValidatorMock() + tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) + + let authResultFactoryMock = MSALNativeAuthResultFactoryMock() + let userAccountResult = MSALNativeAuthUserAccountResult(account: MSALNativeAuthUserAccountResultStub.account, + authTokens: MSALNativeAuthTokens(accessToken: nil, + refreshToken: nil, + rawIdToken: nil), + configuration: MSALNativeAuthConfigStubs.configuration, + cacheAccessor: MSALNativeAuthCacheAccessorMock()) + authResultFactoryMock.mockMakeUserAccountResult(userAccountResult) + + let tokenResult = MSIDTokenResult() + tokenResult.rawIdToken = "idToken" + let cacheAccessorMock = MSALNativeAuthCacheAccessorMock() + cacheAccessorMock.expectedMSIDTokenResult = tokenResult + + delegateVerifyCode.expectedUserAccountResult = userAccountResult + let signInController = MSALNativeAuthSignInController(clientId: clientId, + signInRequestProvider: signInRequestProviderMock, + tokenRequestProvider: tokenRequestProviderMock, + cacheAccessor: cacheAccessorMock, + factory: authResultFactoryMock, + signInResponseValidator: signInResponseValidatorMock, + tokenResponseValidator: tokenResponseValidatorMock) + let controllerFactory = MSALNativeAuthControllerProtocolFactoryMock(signInController: signInController) + + sut = MSALNativeAuthPublicClientApplication( + controllerFactory: controllerFactory, + inputValidator: MSALNativeAuthInputValidator(), + internalChallengeTypes: [] + ) + + // Correlation Id is validated internally against contextMock on both initiate and challenge in the + // MSALNativeAuthSignInRequestProviderMock class - checkContext function + sut.signIn(username: "username", scopes: ["scope1", "scope2"], correlationId: correlationId, delegate: delegateCodeStart) + wait(for: [expectationCodeStart]) + + // Correlation Id is validated internally against expectedTokenParams + // MSALNativeAuthTokenRequestProviderMock class - checkContext function + delegateCodeStart.newSignInCodeRequiredState?.submitCode(code: "1234", delegate: delegateVerifyCode) + wait(for: [expectationVerifyCode]) + + // User account result is validated internally against expectedUserAccountResult in the + // SignInVerifyCodeDelegateSpy class - onSignInCompleted function + XCTAssertTrue(delegateVerifyCode.onSignInCompletedCalled) + } + + // PasswordReset + // Testing PasswordResetStart -> PasswordResetChallenge -> PasswordResetContinue -> PasswordResetComplete -> PasswordResetSubmit -> PollCompletion + + func testResetPassword_correlationId_whenSetOnStart_itCascadesToAll() { + let expectationPasswordResetStart = expectation(description: "Password Reset Start") + let delegatePasswordResetStart = ResetPasswordStartDelegateSpy(expectation: expectationPasswordResetStart) + let expectationPasswordResetVerifyCode = expectation(description: "Password Reset Verify Code") + let delegatePasswordResetVerifyCode = ResetPasswordVerifyCodeDelegateSpy(expectation: expectationPasswordResetVerifyCode) + let expectationPasswordResetRequired = expectation(description: "Password Reset Required") + let delegatePasswordResetRequired = ResetPasswordRequiredDelegateSpy(expectation: expectationPasswordResetRequired) + + let resetPasswordRequestProviderMock = MSALNativeAuthResetPasswordRequestProviderMock () + resetPasswordRequestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + resetPasswordRequestProviderMock.expectedStartRequestParameters = expectedResetPasswordStartParams + resetPasswordRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + resetPasswordRequestProviderMock.expectedChallengeRequestParameters = expectedResetPasswordChallengeParams(token: "passwordResetToken") + resetPasswordRequestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + resetPasswordRequestProviderMock.expectedContinueRequestParameters = expectedResetPasswordContinueParams(token: "passwordResetToken 2") + resetPasswordRequestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + resetPasswordRequestProviderMock.expectedSubmitRequestParameters = expectedResetPasswordSubmitParams(token: "passwordSubmitToken") + resetPasswordRequestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + resetPasswordRequestProviderMock.expectedPollCompletionParameters = expectedResetPasswordPollCompletionParameters(token: "passwordResetToken 3") + + let resetPasswordResponseValidator = MSALNativeAuthResetPasswordResponseValidatorMock() + resetPasswordResponseValidator.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) + resetPasswordResponseValidator.mockValidateResetPasswordChallengeFunc(.success("sentTo", .email, 4, "passwordResetToken 2")) + resetPasswordResponseValidator.mockValidateResetPasswordContinueFunc(.success(passwordSubmitToken: "passwordSubmitToken")) + resetPasswordResponseValidator.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken 3", pollInterval: 0)) + resetPasswordResponseValidator.mockValidateResetPasswordPollCompletionFunc(.success(status: .succeeded)) + + let resetPasswordController = MSALNativeAuthResetPasswordController(config: configuration, + requestProvider: resetPasswordRequestProviderMock, + responseValidator: resetPasswordResponseValidator) + + let controllerFactory = MSALNativeAuthControllerProtocolFactoryMock(resetPasswordController: resetPasswordController) + + sut = MSALNativeAuthPublicClientApplication( + controllerFactory: controllerFactory, + inputValidator: MSALNativeAuthInputValidator(), + internalChallengeTypes: [] + ) + + // Correlation Id is validated internally against expectedStartRequestParameters and expectedChallengeRequestParameters in the + // MSALNativeAuthResetPasswordRequestProviderMock class - checkParameters(params: MSALNativeAuthResetPasswordStartRequestProviderParameters) + // and checkParameters(token: String, context: MSIDRequestContext) functions + sut.resetPassword(username: "username", correlationId: correlationId, delegate: delegatePasswordResetStart) + + wait(for: [expectationPasswordResetStart]) + + // Correlation Id is validated internally against expectedContinueRequestParameters in the + // MSALNativeAuthResetPasswordRequestProviderMock class - checkParameters(_ params: MSALNativeAuthResetPasswordContinueRequestParameters) function + delegatePasswordResetStart.newState?.submitCode(code: "1234", delegate: delegatePasswordResetVerifyCode) + + wait(for: [expectationPasswordResetVerifyCode]) + + // Correlation Id is validated internally against expectedSubmitRequestParameters and expectedPollCompletionParameters + // MSALNativeAuthResetPasswordRequestProviderMock class - checkParameters(_ params: MSALNativeAuthResetPasswordSubmitRequestParameters) function + // and checkParameters(_ params: MSALNativeAuthResetPasswordPollCompletionRequestParameters) function + delegatePasswordResetVerifyCode.newPasswordRequiredState?.submitPassword(password: "password", delegate: delegatePasswordResetRequired) + + wait(for: [expectationPasswordResetRequired]) + + XCTAssertTrue(delegatePasswordResetRequired.onResetPasswordCompletedCalled) + } + + private var expectedSignUpStartPasswordParams: MSALNativeAuthSignUpStartRequestProviderParameters { + .init( + username: "username", + password: "password", + attributes: ["key": "value"], + context: contextMock + ) + } + + private var expectedSignUpStartCodeParams: MSALNativeAuthSignUpStartRequestProviderParameters { + .init( + username: "username", + password: nil, + attributes: ["key": "value"], + context: contextMock + ) + } + + private func expectedSignUpChallengeParams(token: String = "signUpToken") -> (token: String, context: MSIDRequestContext) { + return (token: token, context: contextMock) + } + + private func expectedSignUpContinueParams( + grantType: MSALNativeAuthGrantType = .oobCode, + token: String = "signUpToken", + password: String? = nil, + oobCode: String? = "1234", + attributes: [String: Any]? = nil + ) -> MSALNativeAuthSignUpContinueRequestProviderParams { + .init( + grantType: grantType, + signUpToken: token, + password: password, + oobCode: oobCode, + attributes: attributes, + context: contextMock + ) + } + + private var expectedResetPasswordStartParams: MSALNativeAuthResetPasswordStartRequestProviderParameters { + .init( + username: "username", + context: contextMock + ) + } + + private func expectedResetPasswordChallengeParams(token: String = "passwordResetToken") -> (token: String, context: MSIDRequestContext) { + return (token: token, context: contextMock) + } + + private func expectedResetPasswordContinueParams( + grantType: MSALNativeAuthGrantType = .oobCode, + token: String = "passwordResetToken", + oobCode: String? = "1234" + ) -> MSALNativeAuthResetPasswordContinueRequestParameters { + .init( + context: contextMock, + passwordResetToken: token, + grantType: grantType, + oobCode: oobCode + ) + } + + private func expectedResetPasswordSubmitParams( + token: String = "passwordSubmitToken", + password: String = "password" + ) -> MSALNativeAuthResetPasswordSubmitRequestParameters { + .init( + context: contextMock, + passwordSubmitToken: token, + newPassword: password) + } + + private func expectedResetPasswordPollCompletionParameters( + token: String = "passwordResetToken" + ) -> MSALNativeAuthResetPasswordPollCompletionRequestParameters { + .init( + context: contextMock, + passwordResetToken: token) + } } diff --git a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift index 060794a567..2a36707451 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift @@ -30,12 +30,13 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { private var controller: MSALNativeAuthResetPasswordControllerMock! private var sut: ResetPasswordCodeRequiredState! + private var correlationId: UUID = UUID() override func setUpWithError() throws { try super.setUpWithError() controller = .init() - sut = ResetPasswordCodeRequiredState(controller: controller, flowToken: "") + sut = ResetPasswordCodeRequiredState(controller: controller, flowToken: "", correlationId: correlationId) } // MARK: - Delegates @@ -44,7 +45,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { func test_resendCode_delegate_whenError_shouldReturnCorrectError() { let expectedError = ResendCodeError(message: "test error") - let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken") + let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken", correlationId: correlationId) let expectedResult: ResetPasswordResendCodeResult = .error(error: expectedError, newState: expectedState) controller.resendCodeResult = .init(expectedResult) @@ -60,7 +61,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { } func test_resendCode_delegate_success_shouldReturnCodeRequired() { - let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken 2") + let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: ResetPasswordResendCodeResult = .codeRequired( newState: expectedState, @@ -86,7 +87,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { func test_submitCode_delegate_whenError_shouldReturnCorrectError() { let expectedError = VerifyCodeError(type: .invalidCode) - let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken") + let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken", correlationId: correlationId) let expectedResult: ResetPasswordVerifyCodeResult = .error(error: expectedError, newState: expectedState) controller.submitCodeResult = .init(expectedResult) @@ -102,7 +103,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { } func test_submitCode_delegate_success_shouldReturnPasswordRequired() { - let expectedState = ResetPasswordRequiredState(controller: controller, flowToken: "flowToken 2") + let expectedState = ResetPasswordRequiredState(controller: controller, flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: ResetPasswordVerifyCodeResult = .passwordRequired(newState: expectedState) controller.submitCodeResult = .init(expectedResult) diff --git a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift index 30c832d56f..aeed145c4a 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift @@ -29,7 +29,7 @@ import XCTest final class ResetPasswordRequiredStateTests: XCTestCase { - private var correlationId: UUID! + private var correlationId: UUID = UUID() private var exp: XCTestExpectation! private var controller: MSALNativeAuthResetPasswordControllerSpy! private var sut: ResetPasswordRequiredState! @@ -37,17 +37,16 @@ final class ResetPasswordRequiredStateTests: XCTestCase { override func setUpWithError() throws { try super.setUpWithError() - correlationId = UUID() exp = expectation(description: "ResetPasswordRequiredState expectation") controller = MSALNativeAuthResetPasswordControllerSpy(expectation: exp) - sut = ResetPasswordRequiredState(controller: controller, flowToken: "") + sut = ResetPasswordRequiredState(controller: controller, flowToken: "", correlationId: correlationId) } func test_submitPassword_usesControllerSuccessfully() { XCTAssertNil(controller.context) XCTAssertFalse(controller.submitPasswordCalled) - sut.submitPassword(password: "1234", correlationId: correlationId, delegate: ResetPasswordRequiredDelegateSpy()) + sut.submitPassword(password: "1234", delegate: ResetPasswordRequiredDelegateSpy()) wait(for: [exp], timeout: 1) XCTAssertEqual(controller.context?.correlationId(), correlationId) diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift index 3784cbd876..4d8114dc5c 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift @@ -29,12 +29,13 @@ final class SignInCodeRequiredStateTests: XCTestCase { private var sut: SignInCodeRequiredState! private var controller: MSALNativeAuthSignInControllerMock! + private var correlationId: UUID = UUID() override func setUp() { super.setUp() controller = .init() - sut = .init(scopes: [], controller: controller, flowToken: "flowToken") + sut = .init(scopes: [], controller: controller, flowToken: "flowToken", correlationId: correlationId) } // MARK: - Delegates @@ -43,7 +44,7 @@ final class SignInCodeRequiredStateTests: XCTestCase { func test_resendCode_delegate_withError_shouldReturnSignInResendCodeError() { let expectedError = ResendCodeError(message: "test error") - let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2") + let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: SignInResendCodeResult = .error( error: expectedError, @@ -62,7 +63,7 @@ final class SignInCodeRequiredStateTests: XCTestCase { } func test_resendCode_delegate_success_shouldReturnSignInResendCodeCodeRequired() { - let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2") + let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: SignInResendCodeResult = .codeRequired( newState: expectedState, @@ -84,7 +85,7 @@ final class SignInCodeRequiredStateTests: XCTestCase { func test_submitCode_delegate_withError_shouldReturnSignInVerifyCodeError() { let expectedError = VerifyCodeError(type: .invalidCode) - let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2") + let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: SignInVerifyCodeResult = .error( error: expectedError, diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift index 7949fe4775..71c743d36c 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift @@ -29,19 +29,20 @@ final class SignInPasswordRequiredStateTests: XCTestCase { private var sut: SignInPasswordRequiredState! private var controller: MSALNativeAuthSignInControllerMock! + private var correlationId: UUID = UUID() override func setUp() { super.setUp() controller = .init() - sut = .init(scopes: [], username: "username", controller: controller, flowToken: "flowToken") + sut = .init(scopes: [], username: "username", controller: controller, flowToken: "flowToken", correlationId: correlationId) } // MARK: - Delegates func test_submitPassword_delegate_withError_shouldReturnError() { let expectedError = PasswordRequiredError(type: .invalidPassword) - let expectedState = SignInPasswordRequiredState(scopes: [], username: "", controller: controller, flowToken: "flowToken 2") + let expectedState = SignInPasswordRequiredState(scopes: [], username: "", controller: controller, flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: SignInPasswordRequiredResult = .error( error: expectedError, diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift index ad1e5e7aec..0693a586e7 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift @@ -31,12 +31,13 @@ final class SignUpAttributesRequiredStateTests: XCTestCase { private var controller: MSALNativeAuthSignUpControllerMock! private var sut: SignUpAttributesRequiredState! + private var correlationId: UUID = UUID() override func setUpWithError() throws { try super.setUpWithError() controller = .init() - sut = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "") + sut = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "", correlationId: correlationId) } // MARK: - Delegate @@ -57,7 +58,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase { } func test_submitPassword_delegate_whenSuccess_shouldReturnCompleted() { - let expectedState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt") + let expectedState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: correlationId) let expectedResult: SignUpAttributesRequiredResult = .completed(expectedState) controller.submitAttributesResult = .init(expectedResult) @@ -72,7 +73,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase { } func test_submitPassword_delegate_whenAttributesRequired_shouldReturnAttributesRequired() { - let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", flowToken: "slt") + let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", flowToken: "slt", correlationId: correlationId) let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ .init(name: "anAttribute", type: "aType", required: true) ] @@ -91,7 +92,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase { } func test_submitPassword_delegate_whenAttributesAreInvalud_shouldReturnAttributesInvalid() { - let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", flowToken: "slt") + let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", flowToken: "slt", correlationId: correlationId) let expectedAttributes = ["anAttribute"] let expectedResult: SignUpAttributesRequiredResult = .attributesInvalid(attributes: expectedAttributes, newState: expectedState) diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift index ae79ba1826..dfd9aafc5d 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift @@ -30,12 +30,13 @@ final class SignUpCodeRequiredStateTests: XCTestCase { private var controller: MSALNativeAuthSignUpControllerMock! private var sut: SignUpCodeRequiredState! + private var correlationId: UUID = UUID() override func setUpWithError() throws { try super.setUpWithError() controller = .init() - sut = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "") + sut = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "", correlationId: correlationId) } // MARK: - Delegates @@ -58,7 +59,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { } func test_resendCode_delegate_success_shouldReturnCodeRequired() { - let expectedState = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2") + let expectedState = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: SignUpResendCodeResult = .codeRequired( newState: expectedState, @@ -84,7 +85,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { func test_submitCode_delegate_whenError_shouldReturnCorrectError() { let expectedError = VerifyCodeError(type: .invalidCode) - let expectedState = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2") + let expectedState = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: SignUpVerifyCodeResult = .error( error: expectedError, @@ -103,7 +104,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { } func test_submitCode_delegate_whenPasswordRequired_AndUserHasImplementedOptionalDelegate_shouldReturnPasswordRequired() { - let expectedPasswordRequiredState = SignUpPasswordRequiredState(controller: controller, username: "", flowToken: "flowToken 2") + let expectedPasswordRequiredState = SignUpPasswordRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "exp telemetry is called") @@ -127,7 +128,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "exp telemetry is called") - let expectedResult: SignUpVerifyCodeResult = .passwordRequired(.init(controller: controller, username: "", flowToken: "")) + let expectedResult: SignUpVerifyCodeResult = .passwordRequired(.init(controller: controller, username: "", flowToken: "", correlationId: correlationId)) controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in exp2.fulfill() }) @@ -142,7 +143,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { } func test_submitCode_delegate_whenAttributesRequired_AndUserHasImplementedOptionalDelegate_shouldReturnAttributesRequired() { - let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "flowToken 2") + let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "exp telemetry is called") @@ -166,7 +167,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "exp telemetry is called") - let expectedResult: SignUpVerifyCodeResult = .attributesRequired(attributes: [], newState: .init(controller: controller, username: "", flowToken: "")) //.attributesRequired(.init(controller: controller, flowToken: "")) + let expectedResult: SignUpVerifyCodeResult = .attributesRequired(attributes: [], newState: .init(controller: controller, username: "", flowToken: "", correlationId: correlationId)) controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in exp2.fulfill() }) @@ -181,7 +182,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { } func test_submitCode_delegate_whenSuccess_shouldReturnAccountResult() { - let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt") + let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: correlationId) let expectedResult: SignUpVerifyCodeResult = .completed(expectedSignInAfterSignUpState) controller.submitCodeResult = .init(expectedResult) diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift index 1ff53b8273..8a2c4b6e32 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift @@ -31,19 +31,20 @@ final class SignUpPasswordRequiredStateTests: XCTestCase { private var controller: MSALNativeAuthSignUpControllerMock! private var sut: SignUpPasswordRequiredState! + private var correlationId: UUID = UUID() override func setUpWithError() throws { try super.setUpWithError() controller = .init() - sut = SignUpPasswordRequiredState(controller: controller, username: "", flowToken: "") + sut = SignUpPasswordRequiredState(controller: controller, username: "", flowToken: "", correlationId: correlationId) } // MARK: - Delegate func test_submitPassword_delegate_whenError_shouldReturnPasswordRequiredError() { let expectedError = PasswordRequiredError(type: .invalidPassword) - let expectedState = SignUpPasswordRequiredState(controller: controller, username: "", flowToken: "flowToken 2") + let expectedState = SignUpPasswordRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: SignUpPasswordRequiredResult = .error(error: expectedError, newState: expectedState) controller.submitPasswordResult = .init(expectedResult) @@ -59,7 +60,7 @@ final class SignUpPasswordRequiredStateTests: XCTestCase { } func test_submitCode_delegate_whenAttributesRequired_AndUserHasImplementedOptionalDelegate_shouldReturnAttributesRequired() { - let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "flowToken 2") + let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "exp telemetry is called") @@ -79,7 +80,7 @@ final class SignUpPasswordRequiredStateTests: XCTestCase { func test_submitCode_delegate_whenAttributesRequired_ButUserHasNotImplementedOptionalDelegate_shouldReturnPasswordRequiredError() { let expectedError = PasswordRequiredError(type: .generalError, message: MSALNativeAuthErrorMessage.delegateNotImplemented) - let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "flowToken 2") + let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "exp telemetry is called") @@ -99,7 +100,7 @@ final class SignUpPasswordRequiredStateTests: XCTestCase { } func test_submitCode_delegate_whenSuccess_shouldReturnSignUpCompleted() { - let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt") + let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: correlationId) let exp = expectation(description: "sign-up states") From 87fe944cfd3c4e6429b465343af79884b15b8dc7 Mon Sep 17 00:00:00 2001 From: Silviu Petrescu <111577419+spetrescu84@users.noreply.github.com> Date: Wed, 13 Dec 2023 17:09:23 +0000 Subject: [PATCH 17/84] Removed all Native Auth files from iOS Static Library target (#1916) Removed MSALLogMask.h & MSALLogMask.m from Static Libary --- MSAL/MSAL.xcodeproj/project.pbxproj | 220 ------------------ .../MSAL (iOS Static Library).xcscheme | 4 - 2 files changed, 224 deletions(-) diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index 086c674e31..f0616c8a2b 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -240,40 +240,26 @@ 23F32F0D1FF4789200B2905E /* MSIDTestURLResponse+MSAL.m in Sources */ = {isa = PBXBuildFile; fileRef = 23F32F061FF4787600B2905E /* MSIDTestURLResponse+MSAL.m */; }; 23FB5C1E22542B99002BF1EB /* MSALJsonDeserializable.h in Headers */ = {isa = PBXBuildFile; fileRef = 23FB5C1C22542B99002BF1EB /* MSALJsonDeserializable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2814B4DA2A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2814B4D92A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift */; }; - 2814B4DB2A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2814B4D92A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift */; }; 2826932A2A0974750037B93A /* MSALNativeAuthTokenRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282693272A0974740037B93A /* MSALNativeAuthTokenRequestParameters.swift */; }; - 2826932B2A0974750037B93A /* MSALNativeAuthTokenRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282693272A0974740037B93A /* MSALNativeAuthTokenRequestParameters.swift */; }; 2826933B2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2826933A2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift */; }; - 2826933C2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2826933A2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift */; }; 285F36082A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 285F36072A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift */; }; - 285F36092A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 285F36072A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift */; }; 2877081F2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2877081E2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift */; }; - 287708202A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2877081E2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift */; }; 287708222A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287708212A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift */; }; - 287708232A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287708212A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift */; }; 287708252A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287708242A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift */; }; - 287708262A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287708242A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift */; }; 287F64D4297EC29400ED90BD /* MSALNativeAuthTelemetryProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64D2297EC29400ED90BD /* MSALNativeAuthTelemetryProviderTests.swift */; }; 287F64D5297EC29400ED90BD /* MSALNativeAuthCurrentRequestTelemetryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64D3297EC29400ED90BD /* MSALNativeAuthCurrentRequestTelemetryTests.swift */; }; 287F64D92981781A00ED90BD /* MSALNativeAuthSignInParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64D82981781A00ED90BD /* MSALNativeAuthSignInParameters.swift */; }; - 287F64DA2981781A00ED90BD /* MSALNativeAuthSignInParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64D82981781A00ED90BD /* MSALNativeAuthSignInParameters.swift */; }; 287F64E62981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64E52981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift */; }; - 287F64E72981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64E52981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift */; }; 287F64E92981786A00ED90BD /* MSALNativeAuthVerifyCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64E82981786A00ED90BD /* MSALNativeAuthVerifyCodeParameters.swift */; }; 287F64F0298186EA00ED90BD /* MSALNativeAuthInputValidatorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64EF298186EA00ED90BD /* MSALNativeAuthInputValidatorTest.swift */; }; 287F64F32981A00400ED90BD /* MSALNativeAuthPublicClientApplicationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64F22981A00400ED90BD /* MSALNativeAuthPublicClientApplicationTest.swift */; }; 287F650C2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F650B2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift */; }; - 287F650D2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F650B2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift */; }; 287F65182983F77D00ED90BD /* MSALNativeAuthRequestParametersKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F65172983F77D00ED90BD /* MSALNativeAuthRequestParametersKey.swift */; }; - 287F65192983F77D00ED90BD /* MSALNativeAuthRequestParametersKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F65172983F77D00ED90BD /* MSALNativeAuthRequestParametersKey.swift */; }; 287F6524298401AE00ED90BD /* MSALNativeAuthResponseSerializerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F6523298401AE00ED90BD /* MSALNativeAuthResponseSerializerTests.swift */; }; 2884855C295DAFD400516492 /* MSALNativeAuthTokens.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2884855B295DAFD400516492 /* MSALNativeAuthTokens.swift */; }; - 2884855D295DAFD400516492 /* MSALNativeAuthTokens.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2884855B295DAFD400516492 /* MSALNativeAuthTokens.swift */; }; 289747AC2979487900838C80 /* MSALNativeAuthUrlRequestSerializerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289747A92979487900838C80 /* MSALNativeAuthUrlRequestSerializerTests.swift */; }; 289747B129799C6B00838C80 /* MSALNativeAuthInputValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289747AF29799A8700838C80 /* MSALNativeAuthInputValidator.swift */; }; 289747B42979A3C800838C80 /* MSALNativeAuthParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289747B32979A3C800838C80 /* MSALNativeAuthParameters.swift */; }; - 289747B7297ABEA300838C80 /* MSALNativeAuthInputValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289747AF29799A8700838C80 /* MSALNativeAuthInputValidator.swift */; }; - 289747BA297ABEB400838C80 /* MSALNativeAuthParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289747B32979A3C800838C80 /* MSALNativeAuthParameters.swift */; }; 289E15592948E601006104D9 /* MSALNativeAuthCacheInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289E15582948E601006104D9 /* MSALNativeAuthCacheInterface.swift */; }; 289E156D2948EB8A006104D9 /* MSALNativeAuthCacheAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289E156C2948EB8A006104D9 /* MSALNativeAuthCacheAccessor.swift */; }; 28A472EC2A276C3B003F988B /* MSALNativeAuthTokenValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28A472EB2A276C3B003F988B /* MSALNativeAuthTokenValidatedResponse.swift */; }; @@ -285,7 +271,6 @@ 28D1D59C29C2266500CE75F4 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D1D59B29C2266500CE75F4 /* Model.swift */; }; 28D1D59E29C2392000CE75F4 /* MockAPIHandlerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D1D59D29C2392000CE75F4 /* MockAPIHandlerTest.swift */; }; 28D5B05D2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D5B05C2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift */; }; - 28D5B05E2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D5B05C2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift */; }; 28DCD09229D7166F00C4601E /* SignUpDelegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD09129D7166F00C4601E /* SignUpDelegates.swift */; }; 28DCD09A29D7192F00C4601E /* MSALNativeAuthError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD09929D7192F00C4601E /* MSALNativeAuthError.swift */; }; 28DCD09C29D71E7E00C4601E /* SignUpPasswordStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD09B29D71E7E00C4601E /* SignUpPasswordStartError.swift */; }; @@ -302,22 +287,13 @@ 28DCD0B429D73BCE00C4601E /* ResetPasswordDelegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0B329D73BCE00C4601E /* ResetPasswordDelegates.swift */; }; 28DE3FD02A0921E2003148A4 /* SignInTestsValidatorHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DE3FCF2A0921E2003148A4 /* SignInTestsValidatorHelpers.swift */; }; 28DE70D629FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DE70D529FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift */; }; - 28DE70D729FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DE70D529FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift */; }; 28E4D9032A30ABA200280921 /* ResendCodeError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28E4D9022A30ABA200280921 /* ResendCodeError.swift */; }; - 28E4D9042A30ABA200280921 /* ResendCodeError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28E4D9022A30ABA200280921 /* ResendCodeError.swift */; }; 28EDF93E29E6D43900A99F2A /* SignUpStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28EDF93D29E6D43900A99F2A /* SignUpStartError.swift */; }; 28EDF94129E6D52E00A99F2A /* SignInStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28EDF94029E6D52E00A99F2A /* SignInStartError.swift */; }; - 28EDF94229E6D52E00A99F2A /* SignInStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28EDF94029E6D52E00A99F2A /* SignInStartError.swift */; }; 28F19BEB2A2F884D00575581 /* Array+joinScopes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28F19BEA2A2F884D00575581 /* Array+joinScopes.swift */; }; - 28F19BEC2A2F884D00575581 /* Array+joinScopes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28F19BEA2A2F884D00575581 /* Array+joinScopes.swift */; }; - 28F74D54295C90E100B89A78 /* MSALNativeAuthCacheAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289E156C2948EB8A006104D9 /* MSALNativeAuthCacheAccessor.swift */; }; - 28F74D55295C90E100B89A78 /* MSALNativeAuthCacheInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289E15582948E601006104D9 /* MSALNativeAuthCacheInterface.swift */; }; 28FDC49C2A38BFA900E38BE1 /* SignInAfterSignUpState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDC49B2A38BFA900E38BE1 /* SignInAfterSignUpState.swift */; }; - 28FDC49D2A38BFA900E38BE1 /* SignInAfterSignUpState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDC49B2A38BFA900E38BE1 /* SignInAfterSignUpState.swift */; }; 28FDC4A62A38C00900E38BE1 /* SignInAfterSignUpDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDC4A52A38C00900E38BE1 /* SignInAfterSignUpDelegate.swift */; }; - 28FDC4A72A38C00900E38BE1 /* SignInAfterSignUpDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDC4A52A38C00900E38BE1 /* SignInAfterSignUpDelegate.swift */; }; 28FDC4A92A38C0D100E38BE1 /* SignInAfterSignUpError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDC4A82A38C0D000E38BE1 /* SignInAfterSignUpError.swift */; }; - 28FDC4AA2A38C0D100E38BE1 /* SignInAfterSignUpError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDC4A82A38C0D000E38BE1 /* SignInAfterSignUpError.swift */; }; 28FDC4AE2A38D81100E38BE1 /* MSALNativeAuthSignInControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDC4AB2A38D7D200E38BE1 /* MSALNativeAuthSignInControllerMock.swift */; }; 38880DF423280C5900688C24 /* MSALPublicClientApplicationConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 23B1D35D22EA4797000954AF /* MSALPublicClientApplicationConfig.m */; }; 38880DF523280C5A00688C24 /* MSALPublicClientApplicationConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 23B1D35D22EA4797000954AF /* MSALPublicClientApplicationConfig.m */; }; @@ -344,11 +320,8 @@ 886F516729CCA58900F09471 /* MSALCIAMAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 886F516329CCA58900F09471 /* MSALCIAMAuthority.m */; }; 88A25EE729E7347400066311 /* MSALCIAMAuthorityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25ED229E7185B00066311 /* MSALCIAMAuthorityTests.m */; }; 8D2733142AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D2733132AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift */; }; - 8D2733152AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D2733132AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift */; }; 8D35C8E72A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D35C8E62A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift */; }; - 8D35C8E82A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D35C8E62A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift */; }; 8D35C8F12A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D35C8F02A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift */; }; - 8D35C8F22A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D35C8F02A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift */; }; 8D61F9A12A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D61F9A02A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift */; }; 8DDF473F2A98FE1C00126A47 /* MSALNativeAuthRequiredAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DDF473E2A98FE1C00126A47 /* MSALNativeAuthRequiredAttributes.swift */; }; 94E876CE1E492D6000FB96ED /* MSALAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 94E876CB1E492D6000FB96ED /* MSALAuthority.m */; }; @@ -440,10 +413,8 @@ 9B2BBA352A3297F80075F702 /* MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2BBA342A3297F80075F702 /* MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift */; }; 9B2BBA372A3298080075F702 /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2BBA362A3298080075F702 /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift */; }; 9B2E93452A0D3801008A5DD2 /* MSALNativeAuthResetPasswordControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2E93442A0D3801008A5DD2 /* MSALNativeAuthResetPasswordControlling.swift */; }; - 9B2E93462A0D3813008A5DD2 /* MSALNativeAuthResetPasswordControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2E93442A0D3801008A5DD2 /* MSALNativeAuthResetPasswordControlling.swift */; }; 9B4EE9D52A1686A900F243C1 /* MSALNativeAuthResetPasswordControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B4EE9CD2A1686A900F243C1 /* MSALNativeAuthResetPasswordControllerTests.swift */; }; 9B4EE9D82A1687AE00F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B4EE9D62A16874F00F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift */; }; - 9B4EE9DA2A1687B600F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B4EE9D62A16874F00F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift */; }; 9B5D6D062A3CA0E300521576 /* MSALNativeAuthSignInUsernameAndPasswordEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B5D6D052A3CA0E300521576 /* MSALNativeAuthSignInUsernameAndPasswordEndToEndTests.swift */; }; 9B5D6D082A3CA55600521576 /* SignInDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B5D6D072A3CA55600521576 /* SignInDelegateSpies.swift */; }; 9B61C9132A27E51900CE9E3A /* MSALNativeAuthResetPasswordRequestProviderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B61C9122A27E51900CE9E3A /* MSALNativeAuthResetPasswordRequestProviderMock.swift */; }; @@ -453,17 +424,12 @@ 9B839A112A4D7CF600BCC6F6 /* MSAL.docc in Sources */ = {isa = PBXBuildFile; fileRef = 9B839A0F2A4D7CF600BCC6F6 /* MSAL.docc */; }; 9BB5180B2A2A2B5B00D6276A /* MSALNativeAuthResetPasswordControllerSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BB518032A2A2B5B00D6276A /* MSALNativeAuthResetPasswordControllerSpy.swift */; }; 9BD2763D2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD2763C2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift */; }; - 9BD2763E2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD2763C2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift */; }; 9BD2765A2A0E7E6F00FBD033 /* ResetPasswordTestValidatorHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD276582A0E7E6700FBD033 /* ResetPasswordTestValidatorHelpers.swift */; }; 9BD2765B2A0E7E7D00FBD033 /* ResetPasswordCodeSentStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD276562A0E7DEC00FBD033 /* ResetPasswordCodeSentStateTests.swift */; }; 9BD2765F2A0E81CE00FBD033 /* ResetPasswordRequiredStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD2765E2A0E81CE00FBD033 /* ResetPasswordRequiredStateTests.swift */; }; 9BD78D822A126DC400AA7E12 /* MSALNativeAuthChallengeTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BD78D7A2A126A1500AA7E12 /* MSALNativeAuthChallengeTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9BD78D902A127F8000AA7E12 /* MSALNativeAuthChallengeTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BD78D7A2A126A1500AA7E12 /* MSALNativeAuthChallengeTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9BE7E3CB2A1CB70700CC3A62 /* MSALNativeAuthResetPasswordStartRequestProviderParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BE7E3CA2A1CB70700CC3A62 /* MSALNativeAuthResetPasswordStartRequestProviderParameters.swift */; }; - 9BE7E3CC2A1CB70700CC3A62 /* MSALNativeAuthResetPasswordStartRequestProviderParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BE7E3CA2A1CB70700CC3A62 /* MSALNativeAuthResetPasswordStartRequestProviderParameters.swift */; }; 9BE7E3D52A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BE7E3D42A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift */; }; - 9BE7E3D62A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BE7E3D42A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift */; }; - 9BEF84742A31EF70005CB0B6 /* MSALNativeAuthTokenValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28A472EB2A276C3B003F988B /* MSALNativeAuthTokenValidatedResponse.swift */; }; 9D02FCAF28EF33F8003F791C /* MSALWPJMetaData.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DA6473528EC2FF10014F44F /* MSALWPJMetaData.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D02FCB728EF33FE003F791C /* MSALWPJMetaData.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DA6473528EC2FF10014F44F /* MSALWPJMetaData.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D292B1028F05696007FE93C /* MSALWPJMetaData.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D292B0F28F05696007FE93C /* MSALWPJMetaData.m */; }; @@ -949,47 +915,31 @@ D6A206401FC512F400755A51 /* SafariServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A206331FC5109400755A51 /* SafariServices.framework */; }; DE03478A2A39ED6A003CB3B6 /* MSALCIAMOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9244D72A31E1D500C0389F /* MSALCIAMOauth2Provider.m */; }; DE0347A82A41AD08003CB3B6 /* MSALNativeAuthUserAccountResultStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0347A72A41AD08003CB3B6 /* MSALNativeAuthUserAccountResultStub.swift */; }; - DE0347BC2A41B768003CB3B6 /* MSALNativeAuthCredentialsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE92450B2A385ED800C0389F /* MSALNativeAuthCredentialsController.swift */; }; - DE0347BD2A41B76E003CB3B6 /* MSALNativeAuthCredentialsControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE92450D2A38601100C0389F /* MSALNativeAuthCredentialsControlling.swift */; }; - DE0347C12A41B7FC003CB3B6 /* SignUpStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28EDF93D29E6D43900A99F2A /* SignUpStartError.swift */; }; - DE0347C22A41B80C003CB3B6 /* MSALNativeAuthVerifyCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64E82981786A00ED90BD /* MSALNativeAuthVerifyCodeParameters.swift */; }; - DE0347C32A41B819003CB3B6 /* MSALNativeAuthUserAccountResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8BE7DB2A1F6BD2009642A5 /* MSALNativeAuthUserAccountResult.swift */; }; DE0D656F29BF72F7005798B1 /* MSALNativeAuthSignInInitiateRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D656729BF72F6005798B1 /* MSALNativeAuthSignInInitiateRequestParameters.swift */; }; - DE0D657029BF72F7005798B1 /* MSALNativeAuthSignInInitiateRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D656729BF72F6005798B1 /* MSALNativeAuthSignInInitiateRequestParameters.swift */; }; DE0D657629BF73CB005798B1 /* MSALNativeAuthSignInChallengeRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D657429BF73CB005798B1 /* MSALNativeAuthSignInChallengeRequestParameters.swift */; }; - DE0D657729BF73CB005798B1 /* MSALNativeAuthSignInChallengeRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D657429BF73CB005798B1 /* MSALNativeAuthSignInChallengeRequestParameters.swift */; }; DE0D659529C1DCC9005798B1 /* MSALNativeAuthSignInInitiateRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D658E29C1DCA6005798B1 /* MSALNativeAuthSignInInitiateRequestParametersTest.swift */; }; DE0D659629C1DCCC005798B1 /* MSALNativeAuthSignInChallengeRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D658C29C1DCA6005798B1 /* MSALNativeAuthSignInChallengeRequestParametersTest.swift */; }; DE0D659729C1DCCF005798B1 /* MSALNativeAuthTokenRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D658D29C1DCA6005798B1 /* MSALNativeAuthTokenRequestParametersTest.swift */; }; DE0D65AC29CC6A5A005798B1 /* MSALNativeAuthSignInInitiateResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65AB29CC6A59005798B1 /* MSALNativeAuthSignInInitiateResponse.swift */; }; - DE0D65AD29CC6A5A005798B1 /* MSALNativeAuthSignInInitiateResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65AB29CC6A59005798B1 /* MSALNativeAuthSignInInitiateResponse.swift */; }; DE0D65B629CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65B529CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift */; }; - DE0D65B729CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65B529CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift */; }; DE0D65B929D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65B829D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift */; }; - DE0D65BA29D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65B829D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift */; }; DE0D65BF29D30BAE005798B1 /* MSALNativeAuthResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65BE29D30BAE005798B1 /* MSALNativeAuthResponseError.swift */; }; - DE0D65C029D30BAE005798B1 /* MSALNativeAuthResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65BE29D30BAE005798B1 /* MSALNativeAuthResponseError.swift */; }; DE0D65C229D30C38005798B1 /* MSALNativeAuthSignInInitiateOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65C129D30C38005798B1 /* MSALNativeAuthSignInInitiateOauth2ErrorCode.swift */; }; DE0D65C629D344F1005798B1 /* MSALNativeAuthSignInInitiateIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65C529D344F1005798B1 /* MSALNativeAuthSignInInitiateIntegrationTests.swift */; }; DE0D65CD29D5CE56005798B1 /* MSALNativeAuthSignInChallengeIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65CA29D5CD6D005798B1 /* MSALNativeAuthSignInChallengeIntegrationTests.swift */; }; DE0FECAC2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0FECAA2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift */; }; - DE0FECAD2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0FECAA2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift */; }; DE0FECC72993ADAF00B139A8 /* MSALNativeAuthResendCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0FECC62993ADAE00B139A8 /* MSALNativeAuthResendCodeParameters.swift */; }; - DE0FECC82993ADAF00B139A8 /* MSALNativeAuthResendCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0FECC62993ADAE00B139A8 /* MSALNativeAuthResendCodeParameters.swift */; }; DE14096B2A38DE0E008E6F1E /* CredentialsDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE14096A2A38DE0E008E6F1E /* CredentialsDelegateSpies.swift */; }; DE14096D2A38DF41008E6F1E /* MSALNativeAuthCredentialsControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE14096C2A38DF40008E6F1E /* MSALNativeAuthCredentialsControllerTests.swift */; }; DE14D75D29897D8000F37BEF /* MSALNativeAuthTelemetryApiId.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D995296EC35A006CB384 /* MSALNativeAuthTelemetryApiId.swift */; }; DE14D75E29897D9500F37BEF /* MSALNativeAuthUrlRequestSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA49B2953576C00E98964 /* MSALNativeAuthUrlRequestSerializer.swift */; }; DE14D76129898CF900F37BEF /* MSALNativeAuthTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE14D76029898CF900F37BEF /* MSALNativeAuthTestCase.swift */; }; DE1D8AA829E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1D8AA729E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift */; }; - DE1D8AA929E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1D8AA729E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift */; }; DE40A4CA2A8F801200928CEE /* MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE40A4C92A8F801200928CEE /* MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift */; }; DE40A4D32A8F80C100928CEE /* MSALNativeAuthSignUpContinueResponseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE40A4D22A8F80C100928CEE /* MSALNativeAuthSignUpContinueResponseErrorTests.swift */; }; DE4F0F3129D6F1AA00D561FD /* MSALNativeAuthTokenIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4F0F2929D6F1AA00D561FD /* MSALNativeAuthTokenIntegrationTests.swift */; }; DE54B5912A434B9B00460B34 /* MSALNativeAuthTokenController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE54B5902A434B9B00460B34 /* MSALNativeAuthTokenController.swift */; }; - DE54B5922A434B9B00460B34 /* MSALNativeAuthTokenController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE54B5902A434B9B00460B34 /* MSALNativeAuthTokenController.swift */; }; DE54B5942A43587800460B34 /* MSALNativeAuthTokenRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE54B5932A43587800460B34 /* MSALNativeAuthTokenRequestProvider.swift */; }; - DE54B5952A43587800460B34 /* MSALNativeAuthTokenRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE54B5932A43587800460B34 /* MSALNativeAuthTokenRequestProvider.swift */; }; DE54B59F2A4452DB00460B34 /* MSALNativeAuthTokenResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE54B59C2A44521E00460B34 /* MSALNativeAuthTokenResponseValidatorTests.swift */; }; DE54B5AD2A459B0400460B34 /* MSALNativeAuthTokenResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE54B5AC2A459B0400460B34 /* MSALNativeAuthTokenResponseValidator.swift */; }; DE5738B22A8E71D500D9120D /* MSALNativeAuthResetPasswordContinueResponseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE5738AA2A8E71D500D9120D /* MSALNativeAuthResetPasswordContinueResponseErrorTests.swift */; }; @@ -1001,18 +951,15 @@ DE5738BE2A8F7AC600D9120D /* MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE5738BD2A8F7AC600D9120D /* MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift */; }; DE5738C02A8F7C2000D9120D /* MSALNativeAuthSignUpStartResponseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE5738BF2A8F7C1F00D9120D /* MSALNativeAuthSignUpStartResponseErrorTests.swift */; }; DE729ECD2A1793A100A761D9 /* MSALNativeAuthChannelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE729ECC2A1793A100A761D9 /* MSALNativeAuthChannelType.swift */; }; - DE729ECE2A1793A100A761D9 /* MSALNativeAuthChannelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE729ECC2A1793A100A761D9 /* MSALNativeAuthChannelType.swift */; }; DE87DE6A2A39E80B0032BF9E /* MSALNativeAuthUserAccountResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE87DE692A39E80B0032BF9E /* MSALNativeAuthUserAccountResultTests.swift */; }; DE8BE7DC2A1F6BD2009642A5 /* MSALNativeAuthUserAccountResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8BE7DB2A1F6BD2009642A5 /* MSALNativeAuthUserAccountResult.swift */; }; DE8EC8742A026BA0003FA561 /* MSALNativeAuthSignInRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC86C2A026BA0003FA561 /* MSALNativeAuthSignInRequestProvider.swift */; }; - DE8EC8752A026BA0003FA561 /* MSALNativeAuthSignInRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC86C2A026BA0003FA561 /* MSALNativeAuthSignInRequestProvider.swift */; }; DE8EC8A82A026FE2003FA561 /* MSALNativeAuthResetPasswordChallengeIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC8772A026C2E003FA561 /* MSALNativeAuthResetPasswordChallengeIntegrationTests.swift */; }; DE8EC8A92A026FE7003FA561 /* MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC8782A026C2E003FA561 /* MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift */; }; DE8EC8AA2A026FEA003FA561 /* MSALNativeAuthResetPasswordStartIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC8792A026C2E003FA561 /* MSALNativeAuthResetPasswordStartIntegrationTests.swift */; }; DE8EC8AB2A026FEC003FA561 /* MSALNativeAuthResetPasswordContinueIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC87A2A026C2E003FA561 /* MSALNativeAuthResetPasswordContinueIntegrationTests.swift */; }; DE8EC8AC2A026FEF003FA561 /* MSALNativeAuthResetPasswordSubmitIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC87B2A026C2E003FA561 /* MSALNativeAuthResetPasswordSubmitIntegrationTests.swift */; }; DE8EC8B62A053D80003FA561 /* MSALNativeAuthESTSApiErrorCodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC8B52A053D80003FA561 /* MSALNativeAuthESTSApiErrorCodes.swift */; }; - DE8EC8B72A053D80003FA561 /* MSALNativeAuthESTSApiErrorCodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8EC8B52A053D80003FA561 /* MSALNativeAuthESTSApiErrorCodes.swift */; }; DE9244D82A31E1D500C0389F /* MSALCIAMOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = DE9244D62A31E1D500C0389F /* MSALCIAMOauth2Provider.h */; }; DE9244D92A31E1D500C0389F /* MSALCIAMOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = DE9244D62A31E1D500C0389F /* MSALCIAMOauth2Provider.h */; }; DE9244DA2A31E1D500C0389F /* MSALCIAMOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = DE9244D62A31E1D500C0389F /* MSALCIAMOauth2Provider.h */; }; @@ -1033,13 +980,10 @@ DE94C9F029F2AF5E00C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94C9EE29F2AF3200C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParameters.swift */; }; DEC1E425298BE18A00948BED /* MSALNativeAuthServerTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26097C62948FC720060DD7C /* MSALNativeAuthServerTelemetry.swift */; }; DECC1F9629521E35006D9FB1 /* MSALLogMask.m in Sources */ = {isa = PBXBuildFile; fileRef = DECC1F9229521E34006D9FB1 /* MSALLogMask.m */; }; - DECC1F9729521E35006D9FB1 /* MSALLogMask.m in Sources */ = {isa = PBXBuildFile; fileRef = DECC1F9229521E34006D9FB1 /* MSALLogMask.m */; }; DECC1F9829521E35006D9FB1 /* MSALLogMask.h in Headers */ = {isa = PBXBuildFile; fileRef = DECC1F9329521E34006D9FB1 /* MSALLogMask.h */; }; - DECC1F9929521E35006D9FB1 /* MSALLogMask.h in Headers */ = {isa = PBXBuildFile; fileRef = DECC1F9329521E34006D9FB1 /* MSALLogMask.h */; }; DECC1FB329531032006D9FB1 /* MSALLogMaskTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DECC1FB229531032006D9FB1 /* MSALLogMaskTests.m */; }; DECC1FB5295322A8006D9FB1 /* MSALNativeLoggingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DECC1FB4295322A8006D9FB1 /* MSALNativeLoggingTests.swift */; }; DEDB298B29D72D62008DA85B /* MSALNativeAuthInnerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDB298A29D72D62008DA85B /* MSALNativeAuthInnerError.swift */; }; - DEDB298C29D72D62008DA85B /* MSALNativeAuthInnerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDB298A29D72D62008DA85B /* MSALNativeAuthInnerError.swift */; }; DEDB29A529DDA9DC008DA85B /* MSALNativeAuthSignInInitiateResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDB29A429DDA9DC008DA85B /* MSALNativeAuthSignInInitiateResponseError.swift */; }; DEDB29A829DDAEB3008DA85B /* MSALNativeAuthSignInChallengeOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDB29A629DDAEB3008DA85B /* MSALNativeAuthSignInChallengeOauth2ErrorCode.swift */; }; DEDB29A929DDAEB3008DA85B /* MSALNativeAuthTokenOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDB29A729DDAEB3008DA85B /* MSALNativeAuthTokenOauth2ErrorCode.swift */; }; @@ -1049,7 +993,6 @@ DEDD6F0829E83FD20017989F /* MSALNativeAuthRequestConfiguratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEDD6F0729E83FD20017989F /* MSALNativeAuthRequestConfiguratorTests.swift */; }; DEE34F12D170B71C00BC302A /* MSALNativeAuthResetPasswordStartRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F11D170B71C00BC302A /* MSALNativeAuthResetPasswordStartRequestParameters.swift */; }; DEE34F48D170B71C00BC302A /* MSALNativeAuthResultFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F43D170B71C00BC302A /* MSALNativeAuthResultFactory.swift */; }; - DEE34F49D170B71C00BC302A /* MSALNativeAuthResultFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F43D170B71C00BC302A /* MSALNativeAuthResultFactory.swift */; }; DEE34F5CD170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F5BD170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponse.swift */; }; DEE34F60D170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F5ED170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponseError.swift */; }; DEE34F61D170B71C00BC302A /* MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F5FD170B71C00BC302A /* MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift */; }; @@ -1070,29 +1013,18 @@ DEE34F8CD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F8AD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift */; }; DEE34F8DD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F8BD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponseError.swift */; }; DEE34F96D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F95D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift */; }; - DEE34F97D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F95D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift */; }; DEE34FA1D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34FA0D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift */; }; - DEE34FA2D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34FA0D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift */; }; DEF1DD322AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF1DD312AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift */; }; - DEF1DD332AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF1DD312AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift */; }; DEF1DD3C2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF1DD3B2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift */; }; - DEF1DD3D2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF1DD3B2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift */; }; DEF9D989296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D988296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift */; }; - DEF9D98A296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D988296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift */; }; - DEF9D997296EC35A006CB384 /* MSALNativeAuthTelemetryApiId.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D995296EC35A006CB384 /* MSALNativeAuthTelemetryApiId.swift */; }; DEF9D999296EC848006CB384 /* MSALNativeAuthOperationTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D998296EC848006CB384 /* MSALNativeAuthOperationTypes.swift */; }; - DEF9D99A296EC848006CB384 /* MSALNativeAuthOperationTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D998296EC848006CB384 /* MSALNativeAuthOperationTypes.swift */; }; DEF9D99F296F08CE006CB384 /* MSALNativeAuthTelemetryProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D99E296F08CE006CB384 /* MSALNativeAuthTelemetryProvider.swift */; }; - DEF9D9A0296F08CE006CB384 /* MSALNativeAuthTelemetryProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D99E296F08CE006CB384 /* MSALNativeAuthTelemetryProvider.swift */; }; DEFB46ED2A52BA3700DBC006 /* MSALNativeAuthSignOutEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFB46EC2A52BA3700DBC006 /* MSALNativeAuthSignOutEndToEndTests.swift */; }; DEFB46F22A52C11400DBC006 /* MSALNativeAuthResetPasswordEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFB46F12A52C11400DBC006 /* MSALNativeAuthResetPasswordEndToEndTests.swift */; }; DEFB46F42A52C28100DBC006 /* ResetPasswordDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFB46F32A52C28100DBC006 /* ResetPasswordDelegateSpies.swift */; }; E205D62E29B783FF003887BC /* MSALNativeAuthConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = E205D62D29B783FF003887BC /* MSALNativeAuthConfiguration.swift */; }; - E205D62F29B783FF003887BC /* MSALNativeAuthConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = E205D62D29B783FF003887BC /* MSALNativeAuthConfiguration.swift */; }; E206FC5F296D65DE00AF4400 /* MSALNativeAuthInternalError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E206FC5E296D65DE00AF4400 /* MSALNativeAuthInternalError.swift */; }; - E206FC60296D65DE00AF4400 /* MSALNativeAuthInternalError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E206FC5E296D65DE00AF4400 /* MSALNativeAuthInternalError.swift */; }; E206FCEF2979BC4600AF4400 /* MSALNativeAuthSignInController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E206FCEE2979BC4600AF4400 /* MSALNativeAuthSignInController.swift */; }; - E206FCF02979BC4600AF4400 /* MSALNativeAuthSignInController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E206FCEE2979BC4600AF4400 /* MSALNativeAuthSignInController.swift */; }; E20C21752A7A61B600E31598 /* SignUpDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20C21742A7A61B600E31598 /* SignUpDelegateSpies.swift */; }; E20C217E2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20C217D2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift */; }; E20C21842A7A6CA400E31598 /* SignInCodeRequiredStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20C21832A7A6CA400E31598 /* SignInCodeRequiredStateTests.swift */; }; @@ -1100,25 +1032,16 @@ E22952682A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22952672A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift */; }; E22E20282A7936C50073A6FF /* MSALNativeAuthSignUpControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22E20272A7936C50073A6FF /* MSALNativeAuthSignUpControllerMock.swift */; }; E235610E29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235610D29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift */; }; - E235610F29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235610D29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift */; }; E235613129C9CEA8000E01CA /* MSALNativeAuthSignUpStartRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235613029C9CEA8000E01CA /* MSALNativeAuthSignUpStartRequestParameters.swift */; }; - E235613229C9CEA8000E01CA /* MSALNativeAuthSignUpStartRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235613029C9CEA8000E01CA /* MSALNativeAuthSignUpStartRequestParameters.swift */; }; E235613429C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235613329C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift */; }; - E235613529C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235613329C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift */; }; E23E955F29D4B9F7001DC59C /* MSALNativeAuthSignUpChallengeIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E23E955E29D4B9F7001DC59C /* MSALNativeAuthSignUpChallengeIntegrationTests.swift */; }; E23E956929D5BD6B001DC59C /* MSALNativeAuthSignUpRequestProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E23E956829D5BD6B001DC59C /* MSALNativeAuthSignUpRequestProviderTests.swift */; }; E243F69429D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69329D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift */; }; - E243F69529D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69329D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift */; }; E243F69A29D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69929D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift */; }; - E243F69B29D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69929D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift */; }; E243F69D29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69C29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift */; }; - E243F69E29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69C29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift */; }; E243F6A029D1FF9E00DAC60F /* MSALNativeAuthSignUpContinueRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69F29D1FF9E00DAC60F /* MSALNativeAuthSignUpContinueRequestParameters.swift */; }; - E243F6A129D1FF9E00DAC60F /* MSALNativeAuthSignUpContinueRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69F29D1FF9E00DAC60F /* MSALNativeAuthSignUpContinueRequestParameters.swift */; }; E243F6A629D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F6A529D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift */; }; - E243F6A729D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F6A529D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift */; }; E243F6AA29D42FE900DAC60F /* MSALNativeAuthSignUpContinueRequestProviderParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F6A929D42FE900DAC60F /* MSALNativeAuthSignUpContinueRequestProviderParams.swift */; }; - E243F6AB29D42FE900DAC60F /* MSALNativeAuthSignUpContinueRequestProviderParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F6A929D42FE900DAC60F /* MSALNativeAuthSignUpContinueRequestProviderParams.swift */; }; E243F6AF29D446FC00DAC60F /* MSALNativeAuthSignUpStartIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F6AD29D4427E00DAC60F /* MSALNativeAuthSignUpStartIntegrationTests.swift */; }; E248917A2A1CFA6B001ECBE2 /* MSALNativeAuthConfigStubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F5BE9429894FCA00C67EC7 /* MSALNativeAuthConfigStubs.swift */; }; E25BC07A2995423100588549 /* MSALNativeAuthNetworkMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25BC0792995423100588549 /* MSALNativeAuthNetworkMocks.swift */; }; @@ -1129,91 +1052,58 @@ E25E6E5A2AA7727D0094461E /* MSALNativeAuthCredentialsControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25E6E592AA7727D0094461E /* MSALNativeAuthCredentialsControllerMock.swift */; }; E25EA4EC2A4C9B75004C8E40 /* MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26E391A2A4C2BE200063C07 /* MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift */; }; E26097C32948FC4D0060DD7C /* MSALNativeAuthLogging.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26097C22948FC4D0060DD7C /* MSALNativeAuthLogging.swift */; }; - E26097C42948FC4D0060DD7C /* MSALNativeAuthLogging.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26097C22948FC4D0060DD7C /* MSALNativeAuthLogging.swift */; }; - E26097C82948FC720060DD7C /* MSALNativeAuthServerTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26097C62948FC720060DD7C /* MSALNativeAuthServerTelemetry.swift */; }; E26E39242A4C2D7400063C07 /* SignUpDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26E39232A4C2D7400063C07 /* SignUpDelegateSpies.swift */; }; E272C4EC2A4447520013B805 /* MSALNativeAuthSignUpUsernameEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E272C4EA2A4447520013B805 /* MSALNativeAuthSignUpUsernameEndToEndTests.swift */; }; E27332C02A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E27332BF2A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift */; }; - E27332C12A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E27332BF2A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift */; }; E284F5D929F28B4200DBED7D /* MSALNativeAuthSignUpController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E284F5D829F28B4200DBED7D /* MSALNativeAuthSignUpController.swift */; }; - E284F5DA29F28B4200DBED7D /* MSALNativeAuthSignUpController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E284F5D829F28B4200DBED7D /* MSALNativeAuthSignUpController.swift */; }; E284F5E429F2F28A00DBED7D /* MSALNativeAuthSignUpControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = E284F5E329F2F28A00DBED7D /* MSALNativeAuthSignUpControlling.swift */; }; - E284F5E529F2F28A00DBED7D /* MSALNativeAuthSignUpControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = E284F5E329F2F28A00DBED7D /* MSALNativeAuthSignUpControlling.swift */; }; E286E2DD2A1BAEA800666DD0 /* MSALNativeAuthSignUpControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E286E2DC2A1BAEA800666DD0 /* MSALNativeAuthSignUpControllerTests.swift */; }; E2960A112A1F4D2F000F441B /* MSALNativeAuthSignUpChallengeResponseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2960A102A1F4D2F000F441B /* MSALNativeAuthSignUpChallengeResponseErrorTests.swift */; }; E2ACA47B29520C2200E98964 /* MSALNativeAuthEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA47A29520C2200E98964 /* MSALNativeAuthEndpoint.swift */; }; - E2ACA47C29520C2200E98964 /* MSALNativeAuthEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA47A29520C2200E98964 /* MSALNativeAuthEndpoint.swift */; }; E2ACA48B2952302B00E98964 /* MSALNativeAuthRequestContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA48A2952302B00E98964 /* MSALNativeAuthRequestContext.swift */; }; - E2ACA48C2952302B00E98964 /* MSALNativeAuthRequestContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA48A2952302B00E98964 /* MSALNativeAuthRequestContext.swift */; }; E2ACA4952953415E00E98964 /* MSALNativeAuthGrantType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA4942953415E00E98964 /* MSALNativeAuthGrantType.swift */; }; - E2ACA4962953415E00E98964 /* MSALNativeAuthGrantType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA4942953415E00E98964 /* MSALNativeAuthGrantType.swift */; }; - E2ACA49D2953576C00E98964 /* MSALNativeAuthUrlRequestSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ACA49B2953576C00E98964 /* MSALNativeAuthUrlRequestSerializer.swift */; }; E2B8532B2A1531DA007A4776 /* MSALNativeAuthSignUpValidatedResponses.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2B8532A2A1531DA007A4776 /* MSALNativeAuthSignUpValidatedResponses.swift */; }; - E2B8532C2A1531DA007A4776 /* MSALNativeAuthSignUpValidatedResponses.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2B8532A2A1531DA007A4776 /* MSALNativeAuthSignUpValidatedResponses.swift */; }; E2B8532F2A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2B8532E2A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift */; }; - E2B853302A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2B8532E2A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift */; }; E2BC027529D6E0C600041DBC /* MSALNativeAuthSignUpContinueIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BC027429D6E0C600041DBC /* MSALNativeAuthSignUpContinueIntegrationTests.swift */; }; E2BC029829D766A800041DBC /* MSALNativeAuthSignUpChallengeRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BC029729D766A800041DBC /* MSALNativeAuthSignUpChallengeRequestParametersTest.swift */; }; E2BC029A29D766B200041DBC /* MSALNativeAuthSignUpStartRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BC029929D766B200041DBC /* MSALNativeAuthSignUpStartRequestParametersTest.swift */; }; E2BC029C29D766CB00041DBC /* MSALNativeAuthSignUpContinueRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BC029B29D766CB00041DBC /* MSALNativeAuthSignUpContinueRequestParametersTest.swift */; }; E2BDD98B2A28FBDD00E3ED6B /* MSALNativeAuthErrorRequiredAttributesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BDD98A2A28FBDD00E3ED6B /* MSALNativeAuthErrorRequiredAttributesTests.swift */; }; E2C1D287299BA15D00B26449 /* MSALNativeAuthBaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C1D286299BA15D00B26449 /* MSALNativeAuthBaseController.swift */; }; - E2C1D288299BA15D00B26449 /* MSALNativeAuthBaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C1D286299BA15D00B26449 /* MSALNativeAuthBaseController.swift */; }; E2C1D2D429A3992100B26449 /* MSALNativeAuthBaseControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C1D2D329A3992100B26449 /* MSALNativeAuthBaseControllerTests.swift */; }; E2C61FE129DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE029DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift */; }; - E2C61FE229DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE029DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift */; }; E2C61FE429DED15800F15203 /* MSALNativeAuthSignUpStartResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE329DED15800F15203 /* MSALNativeAuthSignUpStartResponseError.swift */; }; - E2C61FE529DED15800F15203 /* MSALNativeAuthSignUpStartResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE329DED15800F15203 /* MSALNativeAuthSignUpStartResponseError.swift */; }; E2C61FE729DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE629DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift */; }; - E2C61FE829DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE629DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift */; }; E2C61FEA29DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE929DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift */; }; - E2C61FEB29DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE929DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift */; }; E2C61FED29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FEC29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift */; }; - E2C61FEE29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FEC29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift */; }; E2C61FF029DEDB0200F15203 /* MSALNativeAuthSignUpContinueResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FEF29DEDB0200F15203 /* MSALNativeAuthSignUpContinueResponseError.swift */; }; - E2C61FF129DEDB0200F15203 /* MSALNativeAuthSignUpContinueResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FEF29DEDB0200F15203 /* MSALNativeAuthSignUpContinueResponseError.swift */; }; E2C872C3294CDEE800C4F580 /* MSALNativeAuthRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C872C2294CDEE800C4F580 /* MSALNativeAuthRequestable.swift */; }; - E2C872C4294CDEE800C4F580 /* MSALNativeAuthRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C872C2294CDEE800C4F580 /* MSALNativeAuthRequestable.swift */; }; E2CD2E4A29FBEA36009F8FFA /* SignUpCodeSentStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2E4929FBEA36009F8FFA /* SignUpCodeSentStateTests.swift */; }; E2CD2E4F29FC0451009F8FFA /* SignUpPasswordRequiredStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2E4E29FC0451009F8FFA /* SignUpPasswordRequiredStateTests.swift */; }; E2CD2E5129FC087A009F8FFA /* SignUpAttributesRequiredStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2E5029FC087A009F8FFA /* SignUpAttributesRequiredStateTests.swift */; }; E2CD2E8D2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2E8C2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift */; }; - E2CD2E8E2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2E8C2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift */; }; E2CD2EB32A040012009F8FFA /* SignUpTestsValidatorHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2EB22A040012009F8FFA /* SignUpTestsValidatorHelpers.swift */; }; E2CD2EB52A0404DA009F8FFA /* MSALNativeAuthSignUpControllerSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2EB42A0404DA009F8FFA /* MSALNativeAuthSignUpControllerSpy.swift */; }; E2D3BC4F2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D3BC4E2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift */; }; - E2D3BC502A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D3BC4E2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift */; }; E2DC31BC29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DC31BB29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift */; }; - E2DC31BD29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DC31BB29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift */; }; E2DC31C829B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DC31C729B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift */; }; - E2DC31C929B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DC31C729B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift */; }; E2EBD6212A1BB4640049467A /* MSALNativeAuthSignUpRequestProviderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EBD6202A1BB4640049467A /* MSALNativeAuthSignUpRequestProviderMock.swift */; }; E2EBD62A2A1BB7700049467A /* MSALNativeAuthSignUpResponseValidatorMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EBD6292A1BB7700049467A /* MSALNativeAuthSignUpResponseValidatorMock.swift */; }; E2EFACFE2A69915100D6C3DE /* SignInResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFACFD2A69915100D6C3DE /* SignInResults.swift */; }; - E2EFACFF2A69915100D6C3DE /* SignInResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFACFD2A69915100D6C3DE /* SignInResults.swift */; }; E2EFAD092A69A34300D6C3DE /* CodeRequiredGenericResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD082A69A34300D6C3DE /* CodeRequiredGenericResult.swift */; }; - E2EFAD0A2A69A34300D6C3DE /* CodeRequiredGenericResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD082A69A34300D6C3DE /* CodeRequiredGenericResult.swift */; }; E2EFAD0C2A69B45100D6C3DE /* SignUpResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD0B2A69B45100D6C3DE /* SignUpResults.swift */; }; - E2EFAD0D2A69B45100D6C3DE /* SignUpResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD0B2A69B45100D6C3DE /* SignUpResults.swift */; }; E2EFAD0F2A69BBB800D6C3DE /* ResetPasswordResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD0E2A69BBB800D6C3DE /* ResetPasswordResults.swift */; }; - E2EFAD102A69BBB800D6C3DE /* ResetPasswordResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD0E2A69BBB800D6C3DE /* ResetPasswordResults.swift */; }; E2EFAD162A70300B00D6C3DE /* MSALNativeAuthControllerTelemetryWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD152A70300B00D6C3DE /* MSALNativeAuthControllerTelemetryWrapper.swift */; }; - E2EFAD172A70300B00D6C3DE /* MSALNativeAuthControllerTelemetryWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFAD152A70300B00D6C3DE /* MSALNativeAuthControllerTelemetryWrapper.swift */; }; E2F4DB242A1F525A009FBCD0 /* MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F4DB232A1F525A009FBCD0 /* MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift */; }; E2F4DB2D2A1F5714009FBCD0 /* MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F4DB2C2A1F5714009FBCD0 /* MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift */; }; E2F5BE8E29893A4100C67EC7 /* MSALNativeAuthEndpointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F5BE8D29893A4100C67EC7 /* MSALNativeAuthEndpointTests.swift */; }; E2F5BE9A29896ADB00C67EC7 /* MSALNativeAuthSignInControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F5BE9929896ADB00C67EC7 /* MSALNativeAuthSignInControllerTests.swift */; }; E2F5BE9D298A6CEB00C67EC7 /* MSALNativeAuthResultFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F5BE9C298A6CEB00C67EC7 /* MSALNativeAuthResultFactoryTests.swift */; }; E2F6269D2A780DDE00C4A303 /* MSALNativeAuthPublicClientApplication+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F6269C2A780DDE00C4A303 /* MSALNativeAuthPublicClientApplication+Internal.swift */; }; - E2F6269E2A780DDE00C4A303 /* MSALNativeAuthPublicClientApplication+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F6269C2A780DDE00C4A303 /* MSALNativeAuthPublicClientApplication+Internal.swift */; }; E2F626A72A780F3D00C4A303 /* SignUpStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626A62A780F3D00C4A303 /* SignUpStates+Internal.swift */; }; - E2F626A82A780F3D00C4A303 /* SignUpStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626A62A780F3D00C4A303 /* SignUpStates+Internal.swift */; }; E2F626AA2A780F8200C4A303 /* SignInStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626A92A780F8200C4A303 /* SignInStates+Internal.swift */; }; - E2F626AB2A780F8200C4A303 /* SignInStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626A92A780F8200C4A303 /* SignInStates+Internal.swift */; }; E2F626AD2A78119900C4A303 /* ResetPasswordStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AC2A78119900C4A303 /* ResetPasswordStates+Internal.swift */; }; - E2F626AE2A78119900C4A303 /* ResetPasswordStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AC2A78119900C4A303 /* ResetPasswordStates+Internal.swift */; }; E2F626B02A78130700C4A303 /* SignInAfterSignUpState+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AF2A78130700C4A303 /* SignInAfterSignUpState+Internal.swift */; }; - E2F626B12A78130700C4A303 /* SignInAfterSignUpState+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AF2A78130700C4A303 /* SignInAfterSignUpState+Internal.swift */; }; E2F626B32A781CE300C4A303 /* SignInDelegatesSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626B22A781CE300C4A303 /* SignInDelegatesSpies.swift */; }; /* End PBXBuildFile section */ @@ -4301,7 +4191,6 @@ DE9244DA2A31E1D500C0389F /* MSALCIAMOauth2Provider.h in Headers */, B273D07B226E84E9005A7BB4 /* MSALDefinitions.h in Headers */, B273D0ED226E8606005A7BB4 /* MSALTokenParameters+Internal.h in Headers */, - 9BD78D902A127F8000AA7E12 /* MSALNativeAuthChallengeTypes.h in Headers */, B273D08F226E8534005A7BB4 /* MSALJsonDeserializable.h in Headers */, B273D077226E84DD005A7BB4 /* MSALHTTPConfig.h in Headers */, B273D0CB226E85C7005A7BB4 /* MSALHTTPConfig+Internal.h in Headers */, @@ -4310,7 +4199,6 @@ B273D06F226E84C3005A7BB4 /* MSALGlobalConfig.h in Headers */, 04A6B5E0226937AD0035C7C2 /* MSALAccountsProvider.h in Headers */, B2D478B6230E3E8D005AE186 /* MSALSerializedADALCacheProvider+Internal.h in Headers */, - DECC1F9929521E35006D9FB1 /* MSALLogMask.h in Headers */, B273D085226E851A005A7BB4 /* MSALInteractiveTokenParameters.h in Headers */, 04A6B5F0226937D00035C7C2 /* MSALB2CAuthority.h in Headers */, 04A6B6012269380B0035C7C2 /* MSALPublicClientApplication.h in Headers */, @@ -5264,170 +5152,62 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E26097C82948FC720060DD7C /* MSALNativeAuthServerTelemetry.swift in Sources */, - 287708202A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift in Sources */, - E27332C12A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift in Sources */, - 28EDF94229E6D52E00A99F2A /* SignInStartError.swift in Sources */, - DEE34FA2D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift in Sources */, B2D478A9230E3E80005AE186 /* MSALLegacySharedAccountsProvider.m in Sources */, 1E5319C024A51E07007BCF30 /* MSALAuthenticationSchemePop.m in Sources */, B273D0E0226E85E3005A7BB4 /* MSALExtraQueryParameters.m in Sources */, - DE0D65BA29D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift in Sources */, - DEF9D997296EC35A006CB384 /* MSALNativeAuthTelemetryApiId.swift in Sources */, - 287F64DA2981781A00ED90BD /* MSALNativeAuthSignInParameters.swift in Sources */, - 287F650D2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift in Sources */, - E284F5E529F2F28A00DBED7D /* MSALNativeAuthSignUpControlling.swift in Sources */, - E2EFAD102A69BBB800D6C3DE /* ResetPasswordResults.swift in Sources */, - DE0347C32A41B819003CB3B6 /* MSALNativeAuthUserAccountResult.swift in Sources */, 2343CBF02576C2D3002D405A /* MSALParameters.m in Sources */, B2D478B4230E3E8B005AE186 /* MSALSerializedADALCacheProvider.m in Sources */, 38880DF423280C5900688C24 /* MSALPublicClientApplicationConfig.m in Sources */, - E243F69E29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift in Sources */, B2D478AF230E3E88005AE186 /* MSALLegacySharedAccount.m in Sources */, - DE0D65B729CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift in Sources */, - DE0FECC82993ADAF00B139A8 /* MSALNativeAuthResendCodeParameters.swift in Sources */, B2D47883230E3DC1005AE186 /* MSALADFSOauth2Provider.m in Sources */, - E2EFAD0D2A69B45100D6C3DE /* SignUpResults.swift in Sources */, - E2EFAD0A2A69A34300D6C3DE /* CodeRequiredGenericResult.swift in Sources */, - E2ACA49D2953576C00E98964 /* MSALNativeAuthUrlRequestSerializer.swift in Sources */, B2D4788A230E3DCF005AE186 /* MSALAADOauth2Provider.m in Sources */, - E2C61FF129DEDB0200F15203 /* MSALNativeAuthSignUpContinueResponseError.swift in Sources */, - DE0D657029BF72F7005798B1 /* MSALNativeAuthSignInInitiateRequestParameters.swift in Sources */, B2D478BF230E3EB0005AE186 /* MSALTenantProfile.m in Sources */, - DE0347BC2A41B768003CB3B6 /* MSALNativeAuthCredentialsController.swift in Sources */, - E2ACA4962953415E00E98964 /* MSALNativeAuthGrantType.swift in Sources */, - E2C1D288299BA15D00B26449 /* MSALNativeAuthBaseController.swift in Sources */, B2D47886230E3DC9005AE186 /* MSALB2COauth2Provider.m in Sources */, - 287F64E72981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift in Sources */, 2396EFCD2582D8A500ADA9EB /* MSALSSOExtensionRequestHandler.m in Sources */, 04A6B5C1226937590035C7C2 /* MSALResult.m in Sources */, - 28D5B05E2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift in Sources */, 04A6B60F226938340035C7C2 /* MSALADFSAuthority.m in Sources */, - DEDB298C29D72D62008DA85B /* MSALNativeAuthInnerError.swift in Sources */, - E2F626AB2A780F8200C4A303 /* SignInStates+Internal.swift in Sources */, 886F516629CCA58900F09471 /* MSALCIAMAuthority.m in Sources */, B273D0F0226E8609005A7BB4 /* MSALTokenParameters.m in Sources */, - DEE34F97D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift in Sources */, B2D478AB230E3E84005AE186 /* MSALLegacySharedADALAccount.m in Sources */, - 8D2733152AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift in Sources */, - E2F626B12A78130700C4A303 /* SignInAfterSignUpState+Internal.swift in Sources */, B273D0F1226E860B005A7BB4 /* MSALInteractiveTokenParameters.m in Sources */, 04A6B5B5226937080035C7C2 /* MSALWebviewType.m in Sources */, - DE8EC8B72A053D80003FA561 /* MSALNativeAuthESTSApiErrorCodes.swift in Sources */, B2D47894230E3DEB005AE186 /* MSALOauth2Authority.m in Sources */, B273D0A3226E8576005A7BB4 /* MSALIndividualClaimRequest.m in Sources */, - E2EFACFF2A69915100D6C3DE /* SignInResults.swift in Sources */, 04A6B5B4226937080035C7C2 /* MSALPromptType.m in Sources */, - DE0D65AD29CC6A5A005798B1 /* MSALNativeAuthSignInInitiateResponse.swift in Sources */, - E2C61FE229DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift in Sources */, - DECC1F9729521E35006D9FB1 /* MSALLogMask.m in Sources */, - DE54B5922A434B9B00460B34 /* MSALNativeAuthTokenController.swift in Sources */, - E2C61FEB29DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift in Sources */, - DE0347BD2A41B76E003CB3B6 /* MSALNativeAuthCredentialsControlling.swift in Sources */, - 9B4EE9DA2A1687B600F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift in Sources */, B2D478A7230E3E5A005AE186 /* MSALTelemetryEventsObservingProxy.m in Sources */, - 9BE7E3CC2A1CB70700CC3A62 /* MSALNativeAuthResetPasswordStartRequestProviderParameters.swift in Sources */, B2D478B3230E3E88005AE186 /* NSString+MSALAccountIdenfiers.m in Sources */, - 289747B7297ABEA300838C80 /* MSALNativeAuthInputValidator.swift in Sources */, - 285F36092A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift in Sources */, - 2814B4DB2A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift in Sources */, 04A6B5BD2269374D0035C7C2 /* MSALAccount.m in Sources */, - E2ACA47C29520C2200E98964 /* MSALNativeAuthEndpoint.swift in Sources */, 04A6B6092269382B0035C7C2 /* MSALAuthority.m in Sources */, 04A6B6162269383F0035C7C2 /* MSALOauth2ProviderFactory.m in Sources */, 1E5319C424A51E51007BCF30 /* MSALAuthScheme.m in Sources */, 04A6B5C92269376A0035C7C2 /* MSALErrorConverter.m in Sources */, - E235610F29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift in Sources */, - DEF9D9A0296F08CE006CB384 /* MSALNativeAuthTelemetryProvider.swift in Sources */, - E235613229C9CEA8000E01CA /* MSALNativeAuthSignUpStartRequestParameters.swift in Sources */, - 28FDC4A72A38C00900E38BE1 /* SignInAfterSignUpDelegate.swift in Sources */, 2396EFE82582DEFC00ADA9EB /* MSALDeviceInformation.m in Sources */, - DEF1DD3D2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift in Sources */, B2D478BB230E3E94005AE186 /* MSALExternalAccountHandler.m in Sources */, - E2B853302A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift in Sources */, - DE0347C12A41B7FC003CB3B6 /* SignUpStartError.swift in Sources */, - 8D35C8F22A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift in Sources */, B273D0DC226E85DD005A7BB4 /* MSALSliceConfig.m in Sources */, 04A6B60B2269382E0035C7C2 /* MSALAADAuthority.m in Sources */, - DEF9D99A296EC848006CB384 /* MSALNativeAuthOperationTypes.swift in Sources */, B2D478C5230E3EC5005AE186 /* MSALAccountEnumerationParameters.m in Sources */, B273D0A7226E857B005A7BB4 /* MSALIndividualClaimRequestAdditionalInfo.m in Sources */, - E2F6269E2A780DDE00C4A303 /* MSALNativeAuthPublicClientApplication+Internal.swift in Sources */, - E243F69B29D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift in Sources */, B2D478BD230E3EA8005AE186 /* MSALWebviewParameters.m in Sources */, 04A6B5AE226936F30035C7C2 /* MSALFramework.m in Sources */, - 9BD2763E2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift in Sources */, - E2C61FEE29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift in Sources */, B273D0C3226E85AA005A7BB4 /* MSALGlobalConfig.m in Sources */, - E2C61FE529DED15800F15203 /* MSALNativeAuthSignUpStartResponseError.swift in Sources */, - E243F6AB29D42FE900DAC60F /* MSALNativeAuthSignUpContinueRequestProviderParams.swift in Sources */, - 9B2E93462A0D3813008A5DD2 /* MSALNativeAuthResetPasswordControlling.swift in Sources */, - E2ACA48C2952302B00E98964 /* MSALNativeAuthRequestContext.swift in Sources */, - E243F69529D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift in Sources */, B273D0DA226E85DB005A7BB4 /* MSALLoggerConfig.m in Sources */, - 9BEF84742A31EF70005CB0B6 /* MSALNativeAuthTokenValidatedResponse.swift in Sources */, B273D0CF226E85CC005A7BB4 /* MSALHTTPConfig.m in Sources */, - 287708262A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift in Sources */, - E2DC31BD29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift in Sources */, - E2B8532C2A1531DA007A4776 /* MSALNativeAuthSignUpValidatedResponses.swift in Sources */, 04A6B5D1226937850035C7C2 /* MSALRedirectUriVerifier.m in Sources */, - 287708232A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift in Sources */, 04A6B5B72269371E0035C7C2 /* MSALAccountId.m in Sources */, - E206FC60296D65DE00AF4400 /* MSALNativeAuthInternalError.swift in Sources */, B273D095226E855B005A7BB4 /* MSALRedirectUri.m in Sources */, - DE8EC8752A026BA0003FA561 /* MSALNativeAuthSignInRequestProvider.swift in Sources */, 04A6B5C7226937660035C7C2 /* MSALLogger.m in Sources */, - E206FCF02979BC4600AF4400 /* MSALNativeAuthSignInController.swift in Sources */, - DEF1DD332AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift in Sources */, - E205D62F29B783FF003887BC /* MSALNativeAuthConfiguration.swift in Sources */, - 28F74D55295C90E100B89A78 /* MSALNativeAuthCacheInterface.swift in Sources */, - E243F6A729D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift in Sources */, 04A6B5B1226936FE0035C7C2 /* MSIDVersion.m in Sources */, - E2EFAD172A70300B00D6C3DE /* MSALNativeAuthControllerTelemetryWrapper.swift in Sources */, - E2F626AE2A78119900C4A303 /* ResetPasswordStates+Internal.swift in Sources */, - DE0FECAD2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift in Sources */, - E2D3BC502A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift in Sources */, - E2DC31C929B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift in Sources */, B273D0A0226E8571005A7BB4 /* MSALClaimsRequest.m in Sources */, - E235613529C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift in Sources */, 04A6B5D6226937940035C7C2 /* MSALTelemetry.m in Sources */, DE9244DE2A31E1D500C0389F /* MSALCIAMOauth2Provider.m in Sources */, - 28E4D9042A30ABA200280921 /* ResendCodeError.swift in Sources */, - 8D35C8E82A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift in Sources */, - E243F6A129D1FF9E00DAC60F /* MSALNativeAuthSignUpContinueRequestParameters.swift in Sources */, - 28FDC4AA2A38C0D100E38BE1 /* SignInAfterSignUpError.swift in Sources */, B2D478AD230E3E88005AE186 /* MSALLegacySharedMSAAccount.m in Sources */, - DE0D65C029D30BAE005798B1 /* MSALNativeAuthResponseError.swift in Sources */, B273D0EA226E85FF005A7BB4 /* MSALPublicClientStatusNotifications.m in Sources */, - 287F65192983F77D00ED90BD /* MSALNativeAuthRequestParametersKey.swift in Sources */, B273D0D5226E85D3005A7BB4 /* MSALTelemetryConfig.m in Sources */, - DE0D657729BF73CB005798B1 /* MSALNativeAuthSignInChallengeRequestParameters.swift in Sources */, - DE1D8AA929E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift in Sources */, - 289747BA297ABEB400838C80 /* MSALNativeAuthParameters.swift in Sources */, - 28F74D54295C90E100B89A78 /* MSALNativeAuthCacheAccessor.swift in Sources */, - E2CD2E8E2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift in Sources */, 04A6B60C226938300035C7C2 /* MSALB2CAuthority.m in Sources */, - DE0347C22A41B80C003CB3B6 /* MSALNativeAuthVerifyCodeParameters.swift in Sources */, - 2826933C2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift in Sources */, - E2F626A82A780F3D00C4A303 /* SignUpStates+Internal.swift in Sources */, - E26097C42948FC4D0060DD7C /* MSALNativeAuthLogging.swift in Sources */, - E2C872C4294CDEE800C4F580 /* MSALNativeAuthRequestable.swift in Sources */, - 9BE7E3D62A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift in Sources */, - 28DE70D729FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift in Sources */, - E2C61FE829DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift in Sources */, B2D478B1230E3E88005AE186 /* MSALLegacySharedAccountFactory.m in Sources */, - 28F19BEC2A2F884D00575581 /* Array+joinScopes.swift in Sources */, - DE729ECE2A1793A100A761D9 /* MSALNativeAuthChannelType.swift in Sources */, - DEF9D98A296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift in Sources */, 2396EFDE2582D8B000ADA9EB /* MSALDeviceInfoProvider.m in Sources */, - E284F5DA29F28B4200DBED7D /* MSALNativeAuthSignUpController.swift in Sources */, - DEE34F49D170B71C00BC302A /* MSALNativeAuthResultFactory.swift in Sources */, - 28FDC49D2A38BFA900E38BE1 /* SignInAfterSignUpState.swift in Sources */, - DE54B5952A43587800460B34 /* MSALNativeAuthTokenRequestProvider.swift in Sources */, 1E5319C824A51FCE007BCF30 /* MSALHttpMethod.m in Sources */, 04A6B5CB226937700035C7C2 /* MSALError.m in Sources */, - 2826932B2A0974750037B93A /* MSALNativeAuthTokenRequestParameters.swift in Sources */, - 2884855D295DAFD400516492 /* MSALNativeAuthTokens.swift in Sources */, B2D4788E230E3DD6005AE186 /* MSALOauth2Provider.m in Sources */, B273D0F3226E860D005A7BB4 /* MSALSilentTokenParameters.m in Sources */, 04A6B5C5226937620035C7C2 /* MSALPublicClientApplication.m in Sources */, diff --git a/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL (iOS Static Library).xcscheme b/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL (iOS Static Library).xcscheme index f68ba05008..5cff5b5a10 100644 --- a/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL (iOS Static Library).xcscheme +++ b/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL (iOS Static Library).xcscheme @@ -29,8 +29,6 @@ shouldUseLaunchSchemeArgsEnv = "YES"> - - - - Date: Thu, 14 Dec 2023 10:08:37 +0000 Subject: [PATCH 18/84] Add optional delegates everywhere (keep delegates that return errors as mandatory). (#1914) Add DelegateDispatchers to handle optional delegate methods Add newState parameter to onSignUpResendCodeError Add comments to clarify why the telemetry event always fails Remove comments because this class will remain internal Rename error methods in SignUpPasswordStartDelegate, SignUpStartDelegate, SignInPasswordStartDelegate, SignInStartDelegate and ResetPasswordStartDelegate. Fix inline doc Updated end to end tests to not use correlation id's Updated End To End tests to use latest delegates --- MSAL/MSAL.xcodeproj/project.pbxproj | 138 ++++++++++++ .../MSALNativeAuthBaseController.swift | 23 ++ .../MSALNativeAuthCredentialsController.swift | 21 +- ...MSALNativeAuthCredentialsControlling.swift | 4 +- ...SALNativeAuthResetPasswordController.swift | 99 ++++---- ...ALNativeAuthResetPasswordControlling.swift | 13 +- .../responses/CodeRequiredGenericResult.swift | 9 - .../responses/ResetPasswordResults.swift | 23 +- .../controllers/responses/SignInResults.swift | 33 --- .../controllers/responses/SignUpResults.swift | 57 +---- .../MSALNativeAuthSignInController.swift | 112 ++++----- .../MSALNativeAuthSignInControlling.swift | 18 +- .../MSALNativeAuthSignUpController.swift | 146 ++++++------ .../MSALNativeAuthSignUpControlling.swift | 6 +- .../errors/MSALNativeAuthErrorMessage.swift | 4 +- ...AuthPublicClientApplication+Internal.swift | 7 +- ...SALNativeAuthPublicClientApplication.swift | 78 +++---- ...NativeAuthUserAccountResult+Internal.swift | 9 +- .../MSALNativeAuthUserAccountResult.swift | 5 +- .../delegate/CredentialsDelegates.swift | 9 +- .../delegate/ResetPasswordDelegates.swift | 14 +- .../delegate/SignInAfterSignUpDelegate.swift | 3 +- .../delegate/SignInDelegates.swift | 39 ++-- .../delegate/SignUpDelegates.swift | 56 +++-- .../CredentialsDelegateDispatcher.swift | 39 ++++ .../DelegateDispatcher.swift | 39 ++++ .../ResetPasswordDelegateDispatchers.swift | 91 ++++++++ .../SignInAfterSignUpDelegateDispatcher.swift | 39 ++++ .../SignInDelegateDispatchers.swift | 132 +++++++++++ .../SignUpDelegateDispatchers.swift | 201 +++++++++++++++++ .../state/ResetPasswordStates+Internal.swift | 10 +- .../state/ResetPasswordStates.swift | 27 ++- .../SignInAfterSignUpState+Internal.swift | 2 +- .../state/SignInAfterSignUpState.swift | 7 +- .../state/SignInStates+Internal.swift | 12 +- .../state_machine/state/SignInStates.swift | 21 +- .../state/SignUpStates+Internal.swift | 4 +- .../state_machine/state/SignUpStates.swift | 58 ++--- .../ResetPasswordDelegateSpies.swift | 2 +- .../sign_in/SignInDelegateSpies.swift | 4 +- .../sign_up/SignUpDelegateSpies.swift | 8 +- ...tiveAuthResetPasswordControllerTests.swift | 4 + .../MSALNativeAuthSignInControllerTests.swift | 2 + .../MSALNativeAuthSignUpControllerTests.swift | 57 ++--- .../mock/CredentialsDelegateSpies.swift | 29 ++- ...LNativeAuthCredentialsControllerMock.swift | 4 +- ...ativeAuthResetPasswordControllerMock.swift | 24 +- .../MSALNativeAuthSignInControllerMock.swift | 16 +- .../MSALNativeAuthSignUpControllerMock.swift | 8 +- .../MSALNativeAuthSignUpControllerSpy.swift | 8 +- .../mock/ResetPasswordDelegateSpies.swift | 72 +++++- .../ResetPasswordTestValidatorHelpers.swift | 34 +-- .../mock/SignInDelegatesSpies.swift | 101 ++++++++- .../mock/SignInTestsValidatorHelpers.swift | 12 +- .../mock/SignUpDelegateSpies.swift | 65 ++++-- .../mock/SignUpTestsValidatorHelpers.swift | 34 +-- ...NativeAuthResetPasswordControllerSpy.swift | 16 +- ...ativeAuthPublicClientApplicationTest.swift | 212 +++++++++++++++--- ...tchAccessTokenRetrieveCompletedTests.swift | 83 +++++++ ...InAfterSignUpDelegateDispatcherTests.swift | 82 +++++++ ...swordRequiredDelegateDispatcherTests.swift | 80 +++++++ ...ordResendCodeDelegateDispatcherTests.swift | 104 +++++++++ ...PasswordStartDelegateDispatcherTests.swift | 105 +++++++++ ...ordVerifyCodeDelegateDispatcherTests.swift | 86 +++++++ ...swordRequiredDelegateDispatcherTests.swift | 84 +++++++ ...PasswordStartDelegateDispatcherTests.swift | 151 +++++++++++++ ...nInResendCodeDelegateDispatcherTests.swift | 101 +++++++++ .../SignInStartDelegateDispatcherTests.swift | 151 +++++++++++++ ...nInVerifyCodeDelegateDispatcherTests.swift | 85 +++++++ ...butesRequiredDelegateDispatcherTests.swift | 189 ++++++++++++++++ ...swordRequiredDelegateDispatcherTests.swift | 142 ++++++++++++ ...PasswordStartDelegateDispatcherTests.swift | 150 +++++++++++++ ...nUpResendCodeDelegateDispatcherTests.swift | 104 +++++++++ .../SignUpStartDelegateDispatcherTests.swift | 150 +++++++++++++ ...nUpVerifyCodeDelegateDispatcherTests.swift | 187 +++++++++++++++ .../ResetPasswordCodeSentStateTests.swift | 68 +++++- .../ResetPasswordRequiredStateTests.swift | 81 +++++-- .../SignInCodeRequiredStateTests.swift | 63 +++++- .../SignInPasswordRequiredStateTests.swift | 30 ++- .../SignUpAttributesRequiredStateTests.swift | 87 ++++++- .../sign_up/SignUpCodeSentStateTests.swift | 82 +++++-- .../SignUpPasswordRequiredStateTests.swift | 32 ++- 82 files changed, 4059 insertions(+), 738 deletions(-) create mode 100644 MSAL/src/native_auth/public/state_machine/delegate_dispatcher/CredentialsDelegateDispatcher.swift create mode 100644 MSAL/src/native_auth/public/state_machine/delegate_dispatcher/DelegateDispatcher.swift create mode 100644 MSAL/src/native_auth/public/state_machine/delegate_dispatcher/ResetPasswordDelegateDispatchers.swift create mode 100644 MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterSignUpDelegateDispatcher.swift create mode 100644 MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInDelegateDispatchers.swift create mode 100644 MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/SignInAfterSignUpDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordRequiredDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/sign_in/SignInResendCodeDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/sign_in/SignInStartDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/sign_in/SignInVerifyCodeDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpResendCodeDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpStartDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index f0616c8a2b..681c831d44 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -1029,6 +1029,35 @@ E20C217E2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20C217D2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift */; }; E20C21842A7A6CA400E31598 /* SignInCodeRequiredStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20C21832A7A6CA400E31598 /* SignInCodeRequiredStateTests.swift */; }; E20C218B2A7A805900E31598 /* SignInPasswordRequiredStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20C218A2A7A805800E31598 /* SignInPasswordRequiredStateTests.swift */; }; + E22427C82B0526660006C55E /* SignUpDelegateDispatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427C72B0526660006C55E /* SignUpDelegateDispatchers.swift */; }; + E22427C92B0526660006C55E /* SignUpDelegateDispatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427C72B0526660006C55E /* SignUpDelegateDispatchers.swift */; }; + E22427D22B0577920006C55E /* SignInDelegateDispatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427D12B0577920006C55E /* SignInDelegateDispatchers.swift */; }; + E22427D32B0577920006C55E /* SignInDelegateDispatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427D12B0577920006C55E /* SignInDelegateDispatchers.swift */; }; + E22427D52B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427D42B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift */; }; + E22427D62B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427D42B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift */; }; + E22427D82B0588AD0006C55E /* DelegateDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427D72B0588AD0006C55E /* DelegateDispatcher.swift */; }; + E22427D92B0588AD0006C55E /* DelegateDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427D72B0588AD0006C55E /* DelegateDispatcher.swift */; }; + E22427DB2B0594670006C55E /* CredentialsDelegateDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427DA2B0594670006C55E /* CredentialsDelegateDispatcher.swift */; }; + E22427DC2B0594670006C55E /* CredentialsDelegateDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427DA2B0594670006C55E /* CredentialsDelegateDispatcher.swift */; }; + E22427DE2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427DD2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift */; }; + E22427DF2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427DD2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift */; }; + E22427E42B0650CD0006C55E /* SignUpPasswordStartDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427E32B0650CD0006C55E /* SignUpPasswordStartDelegateDispatcherTests.swift */; }; + E22427E62B065D0D0006C55E /* SignUpStartDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427E52B065D0D0006C55E /* SignUpStartDelegateDispatcherTests.swift */; }; + E22427E82B065DC00006C55E /* SignUpResendCodeDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427E72B065DC00006C55E /* SignUpResendCodeDelegateDispatcherTests.swift */; }; + E22427EA2B065EAE0006C55E /* SignUpVerifyCodeDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427E92B065EAE0006C55E /* SignUpVerifyCodeDelegateDispatcherTests.swift */; }; + E22427EC2B0662050006C55E /* SignUpPasswordRequiredDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427EB2B0662050006C55E /* SignUpPasswordRequiredDelegateDispatcherTests.swift */; }; + E22427EE2B06637C0006C55E /* SignUpAttributesRequiredDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427ED2B06637C0006C55E /* SignUpAttributesRequiredDelegateDispatcherTests.swift */; }; + E22427F22B0668910006C55E /* SignInPasswordStartDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427F12B0668910006C55E /* SignInPasswordStartDelegateDispatcherTests.swift */; }; + E22427F42B066BBC0006C55E /* SignInStartDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427F32B066BBC0006C55E /* SignInStartDelegateDispatcherTests.swift */; }; + E22427F62B066E850006C55E /* SignInPasswordRequiredDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427F52B066E850006C55E /* SignInPasswordRequiredDelegateDispatcherTests.swift */; }; + E22427F82B066F750006C55E /* SignInResendCodeDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427F72B066F750006C55E /* SignInResendCodeDelegateDispatcherTests.swift */; }; + E22427FA2B0670600006C55E /* SignInVerifyCodeDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427F92B0670600006C55E /* SignInVerifyCodeDelegateDispatcherTests.swift */; }; + E22427FD2B0671A10006C55E /* ResetPasswordStartDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427FC2B0671A10006C55E /* ResetPasswordStartDelegateDispatcherTests.swift */; }; + E22427FF2B06725C0006C55E /* ResetPasswordVerifyCodeDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427FE2B06725C0006C55E /* ResetPasswordVerifyCodeDelegateDispatcherTests.swift */; }; + E22428012B0673290006C55E /* ResetPasswordResendCodeDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22428002B0673290006C55E /* ResetPasswordResendCodeDelegateDispatcherTests.swift */; }; + E22428032B0673DF0006C55E /* ResetPasswordRequiredDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22428022B0673DF0006C55E /* ResetPasswordRequiredDelegateDispatcherTests.swift */; }; + E22428052B0674A50006C55E /* SignInAfterSignUpDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22428042B0674A50006C55E /* SignInAfterSignUpDelegateDispatcherTests.swift */; }; + E22428072B0676970006C55E /* DispatchAccessTokenRetrieveCompletedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22428062B0676970006C55E /* DispatchAccessTokenRetrieveCompletedTests.swift */; }; E22952682A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22952672A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift */; }; E22E20282A7936C50073A6FF /* MSALNativeAuthSignUpControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22E20272A7936C50073A6FF /* MSALNativeAuthSignUpControllerMock.swift */; }; E235610E29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235610D29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift */; }; @@ -2007,6 +2036,29 @@ E20C217D2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordDelegateSpies.swift; sourceTree = ""; }; E20C21832A7A6CA400E31598 /* SignInCodeRequiredStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInCodeRequiredStateTests.swift; sourceTree = ""; }; E20C218A2A7A805800E31598 /* SignInPasswordRequiredStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInPasswordRequiredStateTests.swift; sourceTree = ""; }; + E22427C72B0526660006C55E /* SignUpDelegateDispatchers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpDelegateDispatchers.swift; sourceTree = ""; }; + E22427D12B0577920006C55E /* SignInDelegateDispatchers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInDelegateDispatchers.swift; sourceTree = ""; }; + E22427D42B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordDelegateDispatchers.swift; sourceTree = ""; }; + E22427D72B0588AD0006C55E /* DelegateDispatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegateDispatcher.swift; sourceTree = ""; }; + E22427DA2B0594670006C55E /* CredentialsDelegateDispatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialsDelegateDispatcher.swift; sourceTree = ""; }; + E22427DD2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAfterSignUpDelegateDispatcher.swift; sourceTree = ""; }; + E22427E32B0650CD0006C55E /* SignUpPasswordStartDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpPasswordStartDelegateDispatcherTests.swift; sourceTree = ""; }; + E22427E52B065D0D0006C55E /* SignUpStartDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpStartDelegateDispatcherTests.swift; sourceTree = ""; }; + E22427E72B065DC00006C55E /* SignUpResendCodeDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpResendCodeDelegateDispatcherTests.swift; sourceTree = ""; }; + E22427E92B065EAE0006C55E /* SignUpVerifyCodeDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpVerifyCodeDelegateDispatcherTests.swift; sourceTree = ""; }; + E22427EB2B0662050006C55E /* SignUpPasswordRequiredDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpPasswordRequiredDelegateDispatcherTests.swift; sourceTree = ""; }; + E22427ED2B06637C0006C55E /* SignUpAttributesRequiredDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpAttributesRequiredDelegateDispatcherTests.swift; sourceTree = ""; }; + E22427F12B0668910006C55E /* SignInPasswordStartDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInPasswordStartDelegateDispatcherTests.swift; sourceTree = ""; }; + E22427F32B066BBC0006C55E /* SignInStartDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInStartDelegateDispatcherTests.swift; sourceTree = ""; }; + E22427F52B066E850006C55E /* SignInPasswordRequiredDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInPasswordRequiredDelegateDispatcherTests.swift; sourceTree = ""; }; + E22427F72B066F750006C55E /* SignInResendCodeDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInResendCodeDelegateDispatcherTests.swift; sourceTree = ""; }; + E22427F92B0670600006C55E /* SignInVerifyCodeDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInVerifyCodeDelegateDispatcherTests.swift; sourceTree = ""; }; + E22427FC2B0671A10006C55E /* ResetPasswordStartDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordStartDelegateDispatcherTests.swift; sourceTree = ""; }; + E22427FE2B06725C0006C55E /* ResetPasswordVerifyCodeDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordVerifyCodeDelegateDispatcherTests.swift; sourceTree = ""; }; + E22428002B0673290006C55E /* ResetPasswordResendCodeDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordResendCodeDelegateDispatcherTests.swift; sourceTree = ""; }; + E22428022B0673DF0006C55E /* ResetPasswordRequiredDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordRequiredDelegateDispatcherTests.swift; sourceTree = ""; }; + E22428042B0674A50006C55E /* SignInAfterSignUpDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAfterSignUpDelegateDispatcherTests.swift; sourceTree = ""; }; + E22428062B0676970006C55E /* DispatchAccessTokenRetrieveCompletedTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DispatchAccessTokenRetrieveCompletedTests.swift; sourceTree = ""; }; E22952672A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpResponseValidatorTests.swift; sourceTree = ""; }; E22E20272A7936C50073A6FF /* MSALNativeAuthSignUpControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpControllerMock.swift; sourceTree = ""; }; E235610D29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpRequestProvider.swift; sourceTree = ""; }; @@ -2298,6 +2350,7 @@ 287F64F129819F6B00ED90BD /* public */ = { isa = PBXGroup; children = ( + E22427E02B0650670006C55E /* delegate */, E2CD2E3F29FBE957009F8FFA /* state_machine */, 287F64F22981A00400ED90BD /* MSALNativeAuthPublicClientApplicationTest.swift */, DE87DE692A39E80B0032BF9E /* MSALNativeAuthUserAccountResultTests.swift */, @@ -2443,6 +2496,7 @@ 28DCD08829D70FA000C4601E /* state_machine */ = { isa = PBXGroup; children = ( + E2CE91372B0D077C0009AEDD /* delegate_dispatcher */, 8DDF473E2A98FE1C00126A47 /* MSALNativeAuthRequiredAttributes.swift */, 28DCD09629D7171600C4601E /* error */, 28DCD09529D7170F00C4601E /* state */, @@ -3753,6 +3807,54 @@ path = sign_in; sourceTree = ""; }; + E22427E02B0650670006C55E /* delegate */ = { + isa = PBXGroup; + children = ( + E22427F02B06686C0006C55E /* sign_in */, + E22427EF2B06685B0006C55E /* sign_up */, + E22427FB2B0670E90006C55E /* reset_password */, + E22428042B0674A50006C55E /* SignInAfterSignUpDelegateDispatcherTests.swift */, + E22428062B0676970006C55E /* DispatchAccessTokenRetrieveCompletedTests.swift */, + ); + path = delegate; + sourceTree = ""; + }; + E22427EF2B06685B0006C55E /* sign_up */ = { + isa = PBXGroup; + children = ( + E22427ED2B06637C0006C55E /* SignUpAttributesRequiredDelegateDispatcherTests.swift */, + E22427EB2B0662050006C55E /* SignUpPasswordRequiredDelegateDispatcherTests.swift */, + E22427E32B0650CD0006C55E /* SignUpPasswordStartDelegateDispatcherTests.swift */, + E22427E72B065DC00006C55E /* SignUpResendCodeDelegateDispatcherTests.swift */, + E22427E52B065D0D0006C55E /* SignUpStartDelegateDispatcherTests.swift */, + E22427E92B065EAE0006C55E /* SignUpVerifyCodeDelegateDispatcherTests.swift */, + ); + path = sign_up; + sourceTree = ""; + }; + E22427F02B06686C0006C55E /* sign_in */ = { + isa = PBXGroup; + children = ( + E22427F52B066E850006C55E /* SignInPasswordRequiredDelegateDispatcherTests.swift */, + E22427F12B0668910006C55E /* SignInPasswordStartDelegateDispatcherTests.swift */, + E22427F72B066F750006C55E /* SignInResendCodeDelegateDispatcherTests.swift */, + E22427F32B066BBC0006C55E /* SignInStartDelegateDispatcherTests.swift */, + E22427F92B0670600006C55E /* SignInVerifyCodeDelegateDispatcherTests.swift */, + ); + path = sign_in; + sourceTree = ""; + }; + E22427FB2B0670E90006C55E /* reset_password */ = { + isa = PBXGroup; + children = ( + E22428022B0673DF0006C55E /* ResetPasswordRequiredDelegateDispatcherTests.swift */, + E22428002B0673290006C55E /* ResetPasswordResendCodeDelegateDispatcherTests.swift */, + E22427FC2B0671A10006C55E /* ResetPasswordStartDelegateDispatcherTests.swift */, + E22427FE2B06725C0006C55E /* ResetPasswordVerifyCodeDelegateDispatcherTests.swift */, + ); + path = reset_password; + sourceTree = ""; + }; E235612F29C9CE81000E01CA /* sign_up */ = { isa = PBXGroup; children = ( @@ -4019,6 +4121,19 @@ path = sign_up; sourceTree = ""; }; + E2CE91372B0D077C0009AEDD /* delegate_dispatcher */ = { + isa = PBXGroup; + children = ( + E22427D72B0588AD0006C55E /* DelegateDispatcher.swift */, + E22427C72B0526660006C55E /* SignUpDelegateDispatchers.swift */, + E22427D12B0577920006C55E /* SignInDelegateDispatchers.swift */, + E22427D42B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift */, + E22427DA2B0594670006C55E /* CredentialsDelegateDispatcher.swift */, + E22427DD2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift */, + ); + path = delegate_dispatcher; + sourceTree = ""; + }; E2EFAD072A69A2C300D6C3DE /* responses */ = { isa = PBXGroup; children = ( @@ -5509,12 +5624,14 @@ DE9245122A38736600C0389F /* CredentialsDelegates.swift in Sources */, B223B0C022ADFACB00FB8713 /* MSALLegacySharedAccount.m in Sources */, E2EFACFE2A69915100D6C3DE /* SignInResults.swift in Sources */, + E22427D52B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift in Sources */, D61BD2AF1EBD09F90007E484 /* MSALLogger.m in Sources */, DEE34F82D170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift in Sources */, B253152C23DD66A300432133 /* MSALDeviceInfoProvider.m in Sources */, E27332C02A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift in Sources */, DEDB29A929DDAEB3008DA85B /* MSALNativeAuthTokenOauth2ErrorCode.swift in Sources */, E206FCEF2979BC4600AF4400 /* MSALNativeAuthSignInController.swift in Sources */, + E22427D82B0588AD0006C55E /* DelegateDispatcher.swift in Sources */, DE92450C2A385ED800C0389F /* MSALNativeAuthCredentialsController.swift in Sources */, B28BDA90217E9EAB003E5670 /* MSALOauth2ProviderFactory.m in Sources */, B2AA5D6A23A353F200BD47D8 /* MSALSignoutParameters.m in Sources */, @@ -5534,6 +5651,7 @@ DEE34F72D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeResponseError.swift in Sources */, E2B8532F2A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift in Sources */, B26756CC22921C5B000F01D7 /* MSALB2COauth2Provider.m in Sources */, + E22427D22B0577920006C55E /* SignInDelegateDispatchers.swift in Sources */, 28DCD0A029D7260B00C4601E /* MSALNativeAuthBaseState.swift in Sources */, 287F650C2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift in Sources */, DEDB29A529DDA9DC008DA85B /* MSALNativeAuthSignInInitiateResponseError.swift in Sources */, @@ -5609,8 +5727,11 @@ B2C17B0A1FC8DB2E0070A514 /* MSIDVersion.m in Sources */, E2DC31C829B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift in Sources */, 28DCD0AE29D737E600C4601E /* VerifyCodeError.swift in Sources */, + E22427C82B0526660006C55E /* SignUpDelegateDispatchers.swift in Sources */, 289747B42979A3C800838C80 /* MSALNativeAuthParameters.swift in Sources */, E2F626B02A78130700C4A303 /* SignInAfterSignUpState+Internal.swift in Sources */, + E22427DE2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift in Sources */, + E22427DB2B0594670006C55E /* CredentialsDelegateDispatcher.swift in Sources */, B26756C622921C42000F01D7 /* MSALAADOauth2Provider.m in Sources */, DEE34F12D170B71C00BC302A /* MSALNativeAuthResetPasswordStartRequestParameters.swift in Sources */, 8D35C8E72A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift in Sources */, @@ -5730,11 +5851,13 @@ 23A169B52073325500B051F3 /* MSALPublicClientApplicationTests.m in Sources */, D61F5BC01E5913BE00912CB8 /* SFSafariViewController+TestOverrides.m in Sources */, B2725ED022C04689009B454A /* MSALLegacySharedAccountFactoryTests.m in Sources */, + E22427EE2B06637C0006C55E /* SignUpAttributesRequiredDelegateDispatcherTests.swift in Sources */, E20C218B2A7A805900E31598 /* SignInPasswordRequiredStateTests.swift in Sources */, E20C21752A7A61B600E31598 /* SignUpDelegateSpies.swift in Sources */, E2F5BE9D298A6CEB00C67EC7 /* MSALNativeAuthResultFactoryTests.swift in Sources */, DE14096B2A38DE0E008E6F1E /* CredentialsDelegateSpies.swift in Sources */, DEDB29B129DEC770008DA85B /* MSALNativeAuthRequestErrorHandlerTests.swift in Sources */, + E22428032B0673DF0006C55E /* ResetPasswordRequiredDelegateDispatcherTests.swift in Sources */, D69ADB3F1E516F9B00952049 /* MSALTestURLSessionDataTask.m in Sources */, DEF1DD3C2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift in Sources */, B256121B217EA44900999876 /* MSALOauth2FactoryProducerTests.m in Sources */, @@ -5758,10 +5881,12 @@ E2F5BE8E29893A4100C67EC7 /* MSALNativeAuthEndpointTests.swift in Sources */, 287F64F0298186EA00ED90BD /* MSALNativeAuthInputValidatorTest.swift in Sources */, 8D61F9A12A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift in Sources */, + E22427E42B0650CD0006C55E /* SignUpPasswordStartDelegateDispatcherTests.swift in Sources */, 04D32CD01FD8AFF3000B123E /* MSALErrorConverterTests.m in Sources */, E2F4DB2D2A1F5714009FBCD0 /* MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift in Sources */, 287F6524298401AE00ED90BD /* MSALNativeAuthResponseSerializerTests.swift in Sources */, E2CD2E4F29FC0451009F8FFA /* SignUpPasswordRequiredStateTests.swift in Sources */, + E22427F62B066E850006C55E /* SignInPasswordRequiredDelegateDispatcherTests.swift in Sources */, E2EBD6212A1BB4640049467A /* MSALNativeAuthSignUpRequestProviderMock.swift in Sources */, E2F4DB242A1F525A009FBCD0 /* MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift in Sources */, A0274CDD24B54C8800BD198D /* MSALDevicePopManagerUtil.m in Sources */, @@ -5775,6 +5900,7 @@ 9BD2765F2A0E81CE00FBD033 /* ResetPasswordRequiredStateTests.swift in Sources */, D69ADB371E516F9B00952049 /* MSALTestCase.m in Sources */, DE94C9E829F19E6B00C1EC1F /* MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift in Sources */, + E22427FD2B0671A10006C55E /* ResetPasswordStartDelegateDispatcherTests.swift in Sources */, DE0D659529C1DCC9005798B1 /* MSALNativeAuthSignInInitiateRequestParametersTest.swift in Sources */, E2CD2E5129FC087A009F8FFA /* SignUpAttributesRequiredStateTests.swift in Sources */, 28DE3FD02A0921E2003148A4 /* SignInTestsValidatorHelpers.swift in Sources */, @@ -5809,13 +5935,20 @@ E25BC0832995429D00588549 /* MSALNativeAuthCacheMocks.swift in Sources */, 960751BB2183E82C00F2BF2F /* MSALAccountIdTests.m in Sources */, E20C217E2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift in Sources */, + E22427F82B066F750006C55E /* SignInResendCodeDelegateDispatcherTests.swift in Sources */, E248917A2A1CFA6B001ECBE2 /* MSALNativeAuthConfigStubs.swift in Sources */, + E22427E62B065D0D0006C55E /* SignUpStartDelegateDispatcherTests.swift in Sources */, 9B2BBA352A3297F80075F702 /* MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift in Sources */, 287F64D5297EC29400ED90BD /* MSALNativeAuthCurrentRequestTelemetryTests.swift in Sources */, + E22428072B0676970006C55E /* DispatchAccessTokenRetrieveCompletedTests.swift in Sources */, A0274CBE24B432B100BD198D /* MSALAuthSchemeTests.m in Sources */, + E22427F22B0668910006C55E /* SignInPasswordStartDelegateDispatcherTests.swift in Sources */, B286BA00238A08F6007833AD /* MSALB2CPolicyTests.m in Sources */, + E22428012B0673290006C55E /* ResetPasswordResendCodeDelegateDispatcherTests.swift in Sources */, 9B2BBA2F2A3293330075F702 /* MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift in Sources */, + E22427EC2B0662050006C55E /* SignUpPasswordRequiredDelegateDispatcherTests.swift in Sources */, DE5738BC2A8F79A800D9120D /* MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift in Sources */, + E22427FA2B0670600006C55E /* SignInVerifyCodeDelegateDispatcherTests.swift in Sources */, E2EBD62A2A1BB7700049467A /* MSALNativeAuthSignUpResponseValidatorMock.swift in Sources */, E25BC0852995430B00588549 /* MSALNativeAuthFactoriesMocks.swift in Sources */, E2BC029C29D766CB00041DBC /* MSALNativeAuthSignUpContinueRequestParametersTest.swift in Sources */, @@ -5831,14 +5964,17 @@ E23E956929D5BD6B001DC59C /* MSALNativeAuthSignUpRequestProviderTests.swift in Sources */, DE5738BE2A8F7AC600D9120D /* MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift in Sources */, 609AF9332256BD0C00E2978D /* MSALAccountsProviderTests.m in Sources */, + E22428052B0674A50006C55E /* SignInAfterSignUpDelegateDispatcherTests.swift in Sources */, DE54B59F2A4452DB00460B34 /* MSALNativeAuthTokenResponseValidatorTests.swift in Sources */, DE5738BA2A8F780E00D9120D /* MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift in Sources */, E20C21842A7A6CA400E31598 /* SignInCodeRequiredStateTests.swift in Sources */, B2725EAC22BF2759009B454A /* MSALExternalAccountHandlerTests.m in Sources */, + E22427FF2B06725C0006C55E /* ResetPasswordVerifyCodeDelegateDispatcherTests.swift in Sources */, 232D6192224C53E500260C42 /* MSALClaimsRequestTests.m in Sources */, 9B2BBA312A3296010075F702 /* MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift in Sources */, E25E6E5A2AA7727D0094461E /* MSALNativeAuthCredentialsControllerMock.swift in Sources */, B286B9FD238A07A5007833AD /* MSALAcquireTokenTests.m in Sources */, + E22427F42B066BBC0006C55E /* SignInStartDelegateDispatcherTests.swift in Sources */, DE5738B22A8E71D500D9120D /* MSALNativeAuthResetPasswordContinueResponseErrorTests.swift in Sources */, 9B6EECEF2A3146ED008ABA50 /* MSALNativeAuthResetPasswordResponseValidatorTests.swift in Sources */, 28FDC4AE2A38D81100E38BE1 /* MSALNativeAuthSignInControllerMock.swift in Sources */, @@ -5847,9 +5983,11 @@ 9B4EE9D52A1686A900F243C1 /* MSALNativeAuthResetPasswordControllerTests.swift in Sources */, B29A56D52283D7430023F5E6 /* MSALAADAuthorityTests.m in Sources */, 287F64F32981A00400ED90BD /* MSALNativeAuthPublicClientApplicationTest.swift in Sources */, + E22427E82B065DC00006C55E /* SignUpResendCodeDelegateDispatcherTests.swift in Sources */, E2CD2EB52A0404DA009F8FFA /* MSALNativeAuthSignUpControllerSpy.swift in Sources */, 9BD2765B2A0E7E7D00FBD033 /* ResetPasswordCodeSentStateTests.swift in Sources */, E2F626B32A781CE300C4A303 /* SignInDelegatesSpies.swift in Sources */, + E22427EA2B065EAE0006C55E /* SignUpVerifyCodeDelegateDispatcherTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MSAL/src/native_auth/controllers/MSALNativeAuthBaseController.swift b/MSAL/src/native_auth/controllers/MSALNativeAuthBaseController.swift index 8cd4a1f86f..4aac3fe1ee 100644 --- a/MSAL/src/native_auth/controllers/MSALNativeAuthBaseController.swift +++ b/MSAL/src/native_auth/controllers/MSALNativeAuthBaseController.swift @@ -115,6 +115,29 @@ class MSALNativeAuthBaseController { MSIDTelemetry.sharedInstance().flush(context.telemetryRequestId()) } + /// Stops a telemetry event. + /// - Parameters: + /// - event: The local event to be stopped. + /// - context: The context object. + /// - delegateDispatcherResult: The result sent by the ``DelegateDispatcher`` that contains whether the developer + /// has implemented the optional delegate or not. + /// - controllerError: Optional error set by the Controller when handles the response from API. + /// (ex: SignUpController gets an .attributeValidationFailed. The controller will generate and error and send it here). + func stopTelemetryEvent( + _ event: MSIDTelemetryAPIEvent?, + context: MSIDRequestContext, + delegateDispatcherResult: Result, + controllerError: MSALNativeAuthError? = nil + ) { + switch delegateDispatcherResult { + case .success: + stopTelemetryEvent(event, context: context, error: controllerError) + case .failure(let error): + MSALLogger.log(level: .error, context: context, format: "Error \(error.errorDescription ?? "No error description")") + stopTelemetryEvent(event, context: context, error: error) + } + } + func complete( _ telemetryEvent: MSIDTelemetryAPIEvent?, response: T? = nil, diff --git a/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift index d9752fef25..378364730a 100644 --- a/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift +++ b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift @@ -83,7 +83,7 @@ final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController, return nil } - func refreshToken(context: MSALNativeAuthRequestContext, authTokens: MSALNativeAuthTokens) async -> Result { + func refreshToken(context: MSALNativeAuthRequestContext, authTokens: MSALNativeAuthTokens) async -> RefreshTokenCredentialControllerResponse { MSALLogger.log(level: .verbose, context: context, format: "Refresh started") let telemetryEvent = makeAndStartTelemetryEvent(id: .telemetryApiIdRefreshToken, context: context) let scopes = authTokens.accessToken?.scopes.array as? [String] ?? [] @@ -93,7 +93,7 @@ final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController, context: context ) else { stopTelemetryEvent(telemetryEvent, context: context, error: MSALNativeAuthInternalError.invalidRequest) - return .failure(RetrieveAccessTokenError(type: .generalError)) + return .init(.failure(RetrieveAccessTokenError(type: .generalError))) } let config = factory.makeMSIDConfiguration(scopes: scopes) let response = await performAndValidateTokenRequest(request, config: config, context: context) @@ -145,7 +145,7 @@ final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController, scopes: [String], context: MSALNativeAuthRequestContext, telemetryEvent: MSIDTelemetryAPIEvent? - ) -> Result { + ) -> RefreshTokenCredentialControllerResponse { let config = factory.makeMSIDConfiguration(scopes: scopes) switch response { case .success(let tokenResponse): @@ -162,7 +162,7 @@ final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController, context: context, format: "Refresh Token completed with error: \(error.errorDescription ?? "No error description")") stopTelemetryEvent(telemetryEvent, context: context, error: error) - return .failure(error) + return .init(.failure(error)) } } @@ -171,22 +171,25 @@ final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController, telemetryEvent: MSIDTelemetryAPIEvent?, context: MSALNativeAuthRequestContext, config: MSIDConfiguration - ) -> Result { + ) -> RefreshTokenCredentialControllerResponse { do { let tokenResult = try cacheTokenResponse(tokenResponse, context: context, msidConfiguration: config) - telemetryEvent?.setUserInformation(tokenResult.account) - stopTelemetryEvent(telemetryEvent, context: context) MSALLogger.log( level: .verbose, context: context, format: "Refresh Token completed successfully") - return .success(tokenResult.accessToken.accessToken) + return .init(.success(tokenResult.accessToken.accessToken), telemetryUpdate: { [weak self] result in + telemetryEvent?.setUserInformation(tokenResult.account) + self?.stopTelemetryEvent(telemetryEvent, context: context, delegateDispatcherResult: result) + }) } catch { + let error = RetrieveAccessTokenError(type: .generalError) MSALLogger.log( level: .error, context: context, format: "Token Result was not created properly error - \(error)") - return .failure(RetrieveAccessTokenError(type: .generalError)) + stopTelemetryEvent(telemetryEvent, context: context, error: error) + return .init(.failure(error)) } } } diff --git a/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsControlling.swift b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsControlling.swift index 6b69b64016..0e85fa4531 100644 --- a/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsControlling.swift +++ b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsControlling.swift @@ -25,6 +25,8 @@ import Foundation protocol MSALNativeAuthCredentialsControlling { + typealias RefreshTokenCredentialControllerResponse = MSALNativeAuthControllerTelemetryWrapper> + func retrieveUserAccountResult(context: MSALNativeAuthRequestContext) -> MSALNativeAuthUserAccountResult? - func refreshToken(context: MSALNativeAuthRequestContext, authTokens: MSALNativeAuthTokens) async -> Result + func refreshToken(context: MSALNativeAuthRequestContext, authTokens: MSALNativeAuthTokens) async -> RefreshTokenCredentialControllerResponse } diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift index e705c7c483..b51c0ac7ca 100644 --- a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift @@ -56,19 +56,19 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, // MARK: - Internal interface methods - func resetPassword(parameters: MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartResult { + func resetPassword(parameters: MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordStart, context: parameters.context) let response = await performStartRequest(parameters: parameters) return await handleStartResponse(response, event: event, context: parameters.context) } - func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeResult { + func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordResendCode, context: context) let response = await performChallengeRequest(passwordResetToken: passwordResetToken, context: context) return await handleResendCodeChallengeResponse(response, event: event, context: context) } - func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordVerifyCodeResult { + func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordSubmitCode, context: context) let params = MSALNativeAuthResetPasswordContinueRequestParameters( @@ -86,7 +86,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, password: String, passwordSubmitToken: String, context: MSIDRequestContext - ) async -> ResetPasswordRequiredResult { + ) async -> ResetPasswordSubmitPasswordControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordSubmit, context: context) let params = MSALNativeAuthResetPasswordSubmitRequestParameters( @@ -120,7 +120,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, private func handleStartResponse(_ response: MSALNativeAuthResetPasswordStartValidatedResponse, event: MSIDTelemetryAPIEvent?, - context: MSIDRequestContext) async -> ResetPasswordStartResult { + context: MSIDRequestContext) async -> ResetPasswordStartControllerResponse { MSALLogger.log(level: .verbose, context: context, format: "Finished resetpassword/start request") @@ -134,21 +134,21 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, MSALLogger.log(level: .error, context: context, format: "redirect error in resetpassword/start request \(error.errorDescription ?? "No error description")") - return .error(error) + return .init(.error(error)) case .error(let apiError): let error = apiError.toResetPasswordStartPublicError() stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in resetpassword/start request \(error.errorDescription ?? "No error description")") - return .error(error) + return .init(.error(error)) case .unexpectedError: let error = ResetPasswordStartError(type: .generalError) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in resetpassword/start request \(error.errorDescription ?? "No error description")") - return .error(error) + return .init(.error(error)) } } @@ -177,39 +177,40 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, _ response: MSALNativeAuthResetPasswordChallengeValidatedResponse, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext - ) async -> ResetPasswordStartResult { + ) async -> ResetPasswordStartControllerResponse { switch response { case .success(let sentTo, let channelTargetType, let codeLength, let challengeToken): MSALLogger.log(level: .info, context: context, format: "Successful resetpassword/challenge request") - stopTelemetryEvent(event, context: context) - return .codeRequired( + return .init(.codeRequired( newState: ResetPasswordCodeRequiredState(controller: self, flowToken: challengeToken, correlationId: context.correlationId()), sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength - ) + ), telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) + }) case .error(let apiError): let error = apiError.toResetPasswordStartPublicError() stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in resetpassword/challenge request \(error.errorDescription ?? "No error description")") - return .error(error) + return .init(.error(error)) case .redirect: let error = ResetPasswordStartError(type: .browserRequired, message: MSALNativeAuthErrorMessage.browserRequired) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Redirect error in resetpassword/challenge request \(error.errorDescription ?? "No error description")") - return .error(error) + return .init(.error(error)) case .unexpectedError: let error = ResetPasswordStartError(type: .generalError) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in resetpassword/challenge request \(error.errorDescription ?? "No error description")") - return .error(error) + return .init(.error(error)) } } @@ -217,24 +218,25 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, _ response: MSALNativeAuthResetPasswordChallengeValidatedResponse, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext - ) async -> ResetPasswordResendCodeResult { + ) async -> ResetPasswordResendCodeControllerResponse { switch response { case .success(let sentTo, let channelTargetType, let codeLength, let challengeToken): - stopTelemetryEvent(event, context: context) MSALLogger.log(level: .info, context: context, format: "Successful resetpassword/challenge (resend code) request") - return .codeRequired( + return .init(.codeRequired( newState: ResetPasswordCodeRequiredState(controller: self, flowToken: challengeToken, correlationId: context.correlationId()), sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength - ) + ), telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) + }) case .error(let apiError): let error = apiError.toResendCodePublicError() stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in resetpassword/challenge request (resend code) \(error.errorDescription ?? "No error description")") - return .error(error: error, newState: nil) + return .init(.error(error: error, newState: nil)) case .redirect, .unexpectedError: let error = ResendCodeError() @@ -242,7 +244,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, MSALLogger.log(level: .error, context: context, format: "Error in resetpassword/challenge request (resend code) \(error.errorDescription ?? "No error description")") - return .error(error: error, newState: nil) + return .init(.error(error: error, newState: nil)) } } @@ -271,21 +273,22 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, passwordResetToken: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext - ) async -> ResetPasswordVerifyCodeResult { + ) async -> ResetPasswordSubmitCodeControllerResponse { switch response { case .success(let passwordSubmitToken): - stopTelemetryEvent(event, context: context) MSALLogger.log(level: .info, context: context, format: "Successful resetpassword/continue request") - return .passwordRequired(newState: ResetPasswordRequiredState(controller: self, - flowToken: passwordSubmitToken, - correlationId: context.correlationId())) + let newState = ResetPasswordRequiredState(controller: self, flowToken: passwordSubmitToken, correlationId: context.correlationId()) + return .init(.passwordRequired(newState: newState), + telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) + }) case .error(let apiError): let error = apiError.toVerifyCodePublicError() stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in resetpassword/continue request \(error.errorDescription ?? "No error description")") - return .error(error: error, newState: nil) + return .init(.error(error: error, newState: nil)) case .unexpectedError: let error = VerifyCodeError(type: .generalError) self.stopTelemetryEvent(event, context: context, error: error) @@ -294,7 +297,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context, format: "Error calling resetpassword/continue \(error.errorDescription ?? "No error description")") - return .error(error: error, newState: nil) + return .init(.error(error: error, newState: nil)) case .invalidOOB: let error = VerifyCodeError(type: .invalidCode) self.stopTelemetryEvent(event, context: context, error: error) @@ -304,7 +307,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, format: "Invalid code error calling resetpassword/continue \(error.errorDescription ?? "No error description")") let state = ResetPasswordCodeRequiredState(controller: self, flowToken: passwordResetToken, correlationId: context.correlationId()) - return .error(error: error, newState: state) + return .init(.error(error: error, newState: state)) } } @@ -333,7 +336,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, passwordSubmitToken: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext - ) async -> ResetPasswordRequiredResult { + ) async -> ResetPasswordSubmitPasswordControllerResponse { MSALLogger.log(level: .info, context: context, format: "Finished resetpassword/submit request") switch response { @@ -352,10 +355,8 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, MSALLogger.log(level: .error, context: context, format: "Password error calling resetpassword/submit \(error.errorDescription ?? "No error description")") - - return .error(error: error, newState: ResetPasswordRequiredState(controller: self, - flowToken: passwordSubmitToken, - correlationId: context.correlationId())) + let newState = ResetPasswordRequiredState(controller: self, flowToken: passwordSubmitToken, correlationId: context.correlationId()) + return .init(.error(error: error, newState: newState)) case .error(let apiError): let error = apiError.toPasswordRequiredPublicError() self.stopTelemetryEvent(event, context: context, error: error) @@ -364,7 +365,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context, format: "Error calling resetpassword/submit \(error.errorDescription ?? "No error description")") - return .error(error: error, newState: nil) + return .init(.error(error: error, newState: nil)) case .unexpectedError: let error = PasswordRequiredError(type: .generalError) self.stopTelemetryEvent(event, context: context, error: error) @@ -373,7 +374,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context, format: "Error calling resetpassword/submit \(error.errorDescription ?? "No error description")") - return .error(error: error, newState: nil) + return .init(.error(error: error, newState: nil)) } } @@ -385,7 +386,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, retriesRemaining: Int, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext - ) async -> ResetPasswordRequiredResult { + ) async -> ResetPasswordSubmitPasswordControllerResponse { MSALLogger.log(level: .verbose, context: context, format: "performing poll completion request...") let pollCompletionResponse = await performPollCompletionRequest( @@ -438,7 +439,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, passwordResetToken: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext - ) async -> ResetPasswordRequiredResult { + ) async -> ResetPasswordSubmitPasswordControllerResponse { MSALLogger.log(level: .info, context: context, format: "Finished resetpassword/poll_completion") switch response { @@ -455,15 +456,15 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context ) case .succeeded: - stopTelemetryEvent(event, context: context) - - return .completed + return .init(.completed, telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) + }) case .failed: let error = PasswordRequiredError(type: .generalError) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "password poll success returned status 'failed'") - return .error(error: error, newState: nil) + return .init(.error(error: error, newState: nil)) } case .passwordError(let apiError): let error = apiError.toPasswordRequiredPublicError() @@ -472,10 +473,8 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, MSALLogger.log(level: .error, context: context, format: "Password error calling resetpassword/poll_completion \(error.errorDescription ?? "No error description")") - - return .error(error: error, newState: ResetPasswordRequiredState(controller: self, - flowToken: passwordResetToken, - correlationId: context.correlationId())) + let newState = ResetPasswordRequiredState(controller: self, flowToken: passwordResetToken, correlationId: context.correlationId()) + return .init(.error(error: error, newState: newState)) case .error(let apiError): let error = apiError.toPasswordRequiredPublicError() self.stopTelemetryEvent(event, context: context, error: error) @@ -484,7 +483,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context, format: "Error calling resetpassword/poll_completion \(error.errorDescription ?? "No error description")") - return .error(error: error, newState: nil) + return .init(.error(error: error, newState: nil)) case .unexpectedError: let error = PasswordRequiredError(type: .generalError) self.stopTelemetryEvent(event, context: context, error: error) @@ -493,7 +492,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context, format: "Error calling resetpassword/poll_completion \(error.errorDescription ?? "No error description")") - return .error(error: error, newState: nil) + return .init(.error(error: error, newState: nil)) } } @@ -503,13 +502,13 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, retriesRemaining: Int, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext - ) async -> ResetPasswordRequiredResult { + ) async -> ResetPasswordSubmitPasswordControllerResponse { guard retriesRemaining > 0 else { let error = PasswordRequiredError(type: .generalError) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "password poll completion did not complete in time") - return .error(error: error, newState: nil) + return .init(.error(error: error, newState: nil)) } MSALLogger.log( diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift index 1462d798b7..f1bd2b5360 100644 --- a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift @@ -26,15 +26,20 @@ protocol MSALNativeAuthResetPasswordControlling: AnyObject { - func resetPassword(parameters: MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartResult + typealias ResetPasswordStartControllerResponse = MSALNativeAuthControllerTelemetryWrapper + typealias ResetPasswordResendCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper + typealias ResetPasswordSubmitCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper + typealias ResetPasswordSubmitPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper - func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeResult + func resetPassword(parameters: MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartControllerResponse - func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordVerifyCodeResult + func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse + + func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse func submitPassword( password: String, passwordSubmitToken: String, context: MSIDRequestContext - ) async -> ResetPasswordRequiredResult + ) async -> ResetPasswordSubmitPasswordControllerResponse } diff --git a/MSAL/src/native_auth/controllers/responses/CodeRequiredGenericResult.swift b/MSAL/src/native_auth/controllers/responses/CodeRequiredGenericResult.swift index 5d2c928b5b..e086441d49 100644 --- a/MSAL/src/native_auth/controllers/responses/CodeRequiredGenericResult.swift +++ b/MSAL/src/native_auth/controllers/responses/CodeRequiredGenericResult.swift @@ -24,16 +24,7 @@ import Foundation -/// Result type that contains information about the code sent, the next state of the reset password process and possible errors. enum CodeRequiredGenericResult { - /// Returned if a user has received an email with code. - /// - /// - newState: An object representing the new state of the flow with follow on methods. - /// - sentTo: The email/phone number that the code was sent to. - /// - channelTargetType: The channel (email/phone) the code was sent through. - /// - codeLength: The length of the code required. case codeRequired(newState: State, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) - - /// An error object indicating why the operation failed. case error(error: Error, newState: State?) } diff --git a/MSAL/src/native_auth/controllers/responses/ResetPasswordResults.swift b/MSAL/src/native_auth/controllers/responses/ResetPasswordResults.swift index 952e4b7df2..754121bbfc 100644 --- a/MSAL/src/native_auth/controllers/responses/ResetPasswordResults.swift +++ b/MSAL/src/native_auth/controllers/responses/ResetPasswordResults.swift @@ -24,38 +24,19 @@ import Foundation -/// Represents the result of starting the reset password process. enum ResetPasswordStartResult { - /// Returned if a user has received an email with code. - /// - /// - newState: An object representing the new state of the flow with follow on methods. - /// - sentTo: The email/phone number that the code was sent to. - /// - channelTargetType: The channel (email/phone) the code was sent through. - /// - codeLength: The length of the code required. case codeRequired(newState: ResetPasswordCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) - - /// An error object indicating why the operation failed. case error(ResetPasswordStartError) } -/// Result type that contains information about the code sent, the next state of the reset password process and possible errors. -/// See ``CodeRequiredGenericResult`` for more information. typealias ResetPasswordResendCodeResult = CodeRequiredGenericResult -/// Represents the result of verifying a reset password verification code. -enum ResetPasswordVerifyCodeResult { - /// Returned when a password is required. +enum ResetPasswordSubmitCodeResult { case passwordRequired(newState: ResetPasswordRequiredState) - - /// An error object indicating why the operation failed. case error(error: VerifyCodeError, newState: ResetPasswordCodeRequiredState?) } -/// Represents the result of verifying a reset password verification code. -enum ResetPasswordRequiredResult { - /// Returned after the reset password operation completed successfully. +enum ResetPasswordSubmitPasswordResult { case completed - - /// An error object indicating why the operation failed. case error(error: PasswordRequiredError, newState: ResetPasswordRequiredState?) } diff --git a/MSAL/src/native_auth/controllers/responses/SignInResults.swift b/MSAL/src/native_auth/controllers/responses/SignInResults.swift index 7100a39bea..8115fb4349 100644 --- a/MSAL/src/native_auth/controllers/responses/SignInResults.swift +++ b/MSAL/src/native_auth/controllers/responses/SignInResults.swift @@ -24,59 +24,26 @@ import Foundation -/// Represents the result of sign in using password. enum SignInPasswordStartResult { - /// Returned after the sign in operation completed successfully. An object representing the signed in user account is returned. case completed(MSALNativeAuthUserAccountResult) - - /// Returned if a user registered with email and code tries to sign in using password. - /// In this case MSAL will discard the password and will continue the sign in flow with code. - /// - /// - newState: An object representing the new state of the flow with follow on methods. - /// - sentTo: The email/phone number that the code was sent to. - /// - channelTargetType: The channel (email/phone) the code was sent through. - /// - codeLength: The length of the code required. case codeRequired(newState: SignInCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) - - /// An error object indicating why the operation failed. case error(SignInPasswordStartError) } -/// Represents the result of sign in using code. enum SignInStartResult { - /// Returned if a user has received an email with code. - /// - /// - newState: An object representing the new state of the flow with follow on methods. - /// - sentTo: The email/phone number that the code was sent to. - /// - channelTargetType: The channel (email/phone) the code was sent through. - /// - codeLength: The length of the code required. case codeRequired(newState: SignInCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) - - /// Returned if a user registered with email and password tries to sign in using code. case passwordRequired(newState: SignInPasswordRequiredState) - - /// An error object indicating why the operation failed. case error(SignInStartError) } -/// Result type that contains information about the code sent, the next state of the reset password process and possible errors. -/// See ``CodeRequiredGenericResult`` for more information. typealias SignInResendCodeResult = CodeRequiredGenericResult -/// Result type that contains information about the state of the sign in process. enum SignInPasswordRequiredResult { - /// Returned after the sign in operation completed successfully. An object representing the signed in user account is returned. case completed(MSALNativeAuthUserAccountResult) - - /// An error object indicating why the operation failed. It may contain a ``SignInPasswordRequiredState`` to continue the flow. case error(error: PasswordRequiredError, newState: SignInPasswordRequiredState?) } -/// Result type that contains information about the state of the sign in process. enum SignInVerifyCodeResult { - /// Returned after the sign in operation completed successfully. An object representing the signed in user account is returned. case completed(MSALNativeAuthUserAccountResult) - - /// An error object indicating why the operation failed. It may contain a ``SignInPasswordRequiredState`` to continue the flow. case error(error: VerifyCodeError, newState: SignInCodeRequiredState?) } diff --git a/MSAL/src/native_auth/controllers/responses/SignUpResults.swift b/MSAL/src/native_auth/controllers/responses/SignUpResults.swift index f36ad9695e..7e4754e7fb 100644 --- a/MSAL/src/native_auth/controllers/responses/SignUpResults.swift +++ b/MSAL/src/native_auth/controllers/responses/SignUpResults.swift @@ -25,89 +25,36 @@ import Foundation enum SignUpPasswordStartResult { - /// Returned if a user has received an email with code. - /// - /// - newState: An object representing the new state of the flow with follow on methods. - /// - sentTo: The email/phone number that the code was sent to. - /// - channelTargetType: The channel (email/phone) the code was sent through. - /// - codeLength: The length of the code required. - case codeRequired(newState: SignUpCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) - /// Returned when the attributes sent are invalid. + case codeRequired(newState: SignUpCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) case attributesInvalid([String]) - - /// An error object indicating why the operation failed. case error(SignUpPasswordStartError) } enum SignUpStartResult { - /// Returned if a user has received an email with code. - /// - /// - newState: An object representing the new state of the flow with follow on methods. - /// - sentTo: The email/phone number that the code was sent to. - /// - channelTargetType: The channel (email/phone) the code was sent through. - /// - codeLength: The length of the code required. case codeRequired(newState: SignUpCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) - - /// Returned when the attributes sent are invalid. case attributesInvalid([String]) - - /// An error object indicating why the operation failed. case error(SignUpStartError) } -/// An object of this type is returned after a user submits the code sent to their email/phone. -/// It contains the next state of the flow with follow on methods, depending on the server's response. enum SignUpVerifyCodeResult { - /// Returned after the sign up operation completed successfully. case completed(SignInAfterSignUpState) - - /// Returned when a password is required. case passwordRequired(SignUpPasswordRequiredState) - - /// Returned when attributes are required. case attributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) - - /// An error object indicating why the operation failed. case error(error: VerifyCodeError, newState: SignUpCodeRequiredState?) } -enum SignUpResendCodeResult { - /// Returned if a user has received an email with code. - /// - /// - newState: An object representing the new state of the flow with follow on methods. - /// - sentTo: The email/phone number that the code was sent to. - /// - channelTargetType: The channel (email/phone) the code was sent through. - /// - codeLength: The length of the code required. - case codeRequired(newState: SignUpCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) - - /// An error object indicating why the operation failed. - case error(ResendCodeError) -} +typealias SignUpResendCodeResult = CodeRequiredGenericResult -/// An object of this type is returned after a user submits their password. -/// It contains the next state of the flow with follow on methods, depending on the server's response. enum SignUpPasswordRequiredResult { - /// Returned after the sign up operation completed successfully. case completed(SignInAfterSignUpState) - - /// Returned when attributes are required. case attributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) - - /// An error object indicating why the operation failed. case error(error: PasswordRequiredError, newState: SignUpPasswordRequiredState?) } enum SignUpAttributesRequiredResult { - /// Returned after the sign up operation completed successfully. case completed(SignInAfterSignUpState) - - /// Returned when attributes are required. case attributesRequired(attributes: [MSALNativeAuthRequiredAttributes], state: SignUpAttributesRequiredState) - - /// Returned when the attributes sent are invalid. case attributesInvalid(attributes: [String], newState: SignUpAttributesRequiredState) - - /// An error object indicating why the operation failed. case error(error: AttributesRequiredError) } diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift index 2dc9cd97de..429c66edf7 100644 --- a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift @@ -115,7 +115,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN slt: String?, scopes: [String]?, context: MSALNativeAuthRequestContext - ) async -> Result { + ) async -> SignInAfterSignUpControllerResponse { MSALLogger.log(level: .verbose, context: context, format: "SignIn after signUp started") let telemetryInfo = TelemetryInfo( event: makeAndStartTelemetryEvent(id: .telemetryApiIdSignInAfterSignUp, context: context), @@ -125,7 +125,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN MSALLogger.log(level: .error, context: context, format: "SignIn not available because SLT is nil") let error = SignInAfterSignUpError(message: MSALNativeAuthErrorMessage.signInNotAvailable) stopTelemetryEvent(telemetryInfo, error: error) - return .failure(error) + return .init(.failure(error)) } let scopes = joinScopes(scopes) guard let request = createTokenRequest( @@ -137,7 +137,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN ) else { let error = SignInAfterSignUpError() stopTelemetryEvent(telemetryInfo, error: error) - return .failure(error) + return .init(.failure(error)) } let config = factory.makeMSIDConfiguration(scopes: scopes) let response = await performAndValidateTokenRequest(request, config: config, context: context) @@ -148,10 +148,12 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN scopes: scopes, telemetryInfo: telemetryInfo, onSuccess: { accountResult in - continuation.resume(returning: .success(accountResult)) + continuation.resume(returning: .init(.success(accountResult), telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(telemetryInfo.event, context: context, delegateDispatcherResult: result) + })) }, onError: { error in - continuation.resume(returning: .failure(SignInAfterSignUpError(message: error.errorDescription))) + continuation.resume(returning: .init(.failure(SignInAfterSignUpError(message: error.errorDescription)))) } ) } @@ -163,7 +165,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN credentialToken: String, context: MSALNativeAuthRequestContext, scopes: [String] - ) async -> SignInVerifyCodeResult { + ) async -> SignInSubmitCodeControllerResponse { let telemetryInfo = TelemetryInfo( event: makeAndStartTelemetryEvent(id: .telemetryApiIdSignInSubmitCode, context: context), context: context @@ -196,7 +198,9 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN telemetryInfo: telemetryInfo, config: config, onSuccess: { accountResult in - continuation.resume(returning: .completed(accountResult)) + continuation.resume(returning: .init(.completed(accountResult), telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(telemetryInfo.event, context: context, delegateDispatcherResult: result) + })) }, onError: { [weak self] error in MSALLogger.log(level: .error, context: context, format: "SignIn submit code, token request failed with error \(error)") @@ -229,7 +233,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN credentialToken: String, context: MSALNativeAuthRequestContext, scopes: [String] - ) async -> SignInPasswordRequiredResult { + ) async -> SignInSubmitPasswordControllerResponse { let telemetryInfo = TelemetryInfo( event: makeAndStartTelemetryEvent(id: .telemetryApiIdSignInSubmitPassword, context: context), context: context @@ -261,7 +265,9 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN telemetryInfo: telemetryInfo, config: config, onSuccess: { accountResult in - continuation.resume(returning: .completed(accountResult)) + continuation.resume(returning: .init(.completed(accountResult), telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(telemetryInfo.event, context: context, delegateDispatcherResult: result) + })) }, onError: { [weak self] error in MSALLogger.log(level: .error, context: context, format: "SignIn submit password, token request failed with error \(error)") @@ -292,7 +298,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN credentialToken: String, context: MSALNativeAuthRequestContext, scopes: [String] - ) async -> SignInResendCodeResult { + ) async -> SignInResendCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignInResendCode, context: context) let result = await performAndValidateChallengeRequest(credentialToken: credentialToken, context: context) switch result { @@ -300,19 +306,30 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN let error = ResendCodeError() MSALLogger.log(level: .error, context: context, format: "SignIn ResendCode: received unexpected password required API result") stopTelemetryEvent(event, context: context, error: error) - return .error(error: error, newState: nil) + return .init(.error(error: error, newState: nil)) case .error(let challengeError): let error = ResendCodeError() MSALLogger.log(level: .error, context: context, format: "SignIn ResendCode: received challenge error response: \(challengeError)") stopTelemetryEvent(event, context: context, error: error) - return .error(error: error, newState: SignInCodeRequiredState(scopes: scopes, - controller: self, - flowToken: credentialToken, - correlationId: context.correlationId())) + return .init(.error( + error: error, + newState: SignInCodeRequiredState( + scopes: scopes, + controller: self, + flowToken: credentialToken, + correlationId: context.correlationId())) + ) case .codeRequired(let credentialToken, let sentTo, let channelType, let codeLength): let state = SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken, correlationId: context.correlationId()) - stopTelemetryEvent(event, context: context) - return .codeRequired(newState: state, sentTo: sentTo, channelTargetType: channelType, codeLength: codeLength) + return .init( + .codeRequired( + newState: state, + sentTo: sentTo, + channelTargetType: channelType, + codeLength: codeLength), + telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) + }) } } @@ -324,14 +341,14 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN scopes: [String], credentialToken: String, context: MSALNativeAuthRequestContext - ) -> SignInVerifyCodeResult { + ) -> SignInSubmitCodeControllerResponse { MSALLogger.log( level: .error, context: context, format: "SignIn completed with errorType: \(errorType)") stopTelemetryEvent(telemetryInfo, error: errorType) let state = SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken, correlationId: context.correlationId()) - return .error(error: errorType.convertToVerifyCodeError(), newState: state) + return .init(.error(error: errorType.convertToVerifyCodeError(), newState: state)) } private func processSubmitPasswordFailure( @@ -340,18 +357,20 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN username: String, credentialToken: String, scopes: [String] - ) -> SignInPasswordRequiredResult { + ) -> SignInSubmitPasswordControllerResponse { MSALLogger.log( level: .error, context: telemetryInfo.context, format: "SignIn with username and password completed with errorType: \(errorType)") stopTelemetryEvent(telemetryInfo, error: errorType) - let state = SignInPasswordRequiredState(scopes: scopes, - username: username, - controller: self, - flowToken: credentialToken, - correlationId: telemetryInfo.context.correlationId()) - return .error(error: errorType.convertToPasswordRequiredError(), newState: state) + let state = SignInPasswordRequiredState( + scopes: scopes, + username: username, + controller: self, + flowToken: credentialToken, + correlationId: telemetryInfo.context.correlationId() + ) + return .init(.error(error: errorType.convertToPasswordRequiredError(), newState: state)) } private func performAndValidateSignInInitiate( @@ -464,26 +483,22 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN ) return .init(.passwordRequired(newState: state), telemetryUpdate: { [weak self] result in - switch result { - case .success: - MSALLogger.log(level: .verbose, context: telemetryInfo.context, format: "SignIn, password required") - self?.stopTelemetryEvent(telemetryInfo) - case .failure(let error): - MSALLogger.log( - level: .error, - context: telemetryInfo.context, - format: "SignIn error: \(error.errorDescription ?? "No error description")" - ) - self?.stopTelemetryEvent(telemetryInfo, error: error) - } + self?.stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, delegateDispatcherResult: result) }) case .codeRequired(let credentialToken, let sentTo, let channelType, let codeLength): let state = SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken, correlationId: params.context.correlationId()) - stopTelemetryEvent(telemetryInfo) - return .init(.codeRequired(newState: state, sentTo: sentTo, channelTargetType: channelType, codeLength: codeLength)) + return .init( + .codeRequired( + newState: state, + sentTo: sentTo, + channelTargetType: channelType, + codeLength: codeLength + ), telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, delegateDispatcherResult: result) + }) case .error(let challengeError): let error = challengeError.convertToSignInStartError() MSALLogger.log(level: .error, @@ -516,17 +531,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN ) return .init(result, telemetryUpdate: { [weak self] result in - switch result { - case .success: - self?.stopTelemetryEvent(telemetryInfo) - case .failure(let error): - MSALLogger.log( - level: .error, - context: telemetryInfo.context, - format: "SignIn error \(error.errorDescription ?? "No error description")" - ) - self?.stopTelemetryEvent(telemetryInfo, error: error) - } + self?.stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, delegateDispatcherResult: result) }) case .passwordRequired(let credentialToken): guard let request = createTokenRequest( @@ -549,7 +554,10 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN scopes: scopes, telemetryInfo: telemetryInfo, onSuccess: { accountResult in - continuation.resume(returning: SignInPasswordControllerResponse(.completed(accountResult))) + continuation.resume(returning: SignInPasswordControllerResponse(.completed(accountResult), + telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, delegateDispatcherResult: result) + })) }, onError: { error in continuation.resume(returning: SignInPasswordControllerResponse(.error(error))) diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift index d2c75df5cd..e5e975e17a 100644 --- a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift @@ -27,6 +27,11 @@ import Foundation protocol MSALNativeAuthSignInControlling { typealias SignInPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper typealias SignInCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper + typealias SignInAfterSignUpControllerResponse = + MSALNativeAuthControllerTelemetryWrapper> + typealias SignInSubmitCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper + typealias SignInSubmitPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper + typealias SignInResendCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper func signIn(params: MSALNativeAuthSignInWithPasswordParameters) async -> SignInPasswordControllerResponse @@ -37,9 +42,14 @@ protocol MSALNativeAuthSignInControlling { slt: String?, scopes: [String]?, context: MSALNativeAuthRequestContext - ) async -> Result + ) async -> SignInAfterSignUpControllerResponse - func submitCode(_ code: String, credentialToken: String, context: MSALNativeAuthRequestContext, scopes: [String]) async -> SignInVerifyCodeResult + func submitCode( + _ code: String, + credentialToken: String, + context: MSALNativeAuthRequestContext, + scopes: [String] + ) async -> SignInSubmitCodeControllerResponse func submitPassword( _ password: String, @@ -47,7 +57,7 @@ protocol MSALNativeAuthSignInControlling { credentialToken: String, context: MSALNativeAuthRequestContext, scopes: [String] - ) async -> SignInPasswordRequiredResult + ) async -> SignInSubmitPasswordControllerResponse - func resendCode(credentialToken: String, context: MSALNativeAuthRequestContext, scopes: [String]) async -> SignInResendCodeResult + func resendCode(credentialToken: String, context: MSALNativeAuthRequestContext, scopes: [String]) async -> SignInResendCodeControllerResponse } diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift index ff6a9848b9..41b7ae8b8f 100644 --- a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift @@ -74,10 +74,10 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa return await handleSignUpStartCodeResult(result, username: parameters.username, event: event, context: parameters.context) } - func resendCode(username: String, context: MSIDRequestContext, signUpToken: String) async -> SignUpResendCodeResult { + func resendCode(username: String, context: MSIDRequestContext, signUpToken: String) async -> SignUpResendCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpResendCode, context: context) let challengeResult = await performAndValidateChallengeRequest(signUpToken: signUpToken, context: context) - return handleResendCodeResult(challengeResult, username: username, event: event, context: context) + return handleResendCodeResult(challengeResult, username: username, event: event, signupToken: signUpToken, context: context) } func submitCode(_ code: String, username: String, signUpToken: String, context: MSIDRequestContext) async -> SignUpSubmitCodeControllerResponse { @@ -111,7 +111,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa username: String, signUpToken: String, context: MSIDRequestContext - ) async -> SignUpAttributesRequiredResult { + ) async -> SignUpSubmitAttributesControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpSubmitAttributes, context: context) let params = MSALNativeAuthSignUpContinueRequestProviderParams( grantType: .attributes, @@ -169,17 +169,8 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa let message = String(format: MSALNativeAuthErrorMessage.attributeValidationFailedSignUpStart, invalidAttributes.description) let error = SignUpPasswordStartError(type: .generalError, message: message) return .init(.attributesInvalid(invalidAttributes), telemetryUpdate: { [weak self] result in - switch result { - case .success: - self?.stopTelemetryEvent(event, context: context, error: error) - case .failure(let error): - MSALLogger.log( - level: .error, - context: context, - format: "SignUp with password error: \(error.errorDescription ?? "No error description")" - ) - self?.stopTelemetryEvent(event, context: context, error: error) - } + // The telemetry event always fails because the attribute validation failed + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result, controllerError: error) }) case .redirect: let error = SignUpPasswordStartError(type: .browserRequired) @@ -244,13 +235,8 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa let message = String(format: MSALNativeAuthErrorMessage.attributeValidationFailedSignUpStart, invalidAttributes.description) let error = SignUpStartError(type: .generalError, message: message) return .init(.attributesInvalid(invalidAttributes), telemetryUpdate: { [weak self] result in - switch result { - case .success: - self?.stopTelemetryEvent(event, context: context, error: error) - case .failure(let error): - MSALLogger.log(level: .error, context: context, format: "SignUp error \(error.errorDescription ?? "No error description")") - self?.stopTelemetryEvent(event, context: context, error: error) - } + // The telemetry event always fails because the attribute validation failed + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result, controllerError: error) }) case .redirect: let error = SignUpStartError(type: .browserRequired) @@ -320,7 +306,6 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa switch result { case .codeRequired(let sentTo, let challengeType, let codeLength, let signUpToken): MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge password request") - stopTelemetryEvent(event, context: context) return SignUpStartPasswordControllerResponse( .codeRequired( newState: SignUpCodeRequiredState(controller: self, @@ -330,7 +315,9 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa sentTo: sentTo, channelTargetType: challengeType, codeLength: codeLength - ) + ), telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) + } ) case .error(let apiError): let error = apiError.toSignUpPasswordStartPublicError() @@ -366,7 +353,6 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa switch result { case .codeRequired(let sentTo, let challengeType, let codeLength, let signUpToken): MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge request") - stopTelemetryEvent(event, context: context) return SignUpStartCodeControllerResponse( .codeRequired( newState: SignUpCodeRequiredState(controller: self, @@ -376,7 +362,9 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa sentTo: sentTo, channelTargetType: challengeType, codeLength: codeLength - ) + ), telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) + } ) case .error(let apiError): let error = apiError.toSignUpStartPublicError() @@ -407,28 +395,38 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa _ result: MSALNativeAuthSignUpChallengeValidatedResponse, username: String, event: MSIDTelemetryAPIEvent?, + signupToken: String, context: MSIDRequestContext - ) -> SignUpResendCodeResult { + ) -> SignUpResendCodeControllerResponse { switch result { case .codeRequired(let sentTo, let challengeType, let codeLength, let signUpToken): MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge resendCode request") - stopTelemetryEvent(event, context: context) - return .codeRequired( - newState: SignUpCodeRequiredState(controller: self, - username: username, - flowToken: signUpToken, - correlationId: context.correlationId()), + return .init(.codeRequired( + newState: SignUpCodeRequiredState( + controller: self, + username: username, + flowToken: signUpToken, + correlationId: context.correlationId() + ), sentTo: sentTo, channelTargetType: challengeType, codeLength: codeLength - ) + ), telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) + }) case .error(let apiError): let error = apiError.toResendCodePublicError() stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in signup/challenge resendCode request \(error.errorDescription ?? "No error description")") - return .error(error) + let newState = SignUpCodeRequiredState( + controller: self, + username: username, + flowToken: signupToken, + correlationId: context.correlationId() + ) + return .init(.error(error: error, newState: newState)) case .redirect, .unexpectedError, .passwordRequired: @@ -437,7 +435,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/challenge resendCode request \(error.errorDescription ?? "No error description")") - return .error(error) + return .init(.error(error: error, newState: nil)) } } @@ -458,13 +456,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa correlationId: context.correlationId()) return .init(.passwordRequired(state), telemetryUpdate: { [weak self] result in - switch result { - case .success: - self?.stopTelemetryEvent(event, context: context) - case .failure(let error): - MSALLogger.log(level: .error, context: context, format: "SignUp error \(error.errorDescription ?? "No error description")") - self?.stopTelemetryEvent(event, context: context, error: error) - } + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) case .redirect: let error = VerifyCodeError(type: .browserRequired) @@ -515,7 +507,9 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa switch result { case .success(let slt): let state = createSignInAfterSignUpStateUsingSLT(slt, username: username, event: event, context: context) - return .init(.completed(state)) + return .init(.completed(state), telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) + }) case .invalidUserInput: MSALLogger.log(level: .error, context: context, format: "invalid_user_input error in signup/continue request") @@ -537,13 +531,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa correlationId: context.correlationId()) return .init(.attributesRequired(attributes: attributes, newState: state), telemetryUpdate: { [weak self] result in - switch result { - case .success: - self?.stopTelemetryEvent(event, context: context) - case .failure(let error): - MSALLogger.log(level: .error, context: context, format: "SignUp error \(error.errorDescription ?? "No error description")") - self?.stopTelemetryEvent(event, context: context, error: error) - } + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) case .error(let apiError): let error = apiError.toVerifyCodePublicError() @@ -573,7 +561,9 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa switch result { case .success(let slt): let state = createSignInAfterSignUpStateUsingSLT(slt, username: username, event: event, context: context) - return .init(.completed(state)) + return .init(.completed(state), telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) + }) case .invalidUserInput(let error): let error = error.toPasswordRequiredPublicError() stopTelemetryEvent(event, context: context, error: error) @@ -598,13 +588,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa correlationId: context.correlationId()) return .init(.attributesRequired(attributes: attributes, newState: state), telemetryUpdate: { [weak self] result in - switch result { - case .success: - self?.stopTelemetryEvent(event, context: context) - case .failure(let error): - MSALLogger.log(level: .error, context: context, format: "SignUp error \(error.errorDescription ?? "No error description")") - self?.stopTelemetryEvent(event, context: context, error: error) - } + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) case .error(let apiError): let error = apiError.toPasswordRequiredPublicError() @@ -625,51 +609,59 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa } } + // swiftlint:disable:next function_body_length private func handleSubmitAttributesResult( _ result: MSALNativeAuthSignUpContinueValidatedResponse, username: String, signUpToken: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext - ) -> SignUpAttributesRequiredResult { + ) -> SignUpSubmitAttributesControllerResponse { switch result { case .success(let slt): let state = createSignInAfterSignUpStateUsingSLT(slt, username: username, event: event, context: context) - return .completed(state) + return .init(.completed(state), telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) + }) case .attributesRequired(let signUpToken, let attributes): let error = AttributesRequiredError() - stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "attributes_required received in signup/continue submitAttributes request: \(attributes)") - - let state = SignUpAttributesRequiredState(controller: self, - username: username, - flowToken: signUpToken, - correlationId: context.correlationId()) - - return .attributesRequired(attributes: attributes, state: state) + let state = SignUpAttributesRequiredState( + controller: self, + username: username, + flowToken: signUpToken, + correlationId: context.correlationId() + ) + return .init(.attributesRequired(attributes: attributes, state: state), telemetryUpdate: { [weak self] result in + // The telemetry event always fails because more attributes are required (we consider this an error after having sent attributes) + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result, controllerError: error) + }) case .attributeValidationFailed(let signUpToken, let invalidAttributes): let message = "attribute_validation_failed from signup/continue submitAttributes request. Make sure these attributes are correct: \(invalidAttributes)" // swiftlint:disable:this line_length MSALLogger.log(level: .error, context: context, format: message) let errorMessage = String(format: MSALNativeAuthErrorMessage.attributeValidationFailed, invalidAttributes.description) let error = AttributesRequiredError(message: errorMessage) - stopTelemetryEvent(event, context: context, error: error) - - let state = SignUpAttributesRequiredState(controller: self, - username: username, - flowToken: signUpToken, - correlationId: context.correlationId()) - return .attributesInvalid(attributes: invalidAttributes, newState: state) + let state = SignUpAttributesRequiredState( + controller: self, + username: username, + flowToken: signUpToken, + correlationId: context.correlationId() + ) + return .init(.attributesInvalid(attributes: invalidAttributes, newState: state), telemetryUpdate: { [weak self] result in + // The telemetry event always fails because the attribute validation failed + self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result, controllerError: error) + }) case .error(let apiError): let error = apiError.toAttributesRequiredPublicError() stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in signup/continue submitAttributes request \(error.errorDescription ?? "No error description")") - return .error(error: error) + return .init(.error(error: error)) case .credentialRequired, .unexpectedError, .invalidUserInput: @@ -678,7 +670,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/continue submitAttributes request \(error.errorDescription ?? "No error description")") - return .error(error: error) + return .init(.error(error: error)) } } diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift index 7e79e734ca..56dfbfb06e 100644 --- a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift @@ -28,14 +28,16 @@ protocol MSALNativeAuthSignUpControlling: AnyObject { typealias SignUpStartPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper typealias SignUpStartCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper + typealias SignUpResendCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper typealias SignUpSubmitCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper typealias SignUpSubmitPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper + typealias SignUpSubmitAttributesControllerResponse = MSALNativeAuthControllerTelemetryWrapper func signUpStartPassword(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) async -> SignUpStartPasswordControllerResponse func signUpStartCode(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) async -> SignUpStartCodeControllerResponse - func resendCode(username: String, context: MSIDRequestContext, signUpToken: String) async -> SignUpResendCodeResult + func resendCode(username: String, context: MSIDRequestContext, signUpToken: String) async -> SignUpResendCodeControllerResponse func submitCode(_ code: String, username: String, signUpToken: String, context: MSIDRequestContext) async -> SignUpSubmitCodeControllerResponse @@ -51,5 +53,5 @@ protocol MSALNativeAuthSignUpControlling: AnyObject { username: String, signUpToken: String, context: MSIDRequestContext - ) async -> SignUpAttributesRequiredResult + ) async -> SignUpSubmitAttributesControllerResponse } diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift index dd97229bb1..a19341bba7 100644 --- a/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift @@ -25,7 +25,7 @@ // swiftlint:disable line_length enum MSALNativeAuthErrorMessage { static let invalidScope = "Invalid scope" - static let delegateNotImplemented = "MSALNativeAuth has called an optional delegate method that has not been implemented" + static let delegateNotImplemented = "MSALNativeAuth has called the delegate method %@ that has not been implemented" static let unsupportedMFA = "MFA currently not supported. Use the browser instead" static let browserRequired = "Browser required. Use acquireTokenInteractively instead" static let userDoesNotHavePassword = "User does not have password associated with account" @@ -34,8 +34,6 @@ enum MSALNativeAuthErrorMessage { static let attributeValidationFailedSignUpStart = "Check the invalid attributes and start the sign-up process again. Invalid attributes: %@" static let attributeValidationFailed = "Invalid attributes: %@" static let signInNotAvailable = "Sign In is not available at this point, please use the standalone sign in methods" - static let passwordRequiredNotImplemented = "Implementation of onSignInPasswordRequired required" - static let codeRequiredNotImplemented = "Implementation of onSignInCodeRequired required" static let codeRequiredForPasswordUserLog = "This user does not have a password associated with their account. SDK will call `delegate.onSignInCodeRequired()` and the entered password will be ignored" } diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift index 108f16676f..ae2d7a3254 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift @@ -117,9 +117,12 @@ extension MSALNativeAuthPublicClientApplication { return await controller.signIn(params: params) } - func resetPasswordInternal(username: String, correlationId: UUID?) async -> ResetPasswordStartResult { + func resetPasswordInternal( + username: String, + correlationId: UUID? + ) async -> MSALNativeAuthResetPasswordControlling.ResetPasswordStartControllerResponse { guard inputValidator.isInputValid(username) else { - return .error(ResetPasswordStartError(type: .invalidUsername)) + return .init(.error(ResetPasswordStartError(type: .invalidUsername))) } let controller = controllerFactory.makeResetPasswordController() diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift index 302324c816..bb998010e6 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift @@ -135,25 +135,20 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic correlationId: correlationId ) + let delegateDispatcher = SignUpPasswordStartDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) + switch controllerResponse.result { case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): - await delegate.onSignUpCodeRequired( + await delegateDispatcher.dispatchSignUpPasswordCodeRequired( newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength ) case .attributesInvalid(let attributes): - if let signUpAttributesMethod = delegate.onSignUpAttributesInvalid { - controllerResponse.telemetryUpdate?(.success(())) - await signUpAttributesMethod(attributes) - } else { - let error = SignUpPasswordStartError(type: .generalError, message: MSALNativeAuthErrorMessage.codeRequiredNotImplemented) - controllerResponse.telemetryUpdate?(.failure(error)) - await delegate.onSignUpPasswordError(error: error) - } + await delegateDispatcher.dispatchSignUpAttributesInvalid(attributeNames: attributes) case .error(let error): - await delegate.onSignUpPasswordError(error: error) + await delegate.onSignUpPasswordStartError(error: error) } } } @@ -172,26 +167,20 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic ) { Task { let controllerResponse = await signUpInternal(username: username, attributes: attributes, correlationId: correlationId) + let delegateDispatcher = SignUpStartDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) switch controllerResponse.result { case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): - await delegate.onSignUpCodeRequired( + await delegateDispatcher.dispatchSignUpCodeRequired( newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength ) case .attributesInvalid(let attributes): - if let signUpAttributesMethod = delegate.onSignUpAttributesInvalid { - controllerResponse.telemetryUpdate?(.success(())) - await signUpAttributesMethod(attributes) - } else { - let error = SignUpStartError(type: .generalError, message: MSALNativeAuthErrorMessage.codeRequiredNotImplemented) - controllerResponse.telemetryUpdate?(.failure(error)) - await delegate.onSignUpError(error: error) - } + await delegateDispatcher.dispatchSignUpAttributesInvalid(attributeNames: attributes) case .error(let error): - await delegate.onSignUpError(error: error) + await delegate.onSignUpStartError(error: error) } } } @@ -218,20 +207,20 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic correlationId: correlationId ) + let delegateDispatcher = SignInPasswordStartDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) + switch controllerResponse.result { case .completed(let result): - await delegate.onSignInCompleted(result: result) + await delegateDispatcher.dispatchSignInCompleted(result: result) case .codeRequired(let newState, let sentTo, let channelType, let codeLength): - if let codeRequiredMethod = delegate.onSignInCodeRequired { - controllerResponse.telemetryUpdate?(.success(())) - await codeRequiredMethod(newState, sentTo, channelType, codeLength) - } else { - let error = SignInPasswordStartError(type: .generalError, message: MSALNativeAuthErrorMessage.codeRequiredNotImplemented) - controllerResponse.telemetryUpdate?(.failure(error)) - await delegate.onSignInPasswordError(error: error) - } + await delegateDispatcher.dispatchSignInCodeRequired( + newState: newState, + sentTo: sentTo, + channelTargetType: channelType, + codeLength: codeLength + ) case .error(let error): - await delegate.onSignInPasswordError(error: error) + await delegate.onSignInPasswordStartError(error: error) } } } @@ -255,20 +244,20 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic correlationId: correlationId ) + let delegateDispatcher = SignInStartDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) + switch controllerResponse.result { case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): - await delegate.onSignInCodeRequired(newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength) + await delegateDispatcher.dispatchSignInCodeRequired( + newState: newState, + sentTo: sentTo, + channelTargetType: channelTargetType, + codeLength: codeLength + ) case .passwordRequired(let newState): - if let passwordRequiredMethod = delegate.onSignInPasswordRequired { - controllerResponse.telemetryUpdate?(.success(())) - await passwordRequiredMethod(newState) - } else { - let error = SignInStartError(type: .generalError, message: MSALNativeAuthErrorMessage.passwordRequiredNotImplemented) - controllerResponse.telemetryUpdate?(.failure(error)) - await delegate.onSignInError(error: error) - } + await delegateDispatcher.dispatchSignInPasswordRequired(newState: newState) case .error(let error): - await delegate.onSignInError(error: error) + await delegate.onSignInStartError(error: error) } } } @@ -284,18 +273,19 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic delegate: ResetPasswordStartDelegate ) { Task { - let result = await resetPasswordInternal(username: username, correlationId: correlationId) + let controllerResponse = await resetPasswordInternal(username: username, correlationId: correlationId) + let delegateDispatcher = ResetPasswordStartDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) - switch result { + switch controllerResponse.result { case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): - await delegate.onResetPasswordCodeRequired( + await delegateDispatcher.dispatchResetPasswordCodeRequired( newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength ) case .error(let error): - await delegate.onResetPasswordError(error: error) + await delegate.onResetPasswordStartError(error: error) } } } diff --git a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift index 06cd793ffa..4dfff8685e 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift @@ -26,7 +26,10 @@ import Foundation extension MSALNativeAuthUserAccountResult { - func getAccessTokenInternal(forceRefresh: Bool, correlationId: UUID?) async -> Result { + func getAccessTokenInternal( + forceRefresh: Bool, + correlationId: UUID? + ) async -> MSALNativeAuthCredentialsControlling.RefreshTokenCredentialControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) if let accessToken = self.authTokens.accessToken { @@ -35,11 +38,11 @@ extension MSALNativeAuthUserAccountResult { let credentialsController = controllerFactory.makeCredentialsController() return await credentialsController.refreshToken(context: context, authTokens: authTokens) } else { - return .success(accessToken.accessToken) + return .init(.success(accessToken.accessToken)) } } else { MSALLogger.log(level: .error, context: context, format: "Retrieve Access Token: Existing token not found") - return .failure(RetrieveAccessTokenError(type: .tokenNotFound)) + return .init(.failure(RetrieveAccessTokenError(type: .tokenNotFound))) } } } diff --git a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift index 2a0e4d4823..63e5bc4cea 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift @@ -88,10 +88,11 @@ import Foundation @objc public func getAccessToken(forceRefresh: Bool = false, correlationId: UUID? = nil, delegate: CredentialsDelegate) { Task { let controllerResponse = await getAccessTokenInternal(forceRefresh: forceRefresh, correlationId: correlationId) + let delegateDispatcher = CredentialsDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) - switch controllerResponse { + switch controllerResponse.result { case .success(let accessToken): - await delegate.onAccessTokenRetrieveCompleted(accessToken: accessToken) + await delegateDispatcher.dispatchAccessTokenRetrieveCompleted(accessToken: accessToken) case .failure(let error): await delegate.onAccessTokenRetrieveError(error: error) } diff --git a/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift index 584f349563..53d85cee98 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift @@ -26,11 +26,12 @@ import Foundation @objc public protocol CredentialsDelegate { - /// Notifies the delegate that the operation completed successfully. - /// - Parameter accessToken: The access token string. - @MainActor func onAccessTokenRetrieveCompleted(accessToken: String) - /// Notifies the delegate that the operation resulted in an error. /// - Parameter error: An error object indicating why the operation failed. @MainActor func onAccessTokenRetrieveError(error: RetrieveAccessTokenError) + + /// Notifies the delegate that the operation completed successfully. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onAccessTokenRetrieveError(error:)`` will be called. + /// - Parameter accessToken: The access token string. + @MainActor @objc optional func onAccessTokenRetrieveCompleted(accessToken: String) } diff --git a/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift index 083a7de56a..ccd85a450d 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift @@ -28,15 +28,16 @@ import Foundation public protocol ResetPasswordStartDelegate { /// Notifies the delegate that the operation resulted in an error. /// - Parameter error: An error object indicating why the operation failed. - @MainActor func onResetPasswordError(error: ResetPasswordStartError) + @MainActor func onResetPasswordStartError(error: ResetPasswordStartError) /// Notifies the delegate that a verification code is required from the user to continue. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onResetPasswordStartError(error:)`` will be called. /// - Parameters: /// - newState: An object representing the new state of the flow with follow on methods. /// - sentTo: The email/phone number that the code was sent to. /// - channelTargetType: The channel (email/phone) the code was sent through. /// - codeLength: The length of the code required. - @MainActor func onResetPasswordCodeRequired( + @MainActor @objc optional func onResetPasswordCodeRequired( newState: ResetPasswordCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, @@ -53,8 +54,9 @@ public protocol ResetPasswordVerifyCodeDelegate { @MainActor func onResetPasswordVerifyCodeError(error: VerifyCodeError, newState: ResetPasswordCodeRequiredState?) /// Notifies the delegate that a password is required from the user to continue. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onResetPasswordVerifyCodeError(error:newState:)`` will be called. /// - Parameter newState: An object representing the new state of the flow with follow on methods. - @MainActor func onPasswordRequired(newState: ResetPasswordRequiredState) + @MainActor @objc optional func onPasswordRequired(newState: ResetPasswordRequiredState) } @objc @@ -66,12 +68,13 @@ public protocol ResetPasswordResendCodeDelegate { @MainActor func onResetPasswordResendCodeError(error: ResendCodeError, newState: ResetPasswordCodeRequiredState?) /// Notifies the delegate that a verification code is required from the user to continue. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onResetPasswordResendCodeError(error:newState:)`` will be called. /// - Parameters: /// - newState: An object representing the new state of the flow with follow on methods. /// - sentTo: The email/phone number that the code was sent to. /// - channelTargetType: The channel (email/phone) the code was sent through. /// - codeLength: The length of the code required. - @MainActor func onResetPasswordResendCodeRequired( + @MainActor @objc optional func onResetPasswordResendCodeRequired( newState: ResetPasswordCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, @@ -88,5 +91,6 @@ public protocol ResetPasswordRequiredDelegate { @MainActor func onResetPasswordRequiredError(error: PasswordRequiredError, newState: ResetPasswordRequiredState?) /// Notifies the delegate that the reset password operation completed successfully. - @MainActor func onResetPasswordCompleted() + /// - Note: If a flow requires this optional method and it is not implemented, then ``onResetPasswordRequiredError(error:newState:)`` will be called. + @MainActor @objc optional func onResetPasswordCompleted() } diff --git a/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterSignUpDelegate.swift b/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterSignUpDelegate.swift index 95169051fe..9e6e8443fa 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterSignUpDelegate.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterSignUpDelegate.swift @@ -31,6 +31,7 @@ public protocol SignInAfterSignUpDelegate { @MainActor func onSignInAfterSignUpError(error: SignInAfterSignUpError) /// Notifies the delegate that the sign in operation completed successfully. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignInAfterSignUpError(error:)`` will be called. /// - Parameter result: An object representing the signed in user account. - @MainActor func onSignInCompleted(result: MSALNativeAuthUserAccountResult) + @MainActor @objc optional func onSignInCompleted(result: MSALNativeAuthUserAccountResult) } diff --git a/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift index 6942dbc6b4..d6d7c192d7 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift @@ -28,10 +28,10 @@ import Foundation public protocol SignInPasswordStartDelegate { /// Notifies the delegate that the operation resulted in an error. /// - Parameter error: An error object indicating why the operation failed. - @MainActor func onSignInPasswordError(error: SignInPasswordStartError) + @MainActor func onSignInPasswordStartError(error: SignInPasswordStartError) /// Notifies the delegate that a verification code is required from the user to continue. - /// - Note: If a flow requires a code but this optional method is not implemented, then ``onSignInPasswordError(error:)`` will be called. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignInPasswordStartError(error:)`` will be called. /// - Parameters: /// - newState: An object representing the new state of the flow with follow on methods. /// - sentTo: The email/phone number that the code was sent to. @@ -44,28 +44,30 @@ public protocol SignInPasswordStartDelegate { /// Notifies the delegate that the sign in operation completed successfully. /// - Parameter result: An object representing the signed in user account. - @MainActor func onSignInCompleted(result: MSALNativeAuthUserAccountResult) + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignInPasswordStartError(error:)`` will be called. + @MainActor @objc optional func onSignInCompleted(result: MSALNativeAuthUserAccountResult) } @objc public protocol SignInStartDelegate { /// Notifies the delegate that the operation resulted in an error. /// - Parameter error: An error object indicating why the operation failed. - @MainActor func onSignInError(error: SignInStartError) + @MainActor func onSignInStartError(error: SignInStartError) /// Notifies the delegate that a verification code is required from the user to continue. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignInStartError(error:)`` will be called. /// - Parameters: /// - newState: An object representing the new state of the flow with follow on methods. /// - sentTo: The email/phone number that the code was sent to. /// - channelTargetType: The channel (email/phone) the code was sent through. /// - codeLength: The length of the code required. - @MainActor func onSignInCodeRequired(newState: SignInCodeRequiredState, - sentTo: String, - channelTargetType: MSALNativeAuthChannelType, - codeLength: Int) + @MainActor @objc optional func onSignInCodeRequired(newState: SignInCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int) /// Notifies the delegate that a password is required from the user to continue. - /// - Note: If a flow requires a password but this optional method is not implemented, then ``onSignInError(error:)`` will be called. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignInStartError(error:)`` will be called. /// - Parameter newState: An object representing the new state of the flow with follow on methods. @MainActor @objc optional func onSignInPasswordRequired(newState: SignInPasswordRequiredState) } @@ -79,26 +81,30 @@ public protocol SignInPasswordRequiredDelegate { @MainActor func onSignInPasswordRequiredError(error: PasswordRequiredError, newState: SignInPasswordRequiredState?) /// Notifies the delegate that the sign in operation completed successfully. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignInPasswordRequiredError(error:newState:)`` will be called. /// - Parameter result: An object representing the signed in user account. - @MainActor func onSignInCompleted(result: MSALNativeAuthUserAccountResult) + @MainActor @objc optional func onSignInCompleted(result: MSALNativeAuthUserAccountResult) } @objc public protocol SignInResendCodeDelegate { /// Notifies the delegate that the operation resulted in an error. - /// - Parameter error: An error object indicating why the operation failed. + /// - Parameters: + /// - error: An error object indicating why the operation failed. + /// - newState: An object representing the new state of the flow with follow on methods. @MainActor func onSignInResendCodeError(error: ResendCodeError, newState: SignInCodeRequiredState?) /// Notifies the delegate that a verification code is required from the user to continue. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignInResendCodeError(error:newState:)`` will be called. /// - Parameters: /// - newState: An object representing the new state of the flow with follow on methods. /// - sentTo: The email/phone number that the code was sent to. /// - channelTargetType: The channel (email/phone) the code was sent through. /// - codeLength: The length of the code required. - @MainActor func onSignInResendCodeCodeRequired(newState: SignInCodeRequiredState, - sentTo: String, - channelTargetType: MSALNativeAuthChannelType, - codeLength: Int) + @MainActor @objc optional func onSignInResendCodeCodeRequired(newState: SignInCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int) } @objc @@ -110,6 +116,7 @@ public protocol SignInVerifyCodeDelegate { @MainActor func onSignInVerifyCodeError(error: VerifyCodeError, newState: SignInCodeRequiredState?) /// Notifies the delegate that the sign in operation completed successfully. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignInVerifyCodeError(error:newState:)`` will be called. /// - Parameter result: An object representing the signed in user account. - @MainActor func onSignInCompleted(result: MSALNativeAuthUserAccountResult) + @MainActor @objc optional func onSignInCompleted(result: MSALNativeAuthUserAccountResult) } diff --git a/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift index 3caa85c9e6..94cef5473b 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift @@ -28,21 +28,22 @@ import Foundation public protocol SignUpPasswordStartDelegate { /// Notifies the delegate that the operation resulted in an error. /// - Parameter error: An error object indicating why the operation failed. - @MainActor func onSignUpPasswordError(error: SignUpPasswordStartError) + @MainActor func onSignUpPasswordStartError(error: SignUpPasswordStartError) /// Notifies the delegate that a verification code is required from the user to continue. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpPasswordStartError(error:)`` will be called. /// - Parameters: /// - newState: An object representing the new state of the flow with follow on methods. /// - sentTo: The email/phone number that the code was sent to. /// - channelTargetType: The channel (email/phone) the code was sent through. /// - codeLength: The length of the code required. - @MainActor func onSignUpCodeRequired(newState: SignUpCodeRequiredState, - sentTo: String, - channelTargetType: MSALNativeAuthChannelType, - codeLength: Int) + @MainActor @objc optional func onSignUpCodeRequired(newState: SignUpCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int) /// Notifies the delegate that invalid attributes were sent. - /// - Note: If a flow requires attributes but this optional method is not implemented, then ``onSignUpPasswordError(error)`` will be called. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpPasswordStartError(error:)`` will be called. /// - Parameter attributeNames: List of attribute names that failed validation. @MainActor @objc optional func onSignUpAttributesInvalid(attributeNames: [String]) } @@ -51,21 +52,22 @@ public protocol SignUpPasswordStartDelegate { public protocol SignUpStartDelegate { /// Notifies the delegate that the operation resulted in an error. /// - Parameter error: An error object indicating why the operation failed. - @MainActor func onSignUpError(error: SignUpStartError) + @MainActor func onSignUpStartError(error: SignUpStartError) /// Notifies the delegate that a verification code is required from the user to continue. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpStartError(error:)`` will be called. /// - Parameters: /// - newState: An object representing the new state of the flow with follow on methods. /// - sentTo: The email/phone number that the code was sent to. /// - channelTargetType: The channel (email/phone) the code was sent through. /// - codeLength: The length of the code required. - @MainActor func onSignUpCodeRequired(newState: SignUpCodeRequiredState, - sentTo: String, - channelTargetType: MSALNativeAuthChannelType, - codeLength: Int) + @MainActor @objc optional func onSignUpCodeRequired(newState: SignUpCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int) /// Notifies the delegate that invalid attributes were sent. - /// - Note: If a flow requires attributes but this optional method is not implemented, then ``onSignUpError(error)`` will be called. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpStartError(error:)`` will be called. /// - Parameter attributeNames: List of attribute names that failed validation. @MainActor @objc optional func onSignUpAttributesInvalid(attributeNames: [String]) } @@ -79,35 +81,39 @@ public protocol SignUpVerifyCodeDelegate { @MainActor func onSignUpVerifyCodeError(error: VerifyCodeError, newState: SignUpCodeRequiredState?) /// Notifies the delegate that attributes are required from the user to continue. - /// - Note: If a flow requires attributes but this optional method is not implemented, then ``onSignUpVerifyCodeError(error:newState:)`` will be called. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpVerifyCodeError(error:newState:)`` will be called. /// - Parameters: /// - attributes: List of required attributes. /// - newState: An object representing the new state of the flow with follow on methods. @MainActor @objc optional func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) /// Notifies the delegate that a password is required from the user to continue. - /// - Note: If a flow requires a password but this optional method is not implemented, then ``onSignUpVerifyCodeError(error:newState:)`` will be called. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpVerifyCodeError(error:newState:)`` will be called. /// - Parameter newState: An object representing the new state of the flow with follow on methods. @MainActor @objc optional func onSignUpPasswordRequired(newState: SignUpPasswordRequiredState) /// Notifies the delegate that the sign up operation completed successfully. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpVerifyCodeError(error:newState:)`` will be called. /// - Parameter newState: An object representing the new state of the flow with follow on methods. - @MainActor func onSignUpCompleted(newState: SignInAfterSignUpState) + @MainActor @objc optional func onSignUpCompleted(newState: SignInAfterSignUpState) } @objc public protocol SignUpResendCodeDelegate { /// Notifies the delegate that the operation resulted in an error. - /// - Parameter error: An error object indicating why the operation failed. - @MainActor func onSignUpResendCodeError(error: ResendCodeError) + /// - Parameters: + /// - error: An error object indicating why the operation failed. + /// - newState: An object representing the new state of the flow with follow on methods. + @MainActor func onSignUpResendCodeError(error: ResendCodeError, newState: SignUpCodeRequiredState?) /// Notifies the delegate that a verification code is required from the user to continue. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpResendCodeError(error:newState:)`` will be called. /// - Parameters: /// - newState: An object representing the new state of the flow with follow on methods. /// - sentTo: The email/phone number that the code was sent to. /// - channelTargetType: The channel (email/phone) the code was sent through. /// - codeLength: The length of the code required. - @MainActor func onSignUpResendCodeCodeRequired( + @MainActor @objc optional func onSignUpResendCodeCodeRequired( newState: SignUpCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, @@ -124,15 +130,16 @@ public protocol SignUpPasswordRequiredDelegate { @MainActor func onSignUpPasswordRequiredError(error: PasswordRequiredError, newState: SignUpPasswordRequiredState?) /// Notifies the delegate that attributes are required from the user to continue. - /// - Note: If a flow requires attributes but this optional method is not implemented, then ``onSignUpPasswordRequiredError(error:newState:)`` will be called. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpPasswordRequiredError(error:newState:)`` will be called. /// - Parameters: /// - attributes: List of required attributes. /// - newState: An object representing the new state of the flow with follow on methods. @MainActor @objc optional func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) /// Notifies the delegate that the sign up operation completed successfully. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpPasswordRequiredError(error:newState:)`` will be called. /// - Parameter newState: An object representing the new state of the flow with follow on methods. - @MainActor func onSignUpCompleted(newState: SignInAfterSignUpState) + @MainActor @objc optional func onSignUpCompleted(newState: SignInAfterSignUpState) } @objc @@ -142,18 +149,21 @@ public protocol SignUpAttributesRequiredDelegate { @MainActor func onSignUpAttributesRequiredError(error: AttributesRequiredError) /// Notifies the delegate that there are some required attributes to be sent. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpAttributesRequiredError(error:)`` will be called. /// - Parameters: /// - attributes: List of required attributes. /// - newState: An object representing the new state of the flow with follow on methods. - @MainActor func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) + @MainActor @objc optional func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) /// Notifies the delegate that invalid attributes were sent. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpAttributesRequiredError(error:)`` will be called. /// - Parameters: /// - attributeNames: List of attribute names that failed validation. /// - newState: An object representing the new state of the flow with follow on methods. - @MainActor func onSignUpAttributesInvalid(attributeNames: [String], newState: SignUpAttributesRequiredState) + @MainActor @objc optional func onSignUpAttributesInvalid(attributeNames: [String], newState: SignUpAttributesRequiredState) /// Notifies the delegate that the sign up operation completed successfully. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpAttributesRequiredError(error:)`` will be called. /// - Parameter newState: An object representing the new state of the flow with follow on methods. - @MainActor func onSignUpCompleted(newState: SignInAfterSignUpState) + @MainActor @objc optional func onSignUpCompleted(newState: SignInAfterSignUpState) } diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/CredentialsDelegateDispatcher.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/CredentialsDelegateDispatcher.swift new file mode 100644 index 0000000000..56723f9611 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/CredentialsDelegateDispatcher.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +final class CredentialsDelegateDispatcher: DelegateDispatcher { + + func dispatchAccessTokenRetrieveCompleted(accessToken: String) async { + if let onAccessTokenRetrieveCompleted = delegate.onAccessTokenRetrieveCompleted { + telemetryUpdate?(.success(())) + await onAccessTokenRetrieveCompleted(accessToken) + } else { + let error = RetrieveAccessTokenError(type: .generalError, message: requiredErrorMessage(for: "onAccessTokenRetrieveCompleted")) + telemetryUpdate?(.failure(error)) + await delegate.onAccessTokenRetrieveError(error: error) + } + } +} diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/DelegateDispatcher.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/DelegateDispatcher.swift new file mode 100644 index 0000000000..38ddea2e14 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/DelegateDispatcher.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +class DelegateDispatcher { + let delegate: T + let telemetryUpdate: ((Result) -> Void)? + + init(delegate: T, telemetryUpdate: ((Result) -> Void)?) { + self.delegate = delegate + self.telemetryUpdate = telemetryUpdate + } + + func requiredErrorMessage(for method: String) -> String { + return String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, method) + } +} diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/ResetPasswordDelegateDispatchers.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/ResetPasswordDelegateDispatchers.swift new file mode 100644 index 0000000000..70d136a219 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/ResetPasswordDelegateDispatchers.swift @@ -0,0 +1,91 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +final class ResetPasswordStartDelegateDispatcher: DelegateDispatcher { + + func dispatchResetPasswordCodeRequired( + newState: ResetPasswordCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int + ) async { + if let onResetPasswordCodeRequired = delegate.onResetPasswordCodeRequired { + telemetryUpdate?(.success(())) + await onResetPasswordCodeRequired(newState, sentTo, channelTargetType, codeLength) + } else { + let error = ResetPasswordStartError(type: .generalError, message: requiredErrorMessage(for: "onResetPasswordCodeRequired")) + telemetryUpdate?(.failure(error)) + await delegate.onResetPasswordStartError(error: error) + } + } +} + +final class ResetPasswordVerifyCodeDelegateDispatcher: DelegateDispatcher { + + func dispatchPasswordRequired(newState: ResetPasswordRequiredState) async { + if let onPasswordRequired = delegate.onPasswordRequired { + telemetryUpdate?(.success(())) + await onPasswordRequired(newState) + } else { + let error = VerifyCodeError(type: .generalError, message: requiredErrorMessage(for: "onPasswordRequired")) + telemetryUpdate?(.failure(error)) + await delegate.onResetPasswordVerifyCodeError(error: error, newState: nil) + } + } +} + +final class ResetPasswordResendCodeDelegateDispatcher: DelegateDispatcher { + + func dispatchResetPasswordResendCodeRequired( + newState: ResetPasswordCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int + ) async { + if let onResetPasswordResendCodeRequired = delegate.onResetPasswordResendCodeRequired { + telemetryUpdate?(.success(())) + await onResetPasswordResendCodeRequired(newState, sentTo, channelTargetType, codeLength) + } else { + let error = ResendCodeError(message: requiredErrorMessage(for: "onResetPasswordResendCodeRequired")) + telemetryUpdate?(.failure(error)) + await delegate.onResetPasswordResendCodeError(error: error, newState: nil) + } + } +} + +final class ResetPasswordRequiredDelegateDispatcher: DelegateDispatcher { + + func dispatchResetPasswordCompleted() async { + if let onResetPasswordCompleted = delegate.onResetPasswordCompleted { + telemetryUpdate?(.success(())) + await onResetPasswordCompleted() + } else { + let error = PasswordRequiredError(type: .generalError, message: requiredErrorMessage(for: "onResetPasswordCompleted")) + telemetryUpdate?(.failure(error)) + await delegate.onResetPasswordRequiredError(error: error, newState: nil) + } + } +} diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterSignUpDelegateDispatcher.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterSignUpDelegateDispatcher.swift new file mode 100644 index 0000000000..6f1d88631f --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterSignUpDelegateDispatcher.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +final class SignInAfterSignUpDelegateDispatcher: DelegateDispatcher { + + func dispatchSignInCompleted(result: MSALNativeAuthUserAccountResult) async { + if let onSignInCompleted = delegate.onSignInCompleted { + telemetryUpdate?(.success(())) + await onSignInCompleted(result) + } else { + let error = SignInAfterSignUpError(message: requiredErrorMessage(for: "onSignInCompleted")) + telemetryUpdate?(.failure(error)) + await delegate.onSignInAfterSignUpError(error: error) + } + } +} diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInDelegateDispatchers.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInDelegateDispatchers.swift new file mode 100644 index 0000000000..7c123f5a72 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInDelegateDispatchers.swift @@ -0,0 +1,132 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +final class SignInPasswordStartDelegateDispatcher: DelegateDispatcher { + + func dispatchSignInCodeRequired( + newState: SignInCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int + ) async { + if let onSignInCodeRequired = delegate.onSignInCodeRequired { + telemetryUpdate?(.success(())) + await onSignInCodeRequired(newState, sentTo, channelTargetType, codeLength) + } else { + let error = SignInPasswordStartError(type: .generalError, message: requiredErrorMessage(for: "onSignInCodeRequired")) + telemetryUpdate?(.failure(error)) + await delegate.onSignInPasswordStartError(error: error) + } + } + + func dispatchSignInCompleted(result: MSALNativeAuthUserAccountResult) async { + if let onSignInCompleted = delegate.onSignInCompleted { + telemetryUpdate?(.success(())) + await onSignInCompleted(result) + } else { + let error = SignInPasswordStartError(type: .generalError, message: requiredErrorMessage(for: "onSignInCompleted")) + telemetryUpdate?(.failure(error)) + await delegate.onSignInPasswordStartError(error: error) + } + } +} + +final class SignInStartDelegateDispatcher: DelegateDispatcher { + + func dispatchSignInCodeRequired( + newState: SignInCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int + ) async { + if let onSignInCodeRequired = delegate.onSignInCodeRequired { + telemetryUpdate?(.success(())) + await onSignInCodeRequired(newState, sentTo, channelTargetType, codeLength) + } else { + let error = SignInStartError(type: .generalError, message: requiredErrorMessage(for: "onSignInCodeRequired")) + telemetryUpdate?(.failure(error)) + await delegate.onSignInStartError(error: error) + } + } + + func dispatchSignInPasswordRequired(newState: SignInPasswordRequiredState) async { + if let onSignInPasswordRequired = delegate.onSignInPasswordRequired { + telemetryUpdate?(.success(())) + await onSignInPasswordRequired(newState) + } else { + let error = SignInStartError(type: .generalError, message: requiredErrorMessage(for: "onSignInPasswordRequired")) + telemetryUpdate?(.failure(error)) + await delegate.onSignInStartError(error: error) + } + } +} + +final class SignInPasswordRequiredDelegateDispatcher: DelegateDispatcher { + + func dispatchSignInCompleted(result: MSALNativeAuthUserAccountResult) async { + if let onSignInCompleted = delegate.onSignInCompleted { + telemetryUpdate?(.success(())) + await onSignInCompleted(result) + } else { + let error = PasswordRequiredError(type: .generalError, message: requiredErrorMessage(for: "onSignInCompleted")) + telemetryUpdate?(.failure(error)) + await delegate.onSignInPasswordRequiredError(error: error, newState: nil) + } + } +} + +final class SignInResendCodeDelegateDispatcher: DelegateDispatcher { + + func dispatchSignInResendCodeCodeRequired( + newState: SignInCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int + ) async { + if let onSignInResendCodeCodeRequired = delegate.onSignInResendCodeCodeRequired { + telemetryUpdate?(.success(())) + await onSignInResendCodeCodeRequired(newState, sentTo, channelTargetType, codeLength) + } else { + let error = ResendCodeError(message: requiredErrorMessage(for: "onSignInResendCodeCodeRequired")) + telemetryUpdate?(.failure(error)) + await delegate.onSignInResendCodeError(error: error, newState: nil) + } + } +} + +final class SignInVerifyCodeDelegateDispatcher: DelegateDispatcher { + + func dispatchSignInCompleted(result: MSALNativeAuthUserAccountResult) async { + if let onSignInCompleted = delegate.onSignInCompleted { + telemetryUpdate?(.success(())) + await onSignInCompleted(result) + } else { + let error = VerifyCodeError(type: .generalError, message: requiredErrorMessage(for: "onSignInCompleted")) + telemetryUpdate?(.failure(error)) + await delegate.onSignInVerifyCodeError(error: error, newState: nil) + } + } +} diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift new file mode 100644 index 0000000000..3af063c76c --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift @@ -0,0 +1,201 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +final class SignUpPasswordStartDelegateDispatcher: DelegateDispatcher { + + func dispatchSignUpPasswordCodeRequired( + newState: SignUpCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int + ) async { + if let onSignUpCodeRequired = delegate.onSignUpCodeRequired { + telemetryUpdate?(.success(())) + await onSignUpCodeRequired(newState, sentTo, channelTargetType, codeLength) + } else { + let error = SignUpPasswordStartError(type: .generalError, message: requiredErrorMessage(for: "onSignUpCodeRequired")) + telemetryUpdate?(.failure(error)) + await delegate.onSignUpPasswordStartError(error: error) + } + } + + func dispatchSignUpAttributesInvalid(attributeNames: [String]) async { + if let onSignUpAttributesInvalid = delegate.onSignUpAttributesInvalid { + telemetryUpdate?(.success(())) + await onSignUpAttributesInvalid(attributeNames) + } else { + let error = SignUpPasswordStartError(type: .generalError, message: requiredErrorMessage(for: "onSignUpAttributesInvalid")) + telemetryUpdate?(.failure(error)) + await delegate.onSignUpPasswordStartError(error: error) + } + } +} + +final class SignUpStartDelegateDispatcher: DelegateDispatcher { + + func dispatchSignUpCodeRequired( + newState: SignUpCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int + ) async { + if let onSignUpCodeRequired = delegate.onSignUpCodeRequired { + telemetryUpdate?(.success(())) + await onSignUpCodeRequired(newState, sentTo, channelTargetType, codeLength) + } else { + let error = SignUpStartError(type: .generalError, message: requiredErrorMessage(for: "onSignUpCodeRequired")) + telemetryUpdate?(.failure(error)) + await delegate.onSignUpStartError(error: error) + } + } + + func dispatchSignUpAttributesInvalid(attributeNames: [String]) async { + if let onSignUpAttributesInvalid = delegate.onSignUpAttributesInvalid { + telemetryUpdate?(.success(())) + await onSignUpAttributesInvalid(attributeNames) + } else { + let error = SignUpStartError(type: .generalError, message: requiredErrorMessage(for: "onSignUpAttributesInvalid")) + telemetryUpdate?(.failure(error)) + await delegate.onSignUpStartError(error: error) + } + } +} + +final class SignUpVerifyCodeDelegateDispatcher: DelegateDispatcher { + + func dispatchSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) async { + if let onSignUpAttributesRequired = delegate.onSignUpAttributesRequired { + telemetryUpdate?(.success(())) + await onSignUpAttributesRequired(attributes, newState) + } else { + let error = VerifyCodeError(type: .generalError, message: requiredErrorMessage(for: "onSignUpAttributesRequired")) + telemetryUpdate?(.failure(error)) + await delegate.onSignUpVerifyCodeError(error: error, newState: nil) + } + } + + func dispatchSignUpPasswordRequired(newState: SignUpPasswordRequiredState) async { + if let onSignUpPasswordRequired = delegate.onSignUpPasswordRequired { + telemetryUpdate?(.success(())) + await onSignUpPasswordRequired(newState) + } else { + let error = VerifyCodeError(type: .generalError, message: requiredErrorMessage(for: "onSignUpPasswordRequired")) + telemetryUpdate?(.failure(error)) + await delegate.onSignUpVerifyCodeError(error: error, newState: nil) + } + } + + func dispatchSignUpCompleted(newState: SignInAfterSignUpState) async { + if let onSignUpCompleted = delegate.onSignUpCompleted { + telemetryUpdate?(.success(())) + await onSignUpCompleted(newState) + } else { + let error = VerifyCodeError(type: .generalError, message: requiredErrorMessage(for: "onSignUpCompleted")) + telemetryUpdate?(.failure(error)) + await delegate.onSignUpVerifyCodeError(error: error, newState: nil) + } + } +} + +final class SignUpResendCodeDelegateDispatcher: DelegateDispatcher { + + func dispatchSignUpResendCodeCodeRequired( + newState: SignUpCodeRequiredState, + sentTo: String, + channelTargetType: MSALNativeAuthChannelType, + codeLength: Int + ) async { + if let onSignUpResendCodeCodeRequired = delegate.onSignUpResendCodeCodeRequired { + telemetryUpdate?(.success(())) + await onSignUpResendCodeCodeRequired(newState, sentTo, channelTargetType, codeLength) + } else { + let error = ResendCodeError(message: requiredErrorMessage(for: "onSignUpResendCodeCodeRequired")) + telemetryUpdate?(.failure(error)) + await delegate.onSignUpResendCodeError(error: error, newState: nil) + } + } +} + +final class SignUpPasswordRequiredDelegateDispatcher: DelegateDispatcher { + + func dispatchSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) async { + if let onSignUpAttributesRequired = delegate.onSignUpAttributesRequired { + telemetryUpdate?(.success(())) + await onSignUpAttributesRequired(attributes, newState) + } else { + let error = PasswordRequiredError(type: .generalError, message: requiredErrorMessage(for: "onSignUpAttributesRequired")) + telemetryUpdate?(.failure(error)) + await delegate.onSignUpPasswordRequiredError(error: error, newState: nil) + } + } + + func dispatchSignUpCompleted(newState: SignInAfterSignUpState) async { + if let onSignUpCompleted = delegate.onSignUpCompleted { + telemetryUpdate?(.success(())) + await onSignUpCompleted(newState) + } else { + let error = PasswordRequiredError(type: .generalError, message: requiredErrorMessage(for: "onSignUpCompleted")) + telemetryUpdate?(.failure(error)) + await delegate.onSignUpPasswordRequiredError(error: error, newState: nil) + } + } +} + +final class SignUpAttributesRequiredDelegateDispatcher: DelegateDispatcher { + + func dispatchSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) async { + if let onSignUpAttributesRequired = delegate.onSignUpAttributesRequired { + telemetryUpdate?(.success(())) + await onSignUpAttributesRequired(attributes, newState) + } else { + let error = AttributesRequiredError(message: requiredErrorMessage(for: "onSignUpAttributesRequired")) + telemetryUpdate?(.failure(error)) + await delegate.onSignUpAttributesRequiredError(error: error) + } + } + + func dispatchSignUpAttributesInvalid(attributeNames: [String], newState: SignUpAttributesRequiredState) async { + if let onSignUpAttributesInvalid = delegate.onSignUpAttributesInvalid { + telemetryUpdate?(.success(())) + await onSignUpAttributesInvalid(attributeNames, newState) + } else { + let error = AttributesRequiredError(message: requiredErrorMessage(for: "onSignUpAttributesInvalid")) + telemetryUpdate?(.failure(error)) + await delegate.onSignUpAttributesRequiredError(error: error) + } + } + + func dispatchSignUpCompleted(newState: SignInAfterSignUpState) async { + if let onSignUpCompleted = delegate.onSignUpCompleted { + telemetryUpdate?(.success(())) + await onSignUpCompleted(newState) + } else { + let error = AttributesRequiredError(message: requiredErrorMessage(for: "onSignUpCompleted")) + telemetryUpdate?(.failure(error)) + await delegate.onSignUpAttributesRequiredError(error: error) + } + } +} diff --git a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift index 7b8a1bf168..c982e83cba 100644 --- a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift +++ b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift @@ -26,17 +26,17 @@ import Foundation extension ResetPasswordCodeRequiredState { - func resendCodeInternal() async -> ResetPasswordResendCodeResult { + func resendCodeInternal() async -> MSALNativeAuthResetPasswordControlling.ResetPasswordResendCodeControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) return await controller.resendCode(passwordResetToken: flowToken, context: context) } - func submitCodeInternal(code: String) async -> ResetPasswordVerifyCodeResult { + func submitCodeInternal(code: String) async -> MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitCodeControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) guard inputValidator.isInputValid(code) else { MSALLogger.log(level: .error, context: context, format: "ResetPassword flow, invalid code") - return .error(error: VerifyCodeError(type: .invalidCode), newState: self) + return .init(.error(error: VerifyCodeError(type: .invalidCode), newState: self)) } return await controller.submitCode(code: code, passwordResetToken: flowToken, context: context) @@ -45,12 +45,12 @@ extension ResetPasswordCodeRequiredState { extension ResetPasswordRequiredState { - func submitPasswordInternal(password: String) async -> ResetPasswordRequiredResult { + func submitPasswordInternal(password: String) async -> MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) guard inputValidator.isInputValid(password) else { MSALLogger.log(level: .error, context: context, format: "ResetPassword flow, invalid password") - return .error(error: PasswordRequiredError(type: .invalidPassword), newState: self) + return .init(.error(error: PasswordRequiredError(type: .invalidPassword), newState: self)) } return await controller.submitPassword(password: password, passwordSubmitToken: flowToken, context: context) diff --git a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift index c9cbf62983..09103c3f74 100644 --- a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift +++ b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift @@ -47,11 +47,15 @@ public class ResetPasswordBaseState: MSALNativeAuthBaseState { /// - Parameter delegate: Delegate that receives callbacks for the operation. public func resendCode(delegate: ResetPasswordResendCodeDelegate) { Task { - let result = await resendCodeInternal() + let controllerResponse = await resendCodeInternal() + let delegateDispatcher = ResetPasswordResendCodeDelegateDispatcher( + delegate: delegate, + telemetryUpdate: controllerResponse.telemetryUpdate + ) - switch result { + switch controllerResponse.result { case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): - await delegate.onResetPasswordResendCodeRequired( + await delegateDispatcher.dispatchResetPasswordResendCodeRequired( newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, @@ -69,11 +73,15 @@ public class ResetPasswordBaseState: MSALNativeAuthBaseState { /// - delegate: Delegate that receives callbacks for the operation. public func submitCode(code: String, delegate: ResetPasswordVerifyCodeDelegate) { Task { - let result = await submitCodeInternal(code: code) + let controllerResponse = await submitCodeInternal(code: code) + let delegateDispatcher = ResetPasswordVerifyCodeDelegateDispatcher( + delegate: delegate, + telemetryUpdate: controllerResponse.telemetryUpdate + ) - switch result { + switch controllerResponse.result { case .passwordRequired(let newState): - await delegate.onPasswordRequired(newState: newState) + await delegateDispatcher.dispatchPasswordRequired(newState: newState) case .error(let error, let newState): await delegate.onResetPasswordVerifyCodeError(error: error, newState: newState) } @@ -89,11 +97,12 @@ public class ResetPasswordBaseState: MSALNativeAuthBaseState { /// - delegate: Delegate that receives callbacks for the operation. public func submitPassword(password: String, delegate: ResetPasswordRequiredDelegate) { Task { - let result = await submitPasswordInternal(password: password) + let controllerResponse = await submitPasswordInternal(password: password) + let delegateDispatcher = ResetPasswordRequiredDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) - switch result { + switch controllerResponse.result { case .completed: - await delegate.onResetPasswordCompleted() + await delegateDispatcher.dispatchResetPasswordCompleted() case .error(let error, let newState): await delegate.onResetPasswordRequiredError(error: error, newState: newState) } diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift index e7e7b145d5..e4c18a6c6f 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift @@ -26,7 +26,7 @@ import Foundation extension SignInAfterSignUpState { - func signInInternal(scopes: [String]?) async -> Result { + func signInInternal(scopes: [String]?) async -> MSALNativeAuthSignInControlling.SignInAfterSignUpControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) return await controller.signIn(username: username, slt: slt, scopes: scopes, context: context) } diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift index beed1c2dec..cf33e035ca 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift @@ -48,11 +48,12 @@ import Foundation delegate: SignInAfterSignUpDelegate ) { Task { - let controllerResult = await signInInternal(scopes: scopes) + let controllerResponse = await signInInternal(scopes: scopes) + let delegateDispatcher = SignInAfterSignUpDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) - switch controllerResult { + switch controllerResponse.result { case .success(let accountResult): - await delegate.onSignInCompleted(result: accountResult) + await delegateDispatcher.dispatchSignInCompleted(result: accountResult) case .failure(let error): await delegate.onSignInAfterSignUpError(error: error) } diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift index 7fe582dd03..dda4c7d034 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift @@ -26,18 +26,18 @@ import Foundation extension SignInCodeRequiredState { - func submitCodeInternal(code: String) async -> SignInVerifyCodeResult { + func submitCodeInternal(code: String) async -> MSALNativeAuthSignInControlling.SignInSubmitCodeControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) MSALLogger.log(level: .verbose, context: context, format: "SignIn flow, code submitted") guard inputValidator.isInputValid(code) else { MSALLogger.log(level: .error, context: context, format: "SignIn flow, invalid code") - return .error(error: VerifyCodeError(type: .invalidCode), newState: self) + return .init(.error(error: VerifyCodeError(type: .invalidCode), newState: self)) } return await controller.submitCode(code, credentialToken: flowToken, context: context, scopes: scopes) } - func resendCodeInternal() async -> SignInResendCodeResult { + func resendCodeInternal() async -> MSALNativeAuthSignInControlling.SignInResendCodeControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) MSALLogger.log(level: .verbose, context: context, format: "SignIn flow, resend code requested") @@ -47,15 +47,13 @@ extension SignInCodeRequiredState { extension SignInPasswordRequiredState { - func submitPasswordInternal( - password: String - ) async -> SignInPasswordRequiredResult { + func submitPasswordInternal(password: String) async -> MSALNativeAuthSignInControlling.SignInSubmitPasswordControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) MSALLogger.log(level: .info, context: context, format: "SignIn flow, password submitted") guard inputValidator.isInputValid(password) else { MSALLogger.log(level: .error, context: context, format: "SignIn flow, invalid password") - return .error(error: PasswordRequiredError(type: .invalidPassword), newState: self) + return .init(.error(error: PasswordRequiredError(type: .invalidPassword), newState: self)) } return await controller.submitPassword(password, username: username, credentialToken: flowToken, context: context, scopes: scopes) diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift b/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift index 1301c2b81b..9022ea051c 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift @@ -58,11 +58,12 @@ import Foundation /// - Parameter delegate: Delegate that receives callbacks for the operation. public func resendCode(delegate: SignInResendCodeDelegate) { Task { - let result = await resendCodeInternal() + let controllerResponse = await resendCodeInternal() + let delegateDispatcher = SignInResendCodeDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) - switch result { + switch controllerResponse.result { case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): - await delegate.onSignInResendCodeCodeRequired( + await delegateDispatcher.dispatchSignInResendCodeCodeRequired( newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, @@ -80,11 +81,12 @@ import Foundation /// - delegate: Delegate that receives callbacks for the operation. public func submitCode(code: String, delegate: SignInVerifyCodeDelegate) { Task { - let result = await submitCodeInternal(code: code) + let controllerResponse = await submitCodeInternal(code: code) + let delegateDispatcher = SignInVerifyCodeDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) - switch result { + switch controllerResponse.result { case .completed(let accountResult): - await delegate.onSignInCompleted(result: accountResult) + await delegateDispatcher.dispatchSignInCompleted(result: accountResult) case .error(let error, let newState): await delegate.onSignInVerifyCodeError(error: error, newState: newState) } @@ -116,11 +118,12 @@ import Foundation /// - delegate: Delegate that receives callbacks for the operation. public func submitPassword(password: String, delegate: SignInPasswordRequiredDelegate) { Task { - let result = await submitPasswordInternal(password: password) + let controllerResponse = await submitPasswordInternal(password: password) + let delegateDispatcher = SignInPasswordRequiredDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) - switch result { + switch controllerResponse.result { case .completed(let accountResult): - await delegate.onSignInCompleted(result: accountResult) + await delegateDispatcher.dispatchSignInCompleted(result: accountResult) case .error(let error, let newState): await delegate.onSignInPasswordRequiredError(error: error, newState: newState) } diff --git a/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift index a3c8474076..c053ea7d84 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift @@ -26,7 +26,7 @@ import Foundation extension SignUpCodeRequiredState { - func resendCodeInternal() async -> SignUpResendCodeResult { + func resendCodeInternal() async -> MSALNativeAuthSignUpControlling.SignUpResendCodeControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) return await controller.resendCode(username: username, context: context, signUpToken: flowToken) } @@ -59,7 +59,7 @@ extension SignUpPasswordRequiredState { extension SignUpAttributesRequiredState { - func submitAttributesInternal(attributes: [String: Any]) async -> SignUpAttributesRequiredResult { + func submitAttributesInternal(attributes: [String: Any]) async -> MSALNativeAuthSignUpControlling.SignUpSubmitAttributesControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) return await controller.submitAttributes(attributes, username: username, signUpToken: flowToken, context: context) } diff --git a/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift b/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift index b26451d562..1f3108e31e 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift @@ -50,18 +50,19 @@ public class SignUpBaseState: MSALNativeAuthBaseState { /// - Parameter delegate: Delegate that receives callbacks for the operation. public func resendCode(delegate: SignUpResendCodeDelegate) { Task { - let result = await resendCodeInternal() + let controllerResponse = await resendCodeInternal() + let delegateDispatcher = SignUpResendCodeDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) - switch result { + switch controllerResponse.result { case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): - await delegate.onSignUpResendCodeCodeRequired( + await delegateDispatcher.dispatchSignUpResendCodeCodeRequired( newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength ) - case .error(let error): - await delegate.onSignUpResendCodeError(error: error) + case .error(let error, let newState): + await delegate.onSignUpResendCodeError(error: error, newState: newState) } } } @@ -73,28 +74,15 @@ public class SignUpBaseState: MSALNativeAuthBaseState { public func submitCode(code: String, delegate: SignUpVerifyCodeDelegate) { Task { let controllerResponse = await submitCodeInternal(code: code) + let delegateDispatcher = SignUpVerifyCodeDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) switch controllerResponse.result { case .completed(let state): - await delegate.onSignUpCompleted(newState: state) + await delegateDispatcher.dispatchSignUpCompleted(newState: state) case .passwordRequired(let state): - if let function = delegate.onSignUpPasswordRequired { - controllerResponse.telemetryUpdate?(.success(())) - await function(state) - } else { - let error = VerifyCodeError(type: .generalError, message: MSALNativeAuthErrorMessage.delegateNotImplemented) - controllerResponse.telemetryUpdate?(.failure(error)) - await delegate.onSignUpVerifyCodeError(error: error, newState: nil) - } + await delegateDispatcher.dispatchSignUpPasswordRequired(newState: state) case .attributesRequired(let attributes, let state): - if let function = delegate.onSignUpAttributesRequired { - controllerResponse.telemetryUpdate?(.success(())) - await function(attributes, state) - } else { - let error = VerifyCodeError(type: .generalError, message: MSALNativeAuthErrorMessage.delegateNotImplemented) - controllerResponse.telemetryUpdate?(.failure(error)) - await delegate.onSignUpVerifyCodeError(error: error, newState: nil) - } + await delegateDispatcher.dispatchSignUpAttributesRequired(attributes: attributes, newState: state) case .error(let error, let state): await delegate.onSignUpVerifyCodeError(error: error, newState: state) } @@ -112,19 +100,13 @@ public class SignUpBaseState: MSALNativeAuthBaseState { public func submitPassword(password: String, delegate: SignUpPasswordRequiredDelegate) { Task { let controllerResponse = await submitPasswordInternal(password: password) + let delegateDispatcher = SignUpPasswordRequiredDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) switch controllerResponse.result { case .completed(let state): - await delegate.onSignUpCompleted(newState: state) + await delegateDispatcher.dispatchSignUpCompleted(newState: state) case .attributesRequired(let attributes, let state): - if let function = delegate.onSignUpAttributesRequired { - controllerResponse.telemetryUpdate?(.success(())) - await function(attributes, state) - } else { - let error = PasswordRequiredError(type: .generalError, message: MSALNativeAuthErrorMessage.delegateNotImplemented) - controllerResponse.telemetryUpdate?(.failure(error)) - await delegate.onSignUpPasswordRequiredError(error: error, newState: nil) - } + await delegateDispatcher.dispatchSignUpAttributesRequired(attributes: attributes, newState: state) case .error(let error, let state): await delegate.onSignUpPasswordRequiredError(error: error, newState: state) } @@ -143,17 +125,21 @@ public class SignUpBaseState: MSALNativeAuthBaseState { delegate: SignUpAttributesRequiredDelegate ) { Task { - let result = await submitAttributesInternal(attributes: attributes) + let controllerResponse = await submitAttributesInternal(attributes: attributes) + let delegateDispatcher = SignUpAttributesRequiredDelegateDispatcher( + delegate: delegate, + telemetryUpdate: controllerResponse.telemetryUpdate + ) - switch result { + switch controllerResponse.result { case .completed(let state): - await delegate.onSignUpCompleted(newState: state) + await delegateDispatcher.dispatchSignUpCompleted(newState: state) case .error(let error): await delegate.onSignUpAttributesRequiredError(error: error) case .attributesRequired(let attributes, let state): - await delegate.onSignUpAttributesRequired(attributes: attributes, newState: state) + await delegateDispatcher.dispatchSignUpAttributesRequired(attributes: attributes, newState: state) case .attributesInvalid(let attributes, let state): - await delegate.onSignUpAttributesInvalid(attributeNames: attributes, newState: state) + await delegateDispatcher.dispatchSignUpAttributesInvalid(attributeNames: attributes, newState: state) } } } diff --git a/MSAL/test/integration/native_auth/end_to_end/reset_password/ResetPasswordDelegateSpies.swift b/MSAL/test/integration/native_auth/end_to_end/reset_password/ResetPasswordDelegateSpies.swift index 37827a1e7b..de8de96325 100644 --- a/MSAL/test/integration/native_auth/end_to_end/reset_password/ResetPasswordDelegateSpies.swift +++ b/MSAL/test/integration/native_auth/end_to_end/reset_password/ResetPasswordDelegateSpies.swift @@ -40,7 +40,7 @@ class ResetPasswordStartDelegateSpy: ResetPasswordStartDelegate { self.expectation = expectation } - func onResetPasswordError(error: MSAL.ResetPasswordStartError) { + func onResetPasswordStartError(error: MSAL.ResetPasswordStartError) { onResetPasswordErrorCalled = true self.error = error diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_in/SignInDelegateSpies.swift b/MSAL/test/integration/native_auth/end_to_end/sign_in/SignInDelegateSpies.swift index a3e6174e88..1471dbf4ad 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_in/SignInDelegateSpies.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_in/SignInDelegateSpies.swift @@ -37,7 +37,7 @@ class SignInPasswordStartDelegateSpy: SignInPasswordStartDelegate { self.expectation = expectation } - public func onSignInPasswordError(error: MSAL.SignInPasswordStartError) { + public func onSignInPasswordStartError(error: MSAL.SignInPasswordStartError) { onSignInPasswordErrorCalled = true self.error = error @@ -71,7 +71,7 @@ class SignInStartDelegateSpy: SignInStartDelegate { self.expectation = expectation } - public func onSignInError(error: MSAL.SignInStartError) { + public func onSignInStartError(error: MSAL.SignInStartError) { onSignInErrorCalled = true self.error = error diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift b/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift index a8806f8a0a..c130b2d8fd 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift @@ -26,7 +26,7 @@ import Foundation import XCTest import MSAL -class SignUpPasswordStartDelegateSpy: SignUpPasswordStartDelegate { +class SignUpPasswordStartDelegateSpy: SignUpPasswordStartDelegate { private let expectation: XCTestExpectation private(set) var onSignUpPasswordErrorCalled = false private(set) var error: MSAL.SignUpPasswordStartError? @@ -40,7 +40,7 @@ class SignUpPasswordStartDelegateSpy: SignUpPasswordStartDelegate { self.expectation = expectation } - func onSignUpPasswordError(error: SignUpPasswordStartError) { + func onSignUpPasswordStartError(error: MSAL.SignUpPasswordStartError) { onSignUpPasswordErrorCalled = true self.error = error @@ -72,7 +72,7 @@ class SignUpStartDelegateSpy: SignUpStartDelegate { self.expectation = expectation } - func onSignUpError(error: SignUpStartError) { + func onSignUpStartError(error: SignUpStartError) { onSignUpErrorCalled = true self.error = error @@ -148,7 +148,7 @@ class SignUpResendCodeDelegateSpy: SignUpResendCodeDelegate { self.expectation = expectation } - func onSignUpResendCodeError(error: ResendCodeError) { + func onSignUpResendCodeError(error: MSAL.ResendCodeError, newState: MSAL.SignUpCodeRequiredState?) { onSignUpResendCodeErrorCalled = true self.error = error } diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift index 21089c6f77..3fd4235947 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift @@ -196,6 +196,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let helper = prepareResetPasswordStartValidatorHelper(exp) let result = await sut.resetPassword(parameters: resetPasswordStartParams) + result.telemetryUpdate?(.success(())) helper.onResetPasswordCodeRequired(result) await fulfillment(of: [exp]) @@ -324,6 +325,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let helper = prepareResetPasswordResendCodeValidatorHelper(exp) let result = await sut.resendCode(passwordResetToken: "passwordResetToken", context: contextMock) + result.telemetryUpdate?(.success(())) helper.onResetPasswordResendCodeRequired(result) await fulfillment(of: [exp]) @@ -437,6 +439,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) let result = await sut.submitCode(code: "1234", passwordResetToken: "passwordResetToken", context: contextMock) + result.telemetryUpdate?(.success(())) helper.onPasswordRequired(result) await fulfillment(of: [exp]) @@ -548,6 +551,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + result.telemetryUpdate?(.success(())) helper.onResetPasswordCompleted(result) await fulfillment(of: [exp]) diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift index 9d337a2465..5c900e320a 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift @@ -394,6 +394,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: sentTo, channelType: channelTargetType, codeLength: codeLength) let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + result.telemetryUpdate?(.success(())) helper.onSignInCodeRequired(result) @@ -697,6 +698,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: sentTo, channelType: channelTargetType, codeLength: codeLength) let result = await sut.resendCode(credentialToken: credentialToken, context: expectedContext, scopes: []) + result.telemetryUpdate?(.success(())) helper.onSignInResendCodeCodeRequired(result) diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift index 0e601d7d06..a7d07363ae 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift @@ -80,7 +80,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) - helper.onSignUpPasswordError(result) + helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpPasswordErrorCalled) @@ -104,7 +104,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpPasswordStartValidatorHelper() let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) - helper.onSignUpPasswordError(result) + helper.onSignUpPasswordStartError(result) XCTAssertTrue(requestProviderMock.challengeCalled) @@ -170,7 +170,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpPasswordStartValidatorHelper(exp) let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) - helper.onSignUpPasswordError(result) + helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpPasswordErrorCalled) @@ -201,7 +201,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpPasswordStartValidatorHelper(exp) let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) - helper.onSignUpPasswordError(result) + helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpPasswordErrorCalled) @@ -232,7 +232,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpPasswordStartValidatorHelper(exp) let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) - helper.onSignUpPasswordError(result) + helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpPasswordErrorCalled) @@ -263,7 +263,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpPasswordStartValidatorHelper(exp) let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) - helper.onSignUpPasswordError(result) + helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpPasswordErrorCalled) @@ -285,7 +285,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpPasswordStartValidatorHelper(exp) let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) - helper.onSignUpPasswordError(result) + helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpPasswordErrorCalled) @@ -311,7 +311,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpPasswordStartValidatorHelper(exp) let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) - helper.onSignUpPasswordError(result) + helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpPasswordErrorCalled) @@ -336,6 +336,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpPasswordStartValidatorHelper(exp) let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + result.telemetryUpdate?(.success(())) helper.onSignUpCodeRequired(result) await fulfillment(of: [exp], timeout: 1) @@ -361,7 +362,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpPasswordStartValidatorHelper(exp) let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) - helper.onSignUpPasswordError(result) + helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpPasswordErrorCalled) @@ -386,7 +387,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpPasswordStartValidatorHelper(exp) let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) - helper.onSignUpPasswordError(result) + helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpPasswordErrorCalled) @@ -417,7 +418,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpPasswordStartValidatorHelper(exp) let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) - helper.onSignUpPasswordError(result) + helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpPasswordErrorCalled) @@ -443,7 +444,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpPasswordStartValidatorHelper(exp) let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) - helper.onSignUpPasswordError(result) + helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpPasswordErrorCalled) @@ -466,7 +467,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpCodeStartValidatorHelper(exp) let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) - helper.onSignUpError(result) + helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpCodeErrorCalled) @@ -490,7 +491,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpCodeStartValidatorHelper() let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) - helper.onSignUpError(result) + helper.onSignUpStartError(result) XCTAssertTrue(requestProviderMock.challengeCalled) @@ -554,7 +555,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpCodeStartValidatorHelper(exp) let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) - helper.onSignUpError(result) + helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpCodeErrorCalled) @@ -585,7 +586,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpCodeStartValidatorHelper(exp) let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) - helper.onSignUpError(result) + helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpCodeErrorCalled) @@ -616,7 +617,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpCodeStartValidatorHelper(exp) let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) - helper.onSignUpError(result) + helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpCodeErrorCalled) @@ -647,7 +648,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpCodeStartValidatorHelper(exp) let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) - helper.onSignUpError(result) + helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpCodeErrorCalled) @@ -669,7 +670,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpCodeStartValidatorHelper(exp) let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) - helper.onSignUpError(result) + helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpCodeErrorCalled) @@ -695,7 +696,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpCodeStartValidatorHelper(exp) let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) - helper.onSignUpError(result) + helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpCodeErrorCalled) @@ -720,6 +721,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpCodeStartValidatorHelper(exp) let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + result.telemetryUpdate?(.success(())) helper.onSignUpCodeRequired(result) await fulfillment(of: [exp], timeout: 1) @@ -745,7 +747,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpCodeStartValidatorHelper(exp) let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) - helper.onSignUpError(result) + helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpCodeErrorCalled) @@ -770,7 +772,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpCodeStartValidatorHelper(exp) let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) - helper.onSignUpError(result) + helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpCodeErrorCalled) @@ -801,7 +803,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpCodeStartValidatorHelper(exp) let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) - helper.onSignUpError(result) + helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpCodeErrorCalled) @@ -827,7 +829,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpCodeStartValidatorHelper(exp) let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) - helper.onSignUpError(result) + helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpCodeErrorCalled) @@ -871,6 +873,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpResendCodeValidatorHelper(exp) let result = await sut.resendCode(username: "", context: contextMock, signUpToken: "signUpToken") + result.telemetryUpdate?(.success(())) helper.onSignUpResendCodeCodeRequired(result) await fulfillment(of: [exp], timeout: 1) @@ -924,7 +927,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpResendCodeErrorCalled) - XCTAssertNil(helper.newState) + XCTAssertNotNil(helper.newState) XCTAssertNil(helper.sentTo) XCTAssertNil(helper.codeLength) XCTAssertNotNil(helper.error) @@ -1709,6 +1712,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + result.telemetryUpdate?(.success(())) helper.onSignUpAttributesRequired(result) await fulfillment(of: [exp], timeout: 1) @@ -1775,6 +1779,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + result.telemetryUpdate?(.success(())) helper.onSignUpAttributesValidationFailed(result) await fulfillment(of: [exp], timeout: 1) @@ -1816,7 +1821,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp2 = expectation(description: "SignInAfterSignUp expectation") signInControllerMock.expectation = exp2 - signInControllerMock.signInSLTResult = .failure(.init()) + signInControllerMock.signInSLTResult = .init(.failure(.init())) helper.signInAfterSignUpState?.signIn(delegate: SignInAfterSignUpDelegateStub()) await fulfillment(of: [exp2], timeout: 1) diff --git a/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift b/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift index 764d8ffa14..4255380bd1 100644 --- a/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift +++ b/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift @@ -58,18 +58,39 @@ open class CredentialsDelegateSpy: CredentialsDelegate { } } +final class CredentialsDelegateOptionalMethodsNotImplemented: CredentialsDelegate { + + private let expectation: XCTestExpectation + var expectedError: RetrieveAccessTokenError? + + init(expectation: XCTestExpectation, expectedError: RetrieveAccessTokenError? = nil) { + self.expectation = expectation + self.expectedError = expectedError + } + + public func onAccessTokenRetrieveError(error: MSAL.RetrieveAccessTokenError) { + if let expectedError = expectedError { + XCTAssertTrue(Thread.isMainThread) + XCTAssertEqual(error.type, expectedError.type) + XCTAssertEqual(error.errorDescription, expectedError.errorDescription) + expectation.fulfill() + return + } + } +} + class CredentialsTestValidatorHelper: CredentialsDelegateSpy { - func onAccessTokenRetrieveCompleted(_ result: Result) { - guard case let .success(token) = result else { + func onAccessTokenRetrieveCompleted(_ response: MSALNativeAuthCredentialsController.RefreshTokenCredentialControllerResponse) { + guard case let .success(token) = response.result else { return XCTFail("wrong result") } Task { await self.onAccessTokenRetrieveCompleted(accessToken: token) } } - func onAccessTokenRetrieveError(_ result: Result) { - guard case let .failure(error) = result else { + func onAccessTokenRetrieveError(_ response: MSALNativeAuthCredentialsController.RefreshTokenCredentialControllerResponse) { + guard case let .failure(error) = response.result else { return XCTFail("wrong result") } diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthCredentialsControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthCredentialsControllerMock.swift index 3aa6f12a9c..0bcf5c47d3 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthCredentialsControllerMock.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthCredentialsControllerMock.swift @@ -28,10 +28,10 @@ import XCTest class MSALNativeAuthCredentialsControllerMock: MSALNativeAuthCredentialsControlling { - var refreshTokenResult: Result! + var refreshTokenResult: RefreshTokenCredentialControllerResponse! var accountResult: MSALNativeAuthUserAccountResult? - func refreshToken(context: MSAL.MSALNativeAuthRequestContext, authTokens: MSAL.MSALNativeAuthTokens) async -> Result { + func refreshToken(context: MSAL.MSALNativeAuthRequestContext, authTokens: MSAL.MSALNativeAuthTokens) async -> RefreshTokenCredentialControllerResponse { return refreshTokenResult } diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift index c08b3e1c35..7970b41981 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift @@ -28,24 +28,24 @@ import XCTest class MSALNativeAuthResetPasswordControllerMock: MSALNativeAuthResetPasswordControlling { - var resetPasswordResult: ResetPasswordStartResult! - var resendCodeResult: ResetPasswordResendCodeResult! - var submitCodeResult: ResetPasswordVerifyCodeResult! - var submitPasswordResult: ResetPasswordRequiredResult! + var resetPasswordResponse: ResetPasswordStartControllerResponse! + var resendCodeResponse: ResetPasswordResendCodeControllerResponse! + var submitCodeResponse: ResetPasswordSubmitCodeControllerResponse! + var submitPasswordResponse: ResetPasswordSubmitPasswordControllerResponse! - func resetPassword(parameters: MSAL.MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartResult { - return resetPasswordResult + func resetPassword(parameters: MSAL.MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartControllerResponse { + return resetPasswordResponse } - func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeResult { - return resendCodeResult + func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { + return resendCodeResponse } - func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordVerifyCodeResult { - return submitCodeResult + func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse { + return submitCodeResponse } - func submitPassword(password: String, passwordSubmitToken: String, context: MSIDRequestContext) async -> ResetPasswordRequiredResult { - return submitPasswordResult + func submitPassword(password: String, passwordSubmitToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitPasswordControllerResponse { + return submitPasswordResponse } } diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift index 1aa8fde4a3..d06b205c2e 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift @@ -33,10 +33,10 @@ class MSALNativeAuthSignInControllerMock: MSALNativeAuthSignInControlling { var signInPasswordStartResult: MSALNativeAuthSignInControlling.SignInPasswordControllerResponse! var signInStartResult: MSALNativeAuthSignInControlling.SignInCodeControllerResponse! - var signInSLTResult: Result! - var submitCodeResult: SignInVerifyCodeResult! - var submitPasswordResult: SignInPasswordRequiredResult! - var resendCodeResult: SignInResendCodeResult! + var signInSLTResult: SignInAfterSignUpControllerResponse! + var submitCodeResult: SignInSubmitCodeControllerResponse! + var submitPasswordResult: SignInSubmitPasswordControllerResponse! + var resendCodeResult: SignInResendCodeControllerResponse! func signIn(params: MSAL.MSALNativeAuthSignInWithPasswordParameters) async -> MSALNativeAuthSignInControlling.SignInPasswordControllerResponse { return signInPasswordStartResult @@ -46,7 +46,7 @@ class MSALNativeAuthSignInControllerMock: MSALNativeAuthSignInControlling { return signInStartResult } - func signIn(username: String, slt: String?, scopes: [String]?, context: MSAL.MSALNativeAuthRequestContext) async -> Result { + func signIn(username: String, slt: String?, scopes: [String]?, context: MSAL.MSALNativeAuthRequestContext) async -> SignInAfterSignUpControllerResponse { self.username = username self.slt = slt expectation?.fulfill() @@ -54,15 +54,15 @@ class MSALNativeAuthSignInControllerMock: MSALNativeAuthSignInControlling { return signInSLTResult } - func submitCode(_ code: String, credentialToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInVerifyCodeResult { + func submitCode(_ code: String, credentialToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInSubmitCodeControllerResponse { submitCodeResult } - func submitPassword(_ password: String, username: String, credentialToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInPasswordRequiredResult { + func submitPassword(_ password: String, username: String, credentialToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInSubmitPasswordControllerResponse { return submitPasswordResult } - func resendCode(credentialToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInResendCodeResult { + func resendCode(credentialToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInResendCodeControllerResponse { return resendCodeResult } } diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift index 418db74e41..c5237a0e2f 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift @@ -30,10 +30,10 @@ class MSALNativeAuthSignUpControllerMock: MSALNativeAuthSignUpControlling { var startPasswordResult: MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse! var startResult: MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse! - var resendCodeResult: SignUpResendCodeResult! + var resendCodeResult: SignUpResendCodeControllerResponse! var submitCodeResult: MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse! var submitPasswordResult: MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse! - var submitAttributesResult: SignUpAttributesRequiredResult! + var submitAttributesResult: SignUpSubmitAttributesControllerResponse! func signUpStartPassword(parameters: MSAL.MSALNativeAuthSignUpStartRequestProviderParameters) async -> MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse { return startPasswordResult @@ -43,7 +43,7 @@ class MSALNativeAuthSignUpControllerMock: MSALNativeAuthSignUpControlling { return startResult } - func resendCode(username: String, context: MSIDRequestContext, signUpToken: String) async -> SignUpResendCodeResult { + func resendCode(username: String, context: MSIDRequestContext, signUpToken: String) async -> SignUpResendCodeControllerResponse { return resendCodeResult } @@ -55,7 +55,7 @@ class MSALNativeAuthSignUpControllerMock: MSALNativeAuthSignUpControlling { return submitPasswordResult } - func submitAttributes(_ attributes: [String : Any], username: String, signUpToken: String, context: MSIDRequestContext) async -> SignUpAttributesRequiredResult { + func submitAttributes(_ attributes: [String : Any], username: String, signUpToken: String, context: MSIDRequestContext) async -> SignUpSubmitAttributesControllerResponse { return submitAttributesResult } } diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift index 18803d8e37..8cb044efc2 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift @@ -62,11 +62,11 @@ class MSALNativeAuthSignUpControllerSpy: MSALNativeAuthSignUpControlling { username: String, context: MSIDRequestContext, signUpToken: String - ) async -> SignUpResendCodeResult { + ) async -> SignUpResendCodeControllerResponse { self.context = context resendCodeCalled = true expectation.fulfill() - return .error(.init()) + return .init(.error(error: .init(), newState: nil)) } func submitCode( @@ -98,10 +98,10 @@ class MSALNativeAuthSignUpControllerSpy: MSALNativeAuthSignUpControlling { username: String, signUpToken: String, context: MSIDRequestContext - ) async -> SignUpAttributesRequiredResult { + ) async -> SignUpSubmitAttributesControllerResponse { self.context = context submitAttributesCalled = true expectation.fulfill() - return .error(error: .init()) + return .init(.error(error: .init())) } } diff --git a/MSAL/test/unit/native_auth/mock/ResetPasswordDelegateSpies.swift b/MSAL/test/unit/native_auth/mock/ResetPasswordDelegateSpies.swift index c46139d82e..14fb952b63 100644 --- a/MSAL/test/unit/native_auth/mock/ResetPasswordDelegateSpies.swift +++ b/MSAL/test/unit/native_auth/mock/ResetPasswordDelegateSpies.swift @@ -39,7 +39,7 @@ class ResetPasswordStartDelegateSpy: ResetPasswordStartDelegate { self.expectation = expectation } - func onResetPasswordError(error: MSAL.ResetPasswordStartError) { + func onResetPasswordStartError(error: MSAL.ResetPasswordStartError) { onResetPasswordErrorCalled = true self.error = error @@ -64,6 +64,22 @@ class ResetPasswordStartDelegateSpy: ResetPasswordStartDelegate { } } +class ResetPasswordStartDelegateOptionalMethodsNotImplemented: ResetPasswordStartDelegate { + let expectation: XCTestExpectation? + private(set) var error: ResetPasswordStartError? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onResetPasswordStartError(error: MSAL.ResetPasswordStartError) { + self.error = error + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } +} + class ResetPasswordResendCodeDelegateSpy: ResetPasswordResendCodeDelegate { let expectation: XCTestExpectation? private(set) var onResetPasswordResendCodeErrorCalled = false @@ -101,6 +117,24 @@ class ResetPasswordResendCodeDelegateSpy: ResetPasswordResendCodeDelegate { } } +class ResetPasswordResendCodeDelegateOptionalMethodsNotImplemented: ResetPasswordResendCodeDelegate { + let expectation: XCTestExpectation? + private(set) var error: ResendCodeError? + private(set) var newState: ResetPasswordCodeRequiredState? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onResetPasswordResendCodeError(error: ResendCodeError, newState: ResetPasswordCodeRequiredState?) { + self.error = error + self.newState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } +} + class ResetPasswordVerifyCodeDelegateSpy: ResetPasswordVerifyCodeDelegate { let expectation: XCTestExpectation? private(set) var onResetPasswordVerifyCodeErrorCalled = false @@ -131,6 +165,24 @@ class ResetPasswordVerifyCodeDelegateSpy: ResetPasswordVerifyCodeDelegate { } } +class ResetPasswordVerifyCodeDelegateOptionalMethodsNotImplemented: ResetPasswordVerifyCodeDelegate { + let expectation: XCTestExpectation? + private(set) var error: VerifyCodeError? + private(set) var newCodeRequiredState: ResetPasswordCodeRequiredState? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onResetPasswordVerifyCodeError(error: VerifyCodeError, newState: ResetPasswordCodeRequiredState?) { + self.error = error + newCodeRequiredState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } +} + class ResetPasswordRequiredDelegateSpy: ResetPasswordRequiredDelegate { let expectation: XCTestExpectation? private(set) var onResetPasswordRequiredErrorCalled = false @@ -159,3 +211,21 @@ class ResetPasswordRequiredDelegateSpy: ResetPasswordRequiredDelegate { expectation?.fulfill() } } + +class ResetPasswordRequiredDelegateOptionalMethodsNotImplemented: ResetPasswordRequiredDelegate { + let expectation: XCTestExpectation? + private(set) var error: PasswordRequiredError? + private(set) var newPasswordRequiredState: ResetPasswordRequiredState? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onResetPasswordRequiredError(error: PasswordRequiredError, newState: ResetPasswordRequiredState?) { + self.error = error + newPasswordRequiredState = newState + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } +} diff --git a/MSAL/test/unit/native_auth/mock/ResetPasswordTestValidatorHelpers.swift b/MSAL/test/unit/native_auth/mock/ResetPasswordTestValidatorHelpers.swift index 472a2bdcb6..63151f6f8c 100644 --- a/MSAL/test/unit/native_auth/mock/ResetPasswordTestValidatorHelpers.swift +++ b/MSAL/test/unit/native_auth/mock/ResetPasswordTestValidatorHelpers.swift @@ -27,17 +27,17 @@ import XCTest class ResetPasswordStartTestsValidatorHelper: ResetPasswordStartDelegateSpy { - func onResetPasswordError(_ input: ResetPasswordStartResult) { - guard case let .error(error) = input else { + func onResetPasswordError(_ input: MSALNativeAuthResetPasswordController.ResetPasswordStartControllerResponse) { + guard case let .error(error) = input.result else { expectation?.fulfill() return XCTFail("Should be an .error") } - Task { await self.onResetPasswordError(error: error) } + Task { await self.onResetPasswordStartError(error: error) } } - func onResetPasswordCodeRequired(_ input: ResetPasswordStartResult) { - guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input else { + func onResetPasswordCodeRequired(_ input: MSALNativeAuthResetPasswordController.ResetPasswordStartControllerResponse) { + guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input.result else { expectation?.fulfill() return XCTFail("Should be .codeRequired") } @@ -50,8 +50,8 @@ class ResetPasswordStartTestsValidatorHelper: ResetPasswordStartDelegateSpy { class ResetPasswordResendCodeTestsValidatorHelper: ResetPasswordResendCodeDelegateSpy { - func onResetPasswordResendCodeError(_ input: ResetPasswordResendCodeResult) { - guard case let .error(error, newState) = input else { + func onResetPasswordResendCodeError(_ input: MSALNativeAuthResetPasswordController.ResetPasswordResendCodeControllerResponse) { + guard case let .error(error, newState) = input.result else { expectation?.fulfill() return XCTFail("should be .error") } @@ -59,8 +59,8 @@ class ResetPasswordResendCodeTestsValidatorHelper: ResetPasswordResendCodeDelega Task { await self.onResetPasswordResendCodeError(error: error, newState: newState) } } - func onResetPasswordResendCodeRequired(_ input: ResetPasswordResendCodeResult) { - guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input else { + func onResetPasswordResendCodeRequired(_ input: MSALNativeAuthResetPasswordController.ResetPasswordResendCodeControllerResponse) { + guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input.result else { expectation?.fulfill() return XCTFail("Should be .codeRequired") } @@ -73,8 +73,8 @@ class ResetPasswordResendCodeTestsValidatorHelper: ResetPasswordResendCodeDelega class ResetPasswordVerifyCodeTestsValidatorHelper: ResetPasswordVerifyCodeDelegateSpy { - func onResetPasswordVerifyCodeError(_ input: ResetPasswordVerifyCodeResult) { - guard case let .error(error, newState) = input else { + func onResetPasswordVerifyCodeError(_ input: MSALNativeAuthResetPasswordController.ResetPasswordSubmitCodeControllerResponse) { + guard case let .error(error, newState) = input.result else { expectation?.fulfill() return XCTFail("should be .error") } @@ -82,8 +82,8 @@ class ResetPasswordVerifyCodeTestsValidatorHelper: ResetPasswordVerifyCodeDelega Task { await self.onResetPasswordVerifyCodeError(error: error, newState: newState) } } - func onPasswordRequired(_ input: ResetPasswordVerifyCodeResult) { - guard case let .passwordRequired(newState) = input else { + func onPasswordRequired(_ input: MSALNativeAuthResetPasswordController.ResetPasswordSubmitCodeControllerResponse) { + guard case let .passwordRequired(newState) = input.result else { expectation?.fulfill() return XCTFail("should be .success") } @@ -94,8 +94,8 @@ class ResetPasswordVerifyCodeTestsValidatorHelper: ResetPasswordVerifyCodeDelega class ResetPasswordRequiredTestsValidatorHelper: ResetPasswordRequiredDelegateSpy { - func onResetPasswordRequiredError(_ input: ResetPasswordRequiredResult) { - guard case let .error(error, newState) = input else { + func onResetPasswordRequiredError(_ input: MSALNativeAuthResetPasswordController.ResetPasswordSubmitPasswordControllerResponse) { + guard case let .error(error, newState) = input.result else { expectation?.fulfill() return XCTFail("should be .error") } @@ -103,8 +103,8 @@ class ResetPasswordRequiredTestsValidatorHelper: ResetPasswordRequiredDelegateSp Task { await self.onResetPasswordRequiredError(error: error, newState: newState) } } - func onResetPasswordCompleted(_ input: ResetPasswordRequiredResult) { - guard case .completed = input else { + func onResetPasswordCompleted(_ input: MSALNativeAuthResetPasswordController.ResetPasswordSubmitPasswordControllerResponse) { + guard case .completed = input.result else { expectation?.fulfill() return XCTFail("should be .success") } diff --git a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift index 1da5af64aa..05ff81b91a 100644 --- a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift +++ b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift @@ -40,7 +40,7 @@ open class SignInPasswordStartDelegateSpy: SignInPasswordStartDelegate { self.expectedUserAccountResult = expectedUserAccountResult } - public func onSignInPasswordError(error: MSAL.SignInPasswordStartError) { + public func onSignInPasswordStartError(error: MSAL.SignInPasswordStartError) { if let expectedError = expectedError { XCTAssertTrue(Thread.isMainThread) XCTAssertEqual(error.type, expectedError.type) @@ -115,9 +115,27 @@ class SignInPasswordRequiredDelegateSpy: SignInPasswordRequiredDelegate { } } +final class SignInPasswordRequiredDelegateOptionalMethodsNotImplemented: SignInPasswordRequiredDelegate { + + private(set) var newPasswordRequiredState: SignInPasswordRequiredState? + let expectation: XCTestExpectation + var delegateError: PasswordRequiredError? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onSignInPasswordRequiredError(error: MSAL.PasswordRequiredError, newState: MSAL.SignInPasswordRequiredState?) { + XCTAssertTrue(Thread.isMainThread) + delegateError = error + newPasswordRequiredState = newState + expectation.fulfill() + } +} + open class SignInPasswordStartDelegateFailureSpy: SignInPasswordStartDelegate { - public func onSignInPasswordError(error: MSAL.SignInPasswordStartError) { + public func onSignInPasswordStartError(error: MSAL.SignInPasswordStartError) { XCTFail("This method should not be called") } @@ -151,7 +169,7 @@ open class SignInCodeStartDelegateSpy: SignInStartDelegate { self.expectedError = expectedError } - public func onSignInError(error: SignInStartError) { + public func onSignInStartError(error: SignInStartError) { XCTAssertEqual(error.type, expectedError?.type) XCTAssertEqual(error.localizedDescription, expectedError?.localizedDescription) XCTAssertTrue(Thread.isMainThread) @@ -204,6 +222,23 @@ class SignInResendCodeDelegateSpy: SignInResendCodeDelegate { } } +class SignInResendCodeDelegateOptionalMethodsNotImplemented: SignInResendCodeDelegate { + + private(set) var newSignInCodeRequiredState: SignInCodeRequiredState? + private(set) var newSignInResendCodeError: ResendCodeError? + let expectation: XCTestExpectation + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onSignInResendCodeError(error: ResendCodeError, newState: SignInCodeRequiredState?) { + newSignInCodeRequiredState = newState + newSignInResendCodeError = error + expectation.fulfill() + } +} + class SignInCodeStartDelegateWithPasswordRequiredSpy: SignInCodeStartDelegateSpy { var passwordRequiredState: SignInPasswordRequiredState? @@ -250,6 +285,24 @@ open class SignInVerifyCodeDelegateSpy: SignInVerifyCodeDelegate { } } +final class SignInVerifyCodeDelegateOptionalMethodsNotImplemented: SignInVerifyCodeDelegate { + + private let expectation: XCTestExpectation + var expectedError: VerifyCodeError? + var expectedUserAccountResult: MSALNativeAuthUserAccountResult? + var expectedNewState: SignInCodeRequiredState? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + public func onSignInVerifyCodeError(error: VerifyCodeError, newState: SignInCodeRequiredState?) { + expectedError = error + XCTAssertTrue(Thread.isMainThread) + expectation.fulfill() + } +} + open class SignInAfterSignUpDelegateSpy: SignInAfterSignUpDelegate { private let expectation: XCTestExpectation @@ -283,6 +336,23 @@ open class SignInAfterSignUpDelegateSpy: SignInAfterSignUpDelegate { } } +final class SignInAfterSignUpDelegateOptionalMethodsNotImplemented: SignInAfterSignUpDelegate { + + private let expectation: XCTestExpectation + var expectedError: SignInAfterSignUpError? + + init(expectation: XCTestExpectation, expectedError: SignInAfterSignUpError? = nil) { + self.expectation = expectation + self.expectedError = expectedError + } + + public func onSignInAfterSignUpError(error: MSAL.SignInAfterSignUpError) { + XCTAssertEqual(error.errorDescription, expectedError?.errorDescription) + XCTAssertTrue(Thread.isMainThread) + expectation.fulfill() + } +} + final class SignInPasswordStartDelegateOptionalMethodNotImplemented: SignInPasswordStartDelegate { private let expectation: XCTestExpectation var expectedError: SignInPasswordStartError? @@ -294,7 +364,7 @@ final class SignInPasswordStartDelegateOptionalMethodNotImplemented: SignInPassw self.expectedUserAccountResult = expectedUserAccountResult } - func onSignInPasswordError(error: MSAL.SignInPasswordStartError) { + func onSignInPasswordStartError(error: MSAL.SignInPasswordStartError) { if let expectedError = expectedError { XCTAssertTrue(Thread.isMainThread) XCTAssertEqual(error.type, expectedError.type) @@ -305,15 +375,22 @@ final class SignInPasswordStartDelegateOptionalMethodNotImplemented: SignInPassw XCTFail("This method should not be called") expectation.fulfill() } +} - func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) { - if let expectedUserAccountResult = expectedUserAccountResult { - XCTAssertTrue(Thread.isMainThread) - XCTAssertEqual(expectedUserAccountResult.idToken, result.idToken) - XCTAssertEqual(expectedUserAccountResult.scopes, result.scopes) - } else { - XCTFail("This method should not be called") - } +final class SignInCodeStartDelegateOptionalMethodNotImplemented: SignInStartDelegate { + + let expectation: XCTestExpectation + var expectedError: SignInStartError? + + init(expectation: XCTestExpectation, expectedError: SignInStartError) { + self.expectation = expectation + self.expectedError = expectedError + } + + public func onSignInStartError(error: SignInStartError) { + XCTAssertEqual(error.type, expectedError?.type) + XCTAssertEqual(error.localizedDescription, expectedError?.localizedDescription) + XCTAssertTrue(Thread.isMainThread) expectation.fulfill() } } diff --git a/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift b/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift index cde9b5500b..c5ed0d08fb 100644 --- a/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift +++ b/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift @@ -34,7 +34,7 @@ class SignInPasswordStartTestsValidatorHelper: SignInPasswordStartDelegateSpy { } self.expectedError = error - Task { await self.onSignInPasswordError(error: error) } + Task { await self.onSignInPasswordStartError(error: error) } } func onSignInCodeRequired(_ input: MSALNativeAuthSignInController.SignInPasswordControllerResponse) { @@ -86,7 +86,7 @@ class SignInCodeStartTestsValidatorHelper: SignInCodeStartDelegateSpy { return XCTFail("input should be .error") } - Task { await self.onSignInError(error: error) } + Task { await self.onSignInStartError(error: error) } } func onSignInCodeRequired(_ input: MSALNativeAuthSignInControlling.SignInCodeControllerResponse) { @@ -101,8 +101,8 @@ class SignInCodeStartTestsValidatorHelper: SignInCodeStartDelegateSpy { class SignInResendCodeTestsValidatorHelper: SignInResendCodeDelegateSpy { - func onSignInResendCodeError(_ input: SignInResendCodeResult) { - guard case let .error(error, newState) = input else { + func onSignInResendCodeError(_ input: MSALNativeAuthSignInController.SignInResendCodeControllerResponse) { + guard case let .error(error, newState) = input.result else { expectation.fulfill() return XCTFail("input should be .error") } @@ -110,8 +110,8 @@ class SignInResendCodeTestsValidatorHelper: SignInResendCodeDelegateSpy { Task { await self.onSignInResendCodeError(error: error, newState: newState) } } - func onSignInResendCodeCodeRequired(_ input: SignInResendCodeResult) { - guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input else { + func onSignInResendCodeCodeRequired(_ input: MSALNativeAuthSignInController.SignInResendCodeControllerResponse) { + guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input.result else { expectation.fulfill() return XCTFail("input should be .codeRequired") } diff --git a/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift b/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift index 1585e00961..34d308a29b 100644 --- a/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift +++ b/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift @@ -41,7 +41,7 @@ class SignUpPasswordStartDelegateSpy: SignUpPasswordStartDelegate { self.expectation = expectation } - func onSignUpPasswordError(error: MSAL.SignUpPasswordStartError) { + func onSignUpPasswordStartError(error: MSAL.SignUpPasswordStartError) { onSignUpPasswordErrorCalled = true self.error = error @@ -85,7 +85,7 @@ class SignUpCodeStartDelegateSpy: SignUpStartDelegate { self.expectation = expectation } - func onSignUpError(error: MSAL.SignUpStartError) { + func onSignUpStartError(error: MSAL.SignUpStartError) { onSignUpCodeErrorCalled = true self.error = error @@ -127,8 +127,9 @@ class SignUpResendCodeDelegateSpy: SignUpResendCodeDelegate { self.expectation = expectation } - func onSignUpResendCodeError(error: ResendCodeError) { + func onSignUpResendCodeError(error: MSAL.ResendCodeError, newState: MSAL.SignUpCodeRequiredState?) { onSignUpResendCodeErrorCalled = true + self.newState = newState self.error = error XCTAssertTrue(Thread.isMainThread) @@ -147,6 +148,22 @@ class SignUpResendCodeDelegateSpy: SignUpResendCodeDelegate { } } +class SignUpResendCodeDelegateMethodsNotImplemented: SignUpResendCodeDelegate { + let expectation: XCTestExpectation? + private(set) var error: ResendCodeError? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onSignUpResendCodeError(error: MSAL.ResendCodeError, newState: MSAL.SignUpCodeRequiredState?) { + self.error = error + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } +} + class SignUpVerifyCodeDelegateSpy: SignUpVerifyCodeDelegate { let expectation: XCTestExpectation? private(set) var onSignUpVerifyCodeErrorCalled = false @@ -158,6 +175,7 @@ class SignUpVerifyCodeDelegateSpy: SignUpVerifyCodeDelegate { private(set) var newAttributesRequiredState: SignUpAttributesRequiredState? private(set) var newPasswordRequiredState: SignUpPasswordRequiredState? private(set) var newSignInAfterSignUpState: SignInAfterSignUpState? + private(set) var newAttributesRequired: [MSALNativeAuthRequiredAttributes]? init(expectation: XCTestExpectation? = nil) { self.expectation = expectation @@ -174,6 +192,7 @@ class SignUpVerifyCodeDelegateSpy: SignUpVerifyCodeDelegate { func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: MSAL.SignUpAttributesRequiredState) { onSignUpAttributesRequiredCalled = true + newAttributesRequired = attributes newAttributesRequiredState = newState XCTAssertTrue(Thread.isMainThread) @@ -206,6 +225,7 @@ class SignUpPasswordRequiredDelegateSpy: SignUpPasswordRequiredDelegate { private(set) var newPasswordRequiredState: SignUpPasswordRequiredState? private(set) var newAttributesRequiredState: SignUpAttributesRequiredState? private(set) var signInAfterSignUpState: SignInAfterSignUpState? + private(set) var newAttributesRequired: [MSALNativeAuthRequiredAttributes]? init(expectation: XCTestExpectation? = nil) { self.expectation = expectation @@ -223,6 +243,7 @@ class SignUpPasswordRequiredDelegateSpy: SignUpPasswordRequiredDelegate { func onSignUpAttributesRequired(attributes: [MSAL.MSALNativeAuthRequiredAttributes], newState: MSAL.SignUpAttributesRequiredState) { onSignUpAttributesRequiredCalled = true newAttributesRequiredState = newState + newAttributesRequired = attributes XCTAssertTrue(Thread.isMainThread) expectation?.fulfill() @@ -285,6 +306,22 @@ class SignUpAttributesRequiredDelegateSpy: SignUpAttributesRequiredDelegate { } } +class SignUpAttributesRequiredDelegateOptionalMethodsNotImplemented: SignUpAttributesRequiredDelegate { + private let expectation: XCTestExpectation? + private(set) var error: AttributesRequiredError? + + init(expectation: XCTestExpectation? = nil) { + self.expectation = expectation + } + + func onSignUpAttributesRequiredError(error: MSAL.AttributesRequiredError) { + self.error = error + + XCTAssertTrue(Thread.isMainThread) + expectation?.fulfill() + } +} + class SignUpVerifyCodeDelegateOptionalMethodsNotImplemented: SignUpVerifyCodeDelegate { private let expectation: XCTestExpectation private(set) var error: VerifyCodeError? @@ -298,10 +335,6 @@ class SignUpVerifyCodeDelegateOptionalMethodsNotImplemented: SignUpVerifyCodeDel XCTAssertTrue(Thread.isMainThread) expectation.fulfill() } - - func onSignUpCompleted(newState: SignInAfterSignUpState) { - XCTAssertTrue(Thread.isMainThread) - } } class SignUpPasswordStartDelegateOptionalMethodsNotImplemented: SignUpPasswordStartDelegate { @@ -313,18 +346,13 @@ class SignUpPasswordStartDelegateOptionalMethodsNotImplemented: SignUpPasswordSt self.expectation = expectation } - func onSignUpPasswordError(error: MSAL.SignUpPasswordStartError) { + func onSignUpPasswordStartError(error: MSAL.SignUpPasswordStartError) { onSignUpPasswordErrorCalled = true self.error = error XCTAssertTrue(Thread.isMainThread) self.expectation?.fulfill() } - - func onSignUpCodeRequired(newState: MSAL.SignUpCodeRequiredState, sentTo: String, channelTargetType: MSAL.MSALNativeAuthChannelType, codeLength: Int) { - XCTFail("This method should not be called") - self.expectation?.fulfill() - } } class SignUpStartDelegateOptionalMethodsNotImplemented: SignUpStartDelegate { @@ -336,18 +364,13 @@ class SignUpStartDelegateOptionalMethodsNotImplemented: SignUpStartDelegate { self.expectation = expectation } - func onSignUpError(error: MSAL.SignUpStartError) { + func onSignUpStartError(error: MSAL.SignUpStartError) { onSignUpStartErrorCalled = true self.error = error XCTAssertTrue(Thread.isMainThread) self.expectation?.fulfill() } - - func onSignUpCodeRequired(newState: MSAL.SignUpCodeRequiredState, sentTo: String, channelTargetType: MSAL.MSALNativeAuthChannelType, codeLength: Int) { - XCTFail("This method should not be called") - self.expectation?.fulfill() - } } class SignUpPasswordRequiredDelegateOptionalMethodsNotImplemented: SignUpPasswordRequiredDelegate { @@ -363,8 +386,4 @@ class SignUpPasswordRequiredDelegateOptionalMethodsNotImplemented: SignUpPasswor XCTAssertTrue(Thread.isMainThread) expectation.fulfill() } - - func onSignUpCompleted(newState: SignInAfterSignUpState) { - XCTAssertTrue(Thread.isMainThread) - } } diff --git a/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift b/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift index f4fd6a4595..a4274b7117 100644 --- a/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift +++ b/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift @@ -27,14 +27,14 @@ import XCTest class SignUpPasswordStartTestsValidatorHelper: SignUpPasswordStartDelegateSpy { - func onSignUpPasswordError(_ input: MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse) { + func onSignUpPasswordStartError(_ input: MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse) { guard case let .error(error) = input.result else { expectation?.fulfill() return XCTFail("Should be an .error") } Task { - await self.onSignUpPasswordError(error: error) + await self.onSignUpPasswordStartError(error: error) } } @@ -63,14 +63,14 @@ class SignUpPasswordStartTestsValidatorHelper: SignUpPasswordStartDelegateSpy { class SignUpCodeStartTestsValidatorHelper: SignUpCodeStartDelegateSpy { - func onSignUpError(_ input: MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse) { + func onSignUpStartError(_ input: MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse) { guard case let .error(error) = input.result else { expectation?.fulfill() return XCTFail("Should be an .error") } Task { - await self.onSignUpError(error: error) + await self.onSignUpStartError(error: error) } } @@ -99,19 +99,19 @@ class SignUpCodeStartTestsValidatorHelper: SignUpCodeStartDelegateSpy { class SignUpResendCodeTestsValidatorHelper: SignUpResendCodeDelegateSpy { - func onSignUpResendCodeError(_ input: SignUpResendCodeResult) { - guard case let .error(error) = input else { + func onSignUpResendCodeError(_ input: MSALNativeAuthSignUpController.SignUpResendCodeControllerResponse) { + guard case let .error(error, newState) = input.result else { expectation?.fulfill() return XCTFail("Should be an .error") } Task { - await self.onSignUpResendCodeError(error: error) + await self.onSignUpResendCodeError(error: error, newState: newState) } } - func onSignUpResendCodeCodeRequired(_ input: SignUpResendCodeResult) { - guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input else { + func onSignUpResendCodeCodeRequired(_ input: MSALNativeAuthSignUpController.SignUpResendCodeControllerResponse) { + guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input.result else { expectation?.fulfill() return XCTFail("Should be .codeRequired") } @@ -221,8 +221,8 @@ class SignUpAttributesRequiredTestsValidatorHelper { self.expectation = expectation } - func onSignUpAttributesRequired(_ input: SignUpAttributesRequiredResult) { - guard case let .attributesRequired(attributes, state) = input else { + func onSignUpAttributesRequired(_ input: MSALNativeAuthSignUpController.SignUpSubmitAttributesControllerResponse) { + guard case let .attributesRequired(attributes, state) = input.result else { expectation?.fulfill() return XCTFail("Should be .attributesInvalid") } @@ -234,8 +234,8 @@ class SignUpAttributesRequiredTestsValidatorHelper { expectation?.fulfill() } - func onSignUpAttributesRequiredError(_ input: SignUpAttributesRequiredResult) { - guard case let .error(error) = input else { + func onSignUpAttributesRequiredError(_ input: MSALNativeAuthSignUpController.SignUpSubmitAttributesControllerResponse) { + guard case let .error(error) = input.result else { expectation?.fulfill() return XCTFail("Should be an .error") } @@ -246,8 +246,8 @@ class SignUpAttributesRequiredTestsValidatorHelper { expectation?.fulfill() } - func onSignUpAttributesValidationFailed(_ input: SignUpAttributesRequiredResult) { - guard case let .attributesInvalid(attributes, state) = input else { + func onSignUpAttributesValidationFailed(_ input: MSALNativeAuthSignUpController.SignUpSubmitAttributesControllerResponse) { + guard case let .attributesInvalid(attributes, state) = input.result else { expectation?.fulfill() return XCTFail("Should be an .error") } @@ -259,8 +259,8 @@ class SignUpAttributesRequiredTestsValidatorHelper { expectation?.fulfill() } - func onSignUpCompleted(_ input: SignUpAttributesRequiredResult) { - guard case .completed = input else { + func onSignUpCompleted(_ input: MSALNativeAuthSignUpController.SignUpSubmitAttributesControllerResponse) { + guard case .completed = input.result else { expectation?.fulfill() return XCTFail("Should be an .error") } diff --git a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift index 33011dd286..33a4d1dd4e 100644 --- a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift +++ b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift @@ -39,38 +39,38 @@ class MSALNativeAuthResetPasswordControllerSpy: MSALNativeAuthResetPasswordContr self.expectation = expectation } - func resetPassword(parameters: MSAL.MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartResult { + func resetPassword(parameters: MSAL.MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartControllerResponse { self.context = parameters.context resetPasswordCalled = true expectation.fulfill() - return .error(.init(type: .generalError)) + return .init(.error(.init(type: .generalError))) } - func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeResult { + func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { self.flowToken = passwordResetToken self.context = context resendCodeCalled = true expectation.fulfill() - return .error(error: .init(), newState: nil) + return .init(.error(error: .init(), newState: nil)) } - func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordVerifyCodeResult { + func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse { self.flowToken = passwordResetToken self.context = context submitCodeCalled = true expectation.fulfill() - return .error(error: .init(type: .generalError), newState: nil) + return .init(.error(error: .init(type: .generalError), newState: nil)) } - func submitPassword(password: String, passwordSubmitToken: String, context: MSIDRequestContext) async -> ResetPasswordRequiredResult { + func submitPassword(password: String, passwordSubmitToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitPasswordControllerResponse { self.flowToken = passwordSubmitToken self.context = context submitPasswordCalled = true expectation.fulfill() - return .error(error: .init(type: .generalError), newState: nil) + return .init(.error(error: .init(type: .generalError), newState: nil)) } } diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift index d371cf31ff..c8149a089c 100644 --- a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift +++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift @@ -88,8 +88,9 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { } func testSignUpPassword_delegate_whenValidDataIsPassed_shouldReturnCodeRequired() { - let exp = expectation(description: "sign-up public interface") - let delegate = SignUpPasswordStartDelegateSpy(expectation: exp) + let exp1 = expectation(description: "sign-up public interface") + let exp2 = expectation(description: "sign-up public interface telemetry") + let delegate = SignUpPasswordStartDelegateSpy(expectation: exp1) let expectedResult: SignUpPasswordStartResult = .codeRequired( newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId), @@ -97,11 +98,13 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { channelTargetType: .email, codeLength: 1 ) - controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult) + controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) sut.signUpUsingPassword(username: "correct", password: "correct", delegate: delegate) - wait(for: [exp]) + wait(for: [exp1, exp2]) XCTAssertEqual(delegate.newState?.flowToken, "flowToken") XCTAssertEqual(delegate.sentTo, "sentTo") @@ -109,35 +112,70 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { XCTAssertEqual(delegate.codeLength, 1) } + func testSignUpPassword_delegate_butDelegateMethodIsNotImplemented_shouldReturnError() { + let exp = expectation(description: "sign-up public interface") + let exp2 = expectation(description: "sign-up public interface telemetry") + let delegate = SignUpPasswordStartDelegateOptionalMethodsNotImplemented(expectation: exp) + + let expectedResult: SignUpPasswordStartResult = .codeRequired( + newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId), + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + sut.signUpUsingPassword(username: "correct", password: "correct", delegate: delegate) + + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.type, .generalError) + XCTAssertEqual( + delegate.error?.errorDescription, + String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCodeRequired") + ) + } + func testSignUpPassword_delegate_whenSendAttributes_shouldReturnAttributesInvalid() { let exp = expectation(description: "sign-up public interface") + let exp2 = expectation(description: "expectation Telemetry") let delegate = SignUpPasswordStartDelegateSpy(expectation: exp) let expectedInvalidAttributes = ["attribute"] let expectedResult: SignUpPasswordStartResult = .attributesInvalid(expectedInvalidAttributes) - controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult) + controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) sut.signUpUsingPassword(username: "correct", password: "correct", delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) XCTAssertEqual(delegate.attributeNames, expectedInvalidAttributes) } func testSignUpPassword_delegate_whenSendAttributes_butDelegateMethodIsNotImplemented_itShouldReturnAttributesInvalid() { let exp = expectation(description: "sign-up public interface") + let exp2 = expectation(description: "expectation Telemetry") let delegate = SignUpPasswordStartDelegateOptionalMethodsNotImplemented(expectation: exp) let expectedInvalidAttributes = ["attribute"] let expectedResult: SignUpPasswordStartResult = .attributesInvalid(expectedInvalidAttributes) - controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult) + controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) sut.signUpUsingPassword(username: "correct", password: "correct", delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) XCTAssertEqual(delegate.error?.type, .generalError) - XCTAssertEqual(delegate.error?.errorDescription, MSALNativeAuthErrorMessage.codeRequiredNotImplemented) + XCTAssertEqual( + delegate.error?.errorDescription, + String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid") + ) } // Sign Up with code @@ -152,6 +190,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { func testSignUp_delegate_whenValidDataIsPassed_shouldReturnCodeRequired() { let exp = expectation(description: "sign-up public interface") + let exp2 = expectation(description: "expectation Telemetry") let delegate = SignUpCodeStartDelegateSpy(expectation: exp) let expectedResult: SignUpStartResult = .codeRequired( @@ -160,11 +199,13 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { channelTargetType: .email, codeLength: 1 ) - controllerFactoryMock.signUpController.startResult = .init(expectedResult) + controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) sut.signUp(username: "correct", delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) XCTAssertEqual(delegate.newState?.flowToken, "flowToken") XCTAssertEqual(delegate.sentTo, "sentTo") @@ -172,35 +213,70 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { XCTAssertEqual(delegate.codeLength, 1) } + func testSignUp_delegate_butDelegateMethodIsNotImplemented_shouldReturnError() { + let exp = expectation(description: "sign-up public interface") + let exp2 = expectation(description: "expectation Telemetry") + let delegate = SignUpStartDelegateOptionalMethodsNotImplemented(expectation: exp) + + let expectedResult: SignUpStartResult = .codeRequired( + newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId), + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + sut.signUp(username: "correct", delegate: delegate) + + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.type, .generalError) + XCTAssertEqual( + delegate.error?.errorDescription, + String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCodeRequired") + ) + } + func testSignUp_delegate_whenSendAttributes_shouldReturnAttributesInvalid() { let exp = expectation(description: "sign-up public interface") + let exp2 = expectation(description: "expectation Telemetry") let delegate = SignUpCodeStartDelegateSpy(expectation: exp) let expectedInvalidAttributes = ["attribute"] let expectedResult: SignUpStartResult = .attributesInvalid(expectedInvalidAttributes) - controllerFactoryMock.signUpController.startResult = .init(expectedResult) + controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) sut.signUp(username: "correct", delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) XCTAssertEqual(delegate.attributeNames, expectedInvalidAttributes) } func testSignUp_delegate_whenSendAttributes_butDelegateMethodIsNotImplemented_itShouldReturnAttributesInvalid() { let exp = expectation(description: "sign-up public interface") + let exp2 = expectation(description: "expectation Telemetry") let delegate = SignUpStartDelegateOptionalMethodsNotImplemented(expectation: exp) let expectedInvalidAttributes = ["attribute"] let expectedResult: SignUpStartResult = .attributesInvalid(expectedInvalidAttributes) - controllerFactoryMock.signUpController.startResult = .init(expectedResult) + controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) sut.signUp(username: "correct", delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) XCTAssertEqual(delegate.error?.type, .generalError) - XCTAssertEqual(delegate.error?.errorDescription, MSALNativeAuthErrorMessage.codeRequiredNotImplemented) + XCTAssertEqual( + delegate.error?.errorDescription, + String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid") + ) } // Sign in with password @@ -220,13 +296,34 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { } func testSignInPassword_delegate_whenValidUserAndPasswordAreUsed_shouldReturnSuccess() { - let expectation = expectation(description: "sign-in public interface") - let delegate = SignInPasswordStartDelegateSpy(expectation: expectation, expectedUserAccountResult: MSALNativeAuthUserAccountResultStub.result) + let exp1 = expectation(description: "sign-in public interface") + let exp2 = expectation(description: "expectation Telemetry") + let delegate = SignInPasswordStartDelegateSpy(expectation: exp1, expectedUserAccountResult: MSALNativeAuthUserAccountResultStub.result) + + controllerFactoryMock.signInController.signInPasswordStartResult = .init(.init(.completed(MSALNativeAuthUserAccountResultStub.result), telemetryUpdate: { _ in + exp2.fulfill() + })) + sut.signInUsingPassword(username: "correct", password: "correct", delegate: delegate) + + wait(for: [exp1, exp2], timeout: 1) + } + + func testSignInPassword_delegate_whenSuccessIsReturnedButUserHasNotImplementedOptionalDelegate_shouldReturnError() { + let exp = expectation(description: "sign-in public interface") + let exp2 = expectation(description: "expectation Telemetry") + + let expectedError = SignInPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted")) + let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: exp, expectedError: expectedError) + + let expectedResult: SignInPasswordStartResult = .completed(MSALNativeAuthUserAccountResultStub.result) + + controllerFactoryMock.signInController.signInPasswordStartResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) - controllerFactoryMock.signInController.signInPasswordStartResult = .init(.init(.completed(MSALNativeAuthUserAccountResultStub.result))) sut.signInUsingPassword(username: "correct", password: "correct", delegate: delegate) - wait(for: [expectation], timeout: 1) + wait(for: [exp, exp2], timeout: 1) } func testSignInPassword_delegate_whenCodeIsRequiredAndUserHasImplementedOptionalDelegate_shouldReturnCodeRequired() { @@ -258,7 +355,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let exp = expectation(description: "sign-in public interface") let exp2 = expectation(description: "expectation Telemetry") - let expectedError = SignInPasswordStartError(type: .generalError, message: MSALNativeAuthErrorMessage.codeRequiredNotImplemented) + let expectedError = SignInPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired")) let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: exp, expectedError: expectedError) let expectedResult: SignInPasswordStartResult = .codeRequired( @@ -287,8 +384,9 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { } func testSignIn_delegate_whenValidUserIsUsed_shouldReturnCodeRequired() { - let expectation = expectation(description: "sign-in public interface") - let delegate = SignInCodeStartDelegateSpy(expectation: expectation) + let exp1 = expectation(description: "sign-in public interface") + let exp2 = expectation(description: "expectation Telemetry") + let delegate = SignInCodeStartDelegateSpy(expectation: exp1) delegate.expectedSentTo = "sentTo" delegate.expectedCodeLength = 1 delegate.expectedChannelTargetType = .email @@ -300,10 +398,35 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { codeLength: 1 ) - controllerFactoryMock.signInController.signInStartResult = .init(expectedResult) + controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) sut.signIn(username: "correct", delegate: delegate) - wait(for: [expectation], timeout: 1) + wait(for: [exp1, exp2], timeout: 1) + } + + func testSignIn_delegate_whenValidUserIsUsedButUserHasNotImplementedOptionalDelegate_shouldReturnError() { + let exp = expectation(description: "sign-in public interface") + let exp2 = expectation(description: "expectation Telemetry") + + let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired")) + let delegate = SignInCodeStartDelegateOptionalMethodNotImplemented(expectation: exp, expectedError: expectedError) + + let expectedResult: SignInStartResult = .codeRequired( + newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "", correlationId: correlationId), + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + + controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + sut.signIn(username: "correct", delegate: delegate) + + wait(for: [exp, exp2], timeout: 1) } func testSignIn_delegate_whenPasswordIsRequiredAndUserHasImplementedOptionalDelegate_shouldReturnPasswordRequired() { @@ -330,7 +453,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let exp = expectation(description: "sign-in public interface") let exp2 = expectation(description: "expectation Telemetry") - let expectedError = SignInStartError(type: .generalError, message: MSALNativeAuthErrorMessage.passwordRequiredNotImplemented) + let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInPasswordRequired")) let delegate = SignInCodeStartDelegateSpy(expectation: exp, expectedError: expectedError) let expectedResult: SignInStartResult = .passwordRequired( @@ -357,8 +480,9 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { } func testResetPassword_delegate_whenValidUserIsUsed_shouldReturnCodeRequired() { - let expectation = expectation(description: "sign-in public interface") - let delegate = ResetPasswordStartDelegateSpy(expectation: expectation) + let exp1 = expectation(description: "sign-in public interface") + let exp2 = expectation(description: "expectation Telemetry") + let delegate = ResetPasswordStartDelegateSpy(expectation: exp1) let expectedResult: ResetPasswordStartResult = .codeRequired( newState: .init(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId), @@ -367,16 +491,44 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { codeLength: 1 ) - controllerFactoryMock.resetPasswordController.resetPasswordResult = .init(expectedResult) + controllerFactoryMock.resetPasswordController.resetPasswordResponse = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) sut.resetPassword(username: "correct", delegate: delegate) - wait(for: [expectation], timeout: 1) + wait(for: [exp1, exp2], timeout: 1) XCTAssertEqual(delegate.newState?.flowToken, "flowToken") XCTAssertEqual(delegate.sentTo, "sentTo") XCTAssertEqual(delegate.channelTargetType, .email) XCTAssertEqual(delegate.codeLength, 1) } + + func testResetPassword_delegate_butDelegateMethodIsNotImplemented_shouldReturnError() { + let exp = expectation(description: "reset-password public interface") + let exp2 = expectation(description: "expectation Telemetry") + let delegate = ResetPasswordStartDelegateOptionalMethodsNotImplemented(expectation: exp) + + let expectedResult: ResetPasswordStartResult = .codeRequired( + newState: .init(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId), + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + controllerFactoryMock.resetPasswordController.resetPasswordResponse = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + sut.resetPassword(username: "correct", delegate: delegate) + + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.type, .generalError) + XCTAssertEqual( + delegate.error?.errorDescription, + String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onResetPasswordCodeRequired") + ) + } // MARK: - CorrelationId diff --git a/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift b/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift new file mode 100644 index 0000000000..0e097e8dfa --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift @@ -0,0 +1,83 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class DispatchAccessTokenRetrieveCompletedTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: CredentialsDelegateDispatcher! + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchAccessTokenRetrieveCompleted_whenDelegateMethodsAreImplemented() async { + let expectedToken = "token" + let delegate = CredentialsDelegateSpy(expectation: delegateExp, expectedAccessToken: expectedToken) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + await sut.dispatchAccessTokenRetrieveCompleted(accessToken: expectedToken) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.expectedAccessToken, expectedToken) + } + + func test_dispatchAccessTokenRetrieveCompleted_whenDelegateOptionalMethodsNotImplemented() async { + let expectedError = RetrieveAccessTokenError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onAccessTokenRetrieveCompleted")) + let delegate = CredentialsDelegateOptionalMethodsNotImplemented(expectation: delegateExp, expectedError: expectedError) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? RetrieveAccessTokenError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedResult = MSALNativeAuthUserAccountResultStub.result + + await sut.dispatchAccessTokenRetrieveCompleted(accessToken: "token") + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.expectedError) + + func checkError(_ error: RetrieveAccessTokenError?) { + XCTAssertEqual(error?.type, .generalError) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/SignInAfterSignUpDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/SignInAfterSignUpDelegateDispatcherTests.swift new file mode 100644 index 0000000000..c01727ef48 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/SignInAfterSignUpDelegateDispatcherTests.swift @@ -0,0 +1,82 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class SignInAfterSignUpDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: SignInAfterSignUpDelegateDispatcher! + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchSignInCompleted_whenDelegateMethodsAreImplemented() async { + let expectedResult = MSALNativeAuthUserAccountResultStub.result + let delegate = SignInAfterSignUpDelegateSpy(expectation: delegateExp, expectedUserAccountResult: expectedResult) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + await sut.dispatchSignInCompleted(result: expectedResult) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.expectedUserAccountResult, expectedResult) + } + + func test_dispatchSignInCompleted_whenDelegateOptionalMethodsNotImplemented() async { + let expectedError = SignInAfterSignUpError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted")) + let delegate = SignInAfterSignUpDelegateOptionalMethodsNotImplemented(expectation: delegateExp, expectedError: expectedError) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? SignInAfterSignUpError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedResult = MSALNativeAuthUserAccountResultStub.result + + await sut.dispatchSignInCompleted(result: expectedResult) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.expectedError) + + func checkError(_ error: SignInAfterSignUpError?) { + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift new file mode 100644 index 0000000000..fd68911fcb --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift @@ -0,0 +1,80 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class ResetPasswordRequiredDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: ResetPasswordRequiredDelegateDispatcher! + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchPasswordRequired_whenDelegateMethodsAreImplemented() async { + let delegate = ResetPasswordRequiredDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + await sut.dispatchResetPasswordCompleted() + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertTrue(delegate.onResetPasswordCompletedCalled) + } + + func test_dispatchPasswordRequired_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = ResetPasswordRequiredDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = PasswordRequiredError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onResetPasswordCompleted")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? PasswordRequiredError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + await sut.dispatchResetPasswordCompleted() + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: PasswordRequiredError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift new file mode 100644 index 0000000000..a97017cc97 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift @@ -0,0 +1,104 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class ResetPasswordResendCodeDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: ResetPasswordResendCodeDelegateDispatcher! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + private let correlationId = UUID() + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchResetPasswordResendCodeRequired_whenDelegateMethodsAreImplemented() async { + let delegate = ResetPasswordResendCodeDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + await sut.dispatchResetPasswordResendCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.newState, expectedState) + XCTAssertEqual(delegate.sentTo, expectedSentTo) + XCTAssertEqual(delegate.channelTargetType, expectedChannelTargetType) + XCTAssertEqual(delegate.codeLength, expectedCodeLength) + } + + func test_dispatchResetPasswordResendCodeRequired_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = ResetPasswordResendCodeDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = ResendCodeError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onResetPasswordResendCodeRequired")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? ResendCodeError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + await sut.dispatchResetPasswordResendCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: ResendCodeError?) { + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift new file mode 100644 index 0000000000..f3d9728802 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift @@ -0,0 +1,105 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class ResetPasswordStartDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: ResetPasswordStartDelegateDispatcher! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + private let correlationId = UUID() + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchResetPasswordCodeRequired_whenDelegateMethodsAreImplemented() async { + let delegate = ResetPasswordStartDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + await sut.dispatchResetPasswordCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.newState, expectedState) + XCTAssertEqual(delegate.sentTo, expectedSentTo) + XCTAssertEqual(delegate.channelTargetType, expectedChannelTargetType) + XCTAssertEqual(delegate.codeLength, expectedCodeLength) + } + + func test_dispatchResetPasswordCodeRequired_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = ResetPasswordStartDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = ResetPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onResetPasswordCodeRequired")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? ResetPasswordStartError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + await sut.dispatchResetPasswordCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: ResetPasswordStartError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift new file mode 100644 index 0000000000..f22808ba69 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift @@ -0,0 +1,86 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class ResetPasswordVerifyCodeDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: ResetPasswordVerifyCodeDelegateDispatcher! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + private let correlationId = UUID() + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchPasswordRequired_whenDelegateMethodsAreImplemented() async { + let delegate = ResetPasswordVerifyCodeDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedState = ResetPasswordRequiredState(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId) + + await sut.dispatchPasswordRequired(newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.newPasswordRequiredState, expectedState) + } + + func test_dispatchPasswordRequired_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = ResetPasswordVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onPasswordRequired")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? VerifyCodeError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedState = ResetPasswordRequiredState(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId) + + await sut.dispatchPasswordRequired(newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: VerifyCodeError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordRequiredDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordRequiredDelegateDispatcherTests.swift new file mode 100644 index 0000000000..c394755896 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordRequiredDelegateDispatcherTests.swift @@ -0,0 +1,84 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class SignInPasswordRequiredDelegateDispatcherTests: XCTestCase { + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: SignInPasswordRequiredDelegateDispatcher! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchSignInCompleted_whenDelegateMethodsAreImplemented() async { + let expectedResult = MSALNativeAuthUserAccountResultStub.result + let delegate = SignInPasswordRequiredDelegateSpy(expectation: delegateExp, expectedUserAccountResult: expectedResult) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + await sut.dispatchSignInCompleted(result: expectedResult) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.expectedUserAccountResult, expectedResult) + } + + func test_dispatchSignInCompleted_whenDelegateOptionalMethodsNotImplemented() async { + let expectedError = PasswordRequiredError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted")) + let delegate = SignInPasswordRequiredDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? PasswordRequiredError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedResult = MSALNativeAuthUserAccountResultStub.result + + await sut.dispatchSignInCompleted(result: expectedResult) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.delegateError) + + func checkError(_ error: PasswordRequiredError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift new file mode 100644 index 0000000000..70a2985041 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift @@ -0,0 +1,151 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class SignInPasswordStartDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: SignInPasswordStartDelegateDispatcher! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + private let correlationId = UUID() + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchSignInCodeRequired_whenDelegateMethodsAreImplemented() async { + let delegate = SignInPasswordStartDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + await sut.dispatchSignInCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.newSignInCodeRequiredState, expectedState) + XCTAssertEqual(delegate.expectedSentTo, expectedSentTo) + XCTAssertEqual(delegate.expectedChannelTargetType, expectedChannelTargetType) + XCTAssertEqual(delegate.expectedCodeLength, expectedCodeLength) + } + + func test_dispatchSignInCodeRequired_whenDelegateOptionalMethodsNotImplemented() async { + let expectedError = SignInPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired")) + let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: delegateExp, expectedError: expectedError) + + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? SignInPasswordStartError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + await sut.dispatchSignInCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.expectedError) + + func checkError(_ error: SignInPasswordStartError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } + + func test_dispatchSignInCompleted_whenDelegateMethodsAreImplemented() async { + let expectedResult = MSALNativeAuthUserAccountResultStub.result + let delegate = SignInPasswordStartDelegateSpy(expectation: delegateExp, expectedUserAccountResult: expectedResult) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + await sut.dispatchSignInCompleted(result: expectedResult) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.expectedUserAccountResult, expectedResult) + } + + func test_dispatchSignInCompleted_whenDelegateOptionalMethodsNotImplemented() async { + let expectedError = SignInPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted")) + let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: delegateExp, expectedError: expectedError) + + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? SignInPasswordStartError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedResult = MSALNativeAuthUserAccountResultStub.result + + await sut.dispatchSignInCompleted(result: expectedResult) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.expectedError) + + func checkError(_ error: SignInPasswordStartError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInResendCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInResendCodeDelegateDispatcherTests.swift new file mode 100644 index 0000000000..97662b0692 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInResendCodeDelegateDispatcherTests.swift @@ -0,0 +1,101 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class SignInResendCodeDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: SignInResendCodeDelegateDispatcher! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + private let correlationId = UUID() + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchSignInResendCodeCodeRequired_whenDelegateMethodsAreImplemented() async { + let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + let delegate = SignInResendCodeDelegateSpy(expectation: delegateExp, expectedSentTo: expectedSentTo, expectedChannelTargetType: expectedChannelTargetType, expectedCodeLength: expectedCodeLength) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + await sut.dispatchSignInResendCodeCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.newSignInCodeRequiredState, expectedState) + } + + func test_dispatchSignInResendCodeCodeRequired_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = SignInResendCodeDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = ResendCodeError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInResendCodeCodeRequired")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? ResendCodeError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + await sut.dispatchSignInResendCodeCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.newSignInResendCodeError) + + func checkError(_ error: ResendCodeError?) { + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInStartDelegateDispatcherTests.swift new file mode 100644 index 0000000000..b1ab94b081 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInStartDelegateDispatcherTests.swift @@ -0,0 +1,151 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class SignInStartDelegateDispatcherTests: XCTestCase { + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: SignInStartDelegateDispatcher! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + private let correlationId = UUID() + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchSignInCodeRequired_whenDelegateMethodsAreImplemented() async { + let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + let delegate = SignInCodeStartDelegateSpy(expectation: delegateExp, expectedSentTo: expectedSentTo, expectedChannelTargetType: expectedChannelTargetType, expectedCodeLength: expectedCodeLength) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + await sut.dispatchSignInCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.newSignInCodeRequiredState, expectedState) + XCTAssertEqual(delegate.expectedSentTo, expectedSentTo) + XCTAssertEqual(delegate.expectedChannelTargetType, expectedChannelTargetType) + XCTAssertEqual(delegate.expectedCodeLength, expectedCodeLength) + } + + func test_dispatchSignInCodeRequired_whenDelegateOptionalMethodsNotImplemented() async { + let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired")) + let delegate = SignInCodeStartDelegateOptionalMethodNotImplemented(expectation: delegateExp, expectedError: expectedError) + + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? SignInStartError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + await sut.dispatchSignInCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.expectedError) + + func checkError(_ error: SignInStartError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } + + func test_dispatchSignInPasswordRequired_whenDelegateMethodsAreImplemented() async { + let delegate = SignInCodeStartDelegateWithPasswordRequiredSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedState = SignInPasswordRequiredState(scopes: [], username: "username", controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + + await sut.dispatchSignInPasswordRequired(newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.passwordRequiredState, expectedState) + } + + func test_dispatchSignInPasswordRequired_whenDelegateOptionalMethodsNotImplemented() async { + let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInPasswordRequired")) + let delegate = SignInCodeStartDelegateOptionalMethodNotImplemented(expectation: delegateExp, expectedError: expectedError) + + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? SignInStartError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedState = SignInPasswordRequiredState(scopes: [], username: "username", controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + + await sut.dispatchSignInPasswordRequired(newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.expectedError) + + func checkError(_ error: SignInStartError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInVerifyCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInVerifyCodeDelegateDispatcherTests.swift new file mode 100644 index 0000000000..a1d04bac36 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInVerifyCodeDelegateDispatcherTests.swift @@ -0,0 +1,85 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class SignInVerifyCodeDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: SignInVerifyCodeDelegateDispatcher! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchSignInCompleted_whenDelegateMethodsAreImplemented() async { + let expectedResult = MSALNativeAuthUserAccountResultStub.result + let delegate = SignInVerifyCodeDelegateSpy(expectation: delegateExp, expectedUserAccountResult: expectedResult) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + await sut.dispatchSignInCompleted(result: expectedResult) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.expectedUserAccountResult, expectedResult) + } + + func test_dispatchSignInCompleted_whenDelegateOptionalMethodsNotImplemented() async { + let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted")) + let delegate = SignInVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? VerifyCodeError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedResult = MSALNativeAuthUserAccountResultStub.result + + await sut.dispatchSignInCompleted(result: expectedResult) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.expectedError) + + func checkError(_ error: VerifyCodeError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift new file mode 100644 index 0000000000..308695294e --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift @@ -0,0 +1,189 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: SignUpAttributesRequiredDelegateDispatcher! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + private let correlationId = UUID() + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchSignUpAttributesRequired_whenDelegateMethodsAreImplemented() async { + let delegate = SignUpAttributesRequiredDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + .init(name: "attribute1", type: "", required: true), + .init(name: "attribute2", type: "", required: true), + ] + + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.attributes, expectedAttributes) + XCTAssertEqual(delegate.newState, expectedState) + } + + func test_dispatchSignUpAttributesRequired_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = SignUpAttributesRequiredDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = AttributesRequiredError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? AttributesRequiredError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + .init(name: "attribute1", type: "", required: true), + .init(name: "attribute2", type: "", required: true), + ] + + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: AttributesRequiredError?) { + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } + + func test_dispatchSignUpAttributesInvalid_whenDelegateMethodsAreImplemented() async { + let delegate = SignUpAttributesRequiredDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedAttributeNames = ["attribute1", "attribute2"] + + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames, newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.invalidAttributes, expectedAttributeNames) + XCTAssertEqual(delegate.newState, expectedState) + } + + func test_dispatchSignUpAttributesInvalid_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = SignUpAttributesRequiredDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = AttributesRequiredError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? AttributesRequiredError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedAttributeNames = ["attribute1", "attribute2"] + + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames, newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: AttributesRequiredError?) { + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } + + func test_dispatchSignUpCompleted_whenDelegateMethodsAreImplemented() async { + let delegate = SignUpAttributesRequiredDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", slt: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpCompleted(newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.newSignInAfterSignUpState, expectedState) + } + + func test_dispatchSignUpCompleted_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = SignUpAttributesRequiredDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = AttributesRequiredError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? AttributesRequiredError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", slt: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpCompleted(newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: AttributesRequiredError?) { + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift new file mode 100644 index 0000000000..60c432f233 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift @@ -0,0 +1,142 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: SignUpPasswordRequiredDelegateDispatcher! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + private let correlationId = UUID() + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchSignUpAttributesRequired_whenDelegateMethodsAreImplemented() async { + let delegate = SignUpPasswordRequiredDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + .init(name: "attribute1", type: "", required: true), + .init(name: "attribute2", type: "", required: true), + ] + + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.newAttributesRequired, expectedAttributes) + XCTAssertEqual(delegate.newAttributesRequiredState, expectedState) + } + + func test_dispatchSignUpVerifyCode_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = SignUpPasswordRequiredDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = PasswordRequiredError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? PasswordRequiredError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + .init(name: "attribute1", type: "", required: true), + .init(name: "attribute2", type: "", required: true), + ] + + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: PasswordRequiredError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } + + func test_dispatchSignUpCompleted_whenDelegateMethodsAreImplemented() async { + let delegate = SignUpPasswordRequiredDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", slt: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpCompleted(newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.signInAfterSignUpState, expectedState) + } + + func test_dispatchSignUpCompleted_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = SignUpPasswordRequiredDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = PasswordRequiredError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? PasswordRequiredError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", slt: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpCompleted(newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: PasswordRequiredError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift new file mode 100644 index 0000000000..0e0f7812a8 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift @@ -0,0 +1,150 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: SignUpPasswordStartDelegateDispatcher! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + private let correlationId = UUID() + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchSignUpPasswordCodeRequired_whenDelegateMethodsAreImplemented() async { + let delegate = SignUpPasswordStartDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + await sut.dispatchSignUpPasswordCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.newState, expectedState) + XCTAssertEqual(delegate.sentTo, expectedSentTo) + XCTAssertEqual(delegate.channelTargetType, expectedChannelTargetType) + XCTAssertEqual(delegate.codeLength, expectedCodeLength) + } + + func test_dispatchSignUpPasswordCodeRequired_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = SignUpPasswordStartDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = SignUpPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCodeRequired")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? SignUpPasswordStartError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + await sut.dispatchSignUpPasswordCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: SignUpPasswordStartError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } + + func test_dispatchSignUpAttributesInvalid_whenDelegateMethodsAreImplemented() async { + let delegate = SignUpPasswordStartDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedAttributeNames = ["attribute1", "attribute2"] + + await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.attributeNames, expectedAttributeNames) + } + + func test_dispatchSignUpAttributesInvalid_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = SignUpPasswordStartDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = SignUpPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? SignUpPasswordStartError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedAttributeNames = ["attribute1", "attribute2"] + + await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: SignUpPasswordStartError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpResendCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpResendCodeDelegateDispatcherTests.swift new file mode 100644 index 0000000000..f06109b86f --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpResendCodeDelegateDispatcherTests.swift @@ -0,0 +1,104 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class SignUpResendCodeDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: SignUpResendCodeDelegateDispatcher! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + private let correlationId = UUID() + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchSignUpResendCode_whenDelegateMethodsAreImplemented() async { + let delegate = SignUpResendCodeDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + await sut.dispatchSignUpResendCodeCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.newState, expectedState) + XCTAssertEqual(delegate.sentTo, expectedSentTo) + XCTAssertEqual(delegate.channelTargetType, expectedChannelTargetType) + XCTAssertEqual(delegate.codeLength, expectedCodeLength) + } + + func test_dispatchSignUpResendCode_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = SignUpResendCodeDelegateMethodsNotImplemented(expectation: delegateExp) + let expectedError = ResendCodeError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpResendCodeCodeRequired")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? ResendCodeError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + await sut.dispatchSignUpResendCodeCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: ResendCodeError?) { + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpStartDelegateDispatcherTests.swift new file mode 100644 index 0000000000..afe28bab45 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpStartDelegateDispatcherTests.swift @@ -0,0 +1,150 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class SignUpStartDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: SignUpStartDelegateDispatcher! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + private let correlationId = UUID() + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchSignUpCodeRequired_whenDelegateMethodsAreImplemented() async { + let delegate = SignUpCodeStartDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + await sut.dispatchSignUpCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.newState, expectedState) + XCTAssertEqual(delegate.sentTo, expectedSentTo) + XCTAssertEqual(delegate.channelTargetType, expectedChannelTargetType) + XCTAssertEqual(delegate.codeLength, expectedCodeLength) + } + + func test_dispatchSignUpCodeRequired_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = SignUpStartDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = SignUpStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCodeRequired")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? SignUpStartError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedSentTo = "user@contoso.com" + let expectedChannelTargetType = MSALNativeAuthChannelType.email + let expectedCodeLength = 4 + + await sut.dispatchSignUpCodeRequired( + newState: expectedState, + sentTo: expectedSentTo, + channelTargetType: expectedChannelTargetType, + codeLength: expectedCodeLength + ) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: SignUpStartError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } + + func test_dispatchSignUpAttributesInvalid_whenDelegateMethodsAreImplemented() async { + let delegate = SignUpCodeStartDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedAttributeNames = ["attribute1", "attribute2"] + + await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.attributeNames, expectedAttributeNames) + } + + func test_dispatchSignUpAttributesInvalid_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = SignUpStartDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = SignUpStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? SignUpStartError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedAttributeNames = ["attribute1", "attribute2"] + + await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: SignUpStartError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift new file mode 100644 index 0000000000..9c07d3173f --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift @@ -0,0 +1,187 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: SignUpVerifyCodeDelegateDispatcher! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + private let correlationId = UUID() + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchSignUpAttributesRequired_whenDelegateMethodsAreImplemented() async { + let delegate = SignUpVerifyCodeDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + .init(name: "attribute1", type: "", required: true), + .init(name: "attribute2", type: "", required: true), + ] + + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.newAttributesRequired, expectedAttributes) + XCTAssertEqual(delegate.newAttributesRequiredState, expectedState) + } + + func test_dispatchSignUpVerifyCode_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = SignUpVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? VerifyCodeError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + .init(name: "attribute1", type: "", required: true), + .init(name: "attribute2", type: "", required: true), + ] + + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: VerifyCodeError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } + + func test_dispatchSignUpPasswordRequired_whenDelegateMethodsAreImplemented() async { + let delegate = SignUpVerifyCodeDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedState = SignUpPasswordRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpPasswordRequired(newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.newPasswordRequiredState, expectedState) + } + + func test_dispatchSignUpPasswordRequired_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = SignUpVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpPasswordRequired")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? VerifyCodeError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedState = SignUpPasswordRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpPasswordRequired(newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: VerifyCodeError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } + + func test_dispatchSignUpCompleted_whenDelegateMethodsAreImplemented() async { + let delegate = SignUpVerifyCodeDelegateSpy(expectation: delegateExp) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", slt: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpCompleted(newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.newSignInAfterSignUpState, expectedState) + } + + func test_dispatchSignUpCompleted_whenDelegateOptionalMethodsNotImplemented() async { + let delegate = SignUpVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: delegateExp) + let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted")) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? VerifyCodeError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", slt: "flowToken", correlationId: correlationId) + + await sut.dispatchSignUpCompleted(newState: expectedState) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.error) + + func checkError(_ error: VerifyCodeError?) { + XCTAssertEqual(error?.type, expectedError.type) + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift index 2a36707451..ec15718b45 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift @@ -48,7 +48,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken", correlationId: correlationId) let expectedResult: ResetPasswordResendCodeResult = .error(error: expectedError, newState: expectedState) - controller.resendCodeResult = .init(expectedResult) + controller.resendCodeResponse = .init(expectedResult) let exp = expectation(description: "reset password states") let delegate = ResetPasswordResendCodeDelegateSpy(expectation: exp) @@ -61,6 +61,8 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { } func test_resendCode_delegate_success_shouldReturnCodeRequired() { + let exp = expectation(description: "reset password states") + let exp2 = expectation(description: "telemetry expectation") let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: ResetPasswordResendCodeResult = .codeRequired( @@ -69,13 +71,14 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { channelTargetType: .email, codeLength: 1 ) - controller.resendCodeResult = .init(expectedResult) + controller.resendCodeResponse = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) - let exp = expectation(description: "sign-in states") let delegate = ResetPasswordResendCodeDelegateSpy(expectation: exp) sut.resendCode(delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) XCTAssertEqual(delegate.newState?.flowToken, expectedState.flowToken) XCTAssertEqual(delegate.sentTo, "sentTo") @@ -83,14 +86,37 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { XCTAssertEqual(delegate.codeLength, 1) } + func test_resendCode_delegate_success_whenOptionalMethodNotImplemented_shouldReturnCorrectError() { + let exp = expectation(description: "reset password states") + let exp2 = expectation(description: "telemetry expectation") + let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken 2", correlationId: correlationId) + + let expectedResult: ResetPasswordResendCodeResult = .codeRequired( + newState: expectedState, + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + controller.resendCodeResponse = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = ResetPasswordResendCodeDelegateOptionalMethodsNotImplemented(expectation: exp) + + sut.resendCode(delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onResetPasswordResendCodeRequired")) + } + // SubmitCode func test_submitCode_delegate_whenError_shouldReturnCorrectError() { let expectedError = VerifyCodeError(type: .invalidCode) let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken", correlationId: correlationId) - let expectedResult: ResetPasswordVerifyCodeResult = .error(error: expectedError, newState: expectedState) - controller.submitCodeResult = .init(expectedResult) + let expectedResult: ResetPasswordSubmitCodeResult = .error(error: expectedError, newState: expectedState) + controller.submitCodeResponse = .init(expectedResult) let exp = expectation(description: "reset password states") let delegate = ResetPasswordVerifyCodeDelegateSpy(expectation: exp) @@ -103,17 +129,39 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { } func test_submitCode_delegate_success_shouldReturnPasswordRequired() { + let exp = expectation(description: "reset password states") + let exp2 = expectation(description: "telemetry expectation") let expectedState = ResetPasswordRequiredState(controller: controller, flowToken: "flowToken 2", correlationId: correlationId) - let expectedResult: ResetPasswordVerifyCodeResult = .passwordRequired(newState: expectedState) - controller.submitCodeResult = .init(expectedResult) + let expectedResult: ResetPasswordSubmitCodeResult = .passwordRequired(newState: expectedState) + controller.submitCodeResponse = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) - let exp = expectation(description: "sign-in states") let delegate = ResetPasswordVerifyCodeDelegateSpy(expectation: exp) sut.submitCode(code: "1234", delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) XCTAssertEqual(delegate.newPasswordRequiredState, expectedState) } + + func test_submitCode_delegate_success_whenOptionalMethodsNotImplemented_shouldReturnCorrectError() { + let exp = expectation(description: "reset password states") + let exp2 = expectation(description: "telemetry expectation") + let expectedState = ResetPasswordRequiredState(controller: controller, flowToken: "flowToken 2", correlationId: correlationId) + + let expectedResult: ResetPasswordSubmitCodeResult = .passwordRequired(newState: expectedState) + controller.submitCodeResponse = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = ResetPasswordVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: exp) + + sut.submitCode(code: "1234", delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.type, .generalError) + XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onPasswordRequired")) + } } diff --git a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift index aeed145c4a..55be810ebb 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift @@ -31,25 +31,80 @@ final class ResetPasswordRequiredStateTests: XCTestCase { private var correlationId: UUID = UUID() private var exp: XCTestExpectation! - private var controller: MSALNativeAuthResetPasswordControllerSpy! + private var controllerSpy: MSALNativeAuthResetPasswordControllerSpy! + private var controllerMock: MSALNativeAuthResetPasswordControllerMock! private var sut: ResetPasswordRequiredState! - override func setUpWithError() throws { - try super.setUpWithError() - - exp = expectation(description: "ResetPasswordRequiredState expectation") - controller = MSALNativeAuthResetPasswordControllerSpy(expectation: exp) - sut = ResetPasswordRequiredState(controller: controller, flowToken: "", correlationId: correlationId) - } - func test_submitPassword_usesControllerSuccessfully() { - XCTAssertNil(controller.context) - XCTAssertFalse(controller.submitPasswordCalled) + exp = expectation(description: "ResetPasswordRequiredState expectation") + controllerSpy = MSALNativeAuthResetPasswordControllerSpy(expectation: exp) + XCTAssertNil(controllerSpy.context) + XCTAssertFalse(controllerSpy.submitPasswordCalled) + let sut = ResetPasswordRequiredState(controller: controllerSpy, flowToken: "", correlationId: correlationId) sut.submitPassword(password: "1234", delegate: ResetPasswordRequiredDelegateSpy()) wait(for: [exp], timeout: 1) - XCTAssertEqual(controller.context?.correlationId(), correlationId) - XCTAssertTrue(controller.submitPasswordCalled) + XCTAssertEqual(controllerSpy.context?.correlationId(), correlationId) + XCTAssertTrue(controllerSpy.submitPasswordCalled) + } + + func test_submitPassword_delegate_whenError_shouldReturnCorrectError() { + controllerMock = MSALNativeAuthResetPasswordControllerMock() + let sut = ResetPasswordRequiredState(controller: controllerMock, flowToken: "", correlationId: correlationId) + + let expectedError = PasswordRequiredError(type: .invalidPassword, message: nil) + let expectedState = ResetPasswordRequiredState(controller: controllerMock, flowToken: "flowToken", correlationId: correlationId) + + let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.error(error: expectedError, newState: expectedState)) + controllerMock.submitPasswordResponse = expectedResult + + let exp = expectation(description: "reset password states") + let delegate = ResetPasswordRequiredDelegateSpy(expectation: exp) + + sut.submitPassword(password: "incorrect", delegate: delegate) + wait(for: [exp]) + + XCTAssertEqual(delegate.error?.type, expectedError.type) + XCTAssertEqual(delegate.newPasswordRequiredState, expectedState) + } + + func test_submitPassword_delegate_whenSuccess_shouldReturnCompleted() { + let exp = expectation(description: "reset password states") + let exp2 = expectation(description: "telemetry expectation") + controllerMock = MSALNativeAuthResetPasswordControllerMock() + let sut = ResetPasswordRequiredState(controller: controllerMock, flowToken: "", correlationId: correlationId) + + let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.completed, telemetryUpdate: { _ in + exp2.fulfill() + }) + controllerMock.submitPasswordResponse = expectedResult + + let delegate = ResetPasswordRequiredDelegateSpy(expectation: exp) + + sut.submitPassword(password: "incorrect", delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertTrue(delegate.onResetPasswordCompletedCalled) + } + + func test_submitPassword_delegate_whenSuccess_butOptionalMethodsNotImplemented_shouldReturnCorrectError() { + let exp = expectation(description: "reset password states") + let exp2 = expectation(description: "telemetry expectation") + controllerMock = MSALNativeAuthResetPasswordControllerMock() + let sut = ResetPasswordRequiredState(controller: controllerMock, flowToken: "", correlationId: correlationId) + + let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.completed, telemetryUpdate: { _ in + exp2.fulfill() + }) + controllerMock.submitPasswordResponse = expectedResult + + let delegate = ResetPasswordRequiredDelegateOptionalMethodsNotImplemented(expectation: exp) + + sut.submitPassword(password: "incorrect", delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.type, .generalError) + XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onResetPasswordCompleted")) } } diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift index 4d8114dc5c..a184bb5950 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift @@ -43,6 +43,8 @@ final class SignInCodeRequiredStateTests: XCTestCase { // ResendCode func test_resendCode_delegate_withError_shouldReturnSignInResendCodeError() { + let exp = expectation(description: "sign-in states") + let expectedError = ResendCodeError(message: "test error") let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2", correlationId: correlationId) @@ -52,7 +54,6 @@ final class SignInCodeRequiredStateTests: XCTestCase { ) controller.resendCodeResult = .init(expectedResult) - let exp = expectation(description: "sign-in states") let delegate = SignInResendCodeDelegateSpy(expectation: exp) sut.resendCode(delegate: delegate) @@ -63,6 +64,8 @@ final class SignInCodeRequiredStateTests: XCTestCase { } func test_resendCode_delegate_success_shouldReturnSignInResendCodeCodeRequired() { + let exp = expectation(description: "sign-in states") + let exp2 = expectation(description: "expectation Telemetry") let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: SignInResendCodeResult = .codeRequired( @@ -71,19 +74,43 @@ final class SignInCodeRequiredStateTests: XCTestCase { channelTargetType: .email, codeLength: 1 ) - controller.resendCodeResult = .init(expectedResult) + controller.resendCodeResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) - let exp = expectation(description: "sign-in states") let delegate = SignInResendCodeDelegateSpy(expectation: exp, expectedSentTo: "sentTo", expectedChannelTargetType: .email, expectedCodeLength: 1) sut.resendCode(delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) XCTAssertEqual(delegate.newSignInCodeRequiredState?.flowToken, expectedState.flowToken) } + func test_resendCode_delegate_success_butMethodNotImplemented_shouldReturnCorrectError() { + let exp = expectation(description: "sign-in states") + let exp2 = expectation(description: "expectation Telemetry") + let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2", correlationId: UUID()) + + let expectedResult: SignInResendCodeResult = .codeRequired( + newState: expectedState, + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + controller.resendCodeResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignInResendCodeDelegateOptionalMethodsNotImplemented(expectation: exp) + + sut.resendCode(delegate: delegate) + wait(for: [exp, exp2]) + XCTAssertEqual(delegate.newSignInResendCodeError?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInResendCodeCodeRequired")) + } + // SubmitCode func test_submitCode_delegate_withError_shouldReturnSignInVerifyCodeError() { + let exp = expectation(description: "sign-in states") let expectedError = VerifyCodeError(type: .invalidCode) let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2", correlationId: correlationId) @@ -93,7 +120,6 @@ final class SignInCodeRequiredStateTests: XCTestCase { ) controller.submitCodeResult = .init(expectedResult) - let exp = expectation(description: "sign-in states") let delegate = SignInVerifyCodeDelegateSpy(expectation: exp, expectedError: expectedError) delegate.expectedNewState = expectedState @@ -102,15 +128,36 @@ final class SignInCodeRequiredStateTests: XCTestCase { } func test_submitCode_delegate_success_shouldReturnAccountResult() { + let exp = expectation(description: "sign-in states") + let exp2 = expectation(description: "expectation Telemetry") let expectedAccountResult = MSALNativeAuthUserAccountResultStub.result let expectedResult: SignInVerifyCodeResult = .completed(expectedAccountResult) - controller.submitCodeResult = .init(expectedResult) + controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) - let exp = expectation(description: "sign-in states") let delegate = SignInVerifyCodeDelegateSpy(expectation: exp, expectedUserAccountResult: expectedAccountResult) sut.submitCode(code: "1234", delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) + } + + func test_submitCode_delegate_success_whenMethodsNotImplemented_shouldReturnCorrectError() { + let exp = expectation(description: "sign-in states") + let exp2 = expectation(description: "expectation Telemetry") + let expectedAccountResult = MSALNativeAuthUserAccountResultStub.result + + let expectedResult: SignInVerifyCodeResult = .completed(expectedAccountResult) + controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignInVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: exp) + + sut.submitCode(code: "1234", delegate: delegate) + wait(for: [exp, exp2]) + XCTAssertEqual(delegate.expectedError?.type, .generalError) + XCTAssertEqual(delegate.expectedError?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted")) } } diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift index 71c743d36c..8723bb832f 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift @@ -60,15 +60,37 @@ final class SignInPasswordRequiredStateTests: XCTestCase { } func test_submitPassword_delegate_success_shouldReturnSuccess() { + let exp = expectation(description: "sign-in states") + let exp2 = expectation(description: "expectation Telemetry") let expectedAccountResult = MSALNativeAuthUserAccountResultStub.result let expectedResult: SignInPasswordRequiredResult = .completed(expectedAccountResult) - controller.submitPasswordResult = .init(expectedResult) + controller.submitPasswordResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) - let exp = expectation(description: "sign-in states") let delegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedUserAccountResult: expectedAccountResult) - sut.submitPassword(password: "invalid password", delegate: delegate) - wait(for: [exp]) + sut.submitPassword(password: "password", delegate: delegate) + wait(for: [exp, exp2]) + } + + func test_submitPassword_delegate_success_whenMethodsNotImplemented_shouldReturnCorrectError() { + let exp = expectation(description: "sign-in states") + let exp2 = expectation(description: "expectation Telemetry") + let expectedAccountResult = MSALNativeAuthUserAccountResultStub.result + + let expectedResult: SignInPasswordRequiredResult = .completed(expectedAccountResult) + controller.submitPasswordResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignInPasswordRequiredDelegateOptionalMethodsNotImplemented(expectation: exp) + + sut.submitPassword(password: "password", delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertNil(delegate.newPasswordRequiredState) + XCTAssertEqual(delegate.delegateError?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted")) } } diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift index 0693a586e7..b8e887eeb8 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift @@ -58,53 +58,120 @@ final class SignUpAttributesRequiredStateTests: XCTestCase { } func test_submitPassword_delegate_whenSuccess_shouldReturnCompleted() { + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "telemetry expectation") let expectedState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: correlationId) let expectedResult: SignUpAttributesRequiredResult = .completed(expectedState) - controller.submitAttributesResult = .init(expectedResult) + controller.submitAttributesResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) - let exp = expectation(description: "sign-up states") let delegate = SignUpAttributesRequiredDelegateSpy(expectation: exp) sut.submitAttributes(attributes: ["key":"value"], delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) XCTAssertEqual(delegate.newSignInAfterSignUpState, expectedState) } + func test_submitPassword_delegate_whenSuccess_butMethodNotImplemented_shouldReturnCorrectError() { + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "telemetry expectation") + let expectedState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: UUID()) + + let expectedResult: SignUpAttributesRequiredResult = .completed(expectedState) + controller.submitAttributesResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignUpAttributesRequiredDelegateOptionalMethodsNotImplemented(expectation: exp) + + sut.submitAttributes(attributes: ["key":"value"], delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted")) + } + func test_submitPassword_delegate_whenAttributesRequired_shouldReturnAttributesRequired() { + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "telemetry expectation") let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", flowToken: "slt", correlationId: correlationId) let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ .init(name: "anAttribute", type: "aType", required: true) ] let expectedResult: SignUpAttributesRequiredResult = .attributesRequired(attributes: expectedAttributes, state: expectedState) - controller.submitAttributesResult = .init(expectedResult) + controller.submitAttributesResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) - let exp = expectation(description: "sign-up states") let delegate = SignUpAttributesRequiredDelegateSpy(expectation: exp) sut.submitAttributes(attributes: ["key":"value"], delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) XCTAssertEqual(delegate.attributes, expectedAttributes) XCTAssertEqual(delegate.newState, expectedState) } - func test_submitPassword_delegate_whenAttributesAreInvalud_shouldReturnAttributesInvalid() { + func test_submitPassword_delegate_whenAttributesRequired_butMethodNotImplemented_shouldReturnCorrectError() { + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "telemetry expectation") + let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", flowToken: "slt", correlationId: correlationId) + let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + .init(name: "anAttribute", type: "aType", required: true) + ] + + let expectedResult: SignUpAttributesRequiredResult = .attributesRequired(attributes: expectedAttributes, state: expectedState) + controller.submitAttributesResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignUpAttributesRequiredDelegateOptionalMethodsNotImplemented(expectation: exp) + + sut.submitAttributes(attributes: ["key":"value"], delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired")) + } + + func test_submitPassword_delegate_whenAttributesAreInvalid_shouldReturnAttributesInvalid() { + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "telemetry expectation") let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", flowToken: "slt", correlationId: correlationId) let expectedAttributes = ["anAttribute"] let expectedResult: SignUpAttributesRequiredResult = .attributesInvalid(attributes: expectedAttributes, newState: expectedState) - controller.submitAttributesResult = .init(expectedResult) + controller.submitAttributesResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) - let exp = expectation(description: "sign-up states") let delegate = SignUpAttributesRequiredDelegateSpy(expectation: exp) sut.submitAttributes(attributes: ["key":"value"], delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) XCTAssertEqual(delegate.invalidAttributes, expectedAttributes) XCTAssertEqual(delegate.newState, expectedState) } + + func test_submitPassword_delegate_whenAttributesAreInvalid_butMethodNotImplemented_shouldReturnCorrectError() { + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "telemetry expectation") + let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", flowToken: "slt", correlationId: correlationId) + let expectedAttributes = ["anAttribute"] + + let expectedResult: SignUpAttributesRequiredResult = .attributesInvalid(attributes: expectedAttributes, newState: expectedState) + controller.submitAttributesResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignUpAttributesRequiredDelegateOptionalMethodsNotImplemented(expectation: exp) + + sut.submitAttributes(attributes: ["key":"value"], delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid")) + } } diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift index dfd9aafc5d..c50df1be0d 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift @@ -46,7 +46,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { func test_resendCode_delegate_whenError_shouldReturnCorrectError() { let expectedError = ResendCodeError(message: "test error") - let expectedResult: SignUpResendCodeResult = .error(expectedError) + let expectedResult: SignUpResendCodeResult = .error(error: expectedError, newState: nil) controller.resendCodeResult = .init(expectedResult) let exp = expectation(description: "sign-up states") @@ -59,6 +59,8 @@ final class SignUpCodeRequiredStateTests: XCTestCase { } func test_resendCode_delegate_success_shouldReturnCodeRequired() { + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "telemetry expectation") let expectedState = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: SignUpResendCodeResult = .codeRequired( @@ -67,13 +69,14 @@ final class SignUpCodeRequiredStateTests: XCTestCase { channelTargetType: .email, codeLength: 1 ) - controller.resendCodeResult = .init(expectedResult) + controller.resendCodeResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) - let exp = expectation(description: "sign-in states") let delegate = SignUpResendCodeDelegateSpy(expectation: exp) sut.resendCode(delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) XCTAssertEqual(delegate.newState?.flowToken, expectedState.flowToken) XCTAssertEqual(delegate.sentTo, "sentTo") @@ -81,6 +84,29 @@ final class SignUpCodeRequiredStateTests: XCTestCase { XCTAssertEqual(delegate.codeLength, 1) } + func test_resendCode_delegate_success_butMethodNotImplemented() { + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "telemetry expectation") + let expectedState = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) + + let expectedResult: SignUpResendCodeResult = .codeRequired( + newState: expectedState, + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + controller.resendCodeResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignUpResendCodeDelegateMethodsNotImplemented(expectation: exp) + + sut.resendCode(delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpResendCodeCodeRequired")) + } + // SubmitCode func test_submitCode_delegate_whenError_shouldReturnCorrectError() { @@ -123,8 +149,6 @@ final class SignUpCodeRequiredStateTests: XCTestCase { } func test_submitCode_delegate_whenPasswordRequired_ButUserHasNotImplementedOptionalDelegate_shouldReturnCorrectError() { - let expectedError = VerifyCodeError(type: .generalError, message: MSALNativeAuthErrorMessage.delegateNotImplemented) - let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "exp telemetry is called") @@ -138,8 +162,11 @@ final class SignUpCodeRequiredStateTests: XCTestCase { sut.submitCode(code: "1234", delegate: delegate) wait(for: [exp, exp2]) - XCTAssertEqual(delegate.error?.type, expectedError.type) - XCTAssertEqual(delegate.error?.errorDescription, MSALNativeAuthErrorMessage.delegateNotImplemented) + XCTAssertEqual(delegate.error?.type, .generalError) + XCTAssertEqual( + delegate.error?.errorDescription, + String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpPasswordRequired") + ) } func test_submitCode_delegate_whenAttributesRequired_AndUserHasImplementedOptionalDelegate_shouldReturnAttributesRequired() { @@ -162,8 +189,6 @@ final class SignUpCodeRequiredStateTests: XCTestCase { } func test_submitCode_delegate_whenAttributesRequired_ButUserHasNotImplementedOptionalDelegate_shouldReturnCorrectError() { - let expectedError = VerifyCodeError(type: .generalError, message: MSALNativeAuthErrorMessage.delegateNotImplemented) - let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "exp telemetry is called") @@ -177,22 +202,49 @@ final class SignUpCodeRequiredStateTests: XCTestCase { sut.submitCode(code: "1234", delegate: delegate) wait(for: [exp, exp2]) - XCTAssertEqual(delegate.error?.type, expectedError.type) - XCTAssertEqual(delegate.error?.errorDescription, MSALNativeAuthErrorMessage.delegateNotImplemented) + XCTAssertEqual(delegate.error?.type, .generalError) + XCTAssertEqual( + delegate.error?.errorDescription, + String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired") + ) } func test_submitCode_delegate_whenSuccess_shouldReturnAccountResult() { + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "telemetry expectation") let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: correlationId) let expectedResult: SignUpVerifyCodeResult = .completed(expectedSignInAfterSignUpState) - controller.submitCodeResult = .init(expectedResult) + controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) - let exp = expectation(description: "sign-up states") let delegate = SignUpVerifyCodeDelegateSpy(expectation: exp) sut.submitCode(code: "1234", delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) XCTAssertEqual(delegate.newSignInAfterSignUpState, expectedSignInAfterSignUpState) } + + func test_submitCode_delegate_whenSuccess_ButUserHasNotImplementedOptionalDelegate_shouldReturnCorrectError() { + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "telemetry expectation") + let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: correlationId) + let result: SignUpVerifyCodeResult = .completed(expectedSignInAfterSignUpState) + controller.submitCodeResult = .init(result, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignUpVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: exp) + + sut.submitCode(code: "1234", delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.type, .generalError) + XCTAssertEqual( + delegate.error?.errorDescription, + String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted") + ) + } } diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift index 8a2c4b6e32..fad873c340 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift @@ -79,7 +79,6 @@ final class SignUpPasswordRequiredStateTests: XCTestCase { } func test_submitCode_delegate_whenAttributesRequired_ButUserHasNotImplementedOptionalDelegate_shouldReturnPasswordRequiredError() { - let expectedError = PasswordRequiredError(type: .generalError, message: MSALNativeAuthErrorMessage.delegateNotImplemented) let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) let exp = expectation(description: "sign-up states") @@ -95,23 +94,46 @@ final class SignUpPasswordRequiredStateTests: XCTestCase { sut.submitPassword(password: "1234", delegate: delegate) wait(for: [exp, exp2]) - XCTAssertEqual(delegate.error?.type, expectedError.type) - XCTAssertEqual(delegate.error?.errorDescription, MSALNativeAuthErrorMessage.delegateNotImplemented) + XCTAssertEqual(delegate.error?.type, .generalError) + XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired")) } func test_submitCode_delegate_whenSuccess_shouldReturnSignUpCompleted() { let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: correlationId) let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "telemetry expectation") let expectedResult: SignUpPasswordRequiredResult = .completed(expectedSignInAfterSignUpState) - controller.submitPasswordResult = .init(expectedResult) + controller.submitPasswordResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) let delegate = SignUpPasswordRequiredDelegateSpy(expectation: exp) sut.submitPassword(password: "1234", delegate: delegate) - wait(for: [exp]) + wait(for: [exp, exp2]) XCTAssertEqual(delegate.signInAfterSignUpState, expectedSignInAfterSignUpState) } + + func test_submitCode_delegate_whenSuccess_ButUserHasNotImplementedOptionalDelegate_shouldReturnCorrectError() { + let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: correlationId) + + let exp = expectation(description: "sign-up states") + let exp2 = expectation(description: "telemetry expectation") + + let expectedResult: SignUpPasswordRequiredResult = .completed(expectedSignInAfterSignUpState) + controller.submitPasswordResult = .init(expectedResult, telemetryUpdate: { _ in + exp2.fulfill() + }) + + let delegate = SignUpPasswordRequiredDelegateOptionalMethodsNotImplemented(expectation: exp) + + sut.submitPassword(password: "1234", delegate: delegate) + wait(for: [exp, exp2]) + + XCTAssertEqual(delegate.error?.type, .generalError) + XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted")) + } } From 3c768c9cf943f24fc71c4cbe1f0f4a27952039e9 Mon Sep 17 00:00:00 2001 From: Diego Jerez Barroso <109726904+diegojerezba@users.noreply.github.com> Date: Thu, 14 Dec 2023 10:57:10 +0000 Subject: [PATCH 19/84] Make errors extensible (#1923) Fix broken tests. Add tests for public errors PR code review Change the `identifier` variable from String to Int. This allows us to enable the public ErrorType enums for objc developers. Rename SignInPasswordStartError's invalidPassword to invalidCredentials Fix failing test. Update inline documentation for isBrowserRequired error Remove error.identifier from public interface. Update inline doc to use "username" instead of "email". Fixed integration tests Renamed MockAPIURL env variable to authorityURL to work with the test case --- MSAL/MSAL.xcodeproj/project.pbxproj | 52 ++++++++++ .../errors/MSALNativeAuthErrorMessage.swift | 8 ++ ...MSALNativeAuthTokenValidatedResponse.swift | 2 +- ...AuthPublicClientApplication+Internal.swift | 2 +- .../error/AttributesRequiredError.swift | 3 +- .../error/MSALNativeAuthError.swift | 9 +- .../error/PasswordRequiredError.swift | 37 ++++--- .../state_machine/error/ResendCodeError.swift | 3 +- .../error/ResetPasswordStartError.swift | 55 +++++++---- .../error/RetrieveAccessTokenError.swift | 48 +++++---- .../error/SignInAfterSignUpError.swift | 3 +- .../error/SignInPasswordStartError.swift | 55 +++++++---- .../error/SignInStartError.swift | 44 ++++++--- .../error/SignUpPasswordStartError.swift | 52 ++++++---- .../error/SignUpStartError.swift | 44 ++++++--- .../state_machine/error/VerifyCodeError.swift | 37 ++++--- .../MSALNativeAuthIntegrationBaseTests.swift | 2 +- .../native_auth/common/MockAPIHandler.swift | 2 +- ...gnInUserNameAndPasswordEndToEndTests.swift | 4 +- ...ativeAuthSignInUsernameEndToEndTests.swift | 6 +- .../MSALNativeAuthSignInControllerTests.swift | 18 ++-- ...wordPollCompletionResponseErrorTests.swift | 2 +- ...esetPasswordSubmitResponseErrorTests.swift | 2 +- ...uthSignUpChallengeResponseErrorTests.swift | 6 +- ...AuthSignUpContinueResponseErrorTests.swift | 4 +- ...iveAuthSignUpStartResponseErrorTests.swift | 4 +- ...ignInInitiateValidatedErrorTypeTests.swift | 6 +- ...tiveAuthTokenValidatedErrorTypeTests.swift | 2 +- ...ativeAuthPublicClientApplicationTest.swift | 2 +- .../error/AttributesRequiredErrorTests.swift | 42 ++++++++ .../error/PasswordRequiredErrorTests.swift | 73 ++++++++++++++ .../public/error/ResendCodeErrorTests.swift | 42 ++++++++ .../error/ResetPasswordStartErrorTests.swift | 97 +++++++++++++++++++ .../error/RetrieveAccessTokenErrorTests.swift | 84 ++++++++++++++++ .../error/SignInAfterSignUpErrorTests.swift | 42 ++++++++ .../error/SignInPasswordStartErrorTests.swift | 97 +++++++++++++++++++ .../public/error/SignInStartErrorTests.swift | 84 ++++++++++++++++ .../error/SignUpPasswordStartErrorTests.swift | 97 +++++++++++++++++++ .../public/error/SignUpStartErrorTests.swift | 84 ++++++++++++++++ .../public/error/VerifyCodeErrorTests.swift | 73 ++++++++++++++ 40 files changed, 1161 insertions(+), 168 deletions(-) create mode 100644 MSAL/test/unit/native_auth/public/error/AttributesRequiredErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/public/error/PasswordRequiredErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/public/error/ResendCodeErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/public/error/ResetPasswordStartErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/public/error/RetrieveAccessTokenErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/public/error/SignInAfterSignUpErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/public/error/SignInPasswordStartErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/public/error/SignInStartErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/public/error/SignUpPasswordStartErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/public/error/SignUpStartErrorTests.swift create mode 100644 MSAL/test/unit/native_auth/public/error/VerifyCodeErrorTests.swift diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index 681c831d44..305a31a252 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -1113,6 +1113,17 @@ E2CD2E8D2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2E8C2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift */; }; E2CD2EB32A040012009F8FFA /* SignUpTestsValidatorHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2EB22A040012009F8FFA /* SignUpTestsValidatorHelpers.swift */; }; E2CD2EB52A0404DA009F8FFA /* MSALNativeAuthSignUpControllerSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2EB42A0404DA009F8FFA /* MSALNativeAuthSignUpControllerSpy.swift */; }; + E2CE910A2B0BA37D0009AEDD /* SignUpPasswordStartErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE91092B0BA37D0009AEDD /* SignUpPasswordStartErrorTests.swift */; }; + E2CE910C2B0BA3BB0009AEDD /* SignUpStartErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE910B2B0BA3BB0009AEDD /* SignUpStartErrorTests.swift */; }; + E2CE910E2B0BA3D30009AEDD /* PasswordRequiredErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE910D2B0BA3D30009AEDD /* PasswordRequiredErrorTests.swift */; }; + E2CE91102B0BA3E80009AEDD /* AttributesRequiredErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE910F2B0BA3E80009AEDD /* AttributesRequiredErrorTests.swift */; }; + E2CE91122B0BA3FC0009AEDD /* SignInPasswordStartErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE91112B0BA3FC0009AEDD /* SignInPasswordStartErrorTests.swift */; }; + E2CE91142B0BA40F0009AEDD /* SignInStartErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE91132B0BA40F0009AEDD /* SignInStartErrorTests.swift */; }; + E2CE91162B0BA4490009AEDD /* VerifyCodeErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE91152B0BA4490009AEDD /* VerifyCodeErrorTests.swift */; }; + E2CE91182B0BA4620009AEDD /* ResetPasswordStartErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE91172B0BA4620009AEDD /* ResetPasswordStartErrorTests.swift */; }; + E2CE911A2B0BA4790009AEDD /* ResendCodeErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE91192B0BA4790009AEDD /* ResendCodeErrorTests.swift */; }; + E2CE911C2B0BA48D0009AEDD /* RetrieveAccessTokenErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE911B2B0BA48D0009AEDD /* RetrieveAccessTokenErrorTests.swift */; }; + E2CE911E2B0BA4A60009AEDD /* SignInAfterSignUpErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE911D2B0BA4A60009AEDD /* SignInAfterSignUpErrorTests.swift */; }; E2D3BC4F2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D3BC4E2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift */; }; E2DC31BC29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DC31BB29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift */; }; E2DC31C829B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DC31C729B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift */; }; @@ -2115,6 +2126,17 @@ E2CD2E8C2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpResponseValidator.swift; sourceTree = ""; }; E2CD2EB22A040012009F8FFA /* SignUpTestsValidatorHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpTestsValidatorHelpers.swift; sourceTree = ""; }; E2CD2EB42A0404DA009F8FFA /* MSALNativeAuthSignUpControllerSpy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpControllerSpy.swift; sourceTree = ""; }; + E2CE91092B0BA37D0009AEDD /* SignUpPasswordStartErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpPasswordStartErrorTests.swift; sourceTree = ""; }; + E2CE910B2B0BA3BB0009AEDD /* SignUpStartErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpStartErrorTests.swift; sourceTree = ""; }; + E2CE910D2B0BA3D30009AEDD /* PasswordRequiredErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordRequiredErrorTests.swift; sourceTree = ""; }; + E2CE910F2B0BA3E80009AEDD /* AttributesRequiredErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributesRequiredErrorTests.swift; sourceTree = ""; }; + E2CE91112B0BA3FC0009AEDD /* SignInPasswordStartErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInPasswordStartErrorTests.swift; sourceTree = ""; }; + E2CE91132B0BA40F0009AEDD /* SignInStartErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInStartErrorTests.swift; sourceTree = ""; }; + E2CE91152B0BA4490009AEDD /* VerifyCodeErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifyCodeErrorTests.swift; sourceTree = ""; }; + E2CE91172B0BA4620009AEDD /* ResetPasswordStartErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordStartErrorTests.swift; sourceTree = ""; }; + E2CE91192B0BA4790009AEDD /* ResendCodeErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResendCodeErrorTests.swift; sourceTree = ""; }; + E2CE911B2B0BA48D0009AEDD /* RetrieveAccessTokenErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RetrieveAccessTokenErrorTests.swift; sourceTree = ""; }; + E2CE911D2B0BA4A60009AEDD /* SignInAfterSignUpErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAfterSignUpErrorTests.swift; sourceTree = ""; }; E2D3BC4E2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MSALNativeAuthUserAccountResult+Internal.swift"; sourceTree = ""; }; E2DC31BB29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthPublicClientApplication.swift; sourceTree = ""; }; E2DC31C729B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthAuthorityProvider.swift; sourceTree = ""; }; @@ -2351,6 +2373,7 @@ isa = PBXGroup; children = ( E22427E02B0650670006C55E /* delegate */, + E2CE91012B0BA34F0009AEDD /* error */, E2CD2E3F29FBE957009F8FFA /* state_machine */, 287F64F22981A00400ED90BD /* MSALNativeAuthPublicClientApplicationTest.swift */, DE87DE692A39E80B0032BF9E /* MSALNativeAuthUserAccountResultTests.swift */, @@ -4134,6 +4157,24 @@ path = delegate_dispatcher; sourceTree = ""; }; + E2CE91012B0BA34F0009AEDD /* error */ = { + isa = PBXGroup; + children = ( + E2CE91092B0BA37D0009AEDD /* SignUpPasswordStartErrorTests.swift */, + E2CE910B2B0BA3BB0009AEDD /* SignUpStartErrorTests.swift */, + E2CE910D2B0BA3D30009AEDD /* PasswordRequiredErrorTests.swift */, + E2CE910F2B0BA3E80009AEDD /* AttributesRequiredErrorTests.swift */, + E2CE91112B0BA3FC0009AEDD /* SignInPasswordStartErrorTests.swift */, + E2CE91132B0BA40F0009AEDD /* SignInStartErrorTests.swift */, + E2CE91152B0BA4490009AEDD /* VerifyCodeErrorTests.swift */, + E2CE91172B0BA4620009AEDD /* ResetPasswordStartErrorTests.swift */, + E2CE91192B0BA4790009AEDD /* ResendCodeErrorTests.swift */, + E2CE911B2B0BA48D0009AEDD /* RetrieveAccessTokenErrorTests.swift */, + E2CE911D2B0BA4A60009AEDD /* SignInAfterSignUpErrorTests.swift */, + ); + path = error; + sourceTree = ""; + }; E2EFAD072A69A2C300D6C3DE /* responses */ = { isa = PBXGroup; children = ( @@ -5878,6 +5919,7 @@ DE5738B62A8E790100D9120D /* MSALNativeAuthTokenValidatedErrorTypeTests.swift in Sources */, 9BB5180B2A2A2B5B00D6276A /* MSALNativeAuthResetPasswordControllerSpy.swift in Sources */, DE94C9E229F19AA200C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift in Sources */, + E2CE91102B0BA3E80009AEDD /* AttributesRequiredErrorTests.swift in Sources */, E2F5BE8E29893A4100C67EC7 /* MSALNativeAuthEndpointTests.swift in Sources */, 287F64F0298186EA00ED90BD /* MSALNativeAuthInputValidatorTest.swift in Sources */, 8D61F9A12A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift in Sources */, @@ -5887,6 +5929,7 @@ 287F6524298401AE00ED90BD /* MSALNativeAuthResponseSerializerTests.swift in Sources */, E2CD2E4F29FC0451009F8FFA /* SignUpPasswordRequiredStateTests.swift in Sources */, E22427F62B066E850006C55E /* SignInPasswordRequiredDelegateDispatcherTests.swift in Sources */, + E2CE910C2B0BA3BB0009AEDD /* SignUpStartErrorTests.swift in Sources */, E2EBD6212A1BB4640049467A /* MSALNativeAuthSignUpRequestProviderMock.swift in Sources */, E2F4DB242A1F525A009FBCD0 /* MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift in Sources */, A0274CDD24B54C8800BD198D /* MSALDevicePopManagerUtil.m in Sources */, @@ -5894,6 +5937,7 @@ 9B2BBA372A3298080075F702 /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift in Sources */, B2725E7F22BD88BE009B454A /* NSStringAccountIdentifiersTest.m in Sources */, 287F64D4297EC29400ED90BD /* MSALNativeAuthTelemetryProviderTests.swift in Sources */, + E2CE910A2B0BA37D0009AEDD /* SignUpPasswordStartErrorTests.swift in Sources */, E22952682A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift in Sources */, E286E2DD2A1BAEA800666DD0 /* MSALNativeAuthSignUpControllerTests.swift in Sources */, B2725EC522BF4865009B454A /* MSALMockExternalAccountHandler.m in Sources */, @@ -5915,12 +5959,15 @@ B253153B23DD717900432133 /* MSALDeviceInfoProviderTests.m in Sources */, 9B61C91C2A27E57C00CE9E3A /* MSALNativeAuthResetPasswordResponseValidatorMock.swift in Sources */, DE40A4D32A8F80C100928CEE /* MSALNativeAuthSignUpContinueResponseErrorTests.swift in Sources */, + E2CE91162B0BA4490009AEDD /* VerifyCodeErrorTests.swift in Sources */, DE94C9E029F198D600C1EC1F /* MSALNativeAuthResetPasswordStartRequestParametersTest.swift in Sources */, DE14096D2A38DF41008E6F1E /* MSALNativeAuthCredentialsControllerTests.swift in Sources */, DE5738B42A8E74DC00D9120D /* MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift in Sources */, DE87DE6A2A39E80B0032BF9E /* MSALNativeAuthUserAccountResultTests.swift in Sources */, + E2CE91182B0BA4620009AEDD /* ResetPasswordStartErrorTests.swift in Sources */, E2BDD98B2A28FBDD00E3ED6B /* MSALNativeAuthErrorRequiredAttributesTests.swift in Sources */, E2CD2E4A29FBEA36009F8FFA /* SignUpCodeSentStateTests.swift in Sources */, + E2CE911A2B0BA4790009AEDD /* ResendCodeErrorTests.swift in Sources */, 23A68A9320F59E6B0071E435 /* NSString+MSALTestUtil.m in Sources */, E25E6E512AA7725F0094461E /* MSALNativeAuthResetPasswordControllerMock.swift in Sources */, 9B61C9132A27E51900CE9E3A /* MSALNativeAuthResetPasswordRequestProviderMock.swift in Sources */, @@ -5936,6 +5983,7 @@ 960751BB2183E82C00F2BF2F /* MSALAccountIdTests.m in Sources */, E20C217E2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift in Sources */, E22427F82B066F750006C55E /* SignInResendCodeDelegateDispatcherTests.swift in Sources */, + E2CE911C2B0BA48D0009AEDD /* RetrieveAccessTokenErrorTests.swift in Sources */, E248917A2A1CFA6B001ECBE2 /* MSALNativeAuthConfigStubs.swift in Sources */, E22427E62B065D0D0006C55E /* SignUpStartDelegateDispatcherTests.swift in Sources */, 9B2BBA352A3297F80075F702 /* MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift in Sources */, @@ -5951,6 +5999,7 @@ E22427FA2B0670600006C55E /* SignInVerifyCodeDelegateDispatcherTests.swift in Sources */, E2EBD62A2A1BB7700049467A /* MSALNativeAuthSignUpResponseValidatorMock.swift in Sources */, E25BC0852995430B00588549 /* MSALNativeAuthFactoriesMocks.swift in Sources */, + E2CE91122B0BA3FC0009AEDD /* SignInPasswordStartErrorTests.swift in Sources */, E2BC029C29D766CB00041DBC /* MSALNativeAuthSignUpContinueRequestParametersTest.swift in Sources */, E2960A112A1F4D2F000F441B /* MSALNativeAuthSignUpChallengeResponseErrorTests.swift in Sources */, DE94C9E629F19D9B00C1EC1F /* MSALNativeAuthResetPasswordSubmitRequestParametersTest.swift in Sources */, @@ -5962,6 +6011,7 @@ E2C1D2D429A3992100B26449 /* MSALNativeAuthBaseControllerTests.swift in Sources */, DE40A4CA2A8F801200928CEE /* MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift in Sources */, E23E956929D5BD6B001DC59C /* MSALNativeAuthSignUpRequestProviderTests.swift in Sources */, + E2CE91142B0BA40F0009AEDD /* SignInStartErrorTests.swift in Sources */, DE5738BE2A8F7AC600D9120D /* MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift in Sources */, 609AF9332256BD0C00E2978D /* MSALAccountsProviderTests.m in Sources */, E22428052B0674A50006C55E /* SignInAfterSignUpDelegateDispatcherTests.swift in Sources */, @@ -5977,6 +6027,8 @@ E22427F42B066BBC0006C55E /* SignInStartDelegateDispatcherTests.swift in Sources */, DE5738B22A8E71D500D9120D /* MSALNativeAuthResetPasswordContinueResponseErrorTests.swift in Sources */, 9B6EECEF2A3146ED008ABA50 /* MSALNativeAuthResetPasswordResponseValidatorTests.swift in Sources */, + E2CE911E2B0BA4A60009AEDD /* SignInAfterSignUpErrorTests.swift in Sources */, + E2CE910E2B0BA3D30009AEDD /* PasswordRequiredErrorTests.swift in Sources */, 28FDC4AE2A38D81100E38BE1 /* MSALNativeAuthSignInControllerMock.swift in Sources */, B281B33B226BC225009619AB /* MSALPublicClientApplicationConfigTests.m in Sources */, E2F5BE9A29896ADB00C67EC7 /* MSALNativeAuthSignInControllerTests.swift in Sources */, diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift index a19341bba7..fa9fefe3e7 100644 --- a/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift @@ -35,6 +35,14 @@ enum MSALNativeAuthErrorMessage { static let attributeValidationFailed = "Invalid attributes: %@" static let signInNotAvailable = "Sign In is not available at this point, please use the standalone sign in methods" static let codeRequiredForPasswordUserLog = "This user does not have a password associated with their account. SDK will call `delegate.onSignInCodeRequired()` and the entered password will be ignored" + static let userAlreadyExists = "User already exists" + static let invalidPassword = "Invalid password" + static let invalidCredentials = "Invalid credentials" + static let invalidUsername = "Invalid username" + static let generalError = "General error" + static let invalidCode = "Invalid code" + static let refreshTokenExpired = "Refresh token is expired" + static let tokenNotFound = "Token not found" } // swiftlint:enable line_length diff --git a/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift index 34043e98ab..e8856cbf2d 100644 --- a/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift @@ -63,7 +63,7 @@ enum MSALNativeAuthTokenValidatedErrorType: Error { case .userNotFound(let message): return SignInPasswordStartError(type: .userNotFound, message: message) case .invalidPassword(let message): - return SignInPasswordStartError(type: .invalidPassword, message: message) + return SignInPasswordStartError(type: .invalidCredentials, message: message) case .strongAuthRequired(let message): return SignInPasswordStartError(type: .browserRequired, message: message) case .expiredRefreshToken(let message): diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift index ae2d7a3254..81ff9b84a9 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift @@ -85,7 +85,7 @@ extension MSALNativeAuthPublicClientApplication { } guard inputValidator.isInputValid(password) else { - return .init(.error(SignInPasswordStartError(type: .invalidPassword))) + return .init(.error(SignInPasswordStartError(type: .invalidCredentials))) } let controller = controllerFactory.makeSignInController() diff --git a/MSAL/src/native_auth/public/state_machine/error/AttributesRequiredError.swift b/MSAL/src/native_auth/public/state_machine/error/AttributesRequiredError.swift index 6ab96f409a..3bdc18f050 100644 --- a/MSAL/src/native_auth/public/state_machine/error/AttributesRequiredError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/AttributesRequiredError.swift @@ -26,11 +26,12 @@ import Foundation @objc public class AttributesRequiredError: MSALNativeAuthError { + /// Describes why an error occurred and provides more information about the error. public override var errorDescription: String? { if let description = super.errorDescription { return description } - return "General error" + return MSALNativeAuthErrorMessage.generalError } } diff --git a/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift b/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift index 102612a6ec..a46e217d7e 100644 --- a/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift @@ -24,15 +24,14 @@ import Foundation -@objc +@objcMembers public class MSALNativeAuthError: NSObject, LocalizedError { + /// Describes why an error occurred and provides more information about the error. + public var errorDescription: String? { message } + private let message: String? init(message: String? = nil) { self.message = message } - - public var errorDescription: String? { - message - } } diff --git a/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift b/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift index 9296efe220..808e68a86a 100644 --- a/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift @@ -24,12 +24,17 @@ import Foundation -@objc +@objcMembers public class PasswordRequiredError: MSALNativeAuthError { - /// An error type indicating the type of error that occurred - @objc public let type: PasswordRequiredErrorType + enum ErrorType: CaseIterable { + case browserRequired + case invalidPassword + case generalError + } + + let type: ErrorType - init(type: PasswordRequiredErrorType, message: String? = nil) { + init(type: ErrorType, message: String? = nil) { self.type = type super.init(message: message) } @@ -38,7 +43,7 @@ public class PasswordRequiredError: MSALNativeAuthError { switch signInPasswordError.type { case .browserRequired: self.type = .browserRequired - case .invalidPassword: + case .invalidCredentials: self.type = .invalidPassword default: self.type = .generalError @@ -46,6 +51,7 @@ public class PasswordRequiredError: MSALNativeAuthError { super.init(message: signInPasswordError.errorDescription) } + /// Describes why an error occurred and provides more information about the error. public override var errorDescription: String? { if let description = super.errorDescription { return description @@ -53,18 +59,21 @@ public class PasswordRequiredError: MSALNativeAuthError { switch type { case .browserRequired: - return "Browser required" + return MSALNativeAuthErrorMessage.browserRequired case .invalidPassword: - return "Invalid password" + return MSALNativeAuthErrorMessage.invalidPassword case .generalError: - return "General error" + return MSALNativeAuthErrorMessage.generalError } } -} -@objc -public enum PasswordRequiredErrorType: Int { - case browserRequired - case generalError - case invalidPassword + /// Returns `true` if a browser is required to continue the operation. + public var isBrowserRequired: Bool { + return type == .browserRequired + } + + /// Returns `true` when the password is not valid. + public var isInvalidPassword: Bool { + return type == .invalidPassword + } } diff --git a/MSAL/src/native_auth/public/state_machine/error/ResendCodeError.swift b/MSAL/src/native_auth/public/state_machine/error/ResendCodeError.swift index 36a399b03e..ffb964e173 100644 --- a/MSAL/src/native_auth/public/state_machine/error/ResendCodeError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/ResendCodeError.swift @@ -26,11 +26,12 @@ import Foundation @objc public class ResendCodeError: MSALNativeAuthError { + /// Describes why an error occurred and provides more information about the error. public override var errorDescription: String? { if let description = super.errorDescription { return description } - return "General error" + return MSALNativeAuthErrorMessage.generalError } } diff --git a/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift b/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift index 2871a9e2b7..851bda969d 100644 --- a/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift @@ -24,16 +24,24 @@ import Foundation -@objc +@objcMembers public class ResetPasswordStartError: MSALNativeAuthError { - /// An error type indicating the type of error that occurred - @objc public let type: ResetPasswordStartErrorType + enum ErrorType: CaseIterable { + case browserRequired + case userDoesNotHavePassword + case userNotFound + case invalidUsername + case generalError + } + + let type: ErrorType - init(type: ResetPasswordStartErrorType, message: String? = nil) { + init(type: ErrorType, message: String? = nil) { self.type = type super.init(message: message) } + /// Describes why an error occurred and provides more information about the error. public override var errorDescription: String? { if let description = super.errorDescription { return description @@ -41,24 +49,35 @@ public class ResetPasswordStartError: MSALNativeAuthError { switch type { case .browserRequired: - return "Browser required" - case .generalError: - return "General error" + return MSALNativeAuthErrorMessage.browserRequired case .userDoesNotHavePassword: - return "User does not have a password" + return MSALNativeAuthErrorMessage.userDoesNotHavePassword case .userNotFound: - return "User not found" + return MSALNativeAuthErrorMessage.userNotFound case .invalidUsername: - return "Invalid username" + return MSALNativeAuthErrorMessage.invalidUsername + case .generalError: + return MSALNativeAuthErrorMessage.generalError } } -} -@objc -public enum ResetPasswordStartErrorType: Int { - case browserRequired - case generalError - case userDoesNotHavePassword - case userNotFound - case invalidUsername + /// Returns `true` if a browser is required to continue the operation. + public var isBrowserRequired: Bool { + return type == .browserRequired + } + + /// Returns `true` if the user does not have a password. + public var isUserDoesNotHavePassword: Bool { + return type == .userDoesNotHavePassword + } + + /// Returns `true` if the user that is trying to reset their password cannot be found. + public var isUserNotFound: Bool { + return type == .userNotFound + } + + /// Returns `true` when the username is not valid. + public var isInvalidUsername: Bool { + return type == .invalidUsername + } } diff --git a/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift b/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift index c0eb0fc3d1..b21de75962 100644 --- a/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift @@ -24,38 +24,52 @@ import Foundation -@objc +@objcMembers public class RetrieveAccessTokenError: MSALNativeAuthError { - /// An error type indicating the type of error that occurred - @objc public let type: RetrieveAccessTokenErrorType + enum ErrorType: CaseIterable { + case browserRequired + case refreshTokenExpired + case tokenNotFound + case generalError + } + + let type: ErrorType - init(type: RetrieveAccessTokenErrorType, message: String? = nil) { + init(type: ErrorType, message: String? = nil) { self.type = type super.init(message: message) } + /// Describes why an error occurred and provides more information about the error. public override var errorDescription: String? { if let description = super.errorDescription { return description } switch type { - case .generalError: - return "General error" + case .browserRequired: + return MSALNativeAuthErrorMessage.browserRequired case .refreshTokenExpired: - return "Refresh token expired" + return MSALNativeAuthErrorMessage.refreshTokenExpired case .tokenNotFound: - return "Token not found" - case .browserRequired: - return "Browser required" + return MSALNativeAuthErrorMessage.tokenNotFound + case .generalError: + return MSALNativeAuthErrorMessage.generalError } } -} -@objc -public enum RetrieveAccessTokenErrorType: Int { - case generalError - case refreshTokenExpired - case tokenNotFound - case browserRequired + /// Returns `true` if a browser is required to continue the operation. + public var isBrowserRequired: Bool { + return type == .browserRequired + } + + /// Returns `true` if the refresh token has expired. + public var isRefreshTokenExpired: Bool { + return type == .refreshTokenExpired + } + + /// Returns `true` if the existing token cannot be found. + public var isTokenNotFound: Bool { + return type == .tokenNotFound + } } diff --git a/MSAL/src/native_auth/public/state_machine/error/SignInAfterSignUpError.swift b/MSAL/src/native_auth/public/state_machine/error/SignInAfterSignUpError.swift index da3eaf13a6..6955f658d7 100644 --- a/MSAL/src/native_auth/public/state_machine/error/SignInAfterSignUpError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/SignInAfterSignUpError.swift @@ -26,11 +26,12 @@ import Foundation @objc public class SignInAfterSignUpError: MSALNativeAuthError { + /// Describes why an error occurred and provides more information about the error. public override var errorDescription: String? { if let description = super.errorDescription { return description } - return "General error" + return MSALNativeAuthErrorMessage.generalError } } diff --git a/MSAL/src/native_auth/public/state_machine/error/SignInPasswordStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignInPasswordStartError.swift index c5d97dea3f..b20baafbd3 100644 --- a/MSAL/src/native_auth/public/state_machine/error/SignInPasswordStartError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/SignInPasswordStartError.swift @@ -24,16 +24,24 @@ import Foundation -@objc +@objcMembers public class SignInPasswordStartError: MSALNativeAuthError { - /// An error type indicating the type of error that occurred - @objc public let type: SignInPasswordStartErrorType + enum ErrorType: CaseIterable { + case browserRequired + case userNotFound + case invalidCredentials + case invalidUsername + case generalError + } + + let type: ErrorType - init(type: SignInPasswordStartErrorType, message: String? = nil) { + init(type: ErrorType, message: String? = nil) { self.type = type super.init(message: message) } + /// Describes why an error occurred and provides more information about the error. public override var errorDescription: String? { if let description = super.errorDescription { return description @@ -41,24 +49,35 @@ public class SignInPasswordStartError: MSALNativeAuthError { switch type { case .browserRequired: - return "Browser required" + return MSALNativeAuthErrorMessage.browserRequired case .userNotFound: - return "User not found" - case .invalidPassword: - return "Invalid password" + return MSALNativeAuthErrorMessage.userNotFound + case .invalidCredentials: + return MSALNativeAuthErrorMessage.invalidCredentials case .invalidUsername: - return "Invalid username" + return MSALNativeAuthErrorMessage.invalidUsername case .generalError: - return "General error" + return MSALNativeAuthErrorMessage.generalError } } -} -@objc -public enum SignInPasswordStartErrorType: Int { - case browserRequired - case userNotFound - case invalidPassword - case invalidUsername - case generalError + /// Returns `true` if a browser is required to continue the operation. + public var isBrowserRequired: Bool { + return type == .browserRequired + } + + /// Returns `true` if the user that is trying to sign in cannot be found. + public var isUserNotFound: Bool { + return type == .userNotFound + } + + /// Returns `true` when the credentials are not valid. + public var isInvalidCredentials: Bool { + return type == .invalidCredentials + } + + /// Returns `true` when the username is not valid. + public var isInvalidUsername: Bool { + return type == .invalidUsername + } } diff --git a/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift index 41b20f02e5..6dcd04fcfe 100644 --- a/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift @@ -24,16 +24,23 @@ import Foundation -@objc +@objcMembers public class SignInStartError: MSALNativeAuthError { - /// An error type indicating the type of error that occurred - @objc public let type: SignInStartErrorType + enum ErrorType: CaseIterable { + case browserRequired + case userNotFound + case invalidUsername + case generalError + } + + let type: ErrorType - init(type: SignInStartErrorType, message: String? = nil) { + init(type: ErrorType, message: String? = nil) { self.type = type super.init(message: message) } + /// Describes why an error occurred and provides more information about the error. public override var errorDescription: String? { if let description = super.errorDescription { return description @@ -41,21 +48,28 @@ public class SignInStartError: MSALNativeAuthError { switch type { case .browserRequired: - return "Browser required" + return MSALNativeAuthErrorMessage.browserRequired case .userNotFound: - return "User not found" + return MSALNativeAuthErrorMessage.userNotFound case .invalidUsername: - return "Invalid username" + return MSALNativeAuthErrorMessage.invalidUsername case .generalError: - return "General error" + return MSALNativeAuthErrorMessage.generalError } } -} -@objc -public enum SignInStartErrorType: Int { - case browserRequired - case userNotFound - case invalidUsername - case generalError + /// Returns `true` if a browser is required to continue the operation. + public var isBrowserRequired: Bool { + return type == .browserRequired + } + + /// Returns `true` if the user that is trying to sign in cannot be found. + public var isUserNotFound: Bool { + return type == .userNotFound + } + + /// Returns `true` when the username is not valid. + public var isInvalidUsername: Bool { + return type == .invalidUsername + } } diff --git a/MSAL/src/native_auth/public/state_machine/error/SignUpPasswordStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignUpPasswordStartError.swift index acaac33130..fd0fac3e02 100644 --- a/MSAL/src/native_auth/public/state_machine/error/SignUpPasswordStartError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/SignUpPasswordStartError.swift @@ -24,16 +24,24 @@ import Foundation -@objc +@objcMembers public class SignUpPasswordStartError: MSALNativeAuthError { - /// An error type indicating the type of error that occurred - @objc public let type: SignUpPasswordStartErrorType + enum ErrorType: CaseIterable { + case browserRequired + case userAlreadyExists + case invalidPassword + case invalidUsername + case generalError + } + + let type: ErrorType - init(type: SignUpPasswordStartErrorType, message: String? = nil) { + init(type: ErrorType, message: String? = nil) { self.type = type super.init(message: message) } + /// Describes why an error occurred and provides more information about the error. public override var errorDescription: String? { if let description = super.errorDescription { return description @@ -41,25 +49,35 @@ public class SignUpPasswordStartError: MSALNativeAuthError { switch type { case .browserRequired: - return "Browser required" + return MSALNativeAuthErrorMessage.browserRequired case .userAlreadyExists: - return "User already exists" + return MSALNativeAuthErrorMessage.userAlreadyExists case .invalidPassword: - return "Invalid password" + return MSALNativeAuthErrorMessage.invalidPassword case .invalidUsername: - return "Invalid username" + return MSALNativeAuthErrorMessage.invalidUsername case .generalError: - return "General error" + return MSALNativeAuthErrorMessage.generalError } } -} + /// Returns `true` if a browser is required to continue the operation. + public var isBrowserRequired: Bool { + return type == .browserRequired + } -@objc -public enum SignUpPasswordStartErrorType: Int { - case browserRequired - case userAlreadyExists - case invalidPassword - case invalidUsername - case generalError + /// Returns `true` when the user is trying to register an existing username. + public var isUserAlreadyExists: Bool { + return type == .userAlreadyExists + } + + /// Returns `true` when the password is not valid. + public var isInvalidPassword: Bool { + return type == .invalidPassword + } + + /// Returns `true` when the username is not valid. + public var isInvalidUsername: Bool { + return type == .invalidUsername + } } diff --git a/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift index 5eb4eb203d..db6add8594 100644 --- a/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift @@ -24,16 +24,23 @@ import Foundation -@objc +@objcMembers public class SignUpStartError: MSALNativeAuthError { - /// An error type indicating the type of error that occurred - @objc public let type: SignUpStartErrorType + enum ErrorType: CaseIterable { + case browserRequired + case userAlreadyExists + case invalidUsername + case generalError + } + + let type: ErrorType - init(type: SignUpStartErrorType, message: String? = nil) { + init(type: ErrorType, message: String? = nil) { self.type = type super.init(message: message) } + /// Describes why an error occurred and provides more information about the error. public override var errorDescription: String? { if let description = super.errorDescription { return description @@ -41,21 +48,28 @@ public class SignUpStartError: MSALNativeAuthError { switch type { case .browserRequired: - return "Browser required" + return MSALNativeAuthErrorMessage.browserRequired case .userAlreadyExists: - return "User already exists" + return MSALNativeAuthErrorMessage.userAlreadyExists case .invalidUsername: - return "Invalid username" + return MSALNativeAuthErrorMessage.invalidUsername case .generalError: - return "General error" + return MSALNativeAuthErrorMessage.generalError } } -} -@objc -public enum SignUpStartErrorType: Int { - case browserRequired - case userAlreadyExists - case invalidUsername - case generalError + /// Returns `true` if a browser is required to continue the operation. + public var isBrowserRequired: Bool { + return type == .browserRequired + } + + /// Returns `true` when the user is trying to register an existing username. + public var isUserAlreadyExists: Bool { + return type == .userAlreadyExists + } + + /// Returns `true` when the username is not valid. + public var isInvalidUsername: Bool { + return type == .invalidUsername + } } diff --git a/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift b/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift index ae44d284b3..ef7b98ce1d 100644 --- a/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift @@ -24,16 +24,22 @@ import Foundation -@objc +@objcMembers public class VerifyCodeError: MSALNativeAuthError { - /// An error type indicating the type of error that occurred - @objc public let type: VerifyCodeErrorType + enum ErrorType: CaseIterable { + case browserRequired + case invalidCode + case generalError + } + + let type: ErrorType - init(type: VerifyCodeErrorType, message: String? = nil) { + init(type: ErrorType, message: String? = nil) { self.type = type super.init(message: message) } + /// Describes why an error occurred and provides more information about the error. public override var errorDescription: String? { if let description = super.errorDescription { return description @@ -41,18 +47,21 @@ public class VerifyCodeError: MSALNativeAuthError { switch type { case .browserRequired: - return "Browser required" - case .generalError: - return "General error" + return MSALNativeAuthErrorMessage.browserRequired case .invalidCode: - return "Invalid code" + return MSALNativeAuthErrorMessage.invalidCode + case .generalError: + return MSALNativeAuthErrorMessage.generalError } } -} -@objc -public enum VerifyCodeErrorType: Int { - case browserRequired - case generalError - case invalidCode + /// Returns `true` if a browser is required to continue the operation. + public var isBrowserRequired: Bool { + return type == .browserRequired + } + + /// Returns `true` when the code introduced is not valid. + public var isInvalidCode: Bool { + return type == .invalidCode + } } diff --git a/MSAL/test/integration/native_auth/common/MSALNativeAuthIntegrationBaseTests.swift b/MSAL/test/integration/native_auth/common/MSALNativeAuthIntegrationBaseTests.swift index 55e8b33469..7d6d394c36 100644 --- a/MSAL/test/integration/native_auth/common/MSALNativeAuthIntegrationBaseTests.swift +++ b/MSAL/test/integration/native_auth/common/MSALNativeAuthIntegrationBaseTests.swift @@ -32,7 +32,7 @@ class MSALNativeAuthIntegrationBaseTests: XCTestCase { let mockAPIHandler = MockAPIHandler() let correlationId = UUID() let config: MSALNativeAuthConfiguration = try! MSALNativeAuthConfiguration(clientId: UUID().uuidString, - authority: MSALCIAMAuthority(url: URL(string: (ProcessInfo.processInfo.environment["mockAPIURL"] ?? "") + "/test")!), + authority: MSALCIAMAuthority(url: URL(string: (ProcessInfo.processInfo.environment["authorityURL"] ?? "") + "/test")!), challengeTypes: [.password, .oob, .redirect]) var sut: MSIDHttpRequest! diff --git a/MSAL/test/integration/native_auth/common/MockAPIHandler.swift b/MSAL/test/integration/native_auth/common/MockAPIHandler.swift index d40301784a..8e107e37b9 100644 --- a/MSAL/test/integration/native_auth/common/MockAPIHandler.swift +++ b/MSAL/test/integration/native_auth/common/MockAPIHandler.swift @@ -26,7 +26,7 @@ import XCTest class MockAPIHandler { - private let baseURL = (ProcessInfo.processInfo.environment["mockAPIURL"] ?? "") + "/config/" + private let baseURL = (ProcessInfo.processInfo.environment["authorityURL"] ?? "") + "/config/" func clearQueues(correlationId: UUID) throws { guard let url = URL(string: baseURL + "all") else { diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUserNameAndPasswordEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUserNameAndPasswordEndToEndTests.swift index a6f531f581..9c9810c445 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUserNameAndPasswordEndToEndTests.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUserNameAndPasswordEndToEndTests.swift @@ -45,7 +45,7 @@ final class MSALNativeAuthSignInUsernameAndPasswordEndToEndTests: MSALNativeAuth await fulfillment(of: [signInExpectation], timeout: 2) XCTAssertTrue(signInDelegateSpy.onSignInPasswordErrorCalled) - XCTAssertEqual(signInDelegateSpy.error?.type, .userNotFound) + XCTAssertTrue(signInDelegateSpy.error!.isUserNotFound) } func test_signInWithKnownUsernameInvalidPasswordResultsInError() async throws { @@ -67,7 +67,7 @@ final class MSALNativeAuthSignInUsernameAndPasswordEndToEndTests: MSALNativeAuth await fulfillment(of: [signInExpectation], timeout: 2) XCTAssertTrue(signInDelegateSpy.onSignInPasswordErrorCalled) - XCTAssertEqual(signInDelegateSpy.error?.type, .invalidPassword) + XCTAssertTrue(signInDelegateSpy.error!.isInvalidCredentials) } // Hero Scenario 2.2.1. Sign in – Email and Password on SINGLE screen (Email & Password) diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUsernameEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUsernameEndToEndTests.swift index d9907dc5f0..3cfe3c5238 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUsernameEndToEndTests.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUsernameEndToEndTests.swift @@ -43,7 +43,7 @@ final class MSALNativeAuthSignInUsernameEndToEndTests: MSALNativeAuthEndToEndBas await fulfillment(of: [signInExpectation], timeout: 2) XCTAssertTrue(signInDelegateSpy.onSignInErrorCalled) - XCTAssertEqual(signInDelegateSpy.error?.type, .userNotFound) + XCTAssertTrue(signInDelegateSpy.error!.isUserNotFound) } func test_signInWithKnownUsernameResultsInOTPSent() async throws { @@ -103,7 +103,7 @@ final class MSALNativeAuthSignInUsernameEndToEndTests: MSALNativeAuthEndToEndBas XCTAssertTrue(signInVerifyCodeDelegateSpy.onSignInVerifyCodeErrorCalled) XCTAssertNotNil(signInVerifyCodeDelegateSpy.error) - XCTAssertEqual(signInVerifyCodeDelegateSpy.error?.type, .invalidCode) + XCTAssertTrue(signInVerifyCodeDelegateSpy.error!.isInvalidCode) } // Hero Scenario 1.2.1. Sign in (Email & Email OTP) @@ -204,7 +204,7 @@ final class MSALNativeAuthSignInUsernameEndToEndTests: MSALNativeAuthEndToEndBas await fulfillment(of: [passwordRequiredExpectation], timeout: 2) XCTAssertTrue(signInPasswordRequiredDelegateSpy.onSignInPasswordRequiredErrorCalled) - XCTAssertEqual(signInPasswordRequiredDelegateSpy.error?.type, .invalidPassword) + XCTAssertTrue(signInPasswordRequiredDelegateSpy.error!.isInvalidPassword) } // Hero Scenario 2.2.2. Sign in – Email and Password on MULTIPLE screens (Email & Password) diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift index 5c900e320a..9579e2e6f7 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift @@ -267,7 +267,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError, message: "Unsupported challenge type"), validatorError: .unsupportedChallengeType(message: "Unsupported challenge type")) await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError, message: "Invalid scope"), validatorError: .invalidScope(message: "Invalid scope")) await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .userNotFound), validatorError: .userNotFound(message: nil)) - await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .invalidPassword), validatorError: .invalidPassword(message: nil)) + await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .invalidCredentials), validatorError: .invalidPassword(message: nil)) } func test_whenCredentialsAreRequired_browserRequiredErrorIsReturned() async { @@ -336,7 +336,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { checkTelemetryEventResult(id: .telemetryApiIdSignInWithPasswordStart, isSuccessful: true) } - func test_whenSignInUsingPassword_apiReturnsChallengeTypeOOB__butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { + func test_whenSignInUsingPassword_apiReturnsChallengeTypeOOB_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { let expectedUsername = "username" let expectedPassword = "password" let expectedSentTo = "sentTo" @@ -455,7 +455,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { signInRequestProviderMock.expectedUsername = expectedUsername signInRequestProviderMock.expectedContext = expectedContext - signInRequestProviderMock.throwingInitError = MSALNativeAuthError() + signInRequestProviderMock.throwingInitError = MSALNativeAuthError(message: nil) let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError)) @@ -483,7 +483,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - signInRequestProviderMock.throwingChallengeError = MSALNativeAuthError() + signInRequestProviderMock.throwingChallengeError = MSALNativeAuthError(message: nil) signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: "credentialToken") let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError)) @@ -615,7 +615,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignInController") - tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError() + tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError(message: nil) signInRequestProviderMock.expectedContext = expectedContext let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: PasswordRequiredError(type: .generalError)) @@ -652,7 +652,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectation = expectation(description: "SignInController") signInRequestProviderMock.expectedContext = expectedContext - tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError() + tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError(message: nil) let state = SignInCodeRequiredState(scopes: [], controller: sut, flowToken: credentialToken, correlationId: defaultUUID) state.submitCode(code: "code", delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedError: VerifyCodeError(type: .generalError))) @@ -711,7 +711,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectation = expectation(description: "SignInController") - signInRequestProviderMock.throwingChallengeError = MSALNativeAuthError() + signInRequestProviderMock.throwingChallengeError = MSALNativeAuthError(message: nil) let helper = SignInResendCodeTestsValidatorHelper(expectation: expectation) @@ -802,7 +802,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignInController") - tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError() + tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError(message: nil) signInRequestProviderMock.expectedContext = expectedContext let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: exp, expectedError: SignInAfterSignUpError()) @@ -852,7 +852,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { // MARK: private methods - private func checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: VerifyCodeErrorType, validatorError: MSALNativeAuthTokenValidatedErrorType) { + private func checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: VerifyCodeError.ErrorType, validatorError: MSALNativeAuthTokenValidatedErrorType) { let expectedCredentialToken = "credentialToken" let expectedOOBCode = "code" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift index e522b067c4..530d22ff92 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift @@ -70,7 +70,7 @@ final class MSALNativeAuthResetPasswordPollCompletionResponseErrorTests: XCTestC // MARK: private methods - private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredErrorType) { + private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) { sut = MSALNativeAuthResetPasswordPollCompletionResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) let error = sut.toPasswordRequiredPublicError() XCTAssertEqual(error.type, expectedErrorType) diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift index b9aa4f1a0f..90f71a71b9 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift @@ -66,7 +66,7 @@ final class MSALNativeAuthResetPasswordSubmitResponseErrorTests: XCTestCase { // MARK: private methods - private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredErrorType) { + private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) { sut = MSALNativeAuthResetPasswordSubmitResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) let error = sut.toPasswordRequiredPublicError() XCTAssertEqual(error.type, expectedErrorType) diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift index f4c2081f3c..47e52167b2 100644 --- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift @@ -104,14 +104,14 @@ final class MSALNativeAuthSignUpChallengeResponseErrorTests: XCTestCase { // MARK: private methods - private func testSignUpChallengeErrorToSignUpPasswordStart(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?, expectedErrorType: SignUpPasswordStartErrorType) { + private func testSignUpChallengeErrorToSignUpPasswordStart(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?, expectedErrorType: SignUpPasswordStartError.ErrorType) { sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil) let error = sut.toSignUpPasswordStartPublicError() XCTAssertEqual(error.type, expectedErrorType) XCTAssertEqual(error.errorDescription, description) } - private func testSignUpChallengeErrorToSignUpStart(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?, expectedErrorType: SignUpStartErrorType) { + private func testSignUpChallengeErrorToSignUpStart(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?, expectedErrorType: SignUpStartError.ErrorType) { sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil) let error = sut.toSignUpStartPublicError() XCTAssertEqual(error.type, expectedErrorType) @@ -124,7 +124,7 @@ final class MSALNativeAuthSignUpChallengeResponseErrorTests: XCTestCase { XCTAssertEqual(error.errorDescription, description) } - private func testSignUpChallengeErrorToPasswordRequired(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredErrorType) { + private func testSignUpChallengeErrorToPasswordRequired(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) { sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil) let error = sut.toPasswordRequiredPublicError() XCTAssertEqual(error.type, expectedErrorType) diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift index db6f5fcfea..3f81cdfcdd 100644 --- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift @@ -218,14 +218,14 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase { // MARK: private methods - private func testSignUpContinueErrorToVerifyCode(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, description: String?, expectedErrorType: VerifyCodeErrorType) { + private func testSignUpContinueErrorToVerifyCode(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, description: String?, expectedErrorType: VerifyCodeError.ErrorType) { sut = MSALNativeAuthSignUpContinueResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, expectedErrorType) XCTAssertEqual(error.errorDescription, description) } - private func testSignUpContinueErrorToPasswordRequired(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredErrorType) { + private func testSignUpContinueErrorToPasswordRequired(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) { sut = MSALNativeAuthSignUpContinueResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) let error = sut.toPasswordRequiredPublicError() XCTAssertEqual(error.type, expectedErrorType) diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift index 5b22aca0dd..1f0be321d8 100644 --- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift @@ -140,14 +140,14 @@ final class MSALNativeAuthSignUpStartResponseErrorTests: XCTestCase { // MARK: private methods - private func testSignUpStartErrorToSignUpStartPassword(code: MSALNativeAuthSignUpStartOauth2ErrorCode, description: String?, expectedErrorType: SignUpPasswordStartErrorType) { + private func testSignUpStartErrorToSignUpStartPassword(code: MSALNativeAuthSignUpStartOauth2ErrorCode, description: String?, expectedErrorType: SignUpPasswordStartError.ErrorType) { sut = MSALNativeAuthSignUpStartResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, unverifiedAttributes: nil, invalidAttributes: nil) let error = sut.toSignUpStartPasswordPublicError() XCTAssertEqual(error.type, expectedErrorType) XCTAssertEqual(error.errorDescription, description) } - private func testSignUpStartErrorToSignUpStart(code: MSALNativeAuthSignUpStartOauth2ErrorCode, description: String?, expectedErrorType: SignUpStartErrorType) { + private func testSignUpStartErrorToSignUpStart(code: MSALNativeAuthSignUpStartOauth2ErrorCode, description: String?, expectedErrorType: SignUpStartError.ErrorType) { sut = MSALNativeAuthSignUpStartResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, unverifiedAttributes: nil, invalidAttributes: nil) let error = sut.toSignUpStartPublicError() XCTAssertEqual(error.type, expectedErrorType) diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift index 33ca8c9fc1..5e41ee28fd 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift @@ -36,7 +36,7 @@ final class MSALNativeAuthSignInInitiateValidatedErrorTypeTests: XCTestCase { func test_convertToSignInStartError_redirect() { let error = sut.redirect.convertToSignInStartError() XCTAssertEqual(error.type, .browserRequired) - XCTAssertEqual(error.errorDescription, "Browser required") + XCTAssertEqual(error.errorDescription, MSALNativeAuthErrorMessage.browserRequired) } func test_convertToSignInStartError_invalidClient() { @@ -74,7 +74,7 @@ final class MSALNativeAuthSignInInitiateValidatedErrorTypeTests: XCTestCase { func test_convertToSignInPasswordStartError_redirect() { let error = sut.redirect.convertToSignInPasswordStartError() XCTAssertEqual(error.type, .browserRequired) - XCTAssertEqual(error.errorDescription, "Browser required") + XCTAssertEqual(error.errorDescription, MSALNativeAuthErrorMessage.browserRequired) } func test_convertToSignInPasswordStartError_invalidClient() { @@ -92,7 +92,7 @@ final class MSALNativeAuthSignInInitiateValidatedErrorTypeTests: XCTestCase { func test_convertToSignInPasswordStartError_invalidServerResponse() { let error = sut.invalidServerResponse.convertToSignInPasswordStartError() XCTAssertEqual(error.type, .generalError) - XCTAssertEqual(error.errorDescription, "General error") + XCTAssertEqual(error.errorDescription, MSALNativeAuthErrorMessage.generalError) } func test_convertToSignInPasswordStartError_userNotFound() { diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift index 61043ced6c..00bec14919 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift @@ -77,7 +77,7 @@ final class MSALNativeAuthTokenValidatedErrorTypeTests: XCTestCase { func test_convertToSignInPasswordStartError_invalidPassword() { let error = sut.invalidPassword(message: testDescription).convertToSignInPasswordStartError() - XCTAssertEqual(error.type, .invalidPassword) + XCTAssertEqual(error.type, .invalidCredentials) XCTAssertEqual(error.errorDescription, testDescription) } diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift index c8149a089c..97a97a6d7f 100644 --- a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift +++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift @@ -290,7 +290,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { func testSignInPassword_delegate_whenInvalidPasswordUsed_shouldReturnCorrectError() { let expectation = expectation(description: "sign-in public interface") - let delegate = SignInPasswordStartDelegateSpy(expectation: expectation, expectedError: .init(type: .invalidPassword)) + let delegate = SignInPasswordStartDelegateSpy(expectation: expectation, expectedError: .init(type: .invalidCredentials)) sut.signInUsingPassword(username: "correct", password: "", delegate: delegate) wait(for: [expectation], timeout: 1) } diff --git a/MSAL/test/unit/native_auth/public/error/AttributesRequiredErrorTests.swift b/MSAL/test/unit/native_auth/public/error/AttributesRequiredErrorTests.swift new file mode 100644 index 0000000000..9a3ec5deee --- /dev/null +++ b/MSAL/test/unit/native_auth/public/error/AttributesRequiredErrorTests.swift @@ -0,0 +1,42 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class AttributesRequiredErrorTests: XCTestCase { + + private var sut: AttributesRequiredError! + + func test_customErrorDescription() { + let expectedMessage = "Custom error message" + sut = .init(message: expectedMessage) + XCTAssertEqual(sut.errorDescription, expectedMessage) + } + + func test_defaultErrorDescription() { + sut = .init() + XCTAssertEqual(sut.errorDescription, MSALNativeAuthErrorMessage.generalError) + } +} diff --git a/MSAL/test/unit/native_auth/public/error/PasswordRequiredErrorTests.swift b/MSAL/test/unit/native_auth/public/error/PasswordRequiredErrorTests.swift new file mode 100644 index 0000000000..780fddeabb --- /dev/null +++ b/MSAL/test/unit/native_auth/public/error/PasswordRequiredErrorTests.swift @@ -0,0 +1,73 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class PasswordRequiredErrorTests: XCTestCase { + + private var sut: PasswordRequiredError! + + func test_totalCases() { + XCTAssertEqual(PasswordRequiredError.ErrorType.allCases.count, 3) + } + + func test_customErrorDescription() { + let expectedMessage = "Custom error message" + sut = .init(type: .generalError, message: expectedMessage) + XCTAssertEqual(sut.errorDescription, expectedMessage) + } + + func test_defaultErrorDescription() { + let sut: [PasswordRequiredError] = [ + .init(type: .browserRequired), + .init(type: .invalidPassword), + .init(type: .generalError) + ] + + let expectedErrorDescriptions = [ + MSALNativeAuthErrorMessage.browserRequired, + MSALNativeAuthErrorMessage.invalidPassword, + MSALNativeAuthErrorMessage.generalError + ] + + let errorDescriptions = sut.map { $0.errorDescription } + + zip(errorDescriptions, expectedErrorDescriptions).forEach { + XCTAssertEqual($0, $1) + } + } + + func test_isBrowserRequired() { + sut = .init(type: .browserRequired) + XCTAssertTrue(sut.isBrowserRequired) + XCTAssertFalse(sut.isInvalidPassword) + } + + func test_isInvalidPassword() { + sut = .init(type: .invalidPassword) + XCTAssertTrue(sut.isInvalidPassword) + XCTAssertFalse(sut.isBrowserRequired) + } +} diff --git a/MSAL/test/unit/native_auth/public/error/ResendCodeErrorTests.swift b/MSAL/test/unit/native_auth/public/error/ResendCodeErrorTests.swift new file mode 100644 index 0000000000..7dc8ae6709 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/error/ResendCodeErrorTests.swift @@ -0,0 +1,42 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class ResendCodeErrorTests: XCTestCase { + + private var sut: ResendCodeError! + + func test_customErrorDescription() { + let expectedMessage = "Custom error message" + sut = .init(message: expectedMessage) + XCTAssertEqual(sut.errorDescription, expectedMessage) + } + + func test_defaultErrorDescription() { + sut = .init() + XCTAssertEqual(sut.errorDescription, MSALNativeAuthErrorMessage.generalError) + } +} diff --git a/MSAL/test/unit/native_auth/public/error/ResetPasswordStartErrorTests.swift b/MSAL/test/unit/native_auth/public/error/ResetPasswordStartErrorTests.swift new file mode 100644 index 0000000000..7e6abcb651 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/error/ResetPasswordStartErrorTests.swift @@ -0,0 +1,97 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class ResetPasswordStartErrorTests: XCTestCase { + + private var sut: ResetPasswordStartError! + + func test_totalCases() { + XCTAssertEqual(ResetPasswordStartError.ErrorType.allCases.count, 5) + } + + func test_customErrorDescription() { + let expectedMessage = "Custom error message" + sut = .init(type: .generalError, message: expectedMessage) + XCTAssertEqual(sut.errorDescription, expectedMessage) + } + + func test_defaultErrorDescription() { + let sut: [ResetPasswordStartError] = [ + .init(type: .browserRequired), + .init(type: .userDoesNotHavePassword), + .init(type: .userNotFound), + .init(type: .invalidUsername), + .init(type: .generalError) + ] + + let expectedIdentifiers = [ + MSALNativeAuthErrorMessage.browserRequired, + MSALNativeAuthErrorMessage.userDoesNotHavePassword, + MSALNativeAuthErrorMessage.userNotFound, + MSALNativeAuthErrorMessage.invalidUsername, + MSALNativeAuthErrorMessage.generalError + ] + + let errorDescriptions = sut.map { $0.errorDescription } + + zip(errorDescriptions, expectedIdentifiers).forEach { + XCTAssertEqual($0, $1) + } + } + + func test_isBrowserRequired() { + sut = .init(type: .browserRequired) + XCTAssertTrue(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserDoesNotHavePassword) + XCTAssertFalse(sut.isUserNotFound) + XCTAssertFalse(sut.isInvalidUsername) + } + + func test_isUserDoesNotHaveAPassword() { + sut = .init(type: .userDoesNotHavePassword) + XCTAssertTrue(sut.isUserDoesNotHavePassword) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserNotFound) + XCTAssertFalse(sut.isInvalidUsername) + } + + func test_isUserNotFound() { + sut = .init(type: .userNotFound) + XCTAssertTrue(sut.isUserNotFound) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserDoesNotHavePassword) + XCTAssertFalse(sut.isInvalidUsername) + } + + func test_isInvalidUsername() { + sut = .init(type: .invalidUsername) + XCTAssertTrue(sut.isInvalidUsername) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserDoesNotHavePassword) + XCTAssertFalse(sut.isUserNotFound) + } +} diff --git a/MSAL/test/unit/native_auth/public/error/RetrieveAccessTokenErrorTests.swift b/MSAL/test/unit/native_auth/public/error/RetrieveAccessTokenErrorTests.swift new file mode 100644 index 0000000000..46e0808fb1 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/error/RetrieveAccessTokenErrorTests.swift @@ -0,0 +1,84 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class RetrieveAccessTokenErrorTests: XCTestCase { + + private var sut: RetrieveAccessTokenError! + + func test_totalCases() { + XCTAssertEqual(RetrieveAccessTokenError.ErrorType.allCases.count, 4) + } + + func test_customErrorDescription() { + let expectedMessage = "Custom error message" + sut = .init(type: .generalError, message: expectedMessage) + XCTAssertEqual(sut.errorDescription, expectedMessage) + } + + func test_defaultErrorDescription() { + let sut: [RetrieveAccessTokenError] = [ + .init(type: .browserRequired), + .init(type: .refreshTokenExpired), + .init(type: .tokenNotFound), + .init(type: .generalError) + ] + + let expectedIdentifiers = [ + MSALNativeAuthErrorMessage.browserRequired, + MSALNativeAuthErrorMessage.refreshTokenExpired, + MSALNativeAuthErrorMessage.tokenNotFound, + MSALNativeAuthErrorMessage.generalError + ] + + let errorDescriptions = sut.map { $0.errorDescription } + + zip(errorDescriptions, expectedIdentifiers).forEach { + XCTAssertEqual($0, $1) + } + } + + func test_isBrowserRequired() { + sut = .init(type: .browserRequired) + XCTAssertTrue(sut.isBrowserRequired) + XCTAssertFalse(sut.isRefreshTokenExpired) + XCTAssertFalse(sut.isTokenNotFound) + } + + func test_isRefreshTokenExpired() { + sut = .init(type: .refreshTokenExpired) + XCTAssertTrue(sut.isRefreshTokenExpired) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isTokenNotFound) + } + + func test_isTokenNotFound() { + sut = .init(type: .tokenNotFound) + XCTAssertTrue(sut.isTokenNotFound) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isRefreshTokenExpired) + } +} diff --git a/MSAL/test/unit/native_auth/public/error/SignInAfterSignUpErrorTests.swift b/MSAL/test/unit/native_auth/public/error/SignInAfterSignUpErrorTests.swift new file mode 100644 index 0000000000..96932cbba1 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/error/SignInAfterSignUpErrorTests.swift @@ -0,0 +1,42 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class SignInAfterSignUpErrorTests: XCTestCase { + + private var sut: SignInAfterSignUpError! + + func test_customErrorDescription() { + let expectedMessage = "Custom error message" + sut = .init(message: expectedMessage) + XCTAssertEqual(sut.errorDescription, expectedMessage) + } + + func test_defaultErrorDescription() { + sut = .init() + XCTAssertEqual(sut.errorDescription, MSALNativeAuthErrorMessage.generalError) + } +} diff --git a/MSAL/test/unit/native_auth/public/error/SignInPasswordStartErrorTests.swift b/MSAL/test/unit/native_auth/public/error/SignInPasswordStartErrorTests.swift new file mode 100644 index 0000000000..0c3d0d6f32 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/error/SignInPasswordStartErrorTests.swift @@ -0,0 +1,97 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class SignInPasswordStartErrorTests: XCTestCase { + + private var sut: SignInPasswordStartError! + + func test_totalCases() { + XCTAssertEqual(SignInPasswordStartError.ErrorType.allCases.count, 5) + } + + func test_customErrorDescription() { + let expectedMessage = "Custom error message" + sut = .init(type: .generalError, message: expectedMessage) + XCTAssertEqual(sut.errorDescription, expectedMessage) + } + + func test_defaultErrorDescription() { + let sut: [SignInPasswordStartError] = [ + .init(type: .browserRequired), + .init(type: .userNotFound), + .init(type: .invalidCredentials), + .init(type: .invalidUsername), + .init(type: .generalError) + ] + + let expectedDescriptions = [ + MSALNativeAuthErrorMessage.browserRequired, + MSALNativeAuthErrorMessage.userNotFound, + MSALNativeAuthErrorMessage.invalidCredentials, + MSALNativeAuthErrorMessage.invalidUsername, + MSALNativeAuthErrorMessage.generalError + ] + + let errorDescriptions = sut.map { $0.errorDescription } + + zip(errorDescriptions, expectedDescriptions).forEach { + XCTAssertEqual($0, $1) + } + } + + func test_isBrowserRequired() { + sut = .init(type: .browserRequired) + XCTAssertTrue(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserNotFound) + XCTAssertFalse(sut.isInvalidCredentials) + XCTAssertFalse(sut.isInvalidUsername) + } + + func test_isUserNotFound() { + sut = .init(type: .userNotFound) + XCTAssertTrue(sut.isUserNotFound) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isInvalidCredentials) + XCTAssertFalse(sut.isInvalidUsername) + } + + func test_isInvalidPassword() { + sut = .init(type: .invalidCredentials) + XCTAssertTrue(sut.isInvalidCredentials) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserNotFound) + XCTAssertFalse(sut.isInvalidUsername) + } + + func test_isInvalidUsername() { + sut = .init(type: .invalidUsername) + XCTAssertTrue(sut.isInvalidUsername) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserNotFound) + XCTAssertFalse(sut.isInvalidCredentials) + } +} diff --git a/MSAL/test/unit/native_auth/public/error/SignInStartErrorTests.swift b/MSAL/test/unit/native_auth/public/error/SignInStartErrorTests.swift new file mode 100644 index 0000000000..3309c8bb6b --- /dev/null +++ b/MSAL/test/unit/native_auth/public/error/SignInStartErrorTests.swift @@ -0,0 +1,84 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class SignInStartErrorTests: XCTestCase { + private var sut: SignInStartError! + + func test_totalCases() { + XCTAssertEqual(SignInStartError.ErrorType.allCases.count, 4) + } + + func test_customErrorDescription() { + let expectedMessage = "Custom error message" + sut = .init(type: .generalError, message: expectedMessage) + XCTAssertEqual(sut.errorDescription, expectedMessage) + } + + func test_defaultErrorDescription() { + let sut: [SignInStartError] = [ + .init(type: .browserRequired), + .init(type: .userNotFound), + .init(type: .invalidUsername), + .init(type: .generalError) + ] + + let expectedDescriptions = [ + MSALNativeAuthErrorMessage.browserRequired, + MSALNativeAuthErrorMessage.userNotFound, + MSALNativeAuthErrorMessage.invalidUsername, + MSALNativeAuthErrorMessage.generalError + ] + + let errorDescriptions = sut.map { $0.errorDescription } + + zip(errorDescriptions, expectedDescriptions).forEach { + XCTAssertEqual($0, $1) + } + } + + + func test_isBrowserRequired() { + sut = .init(type: .browserRequired) + XCTAssertTrue(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserNotFound) + XCTAssertFalse(sut.isInvalidUsername) + } + + func test_isUserNotFound() { + sut = .init(type: .userNotFound) + XCTAssertTrue(sut.isUserNotFound) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isInvalidUsername) + } + + func test_isInvalidUsername() { + sut = .init(type: .invalidUsername) + XCTAssertTrue(sut.isInvalidUsername) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserNotFound) + } +} diff --git a/MSAL/test/unit/native_auth/public/error/SignUpPasswordStartErrorTests.swift b/MSAL/test/unit/native_auth/public/error/SignUpPasswordStartErrorTests.swift new file mode 100644 index 0000000000..5215e34a28 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/error/SignUpPasswordStartErrorTests.swift @@ -0,0 +1,97 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class SignUpPasswordStartErrorTests: XCTestCase { + + private var sut: SignUpPasswordStartError! + + func test_totalCases() { + XCTAssertEqual(SignUpPasswordStartError.ErrorType.allCases.count, 5) + } + + func test_customErrorDescription() { + let expectedMessage = "Custom error message" + sut = .init(type: .generalError, message: expectedMessage) + XCTAssertEqual(sut.errorDescription, expectedMessage) + } + + func test_defaultErrorDescription() { + let sut: [SignUpPasswordStartError] = [ + .init(type: .browserRequired), + .init(type: .userAlreadyExists), + .init(type: .invalidPassword), + .init(type: .invalidUsername), + .init(type: .generalError) + ] + + let expectedDescriptions = [ + MSALNativeAuthErrorMessage.browserRequired, + MSALNativeAuthErrorMessage.userAlreadyExists, + MSALNativeAuthErrorMessage.invalidPassword, + MSALNativeAuthErrorMessage.invalidUsername, + MSALNativeAuthErrorMessage.generalError + ] + + let errorDescriptions = sut.map { $0.errorDescription } + + zip(errorDescriptions, expectedDescriptions).forEach { + XCTAssertEqual($0, $1) + } + } + + func test_isBrowserRequired() { + sut = .init(type: .browserRequired) + XCTAssertTrue(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserAlreadyExists) + XCTAssertFalse(sut.isInvalidPassword) + XCTAssertFalse(sut.isInvalidUsername) + } + + func test_isUserAlreadyExists() { + sut = .init(type: .userAlreadyExists) + XCTAssertTrue(sut.isUserAlreadyExists) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isInvalidPassword) + XCTAssertFalse(sut.isInvalidUsername) + } + + func test_isInvalidPassword() { + sut = .init(type: .invalidPassword) + XCTAssertTrue(sut.isInvalidPassword) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserAlreadyExists) + XCTAssertFalse(sut.isInvalidUsername) + } + + func test_isInvalidUsername() { + sut = .init(type: .invalidUsername) + XCTAssertTrue(sut.isInvalidUsername) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserAlreadyExists) + XCTAssertFalse(sut.isInvalidPassword) + } +} diff --git a/MSAL/test/unit/native_auth/public/error/SignUpStartErrorTests.swift b/MSAL/test/unit/native_auth/public/error/SignUpStartErrorTests.swift new file mode 100644 index 0000000000..7f94007f27 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/error/SignUpStartErrorTests.swift @@ -0,0 +1,84 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class SignUpStartErrorTests: XCTestCase { + + private var sut: SignUpStartError! + + func test_totalCases() { + XCTAssertEqual(SignUpStartError.ErrorType.allCases.count, 4) + } + + func test_customErrorDescription() { + let expectedMessage = "Custom error message" + sut = .init(type: .generalError, message: expectedMessage) + XCTAssertEqual(sut.errorDescription, expectedMessage) + } + + func test_defaultErrorDescription() { + let sut: [SignUpPasswordStartError] = [ + .init(type: .browserRequired), + .init(type: .userAlreadyExists), + .init(type: .invalidUsername), + .init(type: .generalError) + ] + + let expectedDescriptions = [ + MSALNativeAuthErrorMessage.browserRequired, + MSALNativeAuthErrorMessage.userAlreadyExists, + MSALNativeAuthErrorMessage.invalidUsername, + MSALNativeAuthErrorMessage.generalError + ] + + let errorDescriptions = sut.map { $0.errorDescription } + + zip(errorDescriptions, expectedDescriptions).forEach { + XCTAssertEqual($0, $1) + } + } + + func test_isBrowserRequired() { + sut = .init(type: .browserRequired) + XCTAssertTrue(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserAlreadyExists) + XCTAssertFalse(sut.isInvalidUsername) + } + + func test_isUserAlreadyExists() { + sut = .init(type: .userAlreadyExists) + XCTAssertTrue(sut.isUserAlreadyExists) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isInvalidUsername) + } + + func test_isInvalidUsername() { + sut = .init(type: .invalidUsername) + XCTAssertTrue(sut.isInvalidUsername) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserAlreadyExists) + } +} diff --git a/MSAL/test/unit/native_auth/public/error/VerifyCodeErrorTests.swift b/MSAL/test/unit/native_auth/public/error/VerifyCodeErrorTests.swift new file mode 100644 index 0000000000..c45b9eb1c9 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/error/VerifyCodeErrorTests.swift @@ -0,0 +1,73 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class VerifyCodeErrorTests: XCTestCase { + + private var sut: VerifyCodeError! + + func test_totalCases() { + XCTAssertEqual(VerifyCodeError.ErrorType.allCases.count, 3) + } + + func test_customErrorDescription() { + let expectedMessage = "Custom error message" + sut = .init(type: .generalError, message: expectedMessage) + XCTAssertEqual(sut.errorDescription, expectedMessage) + } + + func test_defaultErrorDescription() { + let sut: [VerifyCodeError] = [ + .init(type: .browserRequired), + .init(type: .invalidCode), + .init(type: .generalError) + ] + + let expectedDescriptions = [ + MSALNativeAuthErrorMessage.browserRequired, + MSALNativeAuthErrorMessage.invalidCode, + MSALNativeAuthErrorMessage.generalError + ] + + let errorDescriptions = sut.map { $0.errorDescription } + + zip(errorDescriptions, expectedDescriptions).forEach { + XCTAssertEqual($0, $1) + } + } + + func test_isBrowserRequired() { + sut = .init(type: .browserRequired) + XCTAssertTrue(sut.isBrowserRequired) + XCTAssertFalse(sut.isInvalidCode) + } + + func test_isInvalidCode() { + sut = .init(type: .invalidCode) + XCTAssertTrue(sut.isInvalidCode) + XCTAssertFalse(sut.isBrowserRequired) + } +} From b96c2d04277e6c84beb869edbd38b9e7a47fa2b2 Mon Sep 17 00:00:00 2001 From: Danilo Raspa <105228698+nilo-ms@users.noreply.github.com> Date: Thu, 14 Dec 2023 11:47:10 +0000 Subject: [PATCH 20/84] Don't send empty attribute list in SignUp/start (#1940) * do not create an empty list of attributes when no attributes are available * check that request parameter is not nil * fix unit tests after dev merge --- .../MSALNativeAuthSignUpRequestProvider.swift | 16 +++---- ...SignUpStartRequestProviderParameters.swift | 2 +- ...AuthPublicClientApplication+Internal.swift | 4 +- .../MSALNativeAuthSignUpControllerMock.swift | 3 ++ ...LNativeAuthSignUpRequestProviderMock.swift | 3 +- ...NativeAuthSignUpRequestProviderTests.swift | 47 +++++++++++++++++-- ...ativeAuthPublicClientApplicationTest.swift | 40 ++++++++++++++++ 7 files changed, 100 insertions(+), 15 deletions(-) diff --git a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift index 7db181cbab..3517fab078 100644 --- a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift +++ b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift @@ -42,14 +42,11 @@ final class MSALNativeAuthSignUpRequestProvider: MSALNativeAuthSignUpRequestProv } func start(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) throws -> MSIDHttpRequest { - guard let attributes = try formatAttributes(parameters.attributes) else { - throw MSALNativeAuthInternalError.invalidAttributes - } - + let formattedAttributes = try formatAttributes(parameters.attributes) let params = MSALNativeAuthSignUpStartRequestParameters( username: parameters.username, password: parameters.password, - attributes: attributes, + attributes: formattedAttributes, context: parameters.context ) @@ -74,14 +71,14 @@ final class MSALNativeAuthSignUpRequestProvider: MSALNativeAuthSignUpRequestProv } func `continue`(parameters: MSALNativeAuthSignUpContinueRequestProviderParams) throws -> MSIDHttpRequest { - let attributesFormatted = try parameters.attributes.map { try formatAttributes($0) } ?? nil + let formattedAttributes = try formatAttributes(parameters.attributes) let params = MSALNativeAuthSignUpContinueRequestParameters( grantType: parameters.grantType, signUpToken: parameters.signUpToken, password: parameters.password, oobCode: parameters.oobCode, - attributes: attributesFormatted, + attributes: formattedAttributes, context: parameters.context ) @@ -92,7 +89,10 @@ final class MSALNativeAuthSignUpRequestProvider: MSALNativeAuthSignUpRequestProv return request } - private func formatAttributes(_ attributes: [String: Any]) throws -> String? { + private func formatAttributes(_ attributes: [String: Any]?) throws -> String? { + guard let attributes = attributes else { + return nil + } guard JSONSerialization.isValidJSONObject(attributes) else { throw MSALNativeAuthInternalError.invalidAttributes } diff --git a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpStartRequestProviderParameters.swift b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpStartRequestProviderParameters.swift index 74a37d0f95..1e72760f4d 100644 --- a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpStartRequestProviderParameters.swift +++ b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpStartRequestProviderParameters.swift @@ -25,6 +25,6 @@ struct MSALNativeAuthSignUpStartRequestProviderParameters { let username: String let password: String? - let attributes: [String: Any] + let attributes: [String: Any]? let context: MSALNativeAuthRequestContext } diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift index 81ff9b84a9..a9ded0b385 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift @@ -45,7 +45,7 @@ extension MSALNativeAuthPublicClientApplication { let parameters = MSALNativeAuthSignUpStartRequestProviderParameters( username: username, password: password, - attributes: attributes ?? [:], + attributes: attributes, context: context ) @@ -67,7 +67,7 @@ extension MSALNativeAuthPublicClientApplication { let parameters = MSALNativeAuthSignUpStartRequestProviderParameters( username: username, password: nil, - attributes: attributes ?? [:], + attributes: attributes, context: context ) diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift index c5237a0e2f..0710595c6f 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift @@ -33,13 +33,16 @@ class MSALNativeAuthSignUpControllerMock: MSALNativeAuthSignUpControlling { var resendCodeResult: SignUpResendCodeControllerResponse! var submitCodeResult: MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse! var submitPasswordResult: MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse! + var signUpStartRequestParameters: MSALNativeAuthSignUpStartRequestProviderParameters? var submitAttributesResult: SignUpSubmitAttributesControllerResponse! func signUpStartPassword(parameters: MSAL.MSALNativeAuthSignUpStartRequestProviderParameters) async -> MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse { + signUpStartRequestParameters = parameters return startPasswordResult } func signUpStartCode(parameters: MSAL.MSALNativeAuthSignUpStartRequestProviderParameters) async -> MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse { + signUpStartRequestParameters = parameters return startResult } diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift index 0498377e2d..23992d63a9 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift @@ -62,7 +62,8 @@ class MSALNativeAuthSignUpRequestProviderMock: MSALNativeAuthSignUpRequestProvid XCTAssertEqual(params.username, expectedStartRequestParameters.username) XCTAssertEqual(params.password, expectedStartRequestParameters.password) XCTAssertEqual(params.context.correlationId(), expectedStartRequestParameters.context.correlationId()) - XCTAssertEqual(params.attributes["key"] as? String, expectedStartRequestParameters.attributes["key"] as? String) + XCTAssertNotNil(params.attributes) + XCTAssertEqual(params.attributes?["key"] as? String, expectedStartRequestParameters.attributes?["key"] as? String) } func mockChallengeRequestFunc(_ request: MSIDHttpRequest?, throwError: Bool = false) { diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift index eff40e49c0..b20a7de987 100644 --- a/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift @@ -58,6 +58,23 @@ final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase { checkServerTelemetry(request.serverTelemetry, expectedTelemetryResult: expectedTelemetryResult) } + func test_signUpStartRequestWithNoAttributes_is_created_successfully() throws { + let parameters = MSALNativeAuthSignUpStartRequestProviderParameters( + username: DEFAULT_TEST_ID_TOKEN_USERNAME, + password: "1234", + attributes: nil, + context: MSALNativeAuthRequestContext(correlationId: context.correlationId()) + ) + + let request = try sut.start(parameters: parameters) + + checkBodyParams(request.parameters, for: .signUpStart, expectAttributes: false) + checkUrlRequest(request.urlRequest!, for: .signUpStart) + + let expectedTelemetryResult = telemetryProvider.telemetryForSignUp(type: .signUpStart).telemetryString() + checkServerTelemetry(request.serverTelemetry, expectedTelemetryResult: expectedTelemetryResult) + } + func test_signUpStartRequestWithInvalidAttributes_throwAnError() throws { let parameters = MSALNativeAuthSignUpStartRequestProviderParameters( username: DEFAULT_TEST_ID_TOKEN_USERNAME, @@ -85,7 +102,7 @@ final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase { signUpToken: "sign-up-token", password: "1234", oobCode: nil, - attributes: nil, + attributes: ["city": "dublin"], context: context ) @@ -98,6 +115,25 @@ final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase { checkServerTelemetry(request.serverTelemetry, expectedTelemetryResult: expectedTelemetryResult) } + func test_signUpContinueRequestWithNoAttributes_is_created_successfully() throws { + let parameters = MSALNativeAuthSignUpContinueRequestProviderParams( + grantType: .password, + signUpToken: "sign-up-token", + password: "1234", + oobCode: nil, + attributes: nil, + context: context + ) + + let request = try sut.continue(parameters: parameters) + + checkBodyParams(request.parameters, for: .signUpContinue, expectAttributes: false) + checkUrlRequest(request.urlRequest!, for: .signUpContinue) + + let expectedTelemetryResult = telemetryProvider.telemetryForSignUp(type: .signUpContinue).telemetryString() + checkServerTelemetry(request.serverTelemetry, expectedTelemetryResult: expectedTelemetryResult) + } + func test_signUpContinueRequestWithInvalidAttributes_throwAnError() throws { let parameters = MSALNativeAuthSignUpContinueRequestProviderParams( grantType: .password, @@ -111,7 +147,7 @@ final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase { XCTAssertThrowsError(try sut.continue(parameters: parameters)) } - private func checkBodyParams(_ bodyParams: [String: String]?, for endpoint: MSALNativeAuthEndpoint) { + private func checkBodyParams(_ bodyParams: [String: String]?, for endpoint: MSALNativeAuthEndpoint, expectAttributes: Bool = true) { typealias Key = MSALNativeAuthRequestParametersKey var expectedBodyParams: [String: String]! @@ -122,9 +158,11 @@ final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase { Key.clientId.rawValue: DEFAULT_TEST_CLIENT_ID, Key.username.rawValue: DEFAULT_TEST_ID_TOKEN_USERNAME, Key.challengeType.rawValue: "redirect", - Key.attributes.rawValue: "{\"city\":\"dublin\"}", Key.password.rawValue: "1234" ] + if expectAttributes { + expectedBodyParams[Key.attributes.rawValue] = "{\"city\":\"dublin\"}" + } case .signUpChallenge: expectedBodyParams = [ Key.clientId.rawValue: DEFAULT_TEST_CLIENT_ID, @@ -138,6 +176,9 @@ final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase { Key.signUpToken.rawValue: "sign-up-token", Key.password.rawValue: "1234" ] + if expectAttributes { + expectedBodyParams[Key.attributes.rawValue] = "{\"city\":\"dublin\"}" + } default: XCTFail("Case not tested") } diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift index 97a97a6d7f..002736f8e5 100644 --- a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift +++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift @@ -111,6 +111,26 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { XCTAssertEqual(delegate.channelTargetType, .email) XCTAssertEqual(delegate.codeLength, 1) } + + func testSignUpPassword_whenNoAttributesAreSpecified_AttributesShouldBeNil() { + let exp = expectation(description: "sign-up public interface") + let delegate = SignUpPasswordStartDelegateSpy(expectation: exp) + + let expectedResult: SignUpPasswordStartResult = .codeRequired( + newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: UUID()), + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult) + + sut.signUpUsingPassword(username: "correct", password: "correct", delegate: delegate) + + wait(for: [exp]) + + XCTAssertNil(controllerFactoryMock.signUpController.signUpStartRequestParameters?.attributes) + XCTAssertNotNil(controllerFactoryMock.signUpController.signUpStartRequestParameters) + } func testSignUpPassword_delegate_butDelegateMethodIsNotImplemented_shouldReturnError() { let exp = expectation(description: "sign-up public interface") @@ -212,6 +232,26 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { XCTAssertEqual(delegate.channelTargetType, .email) XCTAssertEqual(delegate.codeLength, 1) } + + func testSignUp_whenNoAttributesAreSpecified_AttributesShouldBeNil() { + let exp = expectation(description: "sign-up public interface") + let delegate = SignUpCodeStartDelegateSpy(expectation: exp) + + let expectedResult: SignUpStartResult = .codeRequired( + newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: UUID()), + sentTo: "sentTo", + channelTargetType: .email, + codeLength: 1 + ) + controllerFactoryMock.signUpController.startResult = .init(expectedResult) + + sut.signUp(username: "correct", delegate: delegate) + + wait(for: [exp]) + + XCTAssertNil(controllerFactoryMock.signUpController.signUpStartRequestParameters?.attributes) + XCTAssertNotNil(controllerFactoryMock.signUpController.signUpStartRequestParameters) + } func testSignUp_delegate_butDelegateMethodIsNotImplemented_shouldReturnError() { let exp = expectation(description: "sign-up public interface") From 9b9541de2ebbe54513b6a82de6224552abfa1032 Mon Sep 17 00:00:00 2001 From: Diego Jerez Barroso <109726904+diegojerezba@users.noreply.github.com> Date: Thu, 14 Dec 2023 13:27:40 +0000 Subject: [PATCH 21/84] Add SignInAfterResetPassword (#1932) * - Added correlationId to MSALNativeAuthBaseState - Removed correlationId from state actions - Adjusted tests accordingly - Removed correlation id from `SignInAfterSignUpState` action method - Fixed SwiftLint warnings - Tidy up Unit tests for correlation ids Renamed MSALNativeAuthControllerFactoryRequestProviderMock to MSALNativeAuthControllerRequestProviderFactoryMock PR comments Made prepareMockRequest more flexible Renamed MSALNativeAuthControllerRequestProviderFactoryMock to MSALNativeAuthControllerProtocolFactoryMock PR Comments Clarified where parameters are checked internally PR comment about signInRequestProviderMock.expectedContext = contextMock Updated end to end tests to not use correlation id's Update submodule Update submodule Update submodule New error message when device is not PSSO registered. Hotfix 1.2.19 (#1909) * Update release config * point to latest main from cc --------- Co-authored-by: Yong Zeng Updating MSAL framework checksum & url for 1.2.19 [skip ci] Merge release 1220 into dev (#1934) * Release MSAL 1.2.20 (#1930) * Update submodule * Update submodule * Get token operation for BrowserCore (#1862) * Update core. * Update msal. * Update core. * update core. * Update core. * Update core. * Update core. * Update core. * Update core. * Update core. * Update submodule * Updated submodule * Updated submodule * Update submodule * update submodule for current key change * New error message when device is not PSSO registered. * Release MSAL 1.2.20 * Align with latest main (#1933) --------- Co-authored-by: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Co-authored-by: Sergei Demchenko Co-authored-by: Swasti Gupta Co-authored-by: Swasti Gupta Co-authored-by: Juan Arias Co-authored-by: Kai * Updating MSAL framework checksum & url for 1.2.20 [skip ci] * Update CommonCore to latest dev --------- Co-authored-by: Veena Soman Co-authored-by: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Co-authored-by: Sergei Demchenko Co-authored-by: Swasti Gupta Co-authored-by: Swasti Gupta Co-authored-by: Juan Arias - Changed submodule * Add optional delegates everywhere (keep delegates that return errors as mandatory). Add DelegateDispatchers to handle optional delegate methods PR code review Add newState parameter to onSignUpResendCodeError Add comments to clarify why the telemetry event always fails Remove comments because this class will remain internal PR comments Rename error methods in SignUpPasswordStartDelegate, SignUpStartDelegate, SignInPasswordStartDelegate, SignInStartDelegate and ResetPasswordStartDelegate. Fix inline doc Updated end to end tests to not use correlation id's Updated End To End tests to use latest delegates * Make errors extensible Fix broken tests. Add tests for public errors PR code review Change the `identifier` variable from String to Int. This allows us to enable the public ErrorType enums for objc developers. Rename SignInPasswordStartError's invalidPassword to invalidCredentials Fix failing test. Update inline documentation for isBrowserRequired error Remove error.identifier from public interface. Update inline doc to use "username" instead of "email". Fixed integration tests Renamed MockAPIURL env variable to authorityURL to work with the test case * Add SignInAfterResetPassword rename slt to continuation token for reset password poll complete, fix swiftlint warning update submodules --------- Co-authored-by: Marcos Borges Co-authored-by: Danilo Raspa --- MSAL/MSAL.xcodeproj/project.pbxproj | 87 ++++++++++++-- ...SALNativeAuthResetPasswordController.swift | 100 +++++++++++++--- ...ALNativeAuthResetPasswordControlling.swift | 10 +- .../responses/ResetPasswordResults.swift | 2 +- .../MSALNativeAuthSignInController.swift | 6 +- .../MSALNativeAuthSignInControlling.swift | 6 +- .../MSALNativeAuthSignUpController.swift | 9 +- ...hResetPasswordPollCompletionResponse.swift | 2 +- ...NativeAuthResetPasswordStartResponse.swift | 5 - ...veAuthResetPasswordResponseValidator.swift | 3 +- ...eAuthResetPasswordValidatedResponses.swift | 3 +- .../delegate/ResetPasswordDelegates.swift | 3 +- .../SignInAfterResetPasswordDelegate.swift | 37 ++++++ .../ResetPasswordDelegateDispatchers.swift | 4 +- ...AfterResetPasswordDelegateDispatcher.swift | 39 ++++++ .../error/SignInAfterResetPasswordError.swift | 37 ++++++ .../state/ResetPasswordStates+Internal.swift | 6 +- .../state/ResetPasswordStates.swift | 7 +- ...AfterPreviousFlowBaseState+Internal.swift} | 4 +- .../SignInAfterPreviousFlowBaseState.swift | 39 ++++++ .../state/SignInAfterResetPasswordState.swift | 49 ++++++++ .../state/SignInAfterSignUpState.swift | 22 +--- ...NativeAuthResetPasswordEndToEndTests.swift | 65 ++++++++++ .../ResetPasswordDelegateSpies.swift | 31 ++++- ...sswordPollCompletionIntegrationTests.swift | 8 +- ...tiveAuthResetPasswordControllerTests.swift | 104 +++++++++++----- ...ativeAuthResetPasswordControllerMock.swift | 6 +- .../MSALNativeAuthSignInControllerMock.swift | 4 +- .../mock/ResetPasswordDelegateSpies.swift | 21 +++- .../ResetPasswordTestValidatorHelpers.swift | 4 +- .../mock/SignInDelegatesSpies.swift | 32 +++++ ...NativeAuthResetPasswordControllerSpy.swift | 10 +- ...hResetPasswordResponseValidatorTests.swift | 5 +- ...ativeAuthPublicClientApplicationTest.swift | 111 ++++++++++-------- ...swordRequiredDelegateDispatcherTests.swift | 21 +++- ...ordResendCodeDelegateDispatcherTests.swift | 4 +- ...PasswordStartDelegateDispatcherTests.swift | 4 +- ...ordVerifyCodeDelegateDispatcherTests.swift | 4 +- ...ResetPasswordDelegateDispatcherTests.swift | 81 +++++++++++++ ...InAfterSignUpDelegateDispatcherTests.swift | 82 +++++++++++++ .../SignInAfterResetPasswordErrorTests.swift | 42 +++++++ .../ResetPasswordCodeSentStateTests.swift | 14 +-- .../ResetPasswordRequiredStateTests.swift | 19 +-- 43 files changed, 959 insertions(+), 193 deletions(-) create mode 100644 MSAL/src/native_auth/public/state_machine/delegate/SignInAfterResetPasswordDelegate.swift create mode 100644 MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterResetPasswordDelegateDispatcher.swift create mode 100644 MSAL/src/native_auth/public/state_machine/error/SignInAfterResetPasswordError.swift rename MSAL/src/native_auth/public/state_machine/state/{SignInAfterSignUpState+Internal.swift => SignInAfterPreviousFlowBaseState+Internal.swift} (93%) create mode 100644 MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState.swift create mode 100644 MSAL/src/native_auth/public/state_machine/state/SignInAfterResetPasswordState.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/reset_password/SignInAfterResetPasswordDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/delegate/sign_in/SignInAfterSignUpDelegateDispatcherTests.swift create mode 100644 MSAL/test/unit/native_auth/public/error/SignInAfterResetPasswordErrorTests.swift diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index 305a31a252..77c5ca9b5d 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -1030,17 +1030,11 @@ E20C21842A7A6CA400E31598 /* SignInCodeRequiredStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20C21832A7A6CA400E31598 /* SignInCodeRequiredStateTests.swift */; }; E20C218B2A7A805900E31598 /* SignInPasswordRequiredStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20C218A2A7A805800E31598 /* SignInPasswordRequiredStateTests.swift */; }; E22427C82B0526660006C55E /* SignUpDelegateDispatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427C72B0526660006C55E /* SignUpDelegateDispatchers.swift */; }; - E22427C92B0526660006C55E /* SignUpDelegateDispatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427C72B0526660006C55E /* SignUpDelegateDispatchers.swift */; }; E22427D22B0577920006C55E /* SignInDelegateDispatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427D12B0577920006C55E /* SignInDelegateDispatchers.swift */; }; - E22427D32B0577920006C55E /* SignInDelegateDispatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427D12B0577920006C55E /* SignInDelegateDispatchers.swift */; }; E22427D52B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427D42B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift */; }; - E22427D62B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427D42B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift */; }; E22427D82B0588AD0006C55E /* DelegateDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427D72B0588AD0006C55E /* DelegateDispatcher.swift */; }; - E22427D92B0588AD0006C55E /* DelegateDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427D72B0588AD0006C55E /* DelegateDispatcher.swift */; }; E22427DB2B0594670006C55E /* CredentialsDelegateDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427DA2B0594670006C55E /* CredentialsDelegateDispatcher.swift */; }; - E22427DC2B0594670006C55E /* CredentialsDelegateDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427DA2B0594670006C55E /* CredentialsDelegateDispatcher.swift */; }; E22427DE2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427DD2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift */; }; - E22427DF2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427DD2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift */; }; E22427E42B0650CD0006C55E /* SignUpPasswordStartDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427E32B0650CD0006C55E /* SignUpPasswordStartDelegateDispatcherTests.swift */; }; E22427E62B065D0D0006C55E /* SignUpStartDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427E52B065D0D0006C55E /* SignUpStartDelegateDispatcherTests.swift */; }; E22427E82B065DC00006C55E /* SignUpResendCodeDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22427E72B065DC00006C55E /* SignUpResendCodeDelegateDispatcherTests.swift */; }; @@ -1058,6 +1052,11 @@ E22428032B0673DF0006C55E /* ResetPasswordRequiredDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22428022B0673DF0006C55E /* ResetPasswordRequiredDelegateDispatcherTests.swift */; }; E22428052B0674A50006C55E /* SignInAfterSignUpDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22428042B0674A50006C55E /* SignInAfterSignUpDelegateDispatcherTests.swift */; }; E22428072B0676970006C55E /* DispatchAccessTokenRetrieveCompletedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22428062B0676970006C55E /* DispatchAccessTokenRetrieveCompletedTests.swift */; }; + E224F73E2B18F11F000A7B2E /* SignInAfterResetPasswordState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E224F73D2B18F11F000A7B2E /* SignInAfterResetPasswordState.swift */; }; + E224F7472B18F29F000A7B2E /* SignInAfterResetPasswordDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E224F7462B18F29F000A7B2E /* SignInAfterResetPasswordDelegate.swift */; }; + E224F7492B18F2FE000A7B2E /* SignInAfterResetPasswordError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E224F7482B18F2FE000A7B2E /* SignInAfterResetPasswordError.swift */; }; + E224F74B2B18F891000A7B2E /* SignInAfterResetPasswordDelegateDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E224F74A2B18F891000A7B2E /* SignInAfterResetPasswordDelegateDispatcher.swift */; }; + E224F74D2B18FC9C000A7B2E /* SignInAfterPreviousFlowBaseState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E224F74C2B18FC9C000A7B2E /* SignInAfterPreviousFlowBaseState.swift */; }; E22952682A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22952672A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift */; }; E22E20282A7936C50073A6FF /* MSALNativeAuthSignUpControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22E20272A7936C50073A6FF /* MSALNativeAuthSignUpControllerMock.swift */; }; E235610E29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235610D29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift */; }; @@ -1098,6 +1097,8 @@ E2BC029A29D766B200041DBC /* MSALNativeAuthSignUpStartRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BC029929D766B200041DBC /* MSALNativeAuthSignUpStartRequestParametersTest.swift */; }; E2BC029C29D766CB00041DBC /* MSALNativeAuthSignUpContinueRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BC029B29D766CB00041DBC /* MSALNativeAuthSignUpContinueRequestParametersTest.swift */; }; E2BDD98B2A28FBDD00E3ED6B /* MSALNativeAuthErrorRequiredAttributesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BDD98A2A28FBDD00E3ED6B /* MSALNativeAuthErrorRequiredAttributesTests.swift */; }; + E2C190752B20DE1100095534 /* SignInAfterResetPasswordDelegateDispatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C190742B20DE1100095534 /* SignInAfterResetPasswordDelegateDispatcherTests.swift */; }; + E2C190772B20DF4300095534 /* SignInAfterResetPasswordErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C190762B20DF4300095534 /* SignInAfterResetPasswordErrorTests.swift */; }; E2C1D287299BA15D00B26449 /* MSALNativeAuthBaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C1D286299BA15D00B26449 /* MSALNativeAuthBaseController.swift */; }; E2C1D2D429A3992100B26449 /* MSALNativeAuthBaseControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C1D2D329A3992100B26449 /* MSALNativeAuthBaseControllerTests.swift */; }; E2C61FE129DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C61FE029DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift */; }; @@ -1143,7 +1144,9 @@ E2F626A72A780F3D00C4A303 /* SignUpStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626A62A780F3D00C4A303 /* SignUpStates+Internal.swift */; }; E2F626AA2A780F8200C4A303 /* SignInStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626A92A780F8200C4A303 /* SignInStates+Internal.swift */; }; E2F626AD2A78119900C4A303 /* ResetPasswordStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AC2A78119900C4A303 /* ResetPasswordStates+Internal.swift */; }; - E2F626B02A78130700C4A303 /* SignInAfterSignUpState+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AF2A78130700C4A303 /* SignInAfterSignUpState+Internal.swift */; }; + E2F626AE2A78119900C4A303 /* ResetPasswordStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AC2A78119900C4A303 /* ResetPasswordStates+Internal.swift */; }; + E2F626B12A78130700C4A303 /* SignInAfterSignUpState+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AF2A78130700C4A303 /* SignInAfterSignUpState+Internal.swift */; }; + E2F626B02A78130700C4A303 /* SignInAfterPreviousFlowBaseState+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AF2A78130700C4A303 /* SignInAfterPreviousFlowBaseState+Internal.swift */; }; E2F626B32A781CE300C4A303 /* SignInDelegatesSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626B22A781CE300C4A303 /* SignInDelegatesSpies.swift */; }; /* End PBXBuildFile section */ @@ -2070,6 +2073,11 @@ E22428022B0673DF0006C55E /* ResetPasswordRequiredDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordRequiredDelegateDispatcherTests.swift; sourceTree = ""; }; E22428042B0674A50006C55E /* SignInAfterSignUpDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAfterSignUpDelegateDispatcherTests.swift; sourceTree = ""; }; E22428062B0676970006C55E /* DispatchAccessTokenRetrieveCompletedTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DispatchAccessTokenRetrieveCompletedTests.swift; sourceTree = ""; }; + E224F73D2B18F11F000A7B2E /* SignInAfterResetPasswordState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAfterResetPasswordState.swift; sourceTree = ""; }; + E224F7462B18F29F000A7B2E /* SignInAfterResetPasswordDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAfterResetPasswordDelegate.swift; sourceTree = ""; }; + E224F7482B18F2FE000A7B2E /* SignInAfterResetPasswordError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAfterResetPasswordError.swift; sourceTree = ""; }; + E224F74A2B18F891000A7B2E /* SignInAfterResetPasswordDelegateDispatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAfterResetPasswordDelegateDispatcher.swift; sourceTree = ""; }; + E224F74C2B18FC9C000A7B2E /* SignInAfterPreviousFlowBaseState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAfterPreviousFlowBaseState.swift; sourceTree = ""; }; E22952672A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpResponseValidatorTests.swift; sourceTree = ""; }; E22E20272A7936C50073A6FF /* MSALNativeAuthSignUpControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpControllerMock.swift; sourceTree = ""; }; E235610D29C23B23000E01CA /* MSALNativeAuthSignUpRequestProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpRequestProvider.swift; sourceTree = ""; }; @@ -2111,6 +2119,8 @@ E2BC029929D766B200041DBC /* MSALNativeAuthSignUpStartRequestParametersTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpStartRequestParametersTest.swift; sourceTree = ""; }; E2BC029B29D766CB00041DBC /* MSALNativeAuthSignUpContinueRequestParametersTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpContinueRequestParametersTest.swift; sourceTree = ""; }; E2BDD98A2A28FBDD00E3ED6B /* MSALNativeAuthErrorRequiredAttributesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthErrorRequiredAttributesTests.swift; sourceTree = ""; }; + E2C190742B20DE1100095534 /* SignInAfterResetPasswordDelegateDispatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAfterResetPasswordDelegateDispatcherTests.swift; sourceTree = ""; }; + E2C190762B20DF4300095534 /* SignInAfterResetPasswordErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAfterResetPasswordErrorTests.swift; sourceTree = ""; }; E2C1D286299BA15D00B26449 /* MSALNativeAuthBaseController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthBaseController.swift; sourceTree = ""; }; E2C1D2D329A3992100B26449 /* MSALNativeAuthBaseControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthBaseControllerTests.swift; sourceTree = ""; }; E2C61FE029DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpStartOauth2ErrorCode.swift; sourceTree = ""; }; @@ -2157,7 +2167,7 @@ E2F626A62A780F3D00C4A303 /* SignUpStates+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SignUpStates+Internal.swift"; sourceTree = ""; }; E2F626A92A780F8200C4A303 /* SignInStates+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SignInStates+Internal.swift"; sourceTree = ""; }; E2F626AC2A78119900C4A303 /* ResetPasswordStates+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ResetPasswordStates+Internal.swift"; sourceTree = ""; }; - E2F626AF2A78130700C4A303 /* SignInAfterSignUpState+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SignInAfterSignUpState+Internal.swift"; sourceTree = ""; }; + E2F626AF2A78130700C4A303 /* SignInAfterPreviousFlowBaseState+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SignInAfterPreviousFlowBaseState+Internal.swift"; sourceTree = ""; }; E2F626B22A781CE300C4A303 /* SignInDelegatesSpies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInDelegatesSpies.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -2536,6 +2546,7 @@ 28DCD0B329D73BCE00C4601E /* ResetPasswordDelegates.swift */, DE9245112A38736600C0389F /* CredentialsDelegates.swift */, 28FDC4A52A38C00900E38BE1 /* SignInAfterSignUpDelegate.swift */, + E224F7462B18F29F000A7B2E /* SignInAfterResetPasswordDelegate.swift */, ); path = delegate; sourceTree = ""; @@ -2550,8 +2561,10 @@ E2F626A92A780F8200C4A303 /* SignInStates+Internal.swift */, 28DCD0B129D7392400C4601E /* ResetPasswordStates.swift */, E2F626AC2A78119900C4A303 /* ResetPasswordStates+Internal.swift */, + E224F74C2B18FC9C000A7B2E /* SignInAfterPreviousFlowBaseState.swift */, + E2F626AF2A78130700C4A303 /* SignInAfterPreviousFlowBaseState+Internal.swift */, 28FDC49B2A38BFA900E38BE1 /* SignInAfterSignUpState.swift */, - E2F626AF2A78130700C4A303 /* SignInAfterSignUpState+Internal.swift */, + E224F73D2B18F11F000A7B2E /* SignInAfterResetPasswordState.swift */, ); path = state; sourceTree = ""; @@ -2571,6 +2584,7 @@ 28E4D9022A30ABA200280921 /* ResendCodeError.swift */, DE9245142A3875D700C0389F /* RetrieveAccessTokenError.swift */, 28FDC4A82A38C0D000E38BE1 /* SignInAfterSignUpError.swift */, + E224F7482B18F2FE000A7B2E /* SignInAfterResetPasswordError.swift */, ); path = error; sourceTree = ""; @@ -3863,6 +3877,7 @@ E22427F72B066F750006C55E /* SignInResendCodeDelegateDispatcherTests.swift */, E22427F32B066BBC0006C55E /* SignInStartDelegateDispatcherTests.swift */, E22427F92B0670600006C55E /* SignInVerifyCodeDelegateDispatcherTests.swift */, + E22428042B0674A50006C55E /* SignInAfterSignUpDelegateDispatcherTests.swift */, ); path = sign_in; sourceTree = ""; @@ -3874,6 +3889,7 @@ E22428002B0673290006C55E /* ResetPasswordResendCodeDelegateDispatcherTests.swift */, E22427FC2B0671A10006C55E /* ResetPasswordStartDelegateDispatcherTests.swift */, E22427FE2B06725C0006C55E /* ResetPasswordVerifyCodeDelegateDispatcherTests.swift */, + E2C190742B20DE1100095534 /* SignInAfterResetPasswordDelegateDispatcherTests.swift */, ); path = reset_password; sourceTree = ""; @@ -4171,10 +4187,25 @@ E2CE91192B0BA4790009AEDD /* ResendCodeErrorTests.swift */, E2CE911B2B0BA48D0009AEDD /* RetrieveAccessTokenErrorTests.swift */, E2CE911D2B0BA4A60009AEDD /* SignInAfterSignUpErrorTests.swift */, + E2C190762B20DF4300095534 /* SignInAfterResetPasswordErrorTests.swift */, ); path = error; sourceTree = ""; }; + E2CE91372B0D077C0009AEDD /* delegate_dispatcher */ = { + isa = PBXGroup; + children = ( + E22427D72B0588AD0006C55E /* DelegateDispatcher.swift */, + E22427C72B0526660006C55E /* SignUpDelegateDispatchers.swift */, + E22427D12B0577920006C55E /* SignInDelegateDispatchers.swift */, + E22427D42B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift */, + E22427DA2B0594670006C55E /* CredentialsDelegateDispatcher.swift */, + E22427DD2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift */, + E224F74A2B18F891000A7B2E /* SignInAfterResetPasswordDelegateDispatcher.swift */, + ); + path = delegate_dispatcher; + sourceTree = ""; + }; E2EFAD072A69A2C300D6C3DE /* responses */ = { isa = PBXGroup; children = ( @@ -5330,8 +5361,20 @@ B2D47894230E3DEB005AE186 /* MSALOauth2Authority.m in Sources */, B273D0A3226E8576005A7BB4 /* MSALIndividualClaimRequest.m in Sources */, 04A6B5B4226937080035C7C2 /* MSALPromptType.m in Sources */, + DE0D65AD29CC6A5A005798B1 /* MSALNativeAuthSignInInitiateResponse.swift in Sources */, + E2C61FE229DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift in Sources */, + E22427DF2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift in Sources */, + DECC1F9729521E35006D9FB1 /* MSALLogMask.m in Sources */, + DE54B5922A434B9B00460B34 /* MSALNativeAuthTokenController.swift in Sources */, + E2C61FEB29DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift in Sources */, + DE0347BD2A41B76E003CB3B6 /* MSALNativeAuthCredentialsControlling.swift in Sources */, + 9B4EE9DA2A1687B600F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift in Sources */, B2D478A7230E3E5A005AE186 /* MSALTelemetryEventsObservingProxy.m in Sources */, B2D478B3230E3E88005AE186 /* NSString+MSALAccountIdenfiers.m in Sources */, + 289747B7297ABEA300838C80 /* MSALNativeAuthInputValidator.swift in Sources */, + 285F36092A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift in Sources */, + E22427D92B0588AD0006C55E /* DelegateDispatcher.swift in Sources */, + 2814B4DB2A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift in Sources */, 04A6B5BD2269374D0035C7C2 /* MSALAccount.m in Sources */, 04A6B6092269382B0035C7C2 /* MSALAuthority.m in Sources */, 04A6B6162269383F0035C7C2 /* MSALOauth2ProviderFactory.m in Sources */, @@ -5345,6 +5388,10 @@ B273D0A7226E857B005A7BB4 /* MSALIndividualClaimRequestAdditionalInfo.m in Sources */, B2D478BD230E3EA8005AE186 /* MSALWebviewParameters.m in Sources */, 04A6B5AE226936F30035C7C2 /* MSALFramework.m in Sources */, + 9BD2763E2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift in Sources */, + E22427C92B0526660006C55E /* SignUpDelegateDispatchers.swift in Sources */, + E22427D32B0577920006C55E /* SignInDelegateDispatchers.swift in Sources */, + E2C61FEE29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift in Sources */, B273D0C3226E85AA005A7BB4 /* MSALGlobalConfig.m in Sources */, B273D0DA226E85DB005A7BB4 /* MSALLoggerConfig.m in Sources */, B273D0CF226E85CC005A7BB4 /* MSALHTTPConfig.m in Sources */, @@ -5360,7 +5407,20 @@ B273D0EA226E85FF005A7BB4 /* MSALPublicClientStatusNotifications.m in Sources */, B273D0D5226E85D3005A7BB4 /* MSALTelemetryConfig.m in Sources */, 04A6B60C226938300035C7C2 /* MSALB2CAuthority.m in Sources */, + DE0347C22A41B80C003CB3B6 /* MSALNativeAuthVerifyCodeParameters.swift in Sources */, + 2826933C2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift in Sources */, + E22427DC2B0594670006C55E /* CredentialsDelegateDispatcher.swift in Sources */, + E2F626A82A780F3D00C4A303 /* SignUpStates+Internal.swift in Sources */, + E26097C42948FC4D0060DD7C /* MSALNativeAuthLogging.swift in Sources */, + E2C872C4294CDEE800C4F580 /* MSALNativeAuthRequestable.swift in Sources */, + 9BE7E3D62A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift in Sources */, + 28DE70D729FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift in Sources */, + E2C61FE829DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift in Sources */, B2D478B1230E3E88005AE186 /* MSALLegacySharedAccountFactory.m in Sources */, + 28F19BEC2A2F884D00575581 /* Array+joinScopes.swift in Sources */, + DE729ECE2A1793A100A761D9 /* MSALNativeAuthChannelType.swift in Sources */, + E22427D62B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift in Sources */, + DEF9D98A296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift in Sources */, 2396EFDE2582D8B000ADA9EB /* MSALDeviceInfoProvider.m in Sources */, 1E5319C824A51FCE007BCF30 /* MSALHttpMethod.m in Sources */, 04A6B5CB226937700035C7C2 /* MSALError.m in Sources */, @@ -5633,6 +5693,7 @@ DEF9D99F296F08CE006CB384 /* MSALNativeAuthTelemetryProvider.swift in Sources */, DE9245152A3875D700C0389F /* RetrieveAccessTokenError.swift in Sources */, DE8BE7DC2A1F6BD2009642A5 /* MSALNativeAuthUserAccountResult.swift in Sources */, + E224F73E2B18F11F000A7B2E /* SignInAfterResetPasswordState.swift in Sources */, 287708252A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift in Sources */, DEE34F89D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionStatus.swift in Sources */, 9BE7E3D52A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift in Sources */, @@ -5697,6 +5758,7 @@ 287F650C2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift in Sources */, DEDB29A529DDA9DC008DA85B /* MSALNativeAuthSignInInitiateResponseError.swift in Sources */, E243F6A629D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift in Sources */, + E224F74B2B18F891000A7B2E /* SignInAfterResetPasswordDelegateDispatcher.swift in Sources */, 287F64D92981781A00ED90BD /* MSALNativeAuthSignInParameters.swift in Sources */, 96B5E6E22256D166002232F9 /* MSALTelemetryConfig.m in Sources */, 28DCD0A429D72C7100C4601E /* SignUpStates.swift in Sources */, @@ -5705,6 +5767,7 @@ DEF9D989296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift in Sources */, B253151B23DD607600432133 /* MSALDeviceInformation.m in Sources */, 9BD2763D2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift in Sources */, + E224F7492B18F2FE000A7B2E /* SignInAfterResetPasswordError.swift in Sources */, E2C61FED29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift in Sources */, 963377C1211E14C600943EE0 /* MSALWebviewType.m in Sources */, E235613429C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift in Sources */, @@ -5770,7 +5833,8 @@ 28DCD0AE29D737E600C4601E /* VerifyCodeError.swift in Sources */, E22427C82B0526660006C55E /* SignUpDelegateDispatchers.swift in Sources */, 289747B42979A3C800838C80 /* MSALNativeAuthParameters.swift in Sources */, - E2F626B02A78130700C4A303 /* SignInAfterSignUpState+Internal.swift in Sources */, + E224F7472B18F29F000A7B2E /* SignInAfterResetPasswordDelegate.swift in Sources */, + E2F626B02A78130700C4A303 /* SignInAfterPreviousFlowBaseState+Internal.swift in Sources */, E22427DE2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift in Sources */, E22427DB2B0594670006C55E /* CredentialsDelegateDispatcher.swift in Sources */, B26756C622921C42000F01D7 /* MSALAADOauth2Provider.m in Sources */, @@ -5786,6 +5850,7 @@ DE94C9F029F2AF5E00C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParameters.swift in Sources */, D61BD2B31EBD09F90007E484 /* MSALPromptType.m in Sources */, DEC1E425298BE18A00948BED /* MSALNativeAuthServerTelemetry.swift in Sources */, + E224F74D2B18FC9C000A7B2E /* SignInAfterPreviousFlowBaseState.swift in Sources */, 9B4EE9D82A1687AE00F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift in Sources */, DEE34F61D170B71C00BC302A /* MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift in Sources */, 28FDC49C2A38BFA900E38BE1 /* SignInAfterSignUpState.swift in Sources */, @@ -5941,6 +6006,7 @@ E22952682A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift in Sources */, E286E2DD2A1BAEA800666DD0 /* MSALNativeAuthSignUpControllerTests.swift in Sources */, B2725EC522BF4865009B454A /* MSALMockExternalAccountHandler.m in Sources */, + E2C190772B20DF4300095534 /* SignInAfterResetPasswordErrorTests.swift in Sources */, 9BD2765F2A0E81CE00FBD033 /* ResetPasswordRequiredStateTests.swift in Sources */, D69ADB371E516F9B00952049 /* MSALTestCase.m in Sources */, DE94C9E829F19E6B00C1EC1F /* MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift in Sources */, @@ -5982,6 +6048,7 @@ E25BC0832995429D00588549 /* MSALNativeAuthCacheMocks.swift in Sources */, 960751BB2183E82C00F2BF2F /* MSALAccountIdTests.m in Sources */, E20C217E2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift in Sources */, + E2C190752B20DE1100095534 /* SignInAfterResetPasswordDelegateDispatcherTests.swift in Sources */, E22427F82B066F750006C55E /* SignInResendCodeDelegateDispatcherTests.swift in Sources */, E2CE911C2B0BA48D0009AEDD /* RetrieveAccessTokenErrorTests.swift in Sources */, E248917A2A1CFA6B001ECBE2 /* MSALNativeAuthConfigStubs.swift in Sources */, diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift index b51c0ac7ca..3faf8b0ea1 100644 --- a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift @@ -31,14 +31,17 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, private let requestProvider: MSALNativeAuthResetPasswordRequestProviding private let responseValidator: MSALNativeAuthResetPasswordResponseValidating + private let signInController: MSALNativeAuthSignInControlling init( config: MSALNativeAuthConfiguration, requestProvider: MSALNativeAuthResetPasswordRequestProviding, - responseValidator: MSALNativeAuthResetPasswordResponseValidating + responseValidator: MSALNativeAuthResetPasswordResponseValidating, + signInController: MSALNativeAuthSignInControlling ) { self.requestProvider = requestProvider self.responseValidator = responseValidator + self.signInController = signInController super.init(clientId: config.clientId) } @@ -50,7 +53,8 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, requestConfigurator: MSALNativeAuthRequestConfigurator(config: config), telemetryProvider: MSALNativeAuthTelemetryProvider() ), - responseValidator: MSALNativeAuthResetPasswordResponseValidator() + responseValidator: MSALNativeAuthResetPasswordResponseValidator(), + signInController: MSALNativeAuthSignInController(config: config) ) } @@ -59,16 +63,21 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, func resetPassword(parameters: MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordStart, context: parameters.context) let response = await performStartRequest(parameters: parameters) - return await handleStartResponse(response, event: event, context: parameters.context) + return await handleStartResponse(response, username: parameters.username, event: event, context: parameters.context) } - func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { + func resendCode(username: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordResendCode, context: context) let response = await performChallengeRequest(passwordResetToken: passwordResetToken, context: context) - return await handleResendCodeChallengeResponse(response, event: event, context: context) + return await handleResendCodeChallengeResponse(response, username: username, event: event, context: context) } - func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse { + func submitCode( + code: String, + username: String, + passwordResetToken: String, + context: MSIDRequestContext + ) async -> ResetPasswordSubmitCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordSubmitCode, context: context) let params = MSALNativeAuthResetPasswordContinueRequestParameters( @@ -79,11 +88,12 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, ) let response = await performContinueRequest(parameters: params) - return await handleSubmitCodeResponse(response, passwordResetToken: passwordResetToken, event: event, context: context) + return await handleSubmitCodeResponse(response, username: username, passwordResetToken: passwordResetToken, event: event, context: context) } func submitPassword( password: String, + username: String, passwordSubmitToken: String, context: MSIDRequestContext ) async -> ResetPasswordSubmitPasswordControllerResponse { @@ -95,7 +105,13 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, newPassword: password ) let submitRequestResponse = await performSubmitRequest(parameters: params) - return await handleSubmitPasswordResponse(submitRequestResponse, passwordSubmitToken: passwordSubmitToken, event: event, context: context) + return await handleSubmitPasswordResponse( + submitRequestResponse, + username: username, + passwordSubmitToken: passwordSubmitToken, + event: event, + context: context + ) } // MARK: - Start Request handling @@ -119,6 +135,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, } private func handleStartResponse(_ response: MSALNativeAuthResetPasswordStartValidatedResponse, + username: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext) async -> ResetPasswordStartControllerResponse { @@ -127,7 +144,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, switch response { case .success(let passwordResetToken): let challengeResponse = await performChallengeRequest(passwordResetToken: passwordResetToken, context: context) - return await handleChallengeResponse(challengeResponse, event: event, context: context) + return await handleChallengeResponse(challengeResponse, username: username, event: event, context: context) case .redirect: let error = ResetPasswordStartError(type: .browserRequired, message: MSALNativeAuthErrorMessage.browserRequired) stopTelemetryEvent(event, context: context, error: error) @@ -175,6 +192,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, private func handleChallengeResponse( _ response: MSALNativeAuthResetPasswordChallengeValidatedResponse, + username: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext ) async -> ResetPasswordStartControllerResponse { @@ -183,7 +201,12 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, MSALLogger.log(level: .info, context: context, format: "Successful resetpassword/challenge request") return .init(.codeRequired( - newState: ResetPasswordCodeRequiredState(controller: self, flowToken: challengeToken, correlationId: context.correlationId()), + newState: ResetPasswordCodeRequiredState( + controller: self, + username: username, + flowToken: challengeToken, + correlationId: context.correlationId() + ), sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength @@ -216,6 +239,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, private func handleResendCodeChallengeResponse( _ response: MSALNativeAuthResetPasswordChallengeValidatedResponse, + username: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext ) async -> ResetPasswordResendCodeControllerResponse { @@ -223,7 +247,12 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, case .success(let sentTo, let channelTargetType, let codeLength, let challengeToken): MSALLogger.log(level: .info, context: context, format: "Successful resetpassword/challenge (resend code) request") return .init(.codeRequired( - newState: ResetPasswordCodeRequiredState(controller: self, flowToken: challengeToken, correlationId: context.correlationId()), + newState: ResetPasswordCodeRequiredState( + controller: self, + username: username, + flowToken: challengeToken, + correlationId: context.correlationId() + ), sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength @@ -270,6 +299,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, private func handleSubmitCodeResponse( _ response: MSALNativeAuthResetPasswordContinueValidatedResponse, + username: String, passwordResetToken: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext @@ -277,7 +307,12 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, switch response { case .success(let passwordSubmitToken): MSALLogger.log(level: .info, context: context, format: "Successful resetpassword/continue request") - let newState = ResetPasswordRequiredState(controller: self, flowToken: passwordSubmitToken, correlationId: context.correlationId()) + let newState = ResetPasswordRequiredState( + controller: self, + username: username, + flowToken: passwordSubmitToken, + correlationId: context.correlationId() + ) return .init(.passwordRequired(newState: newState), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) @@ -306,7 +341,12 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context, format: "Invalid code error calling resetpassword/continue \(error.errorDescription ?? "No error description")") - let state = ResetPasswordCodeRequiredState(controller: self, flowToken: passwordResetToken, correlationId: context.correlationId()) + let state = ResetPasswordCodeRequiredState( + controller: self, + username: username, + flowToken: passwordResetToken, + correlationId: context.correlationId() + ) return .init(.error(error: error, newState: state)) } } @@ -333,6 +373,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, private func handleSubmitPasswordResponse( _ response: MSALNativeAuthResetPasswordSubmitValidatedResponse, + username: String, passwordSubmitToken: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext @@ -342,6 +383,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, switch response { case .success(let passwordResetToken, let pollInterval): return await doPollCompletionLoop( + username: username, passwordResetToken: passwordResetToken, pollInterval: pollInterval, retriesRemaining: kNumberOfTimesToRetryPollCompletionCall, @@ -355,7 +397,12 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, MSALLogger.log(level: .error, context: context, format: "Password error calling resetpassword/submit \(error.errorDescription ?? "No error description")") - let newState = ResetPasswordRequiredState(controller: self, flowToken: passwordSubmitToken, correlationId: context.correlationId()) + let newState = ResetPasswordRequiredState( + controller: self, + username: username, + flowToken: passwordSubmitToken, + correlationId: context.correlationId() + ) return .init(.error(error: error, newState: newState)) case .error(let apiError): let error = apiError.toPasswordRequiredPublicError() @@ -381,6 +428,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, // MARK: - Poll Completion Request handling private func doPollCompletionLoop( + username: String, passwordResetToken: String, pollInterval: Int, retriesRemaining: Int, @@ -398,6 +446,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, return await handlePollCompletionResponse( pollCompletionResponse, + username: username, pollInterval: pollInterval, retriesRemaining: retriesRemaining, passwordResetToken: passwordResetToken, @@ -432,8 +481,10 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, return responseValidator.validate(result, with: parameters.context) } + // swiftlint:disable function_body_length private func handlePollCompletionResponse( _ response: MSALNativeAuthResetPasswordPollCompletionValidatedResponse, + username: String, pollInterval: Int, retriesRemaining: Int, passwordResetToken: String, @@ -443,7 +494,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, MSALLogger.log(level: .info, context: context, format: "Finished resetpassword/poll_completion") switch response { - case .success(let status): + case .success(let status, let continuationToken): switch status { case .inProgress, .notStarted: @@ -452,11 +503,18 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, passwordResetToken: passwordResetToken, pollInterval: pollInterval, retriesRemaining: retriesRemaining, + username: username, event: event, context: context ) case .succeeded: - return .init(.completed, telemetryUpdate: { [weak self] result in + let signInAfterResetPasswordState = SignInAfterResetPasswordState( + controller: signInController, + username: username, + slt: continuationToken, + correlationId: context.correlationId() + ) + return .init(.completed(signInAfterResetPasswordState), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) case .failed: @@ -473,7 +531,12 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, MSALLogger.log(level: .error, context: context, format: "Password error calling resetpassword/poll_completion \(error.errorDescription ?? "No error description")") - let newState = ResetPasswordRequiredState(controller: self, flowToken: passwordResetToken, correlationId: context.correlationId()) + let newState = ResetPasswordRequiredState( + controller: self, + username: username, + flowToken: passwordResetToken, + correlationId: context.correlationId() + ) return .init(.error(error: error, newState: newState)) case .error(let apiError): let error = apiError.toPasswordRequiredPublicError() @@ -495,11 +558,13 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, return .init(.error(error: error, newState: nil)) } } + // swiftlint:enable function_body_length private func retryPollCompletion( passwordResetToken: String, pollInterval: Int, retriesRemaining: Int, + username: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext ) async -> ResetPasswordSubmitPasswordControllerResponse { @@ -531,6 +596,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, } return await doPollCompletionLoop( + username: username, passwordResetToken: passwordResetToken, pollInterval: pollInterval, retriesRemaining: retriesRemaining - 1, diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift index f1bd2b5360..8381c7e2fb 100644 --- a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift @@ -33,12 +33,18 @@ protocol MSALNativeAuthResetPasswordControlling: AnyObject { func resetPassword(parameters: MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartControllerResponse - func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse + func resendCode(username: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse - func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse + func submitCode( + code: String, + username: String, + passwordResetToken: String, + context: MSIDRequestContext + ) async -> ResetPasswordSubmitCodeControllerResponse func submitPassword( password: String, + username: String, passwordSubmitToken: String, context: MSIDRequestContext ) async -> ResetPasswordSubmitPasswordControllerResponse diff --git a/MSAL/src/native_auth/controllers/responses/ResetPasswordResults.swift b/MSAL/src/native_auth/controllers/responses/ResetPasswordResults.swift index 754121bbfc..2f0133bec8 100644 --- a/MSAL/src/native_auth/controllers/responses/ResetPasswordResults.swift +++ b/MSAL/src/native_auth/controllers/responses/ResetPasswordResults.swift @@ -37,6 +37,6 @@ enum ResetPasswordSubmitCodeResult { } enum ResetPasswordSubmitPasswordResult { - case completed + case completed(SignInAfterResetPasswordState) case error(error: PasswordRequiredError, newState: ResetPasswordRequiredState?) } diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift index 429c66edf7..d7ceb2e5f2 100644 --- a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift @@ -115,14 +115,14 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN slt: String?, scopes: [String]?, context: MSALNativeAuthRequestContext - ) async -> SignInAfterSignUpControllerResponse { - MSALLogger.log(level: .verbose, context: context, format: "SignIn after signUp started") + ) async -> SignInAfterPreviousFlowControllerResponse { + MSALLogger.log(level: .verbose, context: context, format: "SignIn after previous flow started") let telemetryInfo = TelemetryInfo( event: makeAndStartTelemetryEvent(id: .telemetryApiIdSignInAfterSignUp, context: context), context: context ) guard let slt = slt else { - MSALLogger.log(level: .error, context: context, format: "SignIn not available because SLT is nil") + MSALLogger.log(level: .error, context: context, format: "SignIn after previous flow not available because signInSLT is nil") let error = SignInAfterSignUpError(message: MSALNativeAuthErrorMessage.signInNotAvailable) stopTelemetryEvent(telemetryInfo, error: error) return .init(.failure(error)) diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift index e5e975e17a..cfd757a118 100644 --- a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift @@ -27,8 +27,8 @@ import Foundation protocol MSALNativeAuthSignInControlling { typealias SignInPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper typealias SignInCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper - typealias SignInAfterSignUpControllerResponse = - MSALNativeAuthControllerTelemetryWrapper> + typealias SignInAfterPreviousFlowControllerResponse = + MSALNativeAuthControllerTelemetryWrapper> typealias SignInSubmitCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper typealias SignInSubmitPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper typealias SignInResendCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper @@ -42,7 +42,7 @@ protocol MSALNativeAuthSignInControlling { slt: String?, scopes: [String]?, context: MSALNativeAuthRequestContext - ) async -> SignInAfterSignUpControllerResponse + ) async -> SignInAfterPreviousFlowControllerResponse func submitCode( _ code: String, diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift index 41b7ae8b8f..0a6ae01486 100644 --- a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift @@ -405,7 +405,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa newState: SignUpCodeRequiredState( controller: self, username: username, - flowToken: signUpToken, + flowToken: signUpToken, correlationId: context.correlationId() ), sentTo: sentTo, @@ -682,6 +682,11 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa ) -> SignInAfterSignUpState { MSALLogger.log(level: .info, context: context, format: "SignUp completed successfully") stopTelemetryEvent(event, context: context) - return SignInAfterSignUpState(controller: signInController, username: username, slt: slt, correlationId: context.correlationId()) + return SignInAfterSignUpState( + controller: signInController, + username: username, + slt: slt, + correlationId: context.correlationId() + ) } } diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionResponse.swift index 87d5ff11d3..4ea53a96a6 100644 --- a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionResponse.swift +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionResponse.swift @@ -28,6 +28,6 @@ struct MSALNativeAuthResetPasswordPollCompletionResponse: Decodable { // MARK: - Variables let status: MSALNativeAuthResetPasswordPollCompletionStatus - let signInSLT: String? + let continuationToken: String? let expiresIn: Int? } diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift index 0f75b757cb..a47968e180 100644 --- a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift @@ -34,9 +34,4 @@ struct MSALNativeAuthResetPasswordStartResponse: Decodable { case passwordResetToken case challengeType } - - init(passwordResetToken: String?, challengeType: MSALNativeAuthInternalChallengeType?) { - self.passwordResetToken = passwordResetToken - self.challengeType = challengeType - } } diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift index b23159692b..e20fe2c21d 100644 --- a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift @@ -244,7 +244,8 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas private func handlePollCompletionSuccess( _ response: MSALNativeAuthResetPasswordPollCompletionResponse ) -> MSALNativeAuthResetPasswordPollCompletionValidatedResponse { - return .success(status: response.status) + // Even if the `continuationToken` is nil, the ResetPassword flow is considered successfully completed + return .success(status: response.status, continuationToken: response.continuationToken) } private func handlePollCompletionError( diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift index 3e77c380b9..d581ac7ecd 100644 --- a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift +++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift @@ -72,7 +72,8 @@ enum MSALNativeAuthResetPasswordSubmitValidatedResponse: Equatable { } enum MSALNativeAuthResetPasswordPollCompletionValidatedResponse: Equatable { - case success(status: MSALNativeAuthResetPasswordPollCompletionStatus) + // TODO: Update to continuation_token + case success(status: MSALNativeAuthResetPasswordPollCompletionStatus, continuationToken: String?) case passwordError(error: MSALNativeAuthResetPasswordPollCompletionResponseError) case error(MSALNativeAuthResetPasswordPollCompletionResponseError) case unexpectedError diff --git a/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift index ccd85a450d..a0edddb6ab 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift @@ -92,5 +92,6 @@ public protocol ResetPasswordRequiredDelegate { /// Notifies the delegate that the reset password operation completed successfully. /// - Note: If a flow requires this optional method and it is not implemented, then ``onResetPasswordRequiredError(error:newState:)`` will be called. - @MainActor @objc optional func onResetPasswordCompleted() + /// - Parameter newState: An object representing the new state of the flow with follow on methods. + @MainActor @objc optional func onResetPasswordCompleted(newState: SignInAfterResetPasswordState) } diff --git a/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterResetPasswordDelegate.swift b/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterResetPasswordDelegate.swift new file mode 100644 index 0000000000..8c24f02e03 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterResetPasswordDelegate.swift @@ -0,0 +1,37 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public protocol SignInAfterResetPasswordDelegate { + /// Notifies the delegate that the operation resulted in an error. + /// - Parameter error: An error object indicating why the operation failed. + @MainActor func onSignInAfterResetPasswordError(error: SignInAfterResetPasswordError) + + /// Notifies the delegate that the sign in operation completed successfully. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignInAfterResetPasswordError(error:)`` will be called. + /// - Parameter result: An object representing the signed in user account. + @MainActor @objc optional func onSignInCompleted(result: MSALNativeAuthUserAccountResult) +} diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/ResetPasswordDelegateDispatchers.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/ResetPasswordDelegateDispatchers.swift index 70d136a219..d879c25bd0 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/ResetPasswordDelegateDispatchers.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/ResetPasswordDelegateDispatchers.swift @@ -78,10 +78,10 @@ final class ResetPasswordResendCodeDelegateDispatcher: DelegateDispatcher { - func dispatchResetPasswordCompleted() async { + func dispatchResetPasswordCompleted(newState: SignInAfterResetPasswordState) async { if let onResetPasswordCompleted = delegate.onResetPasswordCompleted { telemetryUpdate?(.success(())) - await onResetPasswordCompleted() + await onResetPasswordCompleted(newState) } else { let error = PasswordRequiredError(type: .generalError, message: requiredErrorMessage(for: "onResetPasswordCompleted")) telemetryUpdate?(.failure(error)) diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterResetPasswordDelegateDispatcher.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterResetPasswordDelegateDispatcher.swift new file mode 100644 index 0000000000..0aa3c3f2d7 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterResetPasswordDelegateDispatcher.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +final class SignInAfterResetPasswordDelegateDispatcher: DelegateDispatcher { + + func dispatchSignInCompleted(result: MSALNativeAuthUserAccountResult) async { + if let onSignInCompleted = delegate.onSignInCompleted { + telemetryUpdate?(.success(())) + await onSignInCompleted(result) + } else { + let error = SignInAfterResetPasswordError(message: requiredErrorMessage(for: "onSignInCompleted")) + telemetryUpdate?(.failure(error)) + await delegate.onSignInAfterResetPasswordError(error: error) + } + } +} diff --git a/MSAL/src/native_auth/public/state_machine/error/SignInAfterResetPasswordError.swift b/MSAL/src/native_auth/public/state_machine/error/SignInAfterResetPasswordError.swift new file mode 100644 index 0000000000..be75c1bfa3 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/error/SignInAfterResetPasswordError.swift @@ -0,0 +1,37 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objc +public class SignInAfterResetPasswordError: MSALNativeAuthError { + /// Describes why an error occurred and provides more information about the error. + public override var errorDescription: String? { + if let description = super.errorDescription { + return description + } + + return MSALNativeAuthErrorMessage.generalError + } +} diff --git a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift index c982e83cba..d47174612c 100644 --- a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift +++ b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift @@ -28,7 +28,7 @@ extension ResetPasswordCodeRequiredState { func resendCodeInternal() async -> MSALNativeAuthResetPasswordControlling.ResetPasswordResendCodeControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) - return await controller.resendCode(passwordResetToken: flowToken, context: context) + return await controller.resendCode(username: username, passwordResetToken: flowToken, context: context) } func submitCodeInternal(code: String) async -> MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitCodeControllerResponse { @@ -39,7 +39,7 @@ extension ResetPasswordCodeRequiredState { return .init(.error(error: VerifyCodeError(type: .invalidCode), newState: self)) } - return await controller.submitCode(code: code, passwordResetToken: flowToken, context: context) + return await controller.submitCode(code: code, username: username, passwordResetToken: flowToken, context: context) } } @@ -53,6 +53,6 @@ extension ResetPasswordRequiredState { return .init(.error(error: PasswordRequiredError(type: .invalidPassword), newState: self)) } - return await controller.submitPassword(password: password, passwordSubmitToken: flowToken, context: context) + return await controller.submitPassword(password: password, username: username, passwordSubmitToken: flowToken, context: context) } } diff --git a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift index 09103c3f74..1625bf9826 100644 --- a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift +++ b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift @@ -27,15 +27,18 @@ import Foundation @objcMembers public class ResetPasswordBaseState: MSALNativeAuthBaseState { let controller: MSALNativeAuthResetPasswordControlling + let username: String let inputValidator: MSALNativeAuthInputValidating init( controller: MSALNativeAuthResetPasswordControlling, + username: String, flowToken: String, inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator(), correlationId: UUID ) { self.controller = controller + self.username = username self.inputValidator = inputValidator super.init(flowToken: flowToken, correlationId: correlationId) } @@ -101,8 +104,8 @@ public class ResetPasswordBaseState: MSALNativeAuthBaseState { let delegateDispatcher = ResetPasswordRequiredDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) switch controllerResponse.result { - case .completed: - await delegateDispatcher.dispatchResetPasswordCompleted() + case .completed(let newState): + await delegateDispatcher.dispatchResetPasswordCompleted(newState: newState) case .error(let error, let newState): await delegate.onResetPasswordRequiredError(error: error, newState: newState) } diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState+Internal.swift similarity index 93% rename from MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift rename to MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState+Internal.swift index e4c18a6c6f..26f45254fc 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState+Internal.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState+Internal.swift @@ -24,9 +24,9 @@ import Foundation -extension SignInAfterSignUpState { +extension SignInAfterPreviousFlowBaseState { - func signInInternal(scopes: [String]?) async -> MSALNativeAuthSignInControlling.SignInAfterSignUpControllerResponse { + func signInInternal(scopes: [String]?) async -> MSALNativeAuthSignInControlling.SignInAfterPreviousFlowControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) return await controller.signIn(username: username, slt: slt, scopes: scopes, context: context) } diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState.swift new file mode 100644 index 0000000000..4a2c0171e8 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +@objcMembers public class SignInAfterPreviousFlowBaseState: NSObject { + let controller: MSALNativeAuthSignInControlling + let username: String + let slt: String? // TODO: Update to continuation_token + let correlationId: UUID + + init(controller: MSALNativeAuthSignInControlling, username: String, slt: String?, correlationId: UUID) { + self.username = username + self.controller = controller + self.slt = slt + self.correlationId = correlationId + } +} diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterResetPasswordState.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterResetPasswordState.swift new file mode 100644 index 0000000000..7c0cb98529 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterResetPasswordState.swift @@ -0,0 +1,49 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// An object of this type is created when a user has reset their password successfully. +@objcMembers public class SignInAfterResetPasswordState: SignInAfterPreviousFlowBaseState { + /// Sign in the user that just reset the password. + /// - Parameters: + /// - scopes: Optional. Permissions you want included in the access token received after sign in flow has completed. + /// - delegate: Delegate that receives callbacks for the Sign In flow. + public func signIn(scopes: [String]? = nil, delegate: SignInAfterResetPasswordDelegate) { + Task { + let controllerResponse = await signInInternal(scopes: scopes) + let delegateDispatcher = SignInAfterResetPasswordDelegateDispatcher( + delegate: delegate, + telemetryUpdate: controllerResponse.telemetryUpdate + ) + + switch controllerResponse.result { + case .success(let accountResult): + await delegateDispatcher.dispatchSignInCompleted(result: accountResult) + case .failure(let error): + await delegate.onSignInAfterResetPasswordError(error: SignInAfterResetPasswordError(message: error.errorDescription)) + } + } + } +} diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift index cf33e035ca..e08b2f5922 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift @@ -25,28 +25,12 @@ import Foundation /// An object of this type is created when a user has signed up successfully. -@objcMembers public class SignInAfterSignUpState: NSObject { - - let controller: MSALNativeAuthSignInControlling - let username: String - let slt: String? - let correlationId: UUID - - init(controller: MSALNativeAuthSignInControlling, username: String, slt: String?, correlationId: UUID) { - self.username = username - self.slt = slt - self.controller = controller - self.correlationId = correlationId - } - +@objcMembers public class SignInAfterSignUpState: SignInAfterPreviousFlowBaseState { /// Sign in the user that signed up. /// - Parameters: /// - scopes: Optional. Permissions you want included in the access token received after sign in flow has completed. /// - delegate: Delegate that receives callbacks for the Sign In flow. - public func signIn( - scopes: [String]? = nil, - delegate: SignInAfterSignUpDelegate - ) { + public func signIn(scopes: [String]? = nil, delegate: SignInAfterSignUpDelegate) { Task { let controllerResponse = await signInInternal(scopes: scopes) let delegateDispatcher = SignInAfterSignUpDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) @@ -55,7 +39,7 @@ import Foundation case .success(let accountResult): await delegateDispatcher.dispatchSignInCompleted(result: accountResult) case .failure(let error): - await delegate.onSignInAfterSignUpError(error: error) + await delegate.onSignInAfterSignUpError(error: SignInAfterSignUpError(message: error.errorDescription)) } } } diff --git a/MSAL/test/integration/native_auth/end_to_end/reset_password/MSALNativeAuthResetPasswordEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/reset_password/MSALNativeAuthResetPasswordEndToEndTests.swift index b93e1dd47f..f562ef438e 100644 --- a/MSAL/test/integration/native_auth/end_to_end/reset_password/MSALNativeAuthResetPasswordEndToEndTests.swift +++ b/MSAL/test/integration/native_auth/end_to_end/reset_password/MSALNativeAuthResetPasswordEndToEndTests.swift @@ -79,4 +79,69 @@ final class MSALNativeAuthResetPasswordEndToEndTests: MSALNativeAuthEndToEndBase XCTAssertTrue(resetPasswordRequiredDelegate.onResetPasswordCompletedCalled) } + // SSPR - with automatic sign in + func test_resetPassword_withAutomaticSignIn_succeeds() async throws { + try XCTSkipIf(true) // TODO: Remove once we update to continuation_token + + let codeRequiredExp = expectation(description: "code required") + let resetPasswordStartDelegate = ResetPasswordStartDelegateSpy(expectation: codeRequiredExp) + + if usingMockAPI { + try await mockResponse(.ssprStartSuccess, endpoint: .resetPasswordStart) + } + + sut.resetPassword(username: usernameOTP, delegate: resetPasswordStartDelegate) + + await fulfillment(of: [codeRequiredExp], timeout: defaultTimeout) + XCTAssertTrue(resetPasswordStartDelegate.onResetPasswordCodeRequiredCalled) + XCTAssertEqual(resetPasswordStartDelegate.channelTargetType, .email) + XCTAssertFalse(resetPasswordStartDelegate.sentTo?.isEmpty ?? true) + XCTAssertNotNil(resetPasswordStartDelegate.codeLength) + + // Now submit the code... + + let passwordRequiredExp = expectation(description: "password required") + let resetPasswordVerifyDelegate = ResetPasswordVerifyCodeDelegateSpy(expectation: passwordRequiredExp) + + if usingMockAPI { + try await mockResponse(.ssprContinueSuccess, endpoint: .resetPasswordContinue) + } + + resetPasswordStartDelegate.newState?.submitCode(code: "1234", delegate: resetPasswordVerifyDelegate) + + await fulfillment(of: [passwordRequiredExp], timeout: defaultTimeout) + XCTAssertTrue(resetPasswordVerifyDelegate.onPasswordRequiredCalled) + + // Now submit the password... + let resetPasswordCompletedExp = expectation(description: "reset password completed") + let resetPasswordRequiredDelegate = ResetPasswordRequiredDelegateSpy(expectation: resetPasswordCompletedExp) + + if usingMockAPI { + try await mockResponse(.ssprSubmitSuccess, endpoint: .resetPasswordSubmit) + } + + resetPasswordVerifyDelegate.newPasswordRequiredState?.submitPassword(password: "password", delegate: resetPasswordRequiredDelegate) + + await fulfillment(of: [resetPasswordCompletedExp], timeout: defaultTimeout) + XCTAssertTrue(resetPasswordRequiredDelegate.onResetPasswordCompletedCalled) + + // Now sign in... + + let signInAfterResetPasswordExp = expectation(description: "sign in after reset password") + let signInAfterResetPasswordDelegate = SignInAfterResetPasswordDelegateSpy(expectation: signInAfterResetPasswordExp) + + if usingMockAPI { + try await mockResponse(.tokenSuccess, endpoint: .signInToken) + } + + resetPasswordRequiredDelegate.signInAfterResetPasswordState?.signIn(delegate: signInAfterResetPasswordDelegate) + + await fulfillment(of: [signInAfterResetPasswordExp], timeout: defaultTimeout) + XCTAssertTrue(signInAfterResetPasswordDelegate.onSignInCompletedCalled) + XCTAssertEqual(signInAfterResetPasswordDelegate.result?.account.username, usernameOTP) + XCTAssertNotNil(signInAfterResetPasswordDelegate.result?.idToken) + XCTAssertNil(signInAfterResetPasswordDelegate.result?.account.accountClaims) + XCTAssertEqual(signInAfterResetPasswordDelegate.result?.scopes[0], "openid") + XCTAssertEqual(signInAfterResetPasswordDelegate.result?.scopes[1], "offline_access") + } } diff --git a/MSAL/test/integration/native_auth/end_to_end/reset_password/ResetPasswordDelegateSpies.swift b/MSAL/test/integration/native_auth/end_to_end/reset_password/ResetPasswordDelegateSpies.swift index de8de96325..cd940e3cec 100644 --- a/MSAL/test/integration/native_auth/end_to_end/reset_password/ResetPasswordDelegateSpies.swift +++ b/MSAL/test/integration/native_auth/end_to_end/reset_password/ResetPasswordDelegateSpies.swift @@ -97,6 +97,7 @@ class ResetPasswordRequiredDelegateSpy: ResetPasswordRequiredDelegate { private(set) var onResetPasswordCompletedCalled = false private(set) var error: MSAL.PasswordRequiredError? private(set) var newPasswordRequiredState: MSAL.ResetPasswordRequiredState? + private(set) var signInAfterResetPasswordState: SignInAfterResetPasswordState? init(expectation: XCTestExpectation) { self.expectation = expectation @@ -111,9 +112,37 @@ class ResetPasswordRequiredDelegateSpy: ResetPasswordRequiredDelegate { expectation.fulfill() } - func onResetPasswordCompleted() { + func onResetPasswordCompleted(newState: SignInAfterResetPasswordState) { onResetPasswordCompletedCalled = true + signInAfterResetPasswordState = newState + + expectation.fulfill() + } +} + +class SignInAfterResetPasswordDelegateSpy: SignInAfterResetPasswordDelegate { + private let expectation: XCTestExpectation + private(set) var onSignInAfterResetPasswordErrorCalled = false + private(set) var error: SignInAfterResetPasswordError? + private(set) var onSignInCompletedCalled = false + private(set) var result: MSALNativeAuthUserAccountResult? + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + func onSignInAfterResetPasswordError(error: MSAL.SignInAfterResetPasswordError) { + onSignInCompletedCalled = true + self.error = error + + expectation.fulfill() + } + + func onSignInCompleted(result: MSALNativeAuthUserAccountResult) { + onSignInCompletedCalled = true + self.result = result + expectation.fulfill() } } diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift index 0f513cb326..40cc3776cc 100644 --- a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift @@ -57,7 +57,7 @@ final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativ let response: MSALNativeAuthResetPasswordPollCompletionResponse? = try await performTestSucceed() XCTAssertNotNil(response?.status) - XCTAssertNil(response?.signInSLT) + XCTAssertNil(response?.continuationToken) XCTAssertNil(response?.expiresIn) } @@ -71,7 +71,7 @@ final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativ let response: MSALNativeAuthResetPasswordPollCompletionResponse? = try await performTestSucceed() XCTAssertNotNil(response?.status) - XCTAssertNil(response?.signInSLT) + XCTAssertNil(response?.continuationToken) XCTAssertNil(response?.expiresIn) } @@ -85,7 +85,7 @@ final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativ let response: MSALNativeAuthResetPasswordPollCompletionResponse? = try await performTestSucceed() XCTAssertNotNil(response?.status) - XCTAssertNil(response?.signInSLT) + XCTAssertNil(response?.continuationToken) XCTAssertNil(response?.expiresIn) } @@ -99,7 +99,7 @@ final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativ let response: MSALNativeAuthResetPasswordPollCompletionResponse? = try await performTestSucceed() XCTAssertNotNil(response?.status) - XCTAssertNil(response?.signInSLT) + XCTAssertNil(response?.continuationToken) XCTAssertNil(response?.expiresIn) } diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift index 3fd4235947..42c515a535 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift @@ -51,7 +51,8 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { sut = .init(config: MSALNativeAuthConfigStubs.configuration, requestProvider: requestProviderMock, - responseValidator: validatorMock + responseValidator: validatorMock, + signInController: MSALNativeAuthControllerFactoryMock().signInController ) } @@ -302,7 +303,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordResendCodeValidatorHelper(exp) - let result = await sut.resendCode(passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.resendCode(username: "", passwordResetToken: "passwordResetToken", context: contextMock) helper.onResetPasswordResendCodeError(result) await fulfillment(of: [exp]) @@ -324,7 +325,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordResendCodeValidatorHelper(exp) - let result = await sut.resendCode(passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.resendCode(username: "", passwordResetToken: "passwordResetToken", context: contextMock) result.telemetryUpdate?(.success(())) helper.onResetPasswordResendCodeRequired(result) @@ -354,7 +355,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordResendCodeValidatorHelper(exp) - let result = await sut.resendCode(passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.resendCode(username: "", passwordResetToken: "passwordResetToken", context: contextMock) helper.onResetPasswordResendCodeError(result) await fulfillment(of: [exp]) @@ -375,7 +376,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordResendCodeValidatorHelper(exp) - let result = await sut.resendCode(passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.resendCode(username: "", passwordResetToken: "passwordResetToken", context: contextMock) helper.onResetPasswordResendCodeError(result) await fulfillment(of: [exp]) @@ -396,7 +397,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordResendCodeValidatorHelper(exp) - let result = await sut.resendCode(passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.resendCode(username: "", passwordResetToken: "passwordResetToken", context: contextMock) helper.onResetPasswordResendCodeError(result) await fulfillment(of: [exp]) @@ -418,7 +419,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode(code: "1234", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.submitCode(code: "1234", username: "", passwordResetToken: "passwordResetToken", context: contextMock) helper.onResetPasswordVerifyCodeError(result) await fulfillment(of: [exp]) @@ -438,7 +439,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode(code: "1234", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.submitCode(code: "1234", username: "", passwordResetToken: "passwordResetToken", context: contextMock) result.telemetryUpdate?(.success(())) helper.onPasswordRequired(result) @@ -459,7 +460,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode(code: "1234", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.submitCode(code: "1234", username: "", passwordResetToken: "passwordResetToken", context: contextMock) helper.onResetPasswordVerifyCodeError(result) await fulfillment(of: [exp]) @@ -487,7 +488,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode(code: "1234", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.submitCode(code: "1234", username: "", passwordResetToken: "passwordResetToken", context: contextMock) helper.onResetPasswordVerifyCodeError(result) await fulfillment(of: [exp]) @@ -507,7 +508,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode(code: "1234", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.submitCode(code: "1234", username: "", passwordResetToken: "passwordResetToken", context: contextMock) helper.onResetPasswordVerifyCodeError(result) await fulfillment(of: [exp]) @@ -528,7 +529,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -545,12 +546,12 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() - validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .succeeded)) + validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .succeeded, continuationToken: nil)) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) result.telemetryUpdate?(.success(())) helper.onResetPasswordCompleted(result) @@ -577,7 +578,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -604,7 +605,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -623,7 +624,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -647,7 +648,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -668,7 +669,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -698,7 +699,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -728,7 +729,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -746,14 +747,14 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() - validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .notStarted)) + validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .notStarted, continuationToken: "")) prepareMockRequestsForPollCompletionRetries(5) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -769,14 +770,14 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() - validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .failed)) + validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .failed, continuationToken: "")) prepareMockRequestsForPollCompletionRetries(5) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -792,14 +793,14 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() - validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .inProgress)) + validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .inProgress, continuationToken: "")) prepareMockRequestsForPollCompletionRetries(5) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -809,6 +810,55 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) } + // MARK: - Sign-in with continuationToken + + func test_whenResetPasswordSucceeds_and_userCallsSignInWithContinuationToken_ResetPasswordControllerPassesCorrectParams() async { + let username = "username" + let continuationToken = "continuationToken" + + class SignInAfterResetPasswordDelegateStub: SignInAfterResetPasswordDelegate { + func onSignInAfterResetPasswordError(error: MSAL.SignInAfterResetPasswordError) {} + } + + let signInControllerMock = MSALNativeAuthSignInControllerMock() + + sut = .init( + config: MSALNativeAuthConfigStubs.configuration, + requestProvider: requestProviderMock, + responseValidator: validatorMock, + signInController: signInControllerMock + ) + + requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() + validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() + validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .succeeded, continuationToken: continuationToken)) + + let exp = expectation(description: "ResetPasswordController expectation") + let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) + + let result = await sut.submitPassword(password: "password", username: username, passwordSubmitToken: "passwordSubmitToken", context: contextMock) + result.telemetryUpdate?(.success(())) + + helper.onResetPasswordCompleted(result) + + await fulfillment(of: [exp], timeout: 1) + XCTAssertTrue(helper.onResetPasswordCompletedCalled) + + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: true) + + let exp2 = expectation(description: "SignInAfterResetPassword expectation") + signInControllerMock.expectation = exp2 + signInControllerMock.signInSLTResult = .init(.failure(.init())) + + helper.signInAfterResetPasswordState?.signIn(delegate: SignInAfterResetPasswordDelegateStub()) + await fulfillment(of: [exp2], timeout: 1) + + XCTAssertEqual(signInControllerMock.username, username) + XCTAssertEqual(signInControllerMock.slt, continuationToken) + } // MARK: - Common Methods diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift index 7970b41981..a71bcd8a4e 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift @@ -37,15 +37,15 @@ class MSALNativeAuthResetPasswordControllerMock: MSALNativeAuthResetPasswordCont return resetPasswordResponse } - func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { + func resendCode(username: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { return resendCodeResponse } - func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse { + func submitCode(code: String, username: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse { return submitCodeResponse } - func submitPassword(password: String, passwordSubmitToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitPasswordControllerResponse { + func submitPassword(password: String, username: String, passwordSubmitToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitPasswordControllerResponse { return submitPasswordResponse } } diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift index d06b205c2e..ac1d78c0fd 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift @@ -33,7 +33,7 @@ class MSALNativeAuthSignInControllerMock: MSALNativeAuthSignInControlling { var signInPasswordStartResult: MSALNativeAuthSignInControlling.SignInPasswordControllerResponse! var signInStartResult: MSALNativeAuthSignInControlling.SignInCodeControllerResponse! - var signInSLTResult: SignInAfterSignUpControllerResponse! + var signInSLTResult: SignInAfterPreviousFlowControllerResponse! var submitCodeResult: SignInSubmitCodeControllerResponse! var submitPasswordResult: SignInSubmitPasswordControllerResponse! var resendCodeResult: SignInResendCodeControllerResponse! @@ -46,7 +46,7 @@ class MSALNativeAuthSignInControllerMock: MSALNativeAuthSignInControlling { return signInStartResult } - func signIn(username: String, slt: String?, scopes: [String]?, context: MSAL.MSALNativeAuthRequestContext) async -> SignInAfterSignUpControllerResponse { + func signIn(username: String, slt: String?, scopes: [String]?, context: MSAL.MSALNativeAuthRequestContext) async -> SignInAfterPreviousFlowControllerResponse { self.username = username self.slt = slt expectation?.fulfill() diff --git a/MSAL/test/unit/native_auth/mock/ResetPasswordDelegateSpies.swift b/MSAL/test/unit/native_auth/mock/ResetPasswordDelegateSpies.swift index 14fb952b63..220963f23d 100644 --- a/MSAL/test/unit/native_auth/mock/ResetPasswordDelegateSpies.swift +++ b/MSAL/test/unit/native_auth/mock/ResetPasswordDelegateSpies.swift @@ -189,6 +189,7 @@ class ResetPasswordRequiredDelegateSpy: ResetPasswordRequiredDelegate { private(set) var onResetPasswordCompletedCalled = false private(set) var error: PasswordRequiredError? private(set) var newPasswordRequiredState: ResetPasswordRequiredState? + private(set) var signInAfterResetPasswordState: SignInAfterResetPasswordState? init(expectation: XCTestExpectation? = nil) { self.expectation = expectation @@ -204,8 +205,9 @@ class ResetPasswordRequiredDelegateSpy: ResetPasswordRequiredDelegate { expectation?.fulfill() } - func onResetPasswordCompleted() { + func onResetPasswordCompleted(newState: SignInAfterResetPasswordState) { onResetPasswordCompletedCalled = true + signInAfterResetPasswordState = newState XCTAssertTrue(Thread.isMainThread) expectation?.fulfill() @@ -229,3 +231,20 @@ class ResetPasswordRequiredDelegateOptionalMethodsNotImplemented: ResetPasswordR expectation?.fulfill() } } + +class SignInAfterResetPasswordDelegateOptionalMethodsNotImplemented: SignInAfterResetPasswordDelegate { + + private let expectation: XCTestExpectation + var expectedError: SignInAfterResetPasswordError? + + init(expectation: XCTestExpectation, expectedError: SignInAfterResetPasswordError? = nil) { + self.expectation = expectation + self.expectedError = expectedError + } + + public func onSignInAfterResetPasswordError(error: MSAL.SignInAfterResetPasswordError) { + XCTAssertEqual(error.errorDescription, expectedError?.errorDescription) + XCTAssertTrue(Thread.isMainThread) + expectation.fulfill() + } +} diff --git a/MSAL/test/unit/native_auth/mock/ResetPasswordTestValidatorHelpers.swift b/MSAL/test/unit/native_auth/mock/ResetPasswordTestValidatorHelpers.swift index 63151f6f8c..7da32d8e20 100644 --- a/MSAL/test/unit/native_auth/mock/ResetPasswordTestValidatorHelpers.swift +++ b/MSAL/test/unit/native_auth/mock/ResetPasswordTestValidatorHelpers.swift @@ -104,11 +104,11 @@ class ResetPasswordRequiredTestsValidatorHelper: ResetPasswordRequiredDelegateSp } func onResetPasswordCompleted(_ input: MSALNativeAuthResetPasswordController.ResetPasswordSubmitPasswordControllerResponse) { - guard case .completed = input.result else { + guard case let .completed(newState) = input.result else { expectation?.fulfill() return XCTFail("should be .success") } - Task { await self.onResetPasswordCompleted() } + Task { await self.onResetPasswordCompleted(newState: newState) } } } diff --git a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift index 05ff81b91a..af7a531e65 100644 --- a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift +++ b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift @@ -336,6 +336,38 @@ open class SignInAfterSignUpDelegateSpy: SignInAfterSignUpDelegate { } } +class SignInAfterResetPasswordDelegateSpy: SignInAfterResetPasswordDelegate { + private let expectation: XCTestExpectation + var expectedError: SignInAfterResetPasswordError? + var expectedUserAccountResult: MSALNativeAuthUserAccountResult? + private(set) var onSignInCompletedCalled = false + + init(expectation: XCTestExpectation, expectedError: SignInAfterResetPasswordError? = nil, expectedUserAccountResult: MSALNativeAuthUserAccountResult? = nil) { + self.expectation = expectation + self.expectedError = expectedError + self.expectedUserAccountResult = expectedUserAccountResult + } + + func onSignInAfterResetPasswordError(error: SignInAfterResetPasswordError) { + XCTAssertEqual(error.errorDescription, expectedError?.errorDescription) + XCTAssertTrue(Thread.isMainThread) + expectation.fulfill() + } + + public func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) { + onSignInCompletedCalled = true + guard let expectedUserAccountResult = expectedUserAccountResult else { + XCTFail("expectedUserAccount expected not nil") + expectation.fulfill() + return + } + XCTAssertEqual(expectedUserAccountResult.idToken, result.idToken) + XCTAssertEqual(expectedUserAccountResult.scopes, result.scopes) + XCTAssertTrue(Thread.isMainThread) + expectation.fulfill() + } +} + final class SignInAfterSignUpDelegateOptionalMethodsNotImplemented: SignInAfterSignUpDelegate { private let expectation: XCTestExpectation diff --git a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift index 33a4d1dd4e..2ca3c5af24 100644 --- a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift +++ b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift @@ -34,6 +34,7 @@ class MSALNativeAuthResetPasswordControllerSpy: MSALNativeAuthResetPasswordContr private(set) var resendCodeCalled = false private(set) var submitCodeCalled = false private(set) var submitPasswordCalled = false + private(set) var username = "" init(expectation: XCTestExpectation) { self.expectation = expectation @@ -47,8 +48,9 @@ class MSALNativeAuthResetPasswordControllerSpy: MSALNativeAuthResetPasswordContr return .init(.error(.init(type: .generalError))) } - func resendCode(passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { + func resendCode(username: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { self.flowToken = passwordResetToken + self.username = username self.context = context resendCodeCalled = true expectation.fulfill() @@ -56,8 +58,9 @@ class MSALNativeAuthResetPasswordControllerSpy: MSALNativeAuthResetPasswordContr return .init(.error(error: .init(), newState: nil)) } - func submitCode(code: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse { + func submitCode(code: String, username: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse { self.flowToken = passwordResetToken + self.username = username self.context = context submitCodeCalled = true expectation.fulfill() @@ -65,8 +68,9 @@ class MSALNativeAuthResetPasswordControllerSpy: MSALNativeAuthResetPasswordContr return .init(.error(error: .init(type: .generalError), newState: nil)) } - func submitPassword(password: String, passwordSubmitToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitPasswordControllerResponse { + func submitPassword(password: String, username: String, passwordSubmitToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitPasswordControllerResponse { self.flowToken = passwordSubmitToken + self.username = username self.context = context submitPasswordCalled = true expectation.fulfill() diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift index 8afc007709..b44ed52204 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift @@ -422,15 +422,16 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { // MARK: - Poll Completion Response func test_whenResetPasswordPollCompletionSuccessResponse_itReturnsSuccess() { - let response: Result = .success(.init(status: .succeeded, signInSLT: nil, expiresIn: nil)) + let response: Result = .success(.init(status: .succeeded, continuationToken: "continuationToken", expiresIn: nil)) let result = sut.validate(response, with: context) - guard case .success(let status) = result else { + guard case .success(let status, let continuationToken) = result else { return XCTFail("Unexpected response") } XCTAssertEqual(status, .succeeded) + XCTAssertEqual(continuationToken, "continuationToken") } func test_whenResetPasswordPollCompletionErrorResponseIsPasswordTooWeak_itReturnsExpectedError() { diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift index 002736f8e5..0f3b81beaa 100644 --- a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift +++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift @@ -106,28 +106,6 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { wait(for: [exp1, exp2]) - XCTAssertEqual(delegate.newState?.flowToken, "flowToken") - XCTAssertEqual(delegate.sentTo, "sentTo") - XCTAssertEqual(delegate.channelTargetType, .email) - XCTAssertEqual(delegate.codeLength, 1) - } - - func testSignUpPassword_whenNoAttributesAreSpecified_AttributesShouldBeNil() { - let exp = expectation(description: "sign-up public interface") - let delegate = SignUpPasswordStartDelegateSpy(expectation: exp) - - let expectedResult: SignUpPasswordStartResult = .codeRequired( - newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: UUID()), - sentTo: "sentTo", - channelTargetType: .email, - codeLength: 1 - ) - controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult) - - sut.signUpUsingPassword(username: "correct", password: "correct", delegate: delegate) - - wait(for: [exp]) - XCTAssertNil(controllerFactoryMock.signUpController.signUpStartRequestParameters?.attributes) XCTAssertNotNil(controllerFactoryMock.signUpController.signUpStartRequestParameters) } @@ -227,28 +205,6 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { wait(for: [exp, exp2]) - XCTAssertEqual(delegate.newState?.flowToken, "flowToken") - XCTAssertEqual(delegate.sentTo, "sentTo") - XCTAssertEqual(delegate.channelTargetType, .email) - XCTAssertEqual(delegate.codeLength, 1) - } - - func testSignUp_whenNoAttributesAreSpecified_AttributesShouldBeNil() { - let exp = expectation(description: "sign-up public interface") - let delegate = SignUpCodeStartDelegateSpy(expectation: exp) - - let expectedResult: SignUpStartResult = .codeRequired( - newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: UUID()), - sentTo: "sentTo", - channelTargetType: .email, - codeLength: 1 - ) - controllerFactoryMock.signUpController.startResult = .init(expectedResult) - - sut.signUp(username: "correct", delegate: delegate) - - wait(for: [exp]) - XCTAssertNil(controllerFactoryMock.signUpController.signUpStartRequestParameters?.attributes) XCTAssertNotNil(controllerFactoryMock.signUpController.signUpStartRequestParameters) } @@ -525,7 +481,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = ResetPasswordStartDelegateSpy(expectation: exp1) let expectedResult: ResetPasswordStartResult = .codeRequired( - newState: .init(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId), + newState: .init(controller: controllerFactoryMock.resetPasswordController, username: "username", flowToken: "flowToken", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -539,6 +495,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { wait(for: [exp1, exp2], timeout: 1) XCTAssertEqual(delegate.newState?.flowToken, "flowToken") + XCTAssertEqual(delegate.newState?.username, "username") XCTAssertEqual(delegate.sentTo, "sentTo") XCTAssertEqual(delegate.channelTargetType, .email) XCTAssertEqual(delegate.codeLength, 1) @@ -550,7 +507,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = ResetPasswordStartDelegateOptionalMethodsNotImplemented(expectation: exp) let expectedResult: ResetPasswordStartResult = .codeRequired( - newState: .init(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId), + newState: .init(controller: controllerFactoryMock.resetPasswordController, username: "username", flowToken: "flowToken", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -956,7 +913,9 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegatePasswordResetVerifyCode = ResetPasswordVerifyCodeDelegateSpy(expectation: expectationPasswordResetVerifyCode) let expectationPasswordResetRequired = expectation(description: "Password Reset Required") let delegatePasswordResetRequired = ResetPasswordRequiredDelegateSpy(expectation: expectationPasswordResetRequired) - + let expectationSignInAfterResetPassword = expectation(description: "Sign In After Reset Password") + let delegateSignInAfterResetPassword = SignInAfterResetPasswordDelegateSpy(expectation: expectationSignInAfterResetPassword) + let resetPasswordRequestProviderMock = MSALNativeAuthResetPasswordRequestProviderMock () resetPasswordRequestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) resetPasswordRequestProviderMock.expectedStartRequestParameters = expectedResetPasswordStartParams @@ -974,12 +933,53 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { resetPasswordResponseValidator.mockValidateResetPasswordChallengeFunc(.success("sentTo", .email, 4, "passwordResetToken 2")) resetPasswordResponseValidator.mockValidateResetPasswordContinueFunc(.success(passwordSubmitToken: "passwordSubmitToken")) resetPasswordResponseValidator.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken 3", pollInterval: 0)) - resetPasswordResponseValidator.mockValidateResetPasswordPollCompletionFunc(.success(status: .succeeded)) - + resetPasswordResponseValidator.mockValidateResetPasswordPollCompletionFunc(.success(status: .succeeded, continuationToken: "slt")) + + let expectedUsername = "username" + let expectedScopes = "scope1 scope2 openid profile offline_access" + + let tokenResult = MSIDTokenResult() + tokenResult.rawIdToken = "idToken" + let cacheAccessorMock = MSALNativeAuthCacheAccessorMock() + cacheAccessorMock.expectedMSIDTokenResult = tokenResult + + let tokenRequestProviderMock = MSALNativeAuthTokenRequestProviderMock() + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: expectedUsername, credentialToken: nil, signInSLT: "slt", grantType: .slt, scope: expectedScopes, password: nil, oobCode: nil, includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedContext = contextMock + tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) + + let tokenResponse = MSIDCIAMTokenResponse() + tokenResponse.accessToken = "accessToken" + tokenResponse.scope = "openid profile email" + tokenResponse.idToken = "idToken" + tokenResponse.refreshToken = "refreshToken" + + let tokenResponseValidatorMock = MSALNativeAuthTokenResponseValidatorMock() + tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) + + let authResultFactoryMock = MSALNativeAuthResultFactoryMock() + let userAccountResult = MSALNativeAuthUserAccountResult(account: MSALNativeAuthUserAccountResultStub.account, + authTokens: MSALNativeAuthTokens(accessToken: nil, + refreshToken: nil, + rawIdToken: nil), + configuration: MSALNativeAuthConfigStubs.configuration, + cacheAccessor: MSALNativeAuthCacheAccessorMock()) + authResultFactoryMock.mockMakeUserAccountResult(userAccountResult) + delegateSignInAfterResetPassword.expectedUserAccountResult = userAccountResult + + let signInAfterResetPasswordController = MSALNativeAuthSignInController(clientId: clientId, + signInRequestProvider: MSALNativeAuthSignInRequestProviderMock(), + tokenRequestProvider: tokenRequestProviderMock, + cacheAccessor: cacheAccessorMock, + factory: authResultFactoryMock, + signInResponseValidator: MSALNativeAuthSignInResponseValidatorMock(), + tokenResponseValidator: tokenResponseValidatorMock) + let resetPasswordController = MSALNativeAuthResetPasswordController(config: configuration, requestProvider: resetPasswordRequestProviderMock, - responseValidator: resetPasswordResponseValidator) - + responseValidator: resetPasswordResponseValidator, + signInController: signInAfterResetPasswordController) + let controllerFactory = MSALNativeAuthControllerProtocolFactoryMock(resetPasswordController: resetPasswordController) sut = MSALNativeAuthPublicClientApplication( @@ -1009,6 +1009,15 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { wait(for: [expectationPasswordResetRequired]) XCTAssertTrue(delegatePasswordResetRequired.onResetPasswordCompletedCalled) + + // Correlation Id is validated internally against expectedTokenParams in the + // MSALNativeAuthTokenRequestProviderMock class - checkContext function + delegatePasswordResetRequired.signInAfterResetPasswordState?.signIn(scopes: ["scope1", "scope2"], delegate: delegateSignInAfterResetPassword) + wait(for: [expectationSignInAfterResetPassword]) + + // User account result is validated internally against expectedUserAccountResult in the + // SignInAfterSignUpDelegateSpy class - onSignInCompleted function + XCTAssertTrue(delegateSignInAfterResetPassword.onSignInCompletedCalled) } private var expectedSignUpStartPasswordParams: MSALNativeAuthSignUpStartRequestProviderParameters { diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift index fd68911fcb..3d93a1bd5d 100644 --- a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift @@ -30,6 +30,8 @@ final class ResetPasswordRequiredDelegateDispatcherTests: XCTestCase { private var telemetryExp: XCTestExpectation! private var delegateExp: XCTestExpectation! private var sut: ResetPasswordRequiredDelegateDispatcher! + private let signInControllerMock = MSALNativeAuthSignInControllerMock() + private let correlationId = UUID() override func setUp() { super.setUp() @@ -47,11 +49,19 @@ final class ResetPasswordRequiredDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - await sut.dispatchResetPasswordCompleted() + let expectedState = SignInAfterResetPasswordState( + controller: signInControllerMock, + username: "username", + slt: "slt", + correlationId: correlationId + ) + + await sut.dispatchResetPasswordCompleted(newState: expectedState) await fulfillment(of: [telemetryExp, delegateExp]) XCTAssertTrue(delegate.onResetPasswordCompletedCalled) + XCTAssertEqual(delegate.signInAfterResetPasswordState, expectedState) } func test_dispatchPasswordRequired_whenDelegateOptionalMethodsNotImplemented() async { @@ -67,7 +77,14 @@ final class ResetPasswordRequiredDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - await sut.dispatchResetPasswordCompleted() + let expectedState = SignInAfterResetPasswordState( + controller: signInControllerMock, + username: "username", + slt: "slt", + correlationId: correlationId + ) + + await sut.dispatchResetPasswordCompleted(newState: expectedState) await fulfillment(of: [telemetryExp, delegateExp]) checkError(delegate.error) diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift index a97017cc97..664eee0e4a 100644 --- a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift @@ -49,7 +49,7 @@ final class ResetPasswordResendCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "", flowToken: "flowToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 @@ -82,7 +82,7 @@ final class ResetPasswordResendCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "", flowToken: "flowToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift index f3d9728802..242d797d82 100644 --- a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift @@ -49,7 +49,7 @@ final class ResetPasswordStartDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "username", flowToken: "flowToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 @@ -82,7 +82,7 @@ final class ResetPasswordStartDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "username", flowToken: "flowToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift index f22808ba69..78807a3b5d 100644 --- a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift @@ -49,7 +49,7 @@ final class ResetPasswordVerifyCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = ResetPasswordRequiredState(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "username", flowToken: "flowToken", correlationId: correlationId) await sut.dispatchPasswordRequired(newState: expectedState) @@ -71,7 +71,7 @@ final class ResetPasswordVerifyCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = ResetPasswordRequiredState(controller: controllerFactoryMock.resetPasswordController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "username", flowToken: "flowToken", correlationId: correlationId) await sut.dispatchPasswordRequired(newState: expectedState) diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/SignInAfterResetPasswordDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/SignInAfterResetPasswordDelegateDispatcherTests.swift new file mode 100644 index 0000000000..57cfefd442 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/SignInAfterResetPasswordDelegateDispatcherTests.swift @@ -0,0 +1,81 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class SignInAfterResetPasswordDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: SignInAfterResetPasswordDelegateDispatcher! + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchSignInCompleted_whenDelegateMethodsAreImplemented() async { + let expectedResult = MSALNativeAuthUserAccountResultStub.result + let delegate = SignInAfterResetPasswordDelegateSpy(expectation: delegateExp, expectedUserAccountResult: expectedResult) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + await sut.dispatchSignInCompleted(result: expectedResult) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.expectedUserAccountResult, expectedResult) + } + + func test_dispatchSignInCompleted_whenDelegateOptionalMethodsNotImplemented() async { + let expectedError = SignInAfterResetPasswordError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted")) + let delegate = SignInAfterResetPasswordDelegateOptionalMethodsNotImplemented(expectation: delegateExp, expectedError: expectedError) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? SignInAfterResetPasswordError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedResult = MSALNativeAuthUserAccountResultStub.result + + await sut.dispatchSignInCompleted(result: expectedResult) + + await fulfillment(of: [telemetryExp, delegateExp]) + + func checkError(_ error: SignInAfterResetPasswordError?) { + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInAfterSignUpDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInAfterSignUpDelegateDispatcherTests.swift new file mode 100644 index 0000000000..c01727ef48 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInAfterSignUpDelegateDispatcherTests.swift @@ -0,0 +1,82 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@testable import MSAL +import XCTest + +final class SignInAfterSignUpDelegateDispatcherTests: XCTestCase { + + private var telemetryExp: XCTestExpectation! + private var delegateExp: XCTestExpectation! + private var sut: SignInAfterSignUpDelegateDispatcher! + + override func setUp() { + super.setUp() + telemetryExp = expectation(description: "delegateDispatcher telemetry exp") + delegateExp = expectation(description: "delegateDispatcher delegate exp") + } + + func test_dispatchSignInCompleted_whenDelegateMethodsAreImplemented() async { + let expectedResult = MSALNativeAuthUserAccountResultStub.result + let delegate = SignInAfterSignUpDelegateSpy(expectation: delegateExp, expectedUserAccountResult: expectedResult) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case .success = result else { + return XCTFail("wrong result") + } + self.telemetryExp.fulfill() + }) + + await sut.dispatchSignInCompleted(result: expectedResult) + + await fulfillment(of: [telemetryExp, delegateExp]) + + XCTAssertEqual(delegate.expectedUserAccountResult, expectedResult) + } + + func test_dispatchSignInCompleted_whenDelegateOptionalMethodsNotImplemented() async { + let expectedError = SignInAfterSignUpError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted")) + let delegate = SignInAfterSignUpDelegateOptionalMethodsNotImplemented(expectation: delegateExp, expectedError: expectedError) + + sut = .init(delegate: delegate, telemetryUpdate: { result in + guard case let .failure(error) = result, let customError = error as? SignInAfterSignUpError else { + return XCTFail("wrong result") + } + + checkError(customError) + self.telemetryExp.fulfill() + }) + + let expectedResult = MSALNativeAuthUserAccountResultStub.result + + await sut.dispatchSignInCompleted(result: expectedResult) + + await fulfillment(of: [telemetryExp, delegateExp]) + checkError(delegate.expectedError) + + func checkError(_ error: SignInAfterSignUpError?) { + XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) + } + } +} diff --git a/MSAL/test/unit/native_auth/public/error/SignInAfterResetPasswordErrorTests.swift b/MSAL/test/unit/native_auth/public/error/SignInAfterResetPasswordErrorTests.swift new file mode 100644 index 0000000000..b36ebdf1e6 --- /dev/null +++ b/MSAL/test/unit/native_auth/public/error/SignInAfterResetPasswordErrorTests.swift @@ -0,0 +1,42 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class SignInAfterResetPasswordErrorTests: XCTestCase { + + private var sut: SignInAfterResetPasswordError! + + func test_customErrorDescription() { + let expectedMessage = "Custom error message" + sut = .init(message: expectedMessage) + XCTAssertEqual(sut.errorDescription, expectedMessage) + } + + func test_defaultErrorDescription() { + sut = .init() + XCTAssertEqual(sut.errorDescription, MSALNativeAuthErrorMessage.generalError) + } +} diff --git a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift index ec15718b45..a8b849af51 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift @@ -36,7 +36,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { try super.setUpWithError() controller = .init() - sut = ResetPasswordCodeRequiredState(controller: controller, flowToken: "", correlationId: correlationId) + sut = ResetPasswordCodeRequiredState(controller: controller, username: "username", flowToken: "", correlationId: correlationId) } // MARK: - Delegates @@ -45,7 +45,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { func test_resendCode_delegate_whenError_shouldReturnCorrectError() { let expectedError = ResendCodeError(message: "test error") - let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controller, username: "", flowToken: "flowToken", correlationId: correlationId) let expectedResult: ResetPasswordResendCodeResult = .error(error: expectedError, newState: expectedState) controller.resendCodeResponse = .init(expectedResult) @@ -63,7 +63,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { func test_resendCode_delegate_success_shouldReturnCodeRequired() { let exp = expectation(description: "reset password states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: ResetPasswordResendCodeResult = .codeRequired( newState: expectedState, @@ -89,7 +89,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { func test_resendCode_delegate_success_whenOptionalMethodNotImplemented_shouldReturnCorrectError() { let exp = expectation(description: "reset password states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: ResetPasswordResendCodeResult = .codeRequired( newState: expectedState, @@ -113,7 +113,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { func test_submitCode_delegate_whenError_shouldReturnCorrectError() { let expectedError = VerifyCodeError(type: .invalidCode) - let expectedState = ResetPasswordCodeRequiredState(controller: controller, flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controller, username: "", flowToken: "flowToken", correlationId: correlationId) let expectedResult: ResetPasswordSubmitCodeResult = .error(error: expectedError, newState: expectedState) controller.submitCodeResponse = .init(expectedResult) @@ -131,7 +131,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { func test_submitCode_delegate_success_shouldReturnPasswordRequired() { let exp = expectation(description: "reset password states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = ResetPasswordRequiredState(controller: controller, flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = ResetPasswordRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: ResetPasswordSubmitCodeResult = .passwordRequired(newState: expectedState) controller.submitCodeResponse = .init(expectedResult, telemetryUpdate: { _ in @@ -149,7 +149,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { func test_submitCode_delegate_success_whenOptionalMethodsNotImplemented_shouldReturnCorrectError() { let exp = expectation(description: "reset password states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = ResetPasswordRequiredState(controller: controller, flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = ResetPasswordRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) let expectedResult: ResetPasswordSubmitCodeResult = .passwordRequired(newState: expectedState) controller.submitCodeResponse = .init(expectedResult, telemetryUpdate: { _ in diff --git a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift index 55be810ebb..717200d92a 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift @@ -34,6 +34,7 @@ final class ResetPasswordRequiredStateTests: XCTestCase { private var controllerSpy: MSALNativeAuthResetPasswordControllerSpy! private var controllerMock: MSALNativeAuthResetPasswordControllerMock! private var sut: ResetPasswordRequiredState! + private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() func test_submitPassword_usesControllerSuccessfully() { exp = expectation(description: "ResetPasswordRequiredState expectation") @@ -41,20 +42,21 @@ final class ResetPasswordRequiredStateTests: XCTestCase { XCTAssertNil(controllerSpy.context) XCTAssertFalse(controllerSpy.submitPasswordCalled) - let sut = ResetPasswordRequiredState(controller: controllerSpy, flowToken: "", correlationId: correlationId) + let sut = ResetPasswordRequiredState(controller: controllerSpy, username: "username", flowToken: "", correlationId: correlationId) sut.submitPassword(password: "1234", delegate: ResetPasswordRequiredDelegateSpy()) wait(for: [exp], timeout: 1) XCTAssertEqual(controllerSpy.context?.correlationId(), correlationId) + XCTAssertEqual(controllerSpy.username, "username") XCTAssertTrue(controllerSpy.submitPasswordCalled) } func test_submitPassword_delegate_whenError_shouldReturnCorrectError() { controllerMock = MSALNativeAuthResetPasswordControllerMock() - let sut = ResetPasswordRequiredState(controller: controllerMock, flowToken: "", correlationId: correlationId) + let sut = ResetPasswordRequiredState(controller: controllerMock, username: "username", flowToken: "", correlationId: correlationId) let expectedError = PasswordRequiredError(type: .invalidPassword, message: nil) - let expectedState = ResetPasswordRequiredState(controller: controllerMock, flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordRequiredState(controller: controllerMock, username: "username", flowToken: "flowToken", correlationId: correlationId) let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.error(error: expectedError, newState: expectedState)) controllerMock.submitPasswordResponse = expectedResult @@ -73,9 +75,10 @@ final class ResetPasswordRequiredStateTests: XCTestCase { let exp = expectation(description: "reset password states") let exp2 = expectation(description: "telemetry expectation") controllerMock = MSALNativeAuthResetPasswordControllerMock() - let sut = ResetPasswordRequiredState(controller: controllerMock, flowToken: "", correlationId: correlationId) + let sut = ResetPasswordRequiredState(controller: controllerMock, username: "", flowToken: "", correlationId: correlationId) + let expectedState = SignInAfterResetPasswordState(controller: controllerFactoryMock.signInController, username: "", slt: nil, correlationId: correlationId) - let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.completed, telemetryUpdate: { _ in + let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.completed(expectedState), telemetryUpdate: { _ in exp2.fulfill() }) controllerMock.submitPasswordResponse = expectedResult @@ -86,15 +89,17 @@ final class ResetPasswordRequiredStateTests: XCTestCase { wait(for: [exp, exp2]) XCTAssertTrue(delegate.onResetPasswordCompletedCalled) + XCTAssertEqual(delegate.signInAfterResetPasswordState, expectedState) } func test_submitPassword_delegate_whenSuccess_butOptionalMethodsNotImplemented_shouldReturnCorrectError() { let exp = expectation(description: "reset password states") let exp2 = expectation(description: "telemetry expectation") controllerMock = MSALNativeAuthResetPasswordControllerMock() - let sut = ResetPasswordRequiredState(controller: controllerMock, flowToken: "", correlationId: correlationId) + let sut = ResetPasswordRequiredState(controller: controllerMock, username: "", flowToken: "", correlationId: correlationId) + let state = SignInAfterResetPasswordState(controller: controllerFactoryMock.signInController, username: "", slt: nil, correlationId: correlationId) - let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.completed, telemetryUpdate: { _ in + let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.completed(state), telemetryUpdate: { _ in exp2.fulfill() }) controllerMock.submitPasswordResponse = expectedResult From fdffc6b72bc7de2c69265167b43b13afe2396963 Mon Sep 17 00:00:00 2001 From: Olga Dalton Date: Tue, 19 Dec 2023 15:00:06 -0800 Subject: [PATCH 22/84] Update MacOS readme webviewparameters --- README.md | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 91fd23055d..78ef4ffb54 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,8 @@ let scopes = ["your-scope1-here", "your-scope2-here"] if let application = try? MSALPublicClientApplication(configuration: config) { - #if os(iOS) let viewController = ... // Pass a reference to the view controller that should be used when getting a token interactively let webviewParameters = MSALWebviewParameters(authPresentationViewController: viewController) - #else - let webviewParameters = MSALWebviewParameters() - #endif let interactiveParameters = MSALInteractiveTokenParameters(scopes: scopes, webviewParameters: webviewParameters) application.acquireToken(with: interactiveParameters, completionBlock: { (result, error) in @@ -51,12 +47,8 @@ NSArray *scopes = @[@"your-scope1-here", @"your-scope2-here"]; MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithConfiguration:config error:&msalError]; -#if TARGET_OS_IPHONE - UIViewController *viewController = ...; // Pass a reference to the view controller that should be used when getting a token interactively - MSALWebviewParameters *webParameters = [[MSALWebviewParameters alloc] initWithAuthPresentationViewController:viewController]; -#else - MSALWebviewParameters *webParameters = [MSALWebviewParameters new]; -#endif +MSALViewController *viewController = ...; // Pass a reference to the view controller that should be used when getting a token interactively +MSALWebviewParameters *webParameters = [[MSALWebviewParameters alloc] initWithAuthPresentationViewController:viewController]; MSALInteractiveTokenParameters *interactiveParams = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes webviewParameters:webParameters]; [application acquireTokenWithParameters:interactiveParams completionBlock:^(MSALResult *result, NSError *error) { @@ -242,12 +234,9 @@ MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] #### Swift ```swift -#if os(iOS) - let viewController = ... // Pass a reference to the view controller that should be used when getting a token interactively - let webviewParameters = MSALWebviewParameters(authPresentationViewController: viewController) -#else - let webviewParameters = MSALWebviewParameters() -#endif +let viewController = ... // Pass a reference to the view controller that should be used when getting a token interactively +let webviewParameters = MSALWebviewParameters(authPresentationViewController: viewController) + let interactiveParameters = MSALInteractiveTokenParameters(scopes: scopes, webviewParameters: webviewParameters) application.acquireToken(with: interactiveParameters, completionBlock: { (result, error) in @@ -262,16 +251,12 @@ application.acquireToken(with: interactiveParameters, completionBlock: { (result // You'll want to get the account identifier to retrieve and reuse the account for later acquireToken calls let accountIdentifier = authResult.account.identifier }) -``` +`` #### Objective-C ```obj-c -#if TARGET_OS_IPHONE - UIViewController *viewController = ...; // Pass a reference to the view controller that should be used when getting a token interactively - MSALWebviewParameters *webParameters = [[MSALWebviewParameters alloc] initWithAuthPresentationViewController:viewController]; -#else - MSALWebviewParameters *webParameters = [MSALWebviewParameters new]; -#endif +MSALViewController *viewController = ...; // Pass a reference to the view controller that should be used when getting a token interactively +MSALWebviewParameters *webParameters = [[MSALWebviewParameters alloc] initWithAuthPresentationViewController:viewController]; MSALInteractiveTokenParameters *interactiveParams = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes webviewParameters:webParameters]; [application acquireTokenWithParameters:interactiveParams completionBlock:^(MSALResult *result, NSError *error) { From 0eea246c5d91d8b37f7e94e176de35641377dd94 Mon Sep 17 00:00:00 2001 From: mipetriu Date: Wed, 20 Dec 2023 13:42:22 -0800 Subject: [PATCH 23/84] Updated qrPinAvailable to preferredAuthConfig --- MSAL/IdentityCore | 2 +- MSAL/src/MSALDeviceInformation.m | 12 ++++++------ MSAL/src/public/MSALDefinitions.h | 17 +++++++++++++---- MSAL/src/public/MSALDeviceInformation.h | 2 +- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 6ce851f7fe..620960a9d0 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 6ce851f7fe9a6cf83f482752aded1e8f1a72a7c7 +Subproject commit 620960a9d0be56feffc795296e0d1d7b23d73474 diff --git a/MSAL/src/MSALDeviceInformation.m b/MSAL/src/MSALDeviceInformation.m index b8a6b48cdc..e7adec0367 100644 --- a/MSAL/src/MSALDeviceInformation.m +++ b/MSAL/src/MSALDeviceInformation.m @@ -87,7 +87,7 @@ - (instancetype)initWithMSIDDeviceInfo:(MSIDDeviceInfo *)deviceInfo #if TARGET_OS_OSX _platformSSOStatus = [self msalPlatformSSOStatusFromMSIDPlatformSSOStatus:deviceInfo.platformSSOStatus]; #endif - _qrpinAvailable = [self msalQRPinAvailabilityFromMSIDQRPinAvailability:deviceInfo.qrPinAvailability]; + _preferredAuthConfiguration = [self msalPreferredAuthConfigurationFromMSIDPreferredAuthConfiguration:deviceInfo.preferredAuthConfig]; _extraDeviceInformation = [NSMutableDictionary new]; [self initExtraDeviceInformation:deviceInfo]; @@ -136,14 +136,14 @@ - (MSALPlatformSSOStatus)msalPlatformSSOStatusFromMSIDPlatformSSOStatus:(MSIDPla } } -- (MSALQRPinAvailability)msalQRPinAvailabilityFromMSIDQRPinAvailability:(MSIDQRPinAvailability)msidQRPinAvailability +- (MSALPreferredAuthConfiguration)msalPreferredAuthConfigurationFromMSIDPreferredAuthConfiguration:(MSIDPreferredAuthConfiguration)msidPreferredAuthConfig { - switch (msidQRPinAvailability) { - case MSIDQRPinAvailable: - return MSALQRPinAvailable; + switch (msidPreferredAuthConfig) { + case MSIDPreferredAuthConfigurationQRPIN: + return MSALPreferredAuthConfigurationQRPIN; default: - return MSALQRPinNotAvailable; + return MSALPreferredAuthConfigurationNotConfigured; } } diff --git a/MSAL/src/public/MSALDefinitions.h b/MSAL/src/public/MSALDefinitions.h index c413a6ec9a..7baf3a5db0 100644 --- a/MSAL/src/public/MSALDefinitions.h +++ b/MSAL/src/public/MSALDefinitions.h @@ -179,25 +179,34 @@ typedef NS_ENUM(NSUInteger, MSALPlatformSSOStatus) }; /** - Device mode configured by the administrator + Preferred auth method configuration determined by administrator */ -typedef NS_ENUM(NSUInteger, MSALQRPinAvailability) +typedef NS_ENUM(NSUInteger, MSALPreferredAuthConfiguration) { /* Administrator hasn't configured QR+PIN as an authentication method for this device. */ - MSALQRPinNotAvailable, + MSALPreferredAuthConfigurationNotConfigured, /* Administrator has configured QR+PIN as an authentication method for this device. */ - MSALQRPinAvailable + MSALPreferredAuthConfigurationQRPIN }; +/** + Preferred auth method to be passed to the authentication server + */ typedef NS_ENUM(NSUInteger, MSALPreferredAuthMethod) { + /* + No preferred auth method passed with the request to the authetication server. + */ MSALPreferredAuthMethodNone, + /* + QR+PIN preferred as the auth method. + */ MSALPreferredAuthMethodQRPIN }; diff --git a/MSAL/src/public/MSALDeviceInformation.h b/MSAL/src/public/MSALDeviceInformation.h index 90dc94aaf7..bd90f92160 100644 --- a/MSAL/src/public/MSALDeviceInformation.h +++ b/MSAL/src/public/MSALDeviceInformation.h @@ -72,7 +72,7 @@ NS_ASSUME_NONNULL_BEGIN /** Availability of QR+PIN as an authentication method as configured by the admin */ -@property (nonatomic, readonly) MSALQRPinAvailability qrpinAvailable; +@property (nonatomic, readonly) MSALPreferredAuthConfiguration preferredAuthConfiguration; /** Specifies whether AAD SSO extension was detected on the device. From 9ec275017171053c0e5b2a4547e9971c64566fcc Mon Sep 17 00:00:00 2001 From: Marcos Borges <116104275+borgesmb@users.noreply.github.com> Date: Thu, 21 Dec 2023 12:24:25 +0000 Subject: [PATCH 24/84] Added optional password parameter to signUp/signIn methods (#1942) * - Added optional password parameter to signUp/signIn methods - Removed SignUpUsingPassword method from public interface - Removed SignInUsingPassword method from public interface - Unified SignUpPasswordStartError and SignUpStartError - Unified SignUpPasswordStartError and SignUpStartError - Unified SignInStartDelegate and SignInPasswordStartDelegate - Unified SignUpStartDelegate and SignUpPasswordStartDelegate - Unified SignInPasswordStartResult and SignInStartResult - Unified SignUpPasswordStartResult and SignUpStartResult - Unified SignUpPasswordStartDelegateDispatcher and SignUpStartDelegateDispatcher - Unified SignInPasswordStartDelegateDispatcher and SignInStartDelegateDispatcher * - Fixed unit test. * - Fixed unit test. * address comments, remove duplicated code, update unit tests * delete unused public parameter classes * unify signIn with code and password controller methods, update unit tests * fix warnings * unify signUp methods, update unit tests * fix swiflint warnings * remove unused method * Update SignUpStartErrorTests.swift * Update SignUpStartErrorTests.swift --------- Co-authored-by: Danilo Raspa Co-authored-by: Sergei Demchenko --- MSAL/MSAL.xcodeproj/project.pbxproj | 109 +----------- .../controllers/responses/SignInResults.swift | 7 +- .../controllers/responses/SignUpResults.swift | 7 - .../MSALNativeAuthSignInController.swift | 156 +++++++----------- .../MSALNativeAuthSignInControlling.swift | 8 +- ...t => MSALNativeAuthSignInParameters.swift} | 5 +- ...tiveAuthSignInWithPasswordParameters.swift | 41 ----- .../MSALNativeAuthSignUpController.swift | 139 ++-------------- .../MSALNativeAuthSignUpControlling.swift | 7 +- ...tiveAuthSignUpChallengeResponseError.swift | 10 -- ...ALNativeAuthSignUpStartResponseError.swift | 22 +-- ...AuthSignInChallengeValidatedResponse.swift | 15 -- ...eAuthSignInInitiateValidatedResponse.swift | 2 +- ...MSALNativeAuthTokenValidatedResponse.swift | 18 +- ...AuthPublicClientApplication+Internal.swift | 70 ++------ ...SALNativeAuthPublicClientApplication.swift | 88 ++-------- .../parameters/MSALNativeAuthParameters.swift | 38 ----- .../MSALNativeAuthResendCodeParameters.swift | 37 ----- .../MSALNativeAuthSignInOTPParameters.swift | 38 ----- .../MSALNativeAuthSignInParameters.swift | 43 ----- .../MSALNativeAuthVerifyCodeParameters.swift | 40 ----- .../delegate/SignInDelegates.swift | 29 +--- .../delegate/SignUpDelegates.swift | 24 --- .../SignInDelegateDispatchers.swift | 41 ++--- .../SignUpDelegateDispatchers.swift | 30 ---- .../error/PasswordRequiredError.swift | 6 +- .../error/SignInPasswordStartError.swift | 83 ---------- .../error/SignInStartError.swift | 8 + .../error/SignUpPasswordStartError.swift | 83 ---------- .../error/SignUpStartError.swift | 8 + ...gnInUserNameAndPasswordEndToEndTests.swift | 6 +- .../sign_in/SignInDelegateSpies.swift | 6 +- .../MSALNativeAuthSignOutEndToEndTests.swift | 4 +- ...gnUpUsernameAndPasswordEndToEndTests.swift | 12 +- .../sign_up/SignUpDelegateSpies.swift | 6 +- .../MSALNativeAuthSignInControllerTests.swift | 64 +++---- .../MSALNativeAuthSignUpControllerTests.swift | 60 +++---- .../MSALNativeAuthSignInControllerMock.swift | 9 +- .../MSALNativeAuthSignUpControllerMock.swift | 10 +- .../MSALNativeAuthSignUpControllerSpy.swift | 6 +- .../mock/SignInDelegatesSpies.swift | 20 +-- .../mock/SignInTestsValidatorHelpers.swift | 12 +- .../mock/SignUpDelegateSpies.swift | 12 +- .../mock/SignUpTestsValidatorHelpers.swift | 14 +- ...uthSignUpChallengeResponseErrorTests.swift | 25 --- ...iveAuthSignUpStartResponseErrorTests.swift | 71 +------- ...ativeAuthPublicClientApplicationTest.swift | 64 +++---- ...tchAccessTokenRetrieveCompletedTests.swift | 2 - ...PasswordStartDelegateDispatcherTests.swift | 14 +- ...PasswordStartDelegateDispatcherTests.swift | 18 +- .../error/SignInPasswordStartErrorTests.swift | 97 ----------- .../public/error/SignInStartErrorTests.swift | 19 ++- .../error/SignUpPasswordStartErrorTests.swift | 97 ----------- .../public/error/SignUpStartErrorTests.swift | 17 +- 54 files changed, 355 insertions(+), 1522 deletions(-) rename MSAL/src/native_auth/controllers/sign_in/{MSALNativeAuthSignInWithCodeParameters.swift => MSALNativeAuthSignInParameters.swift} (92%) delete mode 100644 MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithPasswordParameters.swift delete mode 100644 MSAL/src/native_auth/public/parameters/MSALNativeAuthParameters.swift delete mode 100644 MSAL/src/native_auth/public/parameters/MSALNativeAuthResendCodeParameters.swift delete mode 100644 MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInOTPParameters.swift delete mode 100644 MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInParameters.swift delete mode 100644 MSAL/src/native_auth/public/parameters/MSALNativeAuthVerifyCodeParameters.swift delete mode 100644 MSAL/src/native_auth/public/state_machine/error/SignInPasswordStartError.swift delete mode 100644 MSAL/src/native_auth/public/state_machine/error/SignUpPasswordStartError.swift delete mode 100644 MSAL/test/unit/native_auth/public/error/SignInPasswordStartErrorTests.swift delete mode 100644 MSAL/test/unit/native_auth/public/error/SignUpPasswordStartErrorTests.swift diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index 77c5ca9b5d..b2ddfbbec3 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -239,18 +239,14 @@ 23F32F0C1FF4789100B2905E /* MSIDTestURLResponse+MSAL.m in Sources */ = {isa = PBXBuildFile; fileRef = 23F32F061FF4787600B2905E /* MSIDTestURLResponse+MSAL.m */; }; 23F32F0D1FF4789200B2905E /* MSIDTestURLResponse+MSAL.m in Sources */ = {isa = PBXBuildFile; fileRef = 23F32F061FF4787600B2905E /* MSIDTestURLResponse+MSAL.m */; }; 23FB5C1E22542B99002BF1EB /* MSALJsonDeserializable.h in Headers */ = {isa = PBXBuildFile; fileRef = 23FB5C1C22542B99002BF1EB /* MSALJsonDeserializable.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2814B4DA2A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2814B4D92A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift */; }; 2826932A2A0974750037B93A /* MSALNativeAuthTokenRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282693272A0974740037B93A /* MSALNativeAuthTokenRequestParameters.swift */; }; - 2826933B2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2826933A2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift */; }; + 2826933B2A0B98750037B93A /* MSALNativeAuthSignInParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2826933A2A0B98750037B93A /* MSALNativeAuthSignInParameters.swift */; }; 285F36082A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 285F36072A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift */; }; 2877081F2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2877081E2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift */; }; 287708222A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287708212A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift */; }; 287708252A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287708242A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift */; }; 287F64D4297EC29400ED90BD /* MSALNativeAuthTelemetryProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64D2297EC29400ED90BD /* MSALNativeAuthTelemetryProviderTests.swift */; }; 287F64D5297EC29400ED90BD /* MSALNativeAuthCurrentRequestTelemetryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64D3297EC29400ED90BD /* MSALNativeAuthCurrentRequestTelemetryTests.swift */; }; - 287F64D92981781A00ED90BD /* MSALNativeAuthSignInParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64D82981781A00ED90BD /* MSALNativeAuthSignInParameters.swift */; }; - 287F64E62981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64E52981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift */; }; - 287F64E92981786A00ED90BD /* MSALNativeAuthVerifyCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64E82981786A00ED90BD /* MSALNativeAuthVerifyCodeParameters.swift */; }; 287F64F0298186EA00ED90BD /* MSALNativeAuthInputValidatorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64EF298186EA00ED90BD /* MSALNativeAuthInputValidatorTest.swift */; }; 287F64F32981A00400ED90BD /* MSALNativeAuthPublicClientApplicationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F64F22981A00400ED90BD /* MSALNativeAuthPublicClientApplicationTest.swift */; }; 287F650C2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287F650B2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift */; }; @@ -259,7 +255,6 @@ 2884855C295DAFD400516492 /* MSALNativeAuthTokens.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2884855B295DAFD400516492 /* MSALNativeAuthTokens.swift */; }; 289747AC2979487900838C80 /* MSALNativeAuthUrlRequestSerializerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289747A92979487900838C80 /* MSALNativeAuthUrlRequestSerializerTests.swift */; }; 289747B129799C6B00838C80 /* MSALNativeAuthInputValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289747AF29799A8700838C80 /* MSALNativeAuthInputValidator.swift */; }; - 289747B42979A3C800838C80 /* MSALNativeAuthParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289747B32979A3C800838C80 /* MSALNativeAuthParameters.swift */; }; 289E15592948E601006104D9 /* MSALNativeAuthCacheInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289E15582948E601006104D9 /* MSALNativeAuthCacheInterface.swift */; }; 289E156D2948EB8A006104D9 /* MSALNativeAuthCacheAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289E156C2948EB8A006104D9 /* MSALNativeAuthCacheAccessor.swift */; }; 28A472EC2A276C3B003F988B /* MSALNativeAuthTokenValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28A472EB2A276C3B003F988B /* MSALNativeAuthTokenValidatedResponse.swift */; }; @@ -273,14 +268,12 @@ 28D5B05D2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D5B05C2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift */; }; 28DCD09229D7166F00C4601E /* SignUpDelegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD09129D7166F00C4601E /* SignUpDelegates.swift */; }; 28DCD09A29D7192F00C4601E /* MSALNativeAuthError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD09929D7192F00C4601E /* MSALNativeAuthError.swift */; }; - 28DCD09C29D71E7E00C4601E /* SignUpPasswordStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD09B29D71E7E00C4601E /* SignUpPasswordStartError.swift */; }; 28DCD0A029D7260B00C4601E /* MSALNativeAuthBaseState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD09F29D7260B00C4601E /* MSALNativeAuthBaseState.swift */; }; 28DCD0A229D7272300C4601E /* SignInDelegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0A129D7272300C4601E /* SignInDelegates.swift */; }; 28DCD0A429D72C7100C4601E /* SignUpStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0A329D72C7100C4601E /* SignUpStates.swift */; }; 28DCD0A629D72F6600C4601E /* PasswordRequiredError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0A529D72F6600C4601E /* PasswordRequiredError.swift */; }; 28DCD0A829D72F9A00C4601E /* AttributesRequiredError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0A729D72F9A00C4601E /* AttributesRequiredError.swift */; }; 28DCD0AA29D7344000C4601E /* SignInStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0A929D7344000C4601E /* SignInStates.swift */; }; - 28DCD0AC29D736BC00C4601E /* SignInPasswordStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0AB29D736BC00C4601E /* SignInPasswordStartError.swift */; }; 28DCD0AE29D737E600C4601E /* VerifyCodeError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0AD29D737E600C4601E /* VerifyCodeError.swift */; }; 28DCD0B029D738DD00C4601E /* ResetPasswordStartError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0AF29D738DD00C4601E /* ResetPasswordStartError.swift */; }; 28DCD0B229D7392400C4601E /* ResetPasswordStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28DCD0B129D7392400C4601E /* ResetPasswordStates.swift */; }; @@ -928,7 +921,6 @@ DE0D65C629D344F1005798B1 /* MSALNativeAuthSignInInitiateIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65C529D344F1005798B1 /* MSALNativeAuthSignInInitiateIntegrationTests.swift */; }; DE0D65CD29D5CE56005798B1 /* MSALNativeAuthSignInChallengeIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0D65CA29D5CD6D005798B1 /* MSALNativeAuthSignInChallengeIntegrationTests.swift */; }; DE0FECAC2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0FECAA2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift */; }; - DE0FECC72993ADAF00B139A8 /* MSALNativeAuthResendCodeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0FECC62993ADAE00B139A8 /* MSALNativeAuthResendCodeParameters.swift */; }; DE14096B2A38DE0E008E6F1E /* CredentialsDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE14096A2A38DE0E008E6F1E /* CredentialsDelegateSpies.swift */; }; DE14096D2A38DF41008E6F1E /* MSALNativeAuthCredentialsControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE14096C2A38DF40008E6F1E /* MSALNativeAuthCredentialsControllerTests.swift */; }; DE14D75D29897D8000F37BEF /* MSALNativeAuthTelemetryApiId.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D995296EC35A006CB384 /* MSALNativeAuthTelemetryApiId.swift */; }; @@ -1114,12 +1106,10 @@ E2CD2E8D2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2E8C2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift */; }; E2CD2EB32A040012009F8FFA /* SignUpTestsValidatorHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2EB22A040012009F8FFA /* SignUpTestsValidatorHelpers.swift */; }; E2CD2EB52A0404DA009F8FFA /* MSALNativeAuthSignUpControllerSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CD2EB42A0404DA009F8FFA /* MSALNativeAuthSignUpControllerSpy.swift */; }; - E2CE910A2B0BA37D0009AEDD /* SignUpPasswordStartErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE91092B0BA37D0009AEDD /* SignUpPasswordStartErrorTests.swift */; }; E2CE910C2B0BA3BB0009AEDD /* SignUpStartErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE910B2B0BA3BB0009AEDD /* SignUpStartErrorTests.swift */; }; E2CE910E2B0BA3D30009AEDD /* PasswordRequiredErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE910D2B0BA3D30009AEDD /* PasswordRequiredErrorTests.swift */; }; E2CE91102B0BA3E80009AEDD /* AttributesRequiredErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE910F2B0BA3E80009AEDD /* AttributesRequiredErrorTests.swift */; }; - E2CE91122B0BA3FC0009AEDD /* SignInPasswordStartErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE91112B0BA3FC0009AEDD /* SignInPasswordStartErrorTests.swift */; }; - E2CE91142B0BA40F0009AEDD /* SignInStartErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE91132B0BA40F0009AEDD /* SignInStartErrorTests.swift */; }; + E2CE91122B0BA3FC0009AEDD /* SignInStartErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE91112B0BA3FC0009AEDD /* SignInStartErrorTests.swift */; }; E2CE91162B0BA4490009AEDD /* VerifyCodeErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE91152B0BA4490009AEDD /* VerifyCodeErrorTests.swift */; }; E2CE91182B0BA4620009AEDD /* ResetPasswordStartErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE91172B0BA4620009AEDD /* ResetPasswordStartErrorTests.swift */; }; E2CE911A2B0BA4790009AEDD /* ResendCodeErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CE91192B0BA4790009AEDD /* ResendCodeErrorTests.swift */; }; @@ -1144,8 +1134,6 @@ E2F626A72A780F3D00C4A303 /* SignUpStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626A62A780F3D00C4A303 /* SignUpStates+Internal.swift */; }; E2F626AA2A780F8200C4A303 /* SignInStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626A92A780F8200C4A303 /* SignInStates+Internal.swift */; }; E2F626AD2A78119900C4A303 /* ResetPasswordStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AC2A78119900C4A303 /* ResetPasswordStates+Internal.swift */; }; - E2F626AE2A78119900C4A303 /* ResetPasswordStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AC2A78119900C4A303 /* ResetPasswordStates+Internal.swift */; }; - E2F626B12A78130700C4A303 /* SignInAfterSignUpState+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AF2A78130700C4A303 /* SignInAfterSignUpState+Internal.swift */; }; E2F626B02A78130700C4A303 /* SignInAfterPreviousFlowBaseState+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AF2A78130700C4A303 /* SignInAfterPreviousFlowBaseState+Internal.swift */; }; E2F626B32A781CE300C4A303 /* SignInDelegatesSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626B22A781CE300C4A303 /* SignInDelegatesSpies.swift */; }; /* End PBXBuildFile section */ @@ -1540,18 +1528,14 @@ 23F32F051FF4787600B2905E /* MSIDTestURLResponse+MSAL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MSIDTestURLResponse+MSAL.h"; sourceTree = ""; }; 23F32F061FF4787600B2905E /* MSIDTestURLResponse+MSAL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MSIDTestURLResponse+MSAL.m"; sourceTree = ""; }; 23FB5C1C22542B99002BF1EB /* MSALJsonDeserializable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALJsonDeserializable.h; sourceTree = ""; }; - 2814B4D92A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInWithPasswordParameters.swift; sourceTree = ""; }; 282693272A0974740037B93A /* MSALNativeAuthTokenRequestParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenRequestParameters.swift; sourceTree = ""; }; - 2826933A2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInWithCodeParameters.swift; sourceTree = ""; }; + 2826933A2A0B98750037B93A /* MSALNativeAuthSignInParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInParameters.swift; sourceTree = ""; }; 285F36072A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInControlling.swift; sourceTree = ""; }; 2877081E2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInChallengeValidatedResponse.swift; sourceTree = ""; }; 287708212A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthInternalChannelType.swift; sourceTree = ""; }; 287708242A178DC500E371ED /* MSALNativeAuthSignInInitiateValidatedResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInInitiateValidatedResponse.swift; sourceTree = ""; }; 287F64D2297EC29400ED90BD /* MSALNativeAuthTelemetryProviderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTelemetryProviderTests.swift; sourceTree = ""; }; 287F64D3297EC29400ED90BD /* MSALNativeAuthCurrentRequestTelemetryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCurrentRequestTelemetryTests.swift; sourceTree = ""; }; - 287F64D82981781A00ED90BD /* MSALNativeAuthSignInParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInParameters.swift; sourceTree = ""; }; - 287F64E52981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInOTPParameters.swift; sourceTree = ""; }; - 287F64E82981786A00ED90BD /* MSALNativeAuthVerifyCodeParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthVerifyCodeParameters.swift; sourceTree = ""; }; 287F64EF298186EA00ED90BD /* MSALNativeAuthInputValidatorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthInputValidatorTest.swift; sourceTree = ""; }; 287F64F22981A00400ED90BD /* MSALNativeAuthPublicClientApplicationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthPublicClientApplicationTest.swift; sourceTree = ""; }; 287F650B2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResponseSerializer.swift; sourceTree = ""; }; @@ -1560,7 +1544,6 @@ 2884855B295DAFD400516492 /* MSALNativeAuthTokens.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokens.swift; sourceTree = ""; }; 289747A92979487900838C80 /* MSALNativeAuthUrlRequestSerializerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthUrlRequestSerializerTests.swift; sourceTree = ""; }; 289747AF29799A8700838C80 /* MSALNativeAuthInputValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthInputValidator.swift; sourceTree = ""; }; - 289747B32979A3C800838C80 /* MSALNativeAuthParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthParameters.swift; sourceTree = ""; }; 289E15582948E601006104D9 /* MSALNativeAuthCacheInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCacheInterface.swift; sourceTree = ""; }; 289E156C2948EB8A006104D9 /* MSALNativeAuthCacheAccessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCacheAccessor.swift; sourceTree = ""; }; 28A472EB2A276C3B003F988B /* MSALNativeAuthTokenValidatedResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenValidatedResponse.swift; sourceTree = ""; }; @@ -1574,14 +1557,12 @@ 28D5B05C2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthControllerFactory.swift; sourceTree = ""; }; 28DCD09129D7166F00C4601E /* SignUpDelegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpDelegates.swift; sourceTree = ""; }; 28DCD09929D7192F00C4601E /* MSALNativeAuthError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthError.swift; sourceTree = ""; }; - 28DCD09B29D71E7E00C4601E /* SignUpPasswordStartError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpPasswordStartError.swift; sourceTree = ""; }; 28DCD09F29D7260B00C4601E /* MSALNativeAuthBaseState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthBaseState.swift; sourceTree = ""; }; 28DCD0A129D7272300C4601E /* SignInDelegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInDelegates.swift; sourceTree = ""; }; 28DCD0A329D72C7100C4601E /* SignUpStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpStates.swift; sourceTree = ""; }; 28DCD0A529D72F6600C4601E /* PasswordRequiredError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordRequiredError.swift; sourceTree = ""; }; 28DCD0A729D72F9A00C4601E /* AttributesRequiredError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributesRequiredError.swift; sourceTree = ""; }; 28DCD0A929D7344000C4601E /* SignInStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInStates.swift; sourceTree = ""; }; - 28DCD0AB29D736BC00C4601E /* SignInPasswordStartError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInPasswordStartError.swift; sourceTree = ""; }; 28DCD0AD29D737E600C4601E /* VerifyCodeError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifyCodeError.swift; sourceTree = ""; }; 28DCD0AF29D738DD00C4601E /* ResetPasswordStartError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordStartError.swift; sourceTree = ""; }; 28DCD0B129D7392400C4601E /* ResetPasswordStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordStates.swift; sourceTree = ""; }; @@ -1954,7 +1935,6 @@ DE0D65C529D344F1005798B1 /* MSALNativeAuthSignInInitiateIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInInitiateIntegrationTests.swift; sourceTree = ""; }; DE0D65CA29D5CD6D005798B1 /* MSALNativeAuthSignInChallengeIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInChallengeIntegrationTests.swift; sourceTree = ""; }; DE0FECAA2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResendCodeRequestResponse.swift; sourceTree = ""; }; - DE0FECC62993ADAE00B139A8 /* MSALNativeAuthResendCodeParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResendCodeParameters.swift; sourceTree = ""; }; DE14096A2A38DE0E008E6F1E /* CredentialsDelegateSpies.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CredentialsDelegateSpies.swift; sourceTree = ""; }; DE14096C2A38DF40008E6F1E /* MSALNativeAuthCredentialsControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCredentialsControllerTests.swift; sourceTree = ""; }; DE14D76029898CF900F37BEF /* MSALNativeAuthTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTestCase.swift; sourceTree = ""; }; @@ -2136,12 +2116,10 @@ E2CD2E8C2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpResponseValidator.swift; sourceTree = ""; }; E2CD2EB22A040012009F8FFA /* SignUpTestsValidatorHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpTestsValidatorHelpers.swift; sourceTree = ""; }; E2CD2EB42A0404DA009F8FFA /* MSALNativeAuthSignUpControllerSpy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpControllerSpy.swift; sourceTree = ""; }; - E2CE91092B0BA37D0009AEDD /* SignUpPasswordStartErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpPasswordStartErrorTests.swift; sourceTree = ""; }; E2CE910B2B0BA3BB0009AEDD /* SignUpStartErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpStartErrorTests.swift; sourceTree = ""; }; E2CE910D2B0BA3D30009AEDD /* PasswordRequiredErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordRequiredErrorTests.swift; sourceTree = ""; }; E2CE910F2B0BA3E80009AEDD /* AttributesRequiredErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributesRequiredErrorTests.swift; sourceTree = ""; }; - E2CE91112B0BA3FC0009AEDD /* SignInPasswordStartErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInPasswordStartErrorTests.swift; sourceTree = ""; }; - E2CE91132B0BA40F0009AEDD /* SignInStartErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInStartErrorTests.swift; sourceTree = ""; }; + E2CE91112B0BA3FC0009AEDD /* SignInStartErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInStartErrorTests.swift; sourceTree = ""; }; E2CE91152B0BA4490009AEDD /* VerifyCodeErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifyCodeErrorTests.swift; sourceTree = ""; }; E2CE91172B0BA4620009AEDD /* ResetPasswordStartErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordStartErrorTests.swift; sourceTree = ""; }; E2CE91192B0BA4790009AEDD /* ResendCodeErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResendCodeErrorTests.swift; sourceTree = ""; }; @@ -2347,8 +2325,7 @@ children = ( 285F36072A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift */, E206FCEE2979BC4600AF4400 /* MSALNativeAuthSignInController.swift */, - 2814B4D92A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift */, - 2826933A2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift */, + 2826933A2A0B98750037B93A /* MSALNativeAuthSignInParameters.swift */, ); path = sign_in; sourceTree = ""; @@ -2438,18 +2415,6 @@ path = input_validator; sourceTree = ""; }; - 289747B22979A3AD00838C80 /* parameters */ = { - isa = PBXGroup; - children = ( - 289747B32979A3C800838C80 /* MSALNativeAuthParameters.swift */, - 287F64D82981781A00ED90BD /* MSALNativeAuthSignInParameters.swift */, - 287F64E52981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift */, - DE0FECC62993ADAE00B139A8 /* MSALNativeAuthResendCodeParameters.swift */, - 287F64E82981786A00ED90BD /* MSALNativeAuthVerifyCodeParameters.swift */, - ); - path = parameters; - sourceTree = ""; - }; 28A3147029705B4500573AFF /* network */ = { isa = PBXGroup; children = ( @@ -2573,11 +2538,9 @@ isa = PBXGroup; children = ( 28DCD09929D7192F00C4601E /* MSALNativeAuthError.swift */, - 28DCD09B29D71E7E00C4601E /* SignUpPasswordStartError.swift */, 28EDF93D29E6D43900A99F2A /* SignUpStartError.swift */, 28DCD0A529D72F6600C4601E /* PasswordRequiredError.swift */, 28DCD0A729D72F9A00C4601E /* AttributesRequiredError.swift */, - 28DCD0AB29D736BC00C4601E /* SignInPasswordStartError.swift */, 28EDF94029E6D52E00A99F2A /* SignInStartError.swift */, 28DCD0AD29D737E600C4601E /* VerifyCodeError.swift */, 28DCD0AF29D738DD00C4601E /* ResetPasswordStartError.swift */, @@ -3877,7 +3840,6 @@ E22427F72B066F750006C55E /* SignInResendCodeDelegateDispatcherTests.swift */, E22427F32B066BBC0006C55E /* SignInStartDelegateDispatcherTests.swift */, E22427F92B0670600006C55E /* SignInVerifyCodeDelegateDispatcherTests.swift */, - E22428042B0674A50006C55E /* SignInAfterSignUpDelegateDispatcherTests.swift */, ); path = sign_in; sourceTree = ""; @@ -3946,7 +3908,6 @@ isa = PBXGroup; children = ( 28DCD08829D70FA000C4601E /* state_machine */, - 289747B22979A3AD00838C80 /* parameters */, E2DC31BB29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift */, E2F6269C2A780DDE00C4A303 /* MSALNativeAuthPublicClientApplication+Internal.swift */, DE729ECC2A1793A100A761D9 /* MSALNativeAuthChannelType.swift */, @@ -4160,28 +4121,13 @@ path = sign_up; sourceTree = ""; }; - E2CE91372B0D077C0009AEDD /* delegate_dispatcher */ = { - isa = PBXGroup; - children = ( - E22427D72B0588AD0006C55E /* DelegateDispatcher.swift */, - E22427C72B0526660006C55E /* SignUpDelegateDispatchers.swift */, - E22427D12B0577920006C55E /* SignInDelegateDispatchers.swift */, - E22427D42B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift */, - E22427DA2B0594670006C55E /* CredentialsDelegateDispatcher.swift */, - E22427DD2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift */, - ); - path = delegate_dispatcher; - sourceTree = ""; - }; E2CE91012B0BA34F0009AEDD /* error */ = { isa = PBXGroup; children = ( - E2CE91092B0BA37D0009AEDD /* SignUpPasswordStartErrorTests.swift */, E2CE910B2B0BA3BB0009AEDD /* SignUpStartErrorTests.swift */, E2CE910D2B0BA3D30009AEDD /* PasswordRequiredErrorTests.swift */, E2CE910F2B0BA3E80009AEDD /* AttributesRequiredErrorTests.swift */, - E2CE91112B0BA3FC0009AEDD /* SignInPasswordStartErrorTests.swift */, - E2CE91132B0BA40F0009AEDD /* SignInStartErrorTests.swift */, + E2CE91112B0BA3FC0009AEDD /* SignInStartErrorTests.swift */, E2CE91152B0BA4490009AEDD /* VerifyCodeErrorTests.swift */, E2CE91172B0BA4620009AEDD /* ResetPasswordStartErrorTests.swift */, E2CE91192B0BA4790009AEDD /* ResendCodeErrorTests.swift */, @@ -5361,20 +5307,8 @@ B2D47894230E3DEB005AE186 /* MSALOauth2Authority.m in Sources */, B273D0A3226E8576005A7BB4 /* MSALIndividualClaimRequest.m in Sources */, 04A6B5B4226937080035C7C2 /* MSALPromptType.m in Sources */, - DE0D65AD29CC6A5A005798B1 /* MSALNativeAuthSignInInitiateResponse.swift in Sources */, - E2C61FE229DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift in Sources */, - E22427DF2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift in Sources */, - DECC1F9729521E35006D9FB1 /* MSALLogMask.m in Sources */, - DE54B5922A434B9B00460B34 /* MSALNativeAuthTokenController.swift in Sources */, - E2C61FEB29DED8E000F15203 /* MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift in Sources */, - DE0347BD2A41B76E003CB3B6 /* MSALNativeAuthCredentialsControlling.swift in Sources */, - 9B4EE9DA2A1687B600F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift in Sources */, B2D478A7230E3E5A005AE186 /* MSALTelemetryEventsObservingProxy.m in Sources */, B2D478B3230E3E88005AE186 /* NSString+MSALAccountIdenfiers.m in Sources */, - 289747B7297ABEA300838C80 /* MSALNativeAuthInputValidator.swift in Sources */, - 285F36092A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift in Sources */, - E22427D92B0588AD0006C55E /* DelegateDispatcher.swift in Sources */, - 2814B4DB2A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift in Sources */, 04A6B5BD2269374D0035C7C2 /* MSALAccount.m in Sources */, 04A6B6092269382B0035C7C2 /* MSALAuthority.m in Sources */, 04A6B6162269383F0035C7C2 /* MSALOauth2ProviderFactory.m in Sources */, @@ -5388,10 +5322,6 @@ B273D0A7226E857B005A7BB4 /* MSALIndividualClaimRequestAdditionalInfo.m in Sources */, B2D478BD230E3EA8005AE186 /* MSALWebviewParameters.m in Sources */, 04A6B5AE226936F30035C7C2 /* MSALFramework.m in Sources */, - 9BD2763E2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift in Sources */, - E22427C92B0526660006C55E /* SignUpDelegateDispatchers.swift in Sources */, - E22427D32B0577920006C55E /* SignInDelegateDispatchers.swift in Sources */, - E2C61FEE29DEDA9500F15203 /* MSALNativeAuthSignUpContinueOauth2ErrorCode.swift in Sources */, B273D0C3226E85AA005A7BB4 /* MSALGlobalConfig.m in Sources */, B273D0DA226E85DB005A7BB4 /* MSALLoggerConfig.m in Sources */, B273D0CF226E85CC005A7BB4 /* MSALHTTPConfig.m in Sources */, @@ -5407,20 +5337,7 @@ B273D0EA226E85FF005A7BB4 /* MSALPublicClientStatusNotifications.m in Sources */, B273D0D5226E85D3005A7BB4 /* MSALTelemetryConfig.m in Sources */, 04A6B60C226938300035C7C2 /* MSALB2CAuthority.m in Sources */, - DE0347C22A41B80C003CB3B6 /* MSALNativeAuthVerifyCodeParameters.swift in Sources */, - 2826933C2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift in Sources */, - E22427DC2B0594670006C55E /* CredentialsDelegateDispatcher.swift in Sources */, - E2F626A82A780F3D00C4A303 /* SignUpStates+Internal.swift in Sources */, - E26097C42948FC4D0060DD7C /* MSALNativeAuthLogging.swift in Sources */, - E2C872C4294CDEE800C4F580 /* MSALNativeAuthRequestable.swift in Sources */, - 9BE7E3D62A1CF51500CC3A62 /* MSALNativeAuthResetPasswordValidatedResponses.swift in Sources */, - 28DE70D729FAC16700EB75AA /* MSALNativeAuthSignInResponseValidator.swift in Sources */, - E2C61FE829DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift in Sources */, B2D478B1230E3E88005AE186 /* MSALLegacySharedAccountFactory.m in Sources */, - 28F19BEC2A2F884D00575581 /* Array+joinScopes.swift in Sources */, - DE729ECE2A1793A100A761D9 /* MSALNativeAuthChannelType.swift in Sources */, - E22427D62B05886B0006C55E /* ResetPasswordDelegateDispatchers.swift in Sources */, - DEF9D98A296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift in Sources */, 2396EFDE2582D8B000ADA9EB /* MSALDeviceInfoProvider.m in Sources */, 1E5319C824A51FCE007BCF30 /* MSALHttpMethod.m in Sources */, 04A6B5CB226937700035C7C2 /* MSALError.m in Sources */, @@ -5668,7 +5585,6 @@ DEDB298B29D72D62008DA85B /* MSALNativeAuthInnerError.swift in Sources */, E2C61FE129DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift in Sources */, DEE34F75D170B71C00BC302A /* MSALNativeAuthResetPasswordContinueRequestParameters.swift in Sources */, - 28DCD0AC29D736BC00C4601E /* SignInPasswordStartError.swift in Sources */, B253153223DD684E00432133 /* MSALSSOExtensionRequestHandler.m in Sources */, 23B1D35F22EA4798000954AF /* MSALPublicClientApplicationConfig.m in Sources */, E2F626AD2A78119900C4A303 /* ResetPasswordStates+Internal.swift in Sources */, @@ -5701,7 +5617,6 @@ 04D32CAE1FD615B3000B123E /* MSALErrorConverter.m in Sources */, B26756D222921C6D000F01D7 /* MSALADFSOauth2Provider.m in Sources */, E26097C32948FC4D0060DD7C /* MSALNativeAuthLogging.swift in Sources */, - 2814B4DA2A0518B000AE0346 /* MSALNativeAuthSignInWithPasswordParameters.swift in Sources */, 232D614C2248484C00260C42 /* MSALClaimsRequest.m in Sources */, B203459621AF77FB00B221AA /* MSALRedirectUri.m in Sources */, DEE34F7BD170B71C00BC302A /* MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift in Sources */, @@ -5713,7 +5628,6 @@ 28DCD0B229D7392400C4601E /* ResetPasswordStates.swift in Sources */, 23A68A7620F5386A0071E435 /* MSALAADAuthority.m in Sources */, 28DCD09A29D7192F00C4601E /* MSALNativeAuthError.swift in Sources */, - 28DCD09C29D71E7E00C4601E /* SignUpPasswordStartError.swift in Sources */, 28FDC4A92A38C0D100E38BE1 /* SignInAfterSignUpError.swift in Sources */, 233E96FD22653EFC007FCE2A /* MSALTelemetryEventsObservingProxy.m in Sources */, DE0D65C229D30C38005798B1 /* MSALNativeAuthSignInInitiateOauth2ErrorCode.swift in Sources */, @@ -5740,8 +5654,7 @@ DEE34F65D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeResponse.swift in Sources */, D61BD2B01EBD09F90007E484 /* MSALPublicClientApplication.m in Sources */, DEDB29AD29DDAF53008DA85B /* MSALNativeAuthTokenResponseError.swift in Sources */, - 2826933B2A0B98750037B93A /* MSALNativeAuthSignInWithCodeParameters.swift in Sources */, - DE0FECC72993ADAF00B139A8 /* MSALNativeAuthResendCodeParameters.swift in Sources */, + 2826933B2A0B98750037B93A /* MSALNativeAuthSignInParameters.swift in Sources */, 28EDF94129E6D52E00A99F2A /* SignInStartError.swift in Sources */, D61BD2AD1EBD09F90007E484 /* MSALError.m in Sources */, DE54B5AD2A459B0400460B34 /* MSALNativeAuthTokenResponseValidator.swift in Sources */, @@ -5759,7 +5672,6 @@ DEDB29A529DDA9DC008DA85B /* MSALNativeAuthSignInInitiateResponseError.swift in Sources */, E243F6A629D206BC00DAC60F /* MSALNativeAuthSignUpContinueResponse.swift in Sources */, E224F74B2B18F891000A7B2E /* SignInAfterResetPasswordDelegateDispatcher.swift in Sources */, - 287F64D92981781A00ED90BD /* MSALNativeAuthSignInParameters.swift in Sources */, 96B5E6E22256D166002232F9 /* MSALTelemetryConfig.m in Sources */, 28DCD0A429D72C7100C4601E /* SignUpStates.swift in Sources */, DE0D65B929D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift in Sources */, @@ -5810,7 +5722,6 @@ DE03478A2A39ED6A003CB3B6 /* MSALCIAMOauth2Provider.m in Sources */, E205D62E29B783FF003887BC /* MSALNativeAuthConfiguration.swift in Sources */, D61BD2B21EBD09F90007E484 /* MSALAccount.m in Sources */, - 287F64E92981786A00ED90BD /* MSALNativeAuthVerifyCodeParameters.swift in Sources */, DE0D65B629CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift in Sources */, E2EFAD092A69A34300D6C3DE /* CodeRequiredGenericResult.swift in Sources */, E2EFAD0C2A69B45100D6C3DE /* SignUpResults.swift in Sources */, @@ -5818,7 +5729,6 @@ B266391C22B4B84600FEB673 /* NSString+MSALAccountIdenfiers.m in Sources */, DEE34F87D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponse.swift in Sources */, 96B5E6D02256D152002232F9 /* MSALCacheConfig.m in Sources */, - 287F64E62981784400ED90BD /* MSALNativeAuthSignInOTPParameters.swift in Sources */, E243F6A029D1FF9E00DAC60F /* MSALNativeAuthSignUpContinueRequestParameters.swift in Sources */, DEE34F5CD170B71C00BC302A /* MSALNativeAuthResetPasswordStartResponse.swift in Sources */, DEE34FA1D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift in Sources */, @@ -5832,7 +5742,6 @@ E2DC31C829B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift in Sources */, 28DCD0AE29D737E600C4601E /* VerifyCodeError.swift in Sources */, E22427C82B0526660006C55E /* SignUpDelegateDispatchers.swift in Sources */, - 289747B42979A3C800838C80 /* MSALNativeAuthParameters.swift in Sources */, E224F7472B18F29F000A7B2E /* SignInAfterResetPasswordDelegate.swift in Sources */, E2F626B02A78130700C4A303 /* SignInAfterPreviousFlowBaseState+Internal.swift in Sources */, E22427DE2B05981A0006C55E /* SignInAfterSignUpDelegateDispatcher.swift in Sources */, @@ -6002,7 +5911,6 @@ 9B2BBA372A3298080075F702 /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift in Sources */, B2725E7F22BD88BE009B454A /* NSStringAccountIdentifiersTest.m in Sources */, 287F64D4297EC29400ED90BD /* MSALNativeAuthTelemetryProviderTests.swift in Sources */, - E2CE910A2B0BA37D0009AEDD /* SignUpPasswordStartErrorTests.swift in Sources */, E22952682A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift in Sources */, E286E2DD2A1BAEA800666DD0 /* MSALNativeAuthSignUpControllerTests.swift in Sources */, B2725EC522BF4865009B454A /* MSALMockExternalAccountHandler.m in Sources */, @@ -6066,7 +5974,7 @@ E22427FA2B0670600006C55E /* SignInVerifyCodeDelegateDispatcherTests.swift in Sources */, E2EBD62A2A1BB7700049467A /* MSALNativeAuthSignUpResponseValidatorMock.swift in Sources */, E25BC0852995430B00588549 /* MSALNativeAuthFactoriesMocks.swift in Sources */, - E2CE91122B0BA3FC0009AEDD /* SignInPasswordStartErrorTests.swift in Sources */, + E2CE91122B0BA3FC0009AEDD /* SignInStartErrorTests.swift in Sources */, E2BC029C29D766CB00041DBC /* MSALNativeAuthSignUpContinueRequestParametersTest.swift in Sources */, E2960A112A1F4D2F000F441B /* MSALNativeAuthSignUpChallengeResponseErrorTests.swift in Sources */, DE94C9E629F19D9B00C1EC1F /* MSALNativeAuthResetPasswordSubmitRequestParametersTest.swift in Sources */, @@ -6078,7 +5986,6 @@ E2C1D2D429A3992100B26449 /* MSALNativeAuthBaseControllerTests.swift in Sources */, DE40A4CA2A8F801200928CEE /* MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift in Sources */, E23E956929D5BD6B001DC59C /* MSALNativeAuthSignUpRequestProviderTests.swift in Sources */, - E2CE91142B0BA40F0009AEDD /* SignInStartErrorTests.swift in Sources */, DE5738BE2A8F7AC600D9120D /* MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift in Sources */, 609AF9332256BD0C00E2978D /* MSALAccountsProviderTests.m in Sources */, E22428052B0674A50006C55E /* SignInAfterSignUpDelegateDispatcherTests.swift in Sources */, diff --git a/MSAL/src/native_auth/controllers/responses/SignInResults.swift b/MSAL/src/native_auth/controllers/responses/SignInResults.swift index 8115fb4349..5607cfb8b8 100644 --- a/MSAL/src/native_auth/controllers/responses/SignInResults.swift +++ b/MSAL/src/native_auth/controllers/responses/SignInResults.swift @@ -24,13 +24,8 @@ import Foundation -enum SignInPasswordStartResult { - case completed(MSALNativeAuthUserAccountResult) - case codeRequired(newState: SignInCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) - case error(SignInPasswordStartError) -} - enum SignInStartResult { + case completed(MSALNativeAuthUserAccountResult) case codeRequired(newState: SignInCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) case passwordRequired(newState: SignInPasswordRequiredState) case error(SignInStartError) diff --git a/MSAL/src/native_auth/controllers/responses/SignUpResults.swift b/MSAL/src/native_auth/controllers/responses/SignUpResults.swift index 7e4754e7fb..afc2c36247 100644 --- a/MSAL/src/native_auth/controllers/responses/SignUpResults.swift +++ b/MSAL/src/native_auth/controllers/responses/SignUpResults.swift @@ -24,13 +24,6 @@ import Foundation -enum SignUpPasswordStartResult { - - case codeRequired(newState: SignUpCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) - case attributesInvalid([String]) - case error(SignUpPasswordStartError) -} - enum SignUpStartResult { case codeRequired(newState: SignUpCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) case attributesInvalid([String]) diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift index d7ceb2e5f2..c205f3eb50 100644 --- a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift @@ -74,28 +74,12 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN // MARK: - Internal - func signIn(params: MSALNativeAuthSignInWithPasswordParameters) async -> SignInPasswordControllerResponse { - MSALLogger.log(level: .verbose, context: params.context, format: "SignIn with username and password started") - let telemetryInfo = TelemetryInfo( - event: makeAndStartTelemetryEvent(id: .telemetryApiIdSignInWithPasswordStart, context: params.context), - context: params.context - ) - - let initiateValidatedResponse = await performAndValidateSignInInitiate(username: params.username, telemetryInfo: telemetryInfo) - let result = await handleInitiateResponse(initiateValidatedResponse, telemetryInfo: telemetryInfo) - - switch result { - case .success(let challengeValidatedResponse): - return await handleChallengeResponse(challengeValidatedResponse, params: params, telemetryInfo: telemetryInfo) - case .failure(let error): - return .init(.error(error.convertToSignInPasswordStartError())) - } - } - - func signIn(params: MSALNativeAuthSignInWithCodeParameters) async -> SignInCodeControllerResponse { + func signIn(params: MSALNativeAuthSignInParameters) async -> SignInControllerResponse { + let eventId: MSALNativeAuthTelemetryApiId = + params.password == nil ? .telemetryApiIdSignInWithCodeStart : .telemetryApiIdSignInWithPasswordStart MSALLogger.log(level: .verbose, context: params.context, format: "SignIn started") let telemetryInfo = TelemetryInfo( - event: makeAndStartTelemetryEvent(id: .telemetryApiIdSignInWithCodeStart, context: params.context), + event: makeAndStartTelemetryEvent(id: eventId, context: params.context), context: params.context ) @@ -412,7 +396,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN scopes: [String], telemetryInfo: TelemetryInfo, onSuccess: @escaping (MSALNativeAuthUserAccountResult) -> Void, - onError: @escaping (SignInPasswordStartError) -> Void + onError: @escaping (SignInStartError) -> Void ) { let config = factory.makeMSIDConfiguration(scopes: scopes) switch response { @@ -441,7 +425,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN telemetryInfo: TelemetryInfo, config: MSIDConfiguration, onSuccess: @escaping (MSALNativeAuthUserAccountResult) -> Void, - onError: @escaping (SignInPasswordStartError) -> Void + onError: @escaping (SignInStartError) -> Void ) { do { let tokenResult = try cacheTokenResponse(tokenResponse, context: context, msidConfiguration: config) @@ -465,27 +449,64 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN } } + // swiftlint:disable:next function_body_length private func handleChallengeResponse( _ validatedResponse: MSALNativeAuthSignInChallengeValidatedResponse, - params: MSALNativeAuthSignInWithCodeParameters, + params: MSALNativeAuthSignInParameters, telemetryInfo: TelemetryInfo - ) async -> SignInCodeControllerResponse { + ) async -> SignInControllerResponse { let scopes = joinScopes(params.scopes) - + let isSignInUsingPassword = params.password != nil switch validatedResponse { case .passwordRequired(let credentialToken): - let state = SignInPasswordRequiredState( - scopes: scopes, - username: params.username, - controller: self, - flowToken: credentialToken, - correlationId: params.context.correlationId() - ) + if isSignInUsingPassword { + guard let request = createTokenRequest( + username: params.username, + password: params.password, + scopes: scopes, + credentialToken: credentialToken, + grantType: .password, + context: telemetryInfo.context + ) else { + stopTelemetryEvent(telemetryInfo, error: MSALNativeAuthInternalError.invalidRequest) + return .init(.error(SignInStartError(type: .generalError))) + } - return .init(.passwordRequired(newState: state), telemetryUpdate: { [weak self] result in - self?.stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, delegateDispatcherResult: result) - }) + let config = factory.makeMSIDConfiguration(scopes: scopes) + let response = await performAndValidateTokenRequest(request, config: config, context: telemetryInfo.context) + + return await withCheckedContinuation { continuation in + handleTokenResponse(response, + scopes: scopes, + telemetryInfo: telemetryInfo, + onSuccess: { accountResult in + continuation.resume(returning: SignInControllerResponse(.completed(accountResult), + telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, delegateDispatcherResult: result) + })) + }, + onError: { error in + continuation.resume(returning: SignInControllerResponse(.error(error))) + } + ) + } + } else { + let state = SignInPasswordRequiredState( + scopes: scopes, + username: params.username, + controller: self, + flowToken: credentialToken, + correlationId: params.context.correlationId() + ) + + return .init(.passwordRequired(newState: state), telemetryUpdate: { [weak self] result in + self?.stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, delegateDispatcherResult: result) + }) + } case .codeRequired(let credentialToken, let sentTo, let channelType, let codeLength): + if isSignInUsingPassword { + MSALLogger.log(level: .warning, context: telemetryInfo.context, format: MSALNativeAuthErrorMessage.codeRequiredForPasswordUserLog) + } let state = SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken, @@ -509,71 +530,6 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN } } - // swiftlint:disable:next function_body_length - private func handleChallengeResponse( - _ validatedResponse: MSALNativeAuthSignInChallengeValidatedResponse, - params: MSALNativeAuthSignInWithPasswordParameters, - telemetryInfo: TelemetryInfo - ) async -> SignInPasswordControllerResponse { - let scopes = joinScopes(params.scopes) - - switch validatedResponse { - case .codeRequired(let credentialToken, let sentTo, let channelType, let codeLength): - MSALLogger.log(level: .warning, context: telemetryInfo.context, format: MSALNativeAuthErrorMessage.codeRequiredForPasswordUserLog) - let result: SignInPasswordStartResult = .codeRequired( - newState: SignInCodeRequiredState(scopes: scopes, - controller: self, - flowToken: credentialToken, - correlationId: params.context.correlationId()), - sentTo: sentTo, - channelTargetType: channelType, - codeLength: codeLength - ) - - return .init(result, telemetryUpdate: { [weak self] result in - self?.stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, delegateDispatcherResult: result) - }) - case .passwordRequired(let credentialToken): - guard let request = createTokenRequest( - username: params.username, - password: params.password, - scopes: scopes, - credentialToken: credentialToken, - grantType: .password, - context: telemetryInfo.context - ) else { - stopTelemetryEvent(telemetryInfo, error: MSALNativeAuthInternalError.invalidRequest) - return .init(.error(SignInPasswordStartError(type: .generalError))) - } - - let config = factory.makeMSIDConfiguration(scopes: scopes) - let response = await performAndValidateTokenRequest(request, config: config, context: telemetryInfo.context) - - return await withCheckedContinuation { continuation in - handleTokenResponse(response, - scopes: scopes, - telemetryInfo: telemetryInfo, - onSuccess: { accountResult in - continuation.resume(returning: SignInPasswordControllerResponse(.completed(accountResult), - telemetryUpdate: { [weak self] result in - self?.stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, delegateDispatcherResult: result) - })) - }, - onError: { error in - continuation.resume(returning: SignInPasswordControllerResponse(.error(error))) - } - ) - } - case .error(let challengeError): - let error = challengeError.convertToSignInPasswordStartError() - MSALLogger.log(level: .error, - context: telemetryInfo.context, - format: "SignIn, completed with error: \(error.errorDescription ?? "No error description")") - stopTelemetryEvent(telemetryInfo, error: error) - return .init(.error(error)) - } - } - private func performAndValidateChallengeRequest( credentialToken: String, context: MSALNativeAuthRequestContext diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift index cfd757a118..3d58598c63 100644 --- a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift @@ -25,17 +25,15 @@ import Foundation protocol MSALNativeAuthSignInControlling { - typealias SignInPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper - typealias SignInCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper + + typealias SignInControllerResponse = MSALNativeAuthControllerTelemetryWrapper typealias SignInAfterPreviousFlowControllerResponse = MSALNativeAuthControllerTelemetryWrapper> typealias SignInSubmitCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper typealias SignInSubmitPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper typealias SignInResendCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper - func signIn(params: MSALNativeAuthSignInWithPasswordParameters) async -> SignInPasswordControllerResponse - - func signIn(params: MSALNativeAuthSignInWithCodeParameters) async -> SignInCodeControllerResponse + func signIn(params: MSALNativeAuthSignInParameters) async -> SignInControllerResponse func signIn( username: String, diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithCodeParameters.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInParameters.swift similarity index 92% rename from MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithCodeParameters.swift rename to MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInParameters.swift index eea8924352..a0c2d8eeac 100644 --- a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithCodeParameters.swift +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInParameters.swift @@ -24,16 +24,19 @@ @_implementationOnly import MSAL_Private -class MSALNativeAuthSignInWithCodeParameters { +class MSALNativeAuthSignInParameters { let username: String + let password: String? let context: MSALNativeAuthRequestContext let scopes: [String]? init( username: String, + password: String?, context: MSALNativeAuthRequestContext, scopes: [String]?) { self.username = username + self.password = password self.context = context self.scopes = scopes } diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithPasswordParameters.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithPasswordParameters.swift deleted file mode 100644 index 4626f0b496..0000000000 --- a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInWithPasswordParameters.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. -// All rights reserved. -// -// This code is licensed under the MIT License. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -@_implementationOnly import MSAL_Private - -class MSALNativeAuthSignInWithPasswordParameters: MSALNativeAuthSignInWithCodeParameters { - let password: String - - init( - username: String, - password: String, - context: MSALNativeAuthRequestContext, - scopes: [String]?) { - self.password = password - super.init( - username: username, - context: context, - scopes: scopes) - } -} diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift index 0a6ae01486..d8cc2c70f2 100644 --- a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift @@ -62,16 +62,12 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa // MARK: - Internal - func signUpStartPassword(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) async -> SignUpStartPasswordControllerResponse { - let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpPasswordStart, context: parameters.context) + func signUpStart(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) async -> SignUpStartControllerResponse { + let eventId: MSALNativeAuthTelemetryApiId = + parameters.password != nil ? .telemetryApiIdSignUpPasswordStart : .telemetryApiIdSignUpCodeStart + let event = makeAndStartTelemetryEvent(id: eventId, context: parameters.context) let result = await performAndValidateStartRequest(parameters: parameters) - return await handleSignUpStartPasswordResult(result, username: parameters.username, event: event, context: parameters.context) - } - - func signUpStartCode(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) async -> SignUpStartCodeControllerResponse { - let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpCodeStart, context: parameters.context) - let result = await performAndValidateStartRequest(parameters: parameters) - return await handleSignUpStartCodeResult(result, username: parameters.username, event: event, context: parameters.context) + return await handleSignUpStartResult(result, username: parameters.username, event: event, context: parameters.context) } func resendCode(username: String, context: MSIDRequestContext, signUpToken: String) async -> SignUpResendCodeControllerResponse { @@ -145,78 +141,12 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa } // swiftlint:disable:next function_body_length - private func handleSignUpStartPasswordResult( + private func handleSignUpStartResult( _ result: MSALNativeAuthSignUpStartValidatedResponse, username: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext - ) async -> SignUpStartPasswordControllerResponse { - switch result { - case .verificationRequired(let signUpToken, let attributes): - MSALLogger.log( - level: .info, - context: context, - format: "verification_required received from signup/start with password request for attributes: \(attributes)" - ) - let challengeResult = await performAndValidateChallengeRequest(signUpToken: signUpToken, context: context) - return handleSignUpPasswordChallengeResult(challengeResult, username: username, event: event, context: context) - case .attributeValidationFailed(let invalidAttributes): - MSALLogger.log( - level: .error, - context: context, - format: "attribute_validation_failed received from signup/start with password request for attributes: \(invalidAttributes)" - ) - let message = String(format: MSALNativeAuthErrorMessage.attributeValidationFailedSignUpStart, invalidAttributes.description) - let error = SignUpPasswordStartError(type: .generalError, message: message) - return .init(.attributesInvalid(invalidAttributes), telemetryUpdate: { [weak self] result in - // The telemetry event always fails because the attribute validation failed - self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result, controllerError: error) - }) - case .redirect: - let error = SignUpPasswordStartError(type: .browserRequired) - stopTelemetryEvent(event, context: context, error: error) - MSALLogger.log(level: .error, - context: context, - format: "redirect error in signup/start with password request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - case .error(let apiError): - let error = apiError.toSignUpStartPasswordPublicError() - stopTelemetryEvent(event, context: context, error: error) - MSALLogger.log(level: .error, - context: context, - format: "Error in signup/start with password request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - case .invalidUsername(let apiError): - let error = SignUpPasswordStartError(type: .invalidUsername, message: apiError.errorDescription) - stopTelemetryEvent(event, context: context, error: error) - MSALLogger.log(level: .error, - context: context, - format: "InvalidUsername in signup/start with password request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - case .invalidClientId(let apiError): - let error = SignUpPasswordStartError(type: .generalError, message: apiError.errorDescription) - stopTelemetryEvent(event, context: context, error: error) - MSALLogger.log(level: .error, - context: context, - format: "Invalid Client Id in signup/start with password request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - case .unexpectedError: - let error = SignUpPasswordStartError(type: .generalError) - stopTelemetryEvent(event, context: context, error: error) - MSALLogger.log(level: .error, - context: context, - format: "Unexpected error in signup/start with password request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - } - } - - // swiftlint:disable:next function_body_length - private func handleSignUpStartCodeResult( - _ result: MSALNativeAuthSignUpStartValidatedResponse, - username: String, - event: MSIDTelemetryAPIEvent?, - context: MSIDRequestContext - ) async -> SignUpStartCodeControllerResponse { + ) async -> SignUpStartControllerResponse { switch result { case .verificationRequired(let signUpToken, let unverifiedAttributes): MSALLogger.log( @@ -225,7 +155,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa format: "verification_required received from signup/start request for attributes: \(unverifiedAttributes)" ) let challengeResult = await performAndValidateChallengeRequest(signUpToken: signUpToken, context: context) - return handleSignUpCodeChallengeResult(challengeResult, username: username, event: event, context: context) + return handleSignUpChallengeResult(challengeResult, username: username, event: event, context: context) case .attributeValidationFailed(let invalidAttributes): MSALLogger.log( level: .error, @@ -297,63 +227,16 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa return responseValidator.validate(result, with: context) } - private func handleSignUpPasswordChallengeResult( - _ result: MSALNativeAuthSignUpChallengeValidatedResponse, - username: String, - event: MSIDTelemetryAPIEvent?, - context: MSIDRequestContext - ) -> SignUpStartPasswordControllerResponse { - switch result { - case .codeRequired(let sentTo, let challengeType, let codeLength, let signUpToken): - MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge password request") - return SignUpStartPasswordControllerResponse( - .codeRequired( - newState: SignUpCodeRequiredState(controller: self, - username: username, - flowToken: signUpToken, - correlationId: context.correlationId()), - sentTo: sentTo, - channelTargetType: challengeType, - codeLength: codeLength - ), telemetryUpdate: { [weak self] result in - self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) - } - ) - case .error(let apiError): - let error = apiError.toSignUpPasswordStartPublicError() - stopTelemetryEvent(event, context: context, error: error) - MSALLogger.log(level: .error, - context: context, - format: "Error in signup/challenge password request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - case .redirect: - let error = SignUpPasswordStartError(type: .browserRequired) - stopTelemetryEvent(event, context: context, error: error) - MSALLogger.log(level: .error, - context: context, - format: "Redirect error in signup/challenge password request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - case .unexpectedError, - .passwordRequired: - let error = SignUpPasswordStartError(type: .generalError) - stopTelemetryEvent(event, context: context, error: error) - MSALLogger.log(level: .error, - context: context, - format: "Unexpected error in signup/challenge password request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - } - } - - private func handleSignUpCodeChallengeResult( + private func handleSignUpChallengeResult( _ result: MSALNativeAuthSignUpChallengeValidatedResponse, username: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext - ) -> SignUpStartCodeControllerResponse { + ) -> SignUpStartControllerResponse { switch result { case .codeRequired(let sentTo, let challengeType, let codeLength, let signUpToken): MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge request") - return SignUpStartCodeControllerResponse( + return SignUpStartControllerResponse( .codeRequired( newState: SignUpCodeRequiredState(controller: self, username: username, diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift index 56dfbfb06e..f1af75660e 100644 --- a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift @@ -26,16 +26,13 @@ protocol MSALNativeAuthSignUpControlling: AnyObject { - typealias SignUpStartPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper - typealias SignUpStartCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper + typealias SignUpStartControllerResponse = MSALNativeAuthControllerTelemetryWrapper typealias SignUpResendCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper typealias SignUpSubmitCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper typealias SignUpSubmitPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper typealias SignUpSubmitAttributesControllerResponse = MSALNativeAuthControllerTelemetryWrapper - func signUpStartPassword(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) async -> SignUpStartPasswordControllerResponse - - func signUpStartCode(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) async -> SignUpStartCodeControllerResponse + func signUpStart(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) async -> SignUpStartControllerResponse func resendCode(username: String, context: MSIDRequestContext, signUpToken: String) async -> SignUpResendCodeControllerResponse diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift index c1aa02f9a7..de7aadff9a 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift @@ -42,16 +42,6 @@ struct MSALNativeAuthSignUpChallengeResponseError: MSALNativeAuthResponseError { extension MSALNativeAuthSignUpChallengeResponseError { - func toSignUpPasswordStartPublicError() -> SignUpPasswordStartError { - switch error { - case .unauthorizedClient, - .unsupportedChallengeType, - .expiredToken, - .invalidRequest: - return .init(type: .generalError, message: errorDescription) - } - } - func toSignUpStartPublicError() -> SignUpStartError { switch error { case .unauthorizedClient, diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift index af469ae349..c67be5a79c 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift @@ -49,7 +49,7 @@ struct MSALNativeAuthSignUpStartResponseError: MSALNativeAuthResponseError { extension MSALNativeAuthSignUpStartResponseError { - func toSignUpStartPasswordPublicError() -> SignUpPasswordStartError { + func toSignUpStartPublicError() -> SignUpStartError { switch error { case .passwordTooWeak, .passwordTooShort, @@ -69,24 +69,4 @@ extension MSALNativeAuthSignUpStartResponseError { return .init(type: .generalError, message: errorDescription) } } - - func toSignUpStartPublicError() -> SignUpStartError { - switch error { - case .userAlreadyExists: - return .init(type: .userAlreadyExists, message: errorDescription) - case .attributeValidationFailed, - .attributesRequired, - .unauthorizedClient, - .invalidRequest, - .passwordTooWeak, /// password errors should not occur when signing up code - .passwordTooShort, - .passwordTooLong, - .passwordRecentlyUsed, - .passwordBanned, - .unsupportedAuthMethod, - .unsupportedChallengeType, - .verificationRequired: /// .verificationRequired is not supported by the API team yet. We treat it as an unexpectedError in the validator - return .init(type: .generalError, message: errorDescription) - } - } } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift index 836d2e6cae..af0c5c2c99 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift @@ -58,19 +58,4 @@ enum MSALNativeAuthSignInChallengeValidatedErrorType: Error { return .init(type: .generalError, message: message) } } - - func convertToSignInPasswordStartError() -> SignInPasswordStartError { - switch self { - case .redirect: - return .init(type: .browserRequired) - case .expiredToken, .invalidToken, .invalidRequest, .invalidServerResponse: - return .init(type: .generalError) - case .invalidClient(let message): - return .init(type: .generalError, message: message) - case .userNotFound: - return .init(type: .userNotFound) - case .unsupportedChallengeType(let message): - return .init(type: .generalError, message: message) - } - } } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift index 09ff8221ed..37744f6956 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift @@ -52,7 +52,7 @@ enum MSALNativeAuthSignInInitiateValidatedErrorType: Error { } } - func convertToSignInPasswordStartError() -> SignInPasswordStartError { + func convertToSignInPasswordStartError() -> SignInStartError { switch self { case .redirect: return .init(type: .browserRequired) diff --git a/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift index e8856cbf2d..e95dae8d7d 100644 --- a/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift @@ -45,7 +45,7 @@ enum MSALNativeAuthTokenValidatedErrorType: Error { case authorizationPending(message: String?) case slowDown(message: String?) - func convertToSignInPasswordStartError() -> SignInPasswordStartError { + func convertToSignInPasswordStartError() -> SignInStartError { switch self { case .expiredToken(let message), .authorizationPending(let message), @@ -55,20 +55,20 @@ enum MSALNativeAuthTokenValidatedErrorType: Error { .invalidClient(let message), .unsupportedChallengeType(let message), .invalidScope(let message): - return SignInPasswordStartError(type: .generalError, message: message) + return SignInStartError(type: .generalError, message: message) case .generalError: - return SignInPasswordStartError(type: .generalError) + return SignInStartError(type: .generalError) case .invalidServerResponse: - return SignInPasswordStartError(type: .generalError, message: MSALNativeAuthErrorMessage.invalidServerResponse) + return SignInStartError(type: .generalError, message: MSALNativeAuthErrorMessage.invalidServerResponse) case .userNotFound(let message): - return SignInPasswordStartError(type: .userNotFound, message: message) + return SignInStartError(type: .userNotFound, message: message) case .invalidPassword(let message): - return SignInPasswordStartError(type: .invalidCredentials, message: message) + return SignInStartError(type: .invalidCredentials, message: message) case .strongAuthRequired(let message): - return SignInPasswordStartError(type: .browserRequired, message: message) + return SignInStartError(type: .browserRequired, message: message) case .expiredRefreshToken(let message): MSALLogger.log(level: .error, context: nil, format: "Error not treated - \(self))") - return SignInPasswordStartError(type: .generalError, message: message) + return SignInStartError(type: .generalError, message: message) } } @@ -123,6 +123,6 @@ enum MSALNativeAuthTokenValidatedErrorType: Error { } func convertToPasswordRequiredError() -> PasswordRequiredError { - return PasswordRequiredError(signInPasswordError: convertToSignInPasswordStartError()) + return PasswordRequiredError(signInStartError: convertToSignInPasswordStartError()) } } diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift index a9ded0b385..a2c0fac2a9 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift @@ -26,94 +26,54 @@ import Foundation extension MSALNativeAuthPublicClientApplication { - func signUpUsingPasswordInternal( - username: String, - password: String, - attributes: [String: Any]?, - correlationId: UUID? - ) async -> MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse { - guard inputValidator.isInputValid(username) else { - return .init(.error(SignUpPasswordStartError(type: .invalidUsername))) - } - guard inputValidator.isInputValid(password) else { - return .init(.error(SignUpPasswordStartError(type: .invalidPassword))) - } - - let controller = controllerFactory.makeSignUpController() - let context = MSALNativeAuthRequestContext(correlationId: correlationId) - - let parameters = MSALNativeAuthSignUpStartRequestProviderParameters( - username: username, - password: password, - attributes: attributes, - context: context - ) - - return await controller.signUpStartPassword(parameters: parameters) - } - func signUpInternal( username: String, + password: String?, attributes: [String: Any]?, correlationId: UUID? - ) async -> MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse { + ) async -> MSALNativeAuthSignUpControlling.SignUpStartControllerResponse { guard inputValidator.isInputValid(username) else { return .init(.error(SignUpStartError(type: .invalidUsername))) } + if let password = password, !inputValidator.isInputValid(password) { + return .init(.error(SignUpStartError(type: .invalidPassword))) + } + let controller = controllerFactory.makeSignUpController() let context = MSALNativeAuthRequestContext(correlationId: correlationId) let parameters = MSALNativeAuthSignUpStartRequestProviderParameters( username: username, - password: nil, + password: password, attributes: attributes, context: context ) - - return await controller.signUpStartCode(parameters: parameters) + return await controller.signUpStart(parameters: parameters) } - func signInUsingPasswordInternal( + func signInInternal( username: String, - password: String, + password: String?, scopes: [String]?, correlationId: UUID? - ) async -> MSALNativeAuthSignInControlling.SignInPasswordControllerResponse { + ) async -> MSALNativeAuthSignInControlling.SignInControllerResponse { guard inputValidator.isInputValid(username) else { - return .init(.error(SignInPasswordStartError(type: .invalidUsername))) + return .init(.error(SignInStartError(type: .invalidUsername))) } - guard inputValidator.isInputValid(password) else { - return .init(.error(SignInPasswordStartError(type: .invalidCredentials))) + if let password = password, !inputValidator.isInputValid(password) { + return .init(.error(SignInStartError(type: .invalidCredentials))) } let controller = controllerFactory.makeSignInController() - let params = MSALNativeAuthSignInWithPasswordParameters( + let params = MSALNativeAuthSignInParameters( username: username, password: password, context: MSALNativeAuthRequestContext(correlationId: correlationId), scopes: scopes ) - - return await controller.signIn(params: params) - } - - func signInInternal( - username: String, - scopes: [String]?, - correlationId: UUID? - ) async -> MSALNativeAuthSignInControlling.SignInCodeControllerResponse { - guard inputValidator.isInputValid(username) else { - return .init(.error(SignInStartError(type: .invalidUsername))) - } - let controller = controllerFactory.makeSignInController() - let params = MSALNativeAuthSignInWithCodeParameters( - username: username, - context: MSALNativeAuthRequestContext(correlationId: correlationId), - scopes: scopes - ) return await controller.signIn(params: params) } diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift index bb998010e6..8a76ee6ce5 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift @@ -116,57 +116,24 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic /// Sign up a user with a given username and password. /// - Parameters: /// - username: Username for the new account. - /// - password: Password to be used for the new account. + /// - password: Optional. Password to be used for the new account. /// - attributes: Optional. User attributes to be used during account creation. /// - correlationId: Optional. UUID to correlate this request with the server for debugging. /// - delegate: Delegate that receives callbacks for the Sign Up flow. - public func signUpUsingPassword( + public func signUp( username: String, - password: String, + password: String? = nil, attributes: [String: Any]? = nil, correlationId: UUID? = nil, - delegate: SignUpPasswordStartDelegate + delegate: SignUpStartDelegate ) { Task { - let controllerResponse = await signUpUsingPasswordInternal( + let controllerResponse = await signUpInternal( username: username, password: password, attributes: attributes, correlationId: correlationId ) - - let delegateDispatcher = SignUpPasswordStartDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) - - switch controllerResponse.result { - case .codeRequired(let newState, let sentTo, let channelTargetType, let codeLength): - await delegateDispatcher.dispatchSignUpPasswordCodeRequired( - newState: newState, - sentTo: sentTo, - channelTargetType: channelTargetType, - codeLength: codeLength - ) - case .attributesInvalid(let attributes): - await delegateDispatcher.dispatchSignUpAttributesInvalid(attributeNames: attributes) - case .error(let error): - await delegate.onSignUpPasswordStartError(error: error) - } - } - } - - /// Sign up a user with a given username. - /// - Parameters: - /// - username: Username for the new account. - /// - attributes: Optional. User attributes to be used during account creation. - /// - correlationId: Optional. UUID to correlate this request with the server for debugging. - /// - delegate: Delegate that receives callbacks for the Sign Up flow. - public func signUp( - username: String, - attributes: [String: Any]? = nil, - correlationId: UUID? = nil, - delegate: SignUpStartDelegate - ) { - Task { - let controllerResponse = await signUpInternal(username: username, attributes: attributes, correlationId: correlationId) let delegateDispatcher = SignUpStartDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) switch controllerResponse.result { @@ -187,52 +154,14 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic /// Sign in a user with a given username and password. /// - Parameters: - /// - username: Username for the account. - /// - password: Password for the account. - /// - scopes: Optional. Permissions you want included in the access token received after sign in flow has completed. - /// - correlationId: Optional. UUID to correlate this request with the server for debugging. - /// - delegate: Delegate that receives callbacks for the Sign In flow. - public func signInUsingPassword( - username: String, - password: String, - scopes: [String]? = nil, - correlationId: UUID? = nil, - delegate: SignInPasswordStartDelegate - ) { - Task { - let controllerResponse = await signInUsingPasswordInternal( - username: username, - password: password, - scopes: scopes, - correlationId: correlationId - ) - - let delegateDispatcher = SignInPasswordStartDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) - - switch controllerResponse.result { - case .completed(let result): - await delegateDispatcher.dispatchSignInCompleted(result: result) - case .codeRequired(let newState, let sentTo, let channelType, let codeLength): - await delegateDispatcher.dispatchSignInCodeRequired( - newState: newState, - sentTo: sentTo, - channelTargetType: channelType, - codeLength: codeLength - ) - case .error(let error): - await delegate.onSignInPasswordStartError(error: error) - } - } - } - - /// Sign in a user with a given username. - /// - Parameters: /// - username: Username for the account + /// - password: Optional. Password for the account. /// - scopes: Optional. Permissions you want included in the access token received after sign in flow has completed. /// - correlationId: Optional. UUID to correlate this request with the server for debugging. /// - delegate: Delegate that receives callbacks for the Sign In flow. public func signIn( username: String, + password: String? = nil, scopes: [String]? = nil, correlationId: UUID? = nil, delegate: SignInStartDelegate @@ -240,6 +169,7 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic Task { let controllerResponse = await signInInternal( username: username, + password: password, scopes: scopes, correlationId: correlationId ) @@ -256,6 +186,8 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic ) case .passwordRequired(let newState): await delegateDispatcher.dispatchSignInPasswordRequired(newState: newState) + case .completed(let result): + await delegateDispatcher.dispatchSignInCompleted(result: result) case .error(let error): await delegate.onSignInStartError(error: error) } diff --git a/MSAL/src/native_auth/public/parameters/MSALNativeAuthParameters.swift b/MSAL/src/native_auth/public/parameters/MSALNativeAuthParameters.swift deleted file mode 100644 index 6a804602be..0000000000 --- a/MSAL/src/native_auth/public/parameters/MSALNativeAuthParameters.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. -// All rights reserved. -// -// This code is licensed under the MIT License. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation - -@objcMembers -public class MSALNativeAuthParameters: NSObject { - - /** - UUID to correlate this request with the server. - */ - public let correlationId: UUID? - - init(correlationId: UUID? = nil) { - self.correlationId = correlationId - } -} diff --git a/MSAL/src/native_auth/public/parameters/MSALNativeAuthResendCodeParameters.swift b/MSAL/src/native_auth/public/parameters/MSALNativeAuthResendCodeParameters.swift deleted file mode 100644 index 0bbaa23828..0000000000 --- a/MSAL/src/native_auth/public/parameters/MSALNativeAuthResendCodeParameters.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. -// All rights reserved. -// -// This code is licensed under the MIT License. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation - -@objcMembers -final public class MSALNativeAuthResendCodeParameters: MSALNativeAuthParameters { - - public let credentialToken: String - - public init(credentialToken: String, - correlationId: UUID? = nil) { - self.credentialToken = credentialToken - super.init(correlationId: correlationId) - } -} diff --git a/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInOTPParameters.swift b/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInOTPParameters.swift deleted file mode 100644 index e3544efc91..0000000000 --- a/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInOTPParameters.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. -// All rights reserved. -// -// This code is licensed under the MIT License. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation - -@objcMembers -final public class MSALNativeAuthSignInOTPParameters: MSALNativeAuthParameters { - - public let email: String - public let scopes: [String] - - public init(email: String, scopes: [String] = [], correlationId: UUID? = nil) { - self.email = email - self.scopes = scopes - super.init(correlationId: correlationId) - } -} diff --git a/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInParameters.swift b/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInParameters.swift deleted file mode 100644 index cf6d9729b6..0000000000 --- a/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignInParameters.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. -// All rights reserved. -// -// This code is licensed under the MIT License. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation - -@objcMembers -final public class MSALNativeAuthSignInParameters: MSALNativeAuthParameters { - - public let email: String - public let password: String - public let scopes: [String] - - public init(email: String, - password: String, - scopes: [String] = [], - correlationId: UUID? = nil) { - self.email = email - self.password = password - self.scopes = scopes - super.init(correlationId: correlationId) - } -} diff --git a/MSAL/src/native_auth/public/parameters/MSALNativeAuthVerifyCodeParameters.swift b/MSAL/src/native_auth/public/parameters/MSALNativeAuthVerifyCodeParameters.swift deleted file mode 100644 index c3818806dc..0000000000 --- a/MSAL/src/native_auth/public/parameters/MSALNativeAuthVerifyCodeParameters.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. -// All rights reserved. -// -// This code is licensed under the MIT License. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation - -@objcMembers -final public class MSALNativeAuthVerifyCodeParameters: MSALNativeAuthParameters { - - public let credentialToken: String - public let otp: String - - public init(credentialToken: String, - otp: String, - correlationId: UUID? = nil) { - self.credentialToken = credentialToken - self.otp = otp - super.init(correlationId: correlationId) - } -} diff --git a/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift index d6d7c192d7..fb39c1a020 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift @@ -24,30 +24,6 @@ import Foundation -@objc -public protocol SignInPasswordStartDelegate { - /// Notifies the delegate that the operation resulted in an error. - /// - Parameter error: An error object indicating why the operation failed. - @MainActor func onSignInPasswordStartError(error: SignInPasswordStartError) - - /// Notifies the delegate that a verification code is required from the user to continue. - /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignInPasswordStartError(error:)`` will be called. - /// - Parameters: - /// - newState: An object representing the new state of the flow with follow on methods. - /// - sentTo: The email/phone number that the code was sent to. - /// - channelTargetType: The channel (email/phone) the code was sent through. - /// - codeLength: The length of the code required. - @MainActor @objc optional func onSignInCodeRequired(newState: SignInCodeRequiredState, - sentTo: String, - channelTargetType: MSALNativeAuthChannelType, - codeLength: Int) - - /// Notifies the delegate that the sign in operation completed successfully. - /// - Parameter result: An object representing the signed in user account. - /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignInPasswordStartError(error:)`` will be called. - @MainActor @objc optional func onSignInCompleted(result: MSALNativeAuthUserAccountResult) -} - @objc public protocol SignInStartDelegate { /// Notifies the delegate that the operation resulted in an error. @@ -70,6 +46,11 @@ public protocol SignInStartDelegate { /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignInStartError(error:)`` will be called. /// - Parameter newState: An object representing the new state of the flow with follow on methods. @MainActor @objc optional func onSignInPasswordRequired(newState: SignInPasswordRequiredState) + + /// Notifies the delegate that the sign in operation completed successfully. + /// - Parameter result: An object representing the signed in user account. + /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignInStartError(error:)`` will be called. + @MainActor @objc optional func onSignInCompleted(result: MSALNativeAuthUserAccountResult) } @objc diff --git a/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift index 94cef5473b..0660521035 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift @@ -24,30 +24,6 @@ import Foundation -@objc -public protocol SignUpPasswordStartDelegate { - /// Notifies the delegate that the operation resulted in an error. - /// - Parameter error: An error object indicating why the operation failed. - @MainActor func onSignUpPasswordStartError(error: SignUpPasswordStartError) - - /// Notifies the delegate that a verification code is required from the user to continue. - /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpPasswordStartError(error:)`` will be called. - /// - Parameters: - /// - newState: An object representing the new state of the flow with follow on methods. - /// - sentTo: The email/phone number that the code was sent to. - /// - channelTargetType: The channel (email/phone) the code was sent through. - /// - codeLength: The length of the code required. - @MainActor @objc optional func onSignUpCodeRequired(newState: SignUpCodeRequiredState, - sentTo: String, - channelTargetType: MSALNativeAuthChannelType, - codeLength: Int) - - /// Notifies the delegate that invalid attributes were sent. - /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpPasswordStartError(error:)`` will be called. - /// - Parameter attributeNames: List of attribute names that failed validation. - @MainActor @objc optional func onSignUpAttributesInvalid(attributeNames: [String]) -} - @objc public protocol SignUpStartDelegate { /// Notifies the delegate that the operation resulted in an error. diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInDelegateDispatchers.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInDelegateDispatchers.swift index 7c123f5a72..a9560488cf 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInDelegateDispatchers.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInDelegateDispatchers.swift @@ -24,36 +24,6 @@ import Foundation -final class SignInPasswordStartDelegateDispatcher: DelegateDispatcher { - - func dispatchSignInCodeRequired( - newState: SignInCodeRequiredState, - sentTo: String, - channelTargetType: MSALNativeAuthChannelType, - codeLength: Int - ) async { - if let onSignInCodeRequired = delegate.onSignInCodeRequired { - telemetryUpdate?(.success(())) - await onSignInCodeRequired(newState, sentTo, channelTargetType, codeLength) - } else { - let error = SignInPasswordStartError(type: .generalError, message: requiredErrorMessage(for: "onSignInCodeRequired")) - telemetryUpdate?(.failure(error)) - await delegate.onSignInPasswordStartError(error: error) - } - } - - func dispatchSignInCompleted(result: MSALNativeAuthUserAccountResult) async { - if let onSignInCompleted = delegate.onSignInCompleted { - telemetryUpdate?(.success(())) - await onSignInCompleted(result) - } else { - let error = SignInPasswordStartError(type: .generalError, message: requiredErrorMessage(for: "onSignInCompleted")) - telemetryUpdate?(.failure(error)) - await delegate.onSignInPasswordStartError(error: error) - } - } -} - final class SignInStartDelegateDispatcher: DelegateDispatcher { func dispatchSignInCodeRequired( @@ -82,6 +52,17 @@ final class SignInStartDelegateDispatcher: DelegateDispatcher { diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift index 3af063c76c..d39149da8c 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift @@ -24,36 +24,6 @@ import Foundation -final class SignUpPasswordStartDelegateDispatcher: DelegateDispatcher { - - func dispatchSignUpPasswordCodeRequired( - newState: SignUpCodeRequiredState, - sentTo: String, - channelTargetType: MSALNativeAuthChannelType, - codeLength: Int - ) async { - if let onSignUpCodeRequired = delegate.onSignUpCodeRequired { - telemetryUpdate?(.success(())) - await onSignUpCodeRequired(newState, sentTo, channelTargetType, codeLength) - } else { - let error = SignUpPasswordStartError(type: .generalError, message: requiredErrorMessage(for: "onSignUpCodeRequired")) - telemetryUpdate?(.failure(error)) - await delegate.onSignUpPasswordStartError(error: error) - } - } - - func dispatchSignUpAttributesInvalid(attributeNames: [String]) async { - if let onSignUpAttributesInvalid = delegate.onSignUpAttributesInvalid { - telemetryUpdate?(.success(())) - await onSignUpAttributesInvalid(attributeNames) - } else { - let error = SignUpPasswordStartError(type: .generalError, message: requiredErrorMessage(for: "onSignUpAttributesInvalid")) - telemetryUpdate?(.failure(error)) - await delegate.onSignUpPasswordStartError(error: error) - } - } -} - final class SignUpStartDelegateDispatcher: DelegateDispatcher { func dispatchSignUpCodeRequired( diff --git a/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift b/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift index 808e68a86a..99385d81b7 100644 --- a/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift @@ -39,8 +39,8 @@ public class PasswordRequiredError: MSALNativeAuthError { super.init(message: message) } - init(signInPasswordError: SignInPasswordStartError) { - switch signInPasswordError.type { + init(signInStartError: SignInStartError) { + switch signInStartError.type { case .browserRequired: self.type = .browserRequired case .invalidCredentials: @@ -48,7 +48,7 @@ public class PasswordRequiredError: MSALNativeAuthError { default: self.type = .generalError } - super.init(message: signInPasswordError.errorDescription) + super.init(message: signInStartError.errorDescription) } /// Describes why an error occurred and provides more information about the error. diff --git a/MSAL/src/native_auth/public/state_machine/error/SignInPasswordStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignInPasswordStartError.swift deleted file mode 100644 index b20baafbd3..0000000000 --- a/MSAL/src/native_auth/public/state_machine/error/SignInPasswordStartError.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. -// All rights reserved. -// -// This code is licensed under the MIT License. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation - -@objcMembers -public class SignInPasswordStartError: MSALNativeAuthError { - enum ErrorType: CaseIterable { - case browserRequired - case userNotFound - case invalidCredentials - case invalidUsername - case generalError - } - - let type: ErrorType - - init(type: ErrorType, message: String? = nil) { - self.type = type - super.init(message: message) - } - - /// Describes why an error occurred and provides more information about the error. - public override var errorDescription: String? { - if let description = super.errorDescription { - return description - } - - switch type { - case .browserRequired: - return MSALNativeAuthErrorMessage.browserRequired - case .userNotFound: - return MSALNativeAuthErrorMessage.userNotFound - case .invalidCredentials: - return MSALNativeAuthErrorMessage.invalidCredentials - case .invalidUsername: - return MSALNativeAuthErrorMessage.invalidUsername - case .generalError: - return MSALNativeAuthErrorMessage.generalError - } - } - - /// Returns `true` if a browser is required to continue the operation. - public var isBrowserRequired: Bool { - return type == .browserRequired - } - - /// Returns `true` if the user that is trying to sign in cannot be found. - public var isUserNotFound: Bool { - return type == .userNotFound - } - - /// Returns `true` when the credentials are not valid. - public var isInvalidCredentials: Bool { - return type == .invalidCredentials - } - - /// Returns `true` when the username is not valid. - public var isInvalidUsername: Bool { - return type == .invalidUsername - } -} diff --git a/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift index 6dcd04fcfe..e5db743a8e 100644 --- a/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift @@ -29,6 +29,7 @@ public class SignInStartError: MSALNativeAuthError { enum ErrorType: CaseIterable { case browserRequired case userNotFound + case invalidCredentials case invalidUsername case generalError } @@ -51,6 +52,8 @@ public class SignInStartError: MSALNativeAuthError { return MSALNativeAuthErrorMessage.browserRequired case .userNotFound: return MSALNativeAuthErrorMessage.userNotFound + case .invalidCredentials: + return MSALNativeAuthErrorMessage.invalidCredentials case .invalidUsername: return MSALNativeAuthErrorMessage.invalidUsername case .generalError: @@ -68,6 +71,11 @@ public class SignInStartError: MSALNativeAuthError { return type == .userNotFound } + /// Returns `true` when the credentials are not valid. + public var isInvalidCredentials: Bool { + return type == .invalidCredentials + } + /// Returns `true` when the username is not valid. public var isInvalidUsername: Bool { return type == .invalidUsername diff --git a/MSAL/src/native_auth/public/state_machine/error/SignUpPasswordStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignUpPasswordStartError.swift deleted file mode 100644 index fd0fac3e02..0000000000 --- a/MSAL/src/native_auth/public/state_machine/error/SignUpPasswordStartError.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. -// All rights reserved. -// -// This code is licensed under the MIT License. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation - -@objcMembers -public class SignUpPasswordStartError: MSALNativeAuthError { - enum ErrorType: CaseIterable { - case browserRequired - case userAlreadyExists - case invalidPassword - case invalidUsername - case generalError - } - - let type: ErrorType - - init(type: ErrorType, message: String? = nil) { - self.type = type - super.init(message: message) - } - - /// Describes why an error occurred and provides more information about the error. - public override var errorDescription: String? { - if let description = super.errorDescription { - return description - } - - switch type { - case .browserRequired: - return MSALNativeAuthErrorMessage.browserRequired - case .userAlreadyExists: - return MSALNativeAuthErrorMessage.userAlreadyExists - case .invalidPassword: - return MSALNativeAuthErrorMessage.invalidPassword - case .invalidUsername: - return MSALNativeAuthErrorMessage.invalidUsername - case .generalError: - return MSALNativeAuthErrorMessage.generalError - } - } - - /// Returns `true` if a browser is required to continue the operation. - public var isBrowserRequired: Bool { - return type == .browserRequired - } - - /// Returns `true` when the user is trying to register an existing username. - public var isUserAlreadyExists: Bool { - return type == .userAlreadyExists - } - - /// Returns `true` when the password is not valid. - public var isInvalidPassword: Bool { - return type == .invalidPassword - } - - /// Returns `true` when the username is not valid. - public var isInvalidUsername: Bool { - return type == .invalidUsername - } -} diff --git a/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift index db6add8594..cc61ed102f 100644 --- a/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift @@ -29,6 +29,7 @@ public class SignUpStartError: MSALNativeAuthError { enum ErrorType: CaseIterable { case browserRequired case userAlreadyExists + case invalidPassword case invalidUsername case generalError } @@ -51,6 +52,8 @@ public class SignUpStartError: MSALNativeAuthError { return MSALNativeAuthErrorMessage.browserRequired case .userAlreadyExists: return MSALNativeAuthErrorMessage.userAlreadyExists + case .invalidPassword: + return MSALNativeAuthErrorMessage.invalidPassword case .invalidUsername: return MSALNativeAuthErrorMessage.invalidUsername case .generalError: @@ -68,6 +71,11 @@ public class SignUpStartError: MSALNativeAuthError { return type == .userAlreadyExists } + /// Returns `true` when the password is not valid. + public var isInvalidPassword: Bool { + return type == .invalidPassword + } + /// Returns `true` when the username is not valid. public var isInvalidUsername: Bool { return type == .invalidUsername diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUserNameAndPasswordEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUserNameAndPasswordEndToEndTests.swift index 9c9810c445..be2dc13f98 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUserNameAndPasswordEndToEndTests.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_in/MSALNativeAuthSignInUserNameAndPasswordEndToEndTests.swift @@ -40,7 +40,7 @@ final class MSALNativeAuthSignInUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.userNotFound, endpoint: .signInToken) } - sut.signInUsingPassword(username: unknownUsername, password: "testpass", correlationId: correlationId, delegate: signInDelegateSpy) + sut.signIn(username: unknownUsername, password: "testpass", correlationId: correlationId, delegate: signInDelegateSpy) await fulfillment(of: [signInExpectation], timeout: 2) @@ -62,7 +62,7 @@ final class MSALNativeAuthSignInUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.invalidPassword, endpoint: .signInToken) } - sut.signInUsingPassword(username: username, password: "An Invalid Password", correlationId: correlationId, delegate: signInDelegateSpy) + sut.signIn(username: username, password: "An Invalid Password", correlationId: correlationId, delegate: signInDelegateSpy) await fulfillment(of: [signInExpectation], timeout: 2) @@ -86,7 +86,7 @@ final class MSALNativeAuthSignInUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.tokenSuccess, endpoint: .signInToken) } - sut.signInUsingPassword(username: username, password: password, correlationId: correlationId, delegate: signInDelegateSpy) + sut.signIn(username: username, password: password, correlationId: correlationId, delegate: signInDelegateSpy) await fulfillment(of: [signInExpectation], timeout: 2) diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_in/SignInDelegateSpies.swift b/MSAL/test/integration/native_auth/end_to_end/sign_in/SignInDelegateSpies.swift index 1471dbf4ad..cda4696f04 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_in/SignInDelegateSpies.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_in/SignInDelegateSpies.swift @@ -26,18 +26,18 @@ import Foundation import XCTest import MSAL -class SignInPasswordStartDelegateSpy: SignInPasswordStartDelegate { +class SignInPasswordStartDelegateSpy: SignInStartDelegate { private let expectation: XCTestExpectation private(set) var onSignInPasswordErrorCalled = false private(set) var onSignInCompletedCalled = false - private(set) var error: MSAL.SignInPasswordStartError? + private(set) var error: MSAL.SignInStartError? private(set) var result: MSAL.MSALNativeAuthUserAccountResult? init(expectation: XCTestExpectation) { self.expectation = expectation } - public func onSignInPasswordStartError(error: MSAL.SignInPasswordStartError) { + public func onSignInStartError(error: MSAL.SignInStartError) { onSignInPasswordErrorCalled = true self.error = error diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_out/MSALNativeAuthSignOutEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_out/MSALNativeAuthSignOutEndToEndTests.swift index 5d79a7dd1c..753e750b2f 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_out/MSALNativeAuthSignOutEndToEndTests.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_out/MSALNativeAuthSignOutEndToEndTests.swift @@ -143,7 +143,7 @@ final class MSALNativeAuthSignOutEndToEndTests: MSALNativeAuthEndToEndBaseTestCa try await mockResponse(.tokenSuccess, endpoint: .signInToken) } - sut.signInUsingPassword(username: username, password: password, correlationId: correlationId, delegate: signInDelegateSpy) + sut.signIn(username: username, password: password, correlationId: correlationId, delegate: signInDelegateSpy) await fulfillment(of: [signInExpectation], timeout: defaultTimeout) @@ -175,7 +175,7 @@ final class MSALNativeAuthSignOutEndToEndTests: MSALNativeAuthEndToEndBaseTestCa try await mockResponse(.tokenSuccess, endpoint: .signInToken) } - sut.signInUsingPassword(username: username, password: password, correlationId: correlationId, delegate: signInDelegateSpy) + sut.signIn(username: username, password: password, correlationId: correlationId, delegate: signInDelegateSpy) await fulfillment(of: [signInExpectation], timeout: defaultTimeout) diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift index 1307d4cc75..9366c4f30a 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift @@ -45,7 +45,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } - sut.signUpUsingPassword( + sut.signUp( username: usernamePassword, password: password, correlationId: correlationId, @@ -94,7 +94,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } - sut.signUpUsingPassword( + sut.signUp( username: usernamePassword, password: "1234", attributes: attributes, @@ -144,7 +144,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } - sut.signUpUsingPassword( + sut.signUp( username: usernamePassword, password: password, correlationId: correlationId, @@ -211,7 +211,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } - sut.signUpUsingPassword( + sut.signUp( username: usernamePassword, password: password, correlationId: correlationId, @@ -295,7 +295,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } - sut.signUpUsingPassword( + sut.signUp( username: usernamePassword, password: password, correlationId: correlationId, @@ -396,7 +396,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } - sut.signUpUsingPassword( + sut.signUp( username: usernamePassword, password: password, correlationId: correlationId, diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift b/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift index c130b2d8fd..8a212e8781 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift @@ -26,10 +26,10 @@ import Foundation import XCTest import MSAL -class SignUpPasswordStartDelegateSpy: SignUpPasswordStartDelegate { +class SignUpPasswordStartDelegateSpy: SignUpStartDelegate { private let expectation: XCTestExpectation private(set) var onSignUpPasswordErrorCalled = false - private(set) var error: MSAL.SignUpPasswordStartError? + private(set) var error: MSAL.SignUpStartError? private(set) var onSignUpCodeRequiredCalled = false private(set) var newState: SignUpCodeRequiredState? private(set) var sentTo: String? @@ -40,7 +40,7 @@ class SignUpPasswordStartDelegateSpy: SignUpPasswordStartDelegate { self.expectation = expectation } - func onSignUpPasswordStartError(error: MSAL.SignUpPasswordStartError) { + func onSignUpStartError(error: MSAL.SignUpStartError) { onSignUpPasswordErrorCalled = true self.error = error diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift index 9579e2e6f7..d7b6d882f7 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift @@ -81,9 +81,9 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { signInRequestProviderMock.expectedContext = expectedContext signInRequestProviderMock.throwingInitError = ErrorMock.error - let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInPasswordStartError(type: .generalError)) + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError)) - let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) helper.onSignInPasswordError(result) @@ -111,9 +111,9 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: expectedScopes, password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) - let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInPasswordStartError(type: .generalError)) + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError)) - let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: ["scope1", "scope2"])) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: ["scope1", "scope2"])) helper.onSignInPasswordError(result) @@ -140,9 +140,9 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: expectedScopes, password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) tokenRequestProviderMock.throwingTokenError = ErrorMock.error - let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInPasswordStartError(type: .generalError)) + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError)) - let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: ["scope1", "openid", "profile"])) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: ["scope1", "openid", "profile"])) helper.onSignInPasswordError(result) @@ -177,7 +177,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { tokenResponseValidatorMock.expectedTokenResponse = tokenResponse cacheAccessorMock.expectedMSIDTokenResult = tokenResult - let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) helper.onSignInCompleted(result) @@ -214,7 +214,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { tokenResponseValidatorMock.expectedTokenResponse = tokenResponse cacheAccessorMock.expectedMSIDTokenResult = nil - let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) helper.onSignInPasswordError(result) @@ -248,7 +248,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) tokenResponseValidatorMock.expectedTokenResponse = tokenResponse - let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) helper.onSignInPasswordError(result) @@ -257,17 +257,17 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_whenErrorIsReturnedFromValidator_itIsCorrectlyTranslatedToDelegateError() async { - await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError), validatorError: .generalError) - await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError), validatorError: .expiredToken(message: nil)) - await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError), validatorError: .authorizationPending(message: nil)) - await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError), validatorError: .slowDown(message: nil)) - await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError), validatorError: .invalidRequest(message: nil)) - await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError, message: "Invalid server response"), validatorError: .invalidServerResponse) - await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError, message: "Invalid Client ID"), validatorError: .invalidClient(message: "Invalid Client ID")) - await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError, message: "Unsupported challenge type"), validatorError: .unsupportedChallengeType(message: "Unsupported challenge type")) - await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .generalError, message: "Invalid scope"), validatorError: .invalidScope(message: "Invalid scope")) - await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .userNotFound), validatorError: .userNotFound(message: nil)) - await checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError(type: .invalidCredentials), validatorError: .invalidPassword(message: nil)) + await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .generalError) + await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .expiredToken(message: nil)) + await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .authorizationPending(message: nil)) + await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .slowDown(message: nil)) + await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidRequest(message: nil)) + await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Invalid server response"), validatorError: .invalidServerResponse) + await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Invalid Client ID"), validatorError: .invalidClient(message: "Invalid Client ID")) + await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Unsupported challenge type"), validatorError: .unsupportedChallengeType(message: "Unsupported challenge type")) + await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Invalid scope"), validatorError: .invalidScope(message: "Invalid scope")) + await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .userNotFound), validatorError: .userNotFound(message: nil)) + await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .invalidCredentials), validatorError: .invalidPassword(message: nil)) } func test_whenCredentialsAreRequired_browserRequiredErrorIsReturned() async { @@ -294,7 +294,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { tokenResponseValidatorMock.tokenValidatedResponse = .error(.strongAuthRequired(message: "MFA currently not supported. Use the browser instead")) - let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) helper.onSignInPasswordError(result) @@ -327,7 +327,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { helper.expectedChannelTargetType = expectedChannelTargetType helper.expectedCodeLength = expectedCodeLength - let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) result.telemetryUpdate?(.success(())) helper.onSignInCodeRequired(result) @@ -361,7 +361,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { helper.expectedChannelTargetType = expectedChannelTargetType helper.expectedCodeLength = expectedCodeLength - let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) result.telemetryUpdate?(.failure(.init(message: "error"))) helper.onSignInCodeRequired(result) @@ -393,7 +393,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: sentTo, channelType: channelTargetType, codeLength: codeLength) - let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: nil, context: expectedContext, scopes: nil)) result.telemetryUpdate?(.success(())) helper.onSignInCodeRequired(result) @@ -459,7 +459,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError)) - let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: nil, context: expectedContext, scopes: nil)) helper.onSignInError(result) @@ -488,7 +488,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError)) - let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: nil, context: expectedContext, scopes: nil)) helper.onSignInError(result) @@ -521,7 +521,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let helper = SignInCodeStartWithPasswordRequiredTestsValidatorHelper(expectation: expectation) - let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: nil, context: expectedContext, scopes: nil)) result.telemetryUpdate?(.success(())) helper.onSignInPasswordRequired(result.result) @@ -545,7 +545,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let helper = SignInCodeStartWithPasswordRequiredTestsValidatorHelper(expectation: expectation) - let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: nil, context: expectedContext, scopes: nil)) result.telemetryUpdate?(.failure(.init(message: "error"))) helper.onSignInPasswordRequired(result.result) @@ -910,7 +910,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: delegateError) - let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: nil, context: expectedContext, scopes: nil)) helper.onSignInError(result) @@ -932,7 +932,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: delegateError) - let result = await sut.signIn(params: MSALNativeAuthSignInWithCodeParameters(username: expectedUsername, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: nil, context: expectedContext, scopes: nil)) helper.onSignInError(result) @@ -941,7 +941,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { receivedEvents.removeAll() } - private func checkDelegateErrorWithValidatorError(delegateError: SignInPasswordStartError, validatorError: MSALNativeAuthTokenValidatedErrorType) async { + private func checkDelegateErrorWithValidatorError(delegateError: SignInStartError, validatorError: MSALNativeAuthTokenValidatedErrorType) async { let expectedUsername = "username" let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) @@ -963,7 +963,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: delegateError) tokenResponseValidatorMock.tokenValidatedResponse = .error(validatorError) - let result = await sut.signIn(params: MSALNativeAuthSignInWithPasswordParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) + let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil)) helper.onSignInPasswordError(result) diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift index a7d07363ae..f41bd08fa1 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift @@ -78,7 +78,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) helper.onSignUpPasswordStartError(result) @@ -103,7 +103,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpPasswordStartValidatorHelper() - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) helper.onSignUpPasswordStartError(result) XCTAssertTrue(requestProviderMock.challengeCalled) @@ -120,7 +120,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) result.telemetryUpdate?(.success(())) helper.onSignUpAttributesInvalid(result) @@ -145,7 +145,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) result.telemetryUpdate?(.failure(.init(message: "error"))) helper.onSignUpAttributesInvalid(result) @@ -169,7 +169,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -200,7 +200,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -231,7 +231,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -262,7 +262,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -284,7 +284,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -310,7 +310,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -335,7 +335,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) result.telemetryUpdate?(.success(())) helper.onSignUpCodeRequired(result) @@ -361,7 +361,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -386,7 +386,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -417,7 +417,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -443,7 +443,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) - let result = await sut.signUpStartPassword(parameters: signUpStartPasswordParams) + let result = await sut.signUpStart(parameters: signUpStartPasswordParams) helper.onSignUpPasswordStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -466,7 +466,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -490,7 +490,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let helper = prepareSignUpCodeStartValidatorHelper() - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) helper.onSignUpStartError(result) XCTAssertTrue(requestProviderMock.challengeCalled) @@ -507,7 +507,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) result.telemetryUpdate?(.success(())) helper.onSignUpAttributesInvalid(result) @@ -531,7 +531,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) result.telemetryUpdate?(.failure(.init(message: "error"))) helper.onSignUpAttributesInvalid(result) @@ -554,7 +554,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -585,7 +585,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -616,7 +616,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -647,7 +647,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -669,7 +669,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -695,7 +695,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -720,7 +720,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) result.telemetryUpdate?(.success(())) helper.onSignUpCodeRequired(result) @@ -746,7 +746,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -771,7 +771,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -802,7 +802,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) @@ -828,7 +828,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) - let result = await sut.signUpStartCode(parameters: signUpStartCodeParams) + let result = await sut.signUpStart(parameters: signUpStartCodeParams) helper.onSignUpStartError(result) await fulfillment(of: [exp], timeout: 1) diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift index ac1d78c0fd..e71850b5dc 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift @@ -31,18 +31,13 @@ class MSALNativeAuthSignInControllerMock: MSALNativeAuthSignInControlling { private(set) var slt: String? var expectation: XCTestExpectation? - var signInPasswordStartResult: MSALNativeAuthSignInControlling.SignInPasswordControllerResponse! - var signInStartResult: MSALNativeAuthSignInControlling.SignInCodeControllerResponse! + var signInStartResult: MSALNativeAuthSignInControlling.SignInControllerResponse! var signInSLTResult: SignInAfterPreviousFlowControllerResponse! var submitCodeResult: SignInSubmitCodeControllerResponse! var submitPasswordResult: SignInSubmitPasswordControllerResponse! var resendCodeResult: SignInResendCodeControllerResponse! - func signIn(params: MSAL.MSALNativeAuthSignInWithPasswordParameters) async -> MSALNativeAuthSignInControlling.SignInPasswordControllerResponse { - return signInPasswordStartResult - } - - func signIn(params: MSAL.MSALNativeAuthSignInWithCodeParameters) async -> MSALNativeAuthSignInControlling.SignInCodeControllerResponse { + func signIn(params: MSAL.MSALNativeAuthSignInParameters) async -> MSALNativeAuthSignInControlling.SignInControllerResponse { return signInStartResult } diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift index 0710595c6f..7ebaca6a9f 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift @@ -28,20 +28,14 @@ import XCTest class MSALNativeAuthSignUpControllerMock: MSALNativeAuthSignUpControlling { - var startPasswordResult: MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse! - var startResult: MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse! + var startResult: MSALNativeAuthSignUpControlling.SignUpStartControllerResponse! var resendCodeResult: SignUpResendCodeControllerResponse! var submitCodeResult: MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse! var submitPasswordResult: MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse! var signUpStartRequestParameters: MSALNativeAuthSignUpStartRequestProviderParameters? var submitAttributesResult: SignUpSubmitAttributesControllerResponse! - func signUpStartPassword(parameters: MSAL.MSALNativeAuthSignUpStartRequestProviderParameters) async -> MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse { - signUpStartRequestParameters = parameters - return startPasswordResult - } - - func signUpStartCode(parameters: MSAL.MSALNativeAuthSignUpStartRequestProviderParameters) async -> MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse { + func signUpStart(parameters: MSAL.MSALNativeAuthSignUpStartRequestProviderParameters) async -> MSALNativeAuthSignUpControlling.SignUpStartControllerResponse { signUpStartRequestParameters = parameters return startResult } diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift index 8cb044efc2..1d021ac41c 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift @@ -42,16 +42,16 @@ class MSALNativeAuthSignUpControllerSpy: MSALNativeAuthSignUpControlling { func signUpStartPassword( parameters: MSAL.MSALNativeAuthSignUpStartRequestProviderParameters - ) async -> MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse { + ) async -> MSALNativeAuthSignUpControlling.SignUpStartControllerResponse { self.context = parameters.context signUpStartPasswordCalled = true expectation.fulfill() return .init(.error(.init(type: .generalError))) } - func signUpStartCode( + func signUpStart( parameters: MSAL.MSALNativeAuthSignUpStartRequestProviderParameters - ) async -> MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse { + ) async -> MSALNativeAuthSignUpControlling.SignUpStartControllerResponse { self.context = parameters.context signUpStartCalled = true expectation.fulfill() diff --git a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift index af7a531e65..f71824533e 100644 --- a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift +++ b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift @@ -25,22 +25,22 @@ @testable import MSAL import XCTest -open class SignInPasswordStartDelegateSpy: SignInPasswordStartDelegate { +open class SignInPasswordStartDelegateSpy: SignInStartDelegate { let expectation: XCTestExpectation - var expectedError: SignInPasswordStartError? + var expectedError: SignInStartError? var expectedUserAccountResult: MSALNativeAuthUserAccountResult? var expectedSentTo: String? var expectedChannelTargetType: MSALNativeAuthChannelType? var expectedCodeLength: Int? private(set) var newSignInCodeRequiredState: SignInCodeRequiredState? - init(expectation: XCTestExpectation, expectedError: SignInPasswordStartError? = nil, expectedUserAccountResult: MSALNativeAuthUserAccountResult? = nil) { + init(expectation: XCTestExpectation, expectedError: SignInStartError? = nil, expectedUserAccountResult: MSALNativeAuthUserAccountResult? = nil) { self.expectation = expectation self.expectedError = expectedError self.expectedUserAccountResult = expectedUserAccountResult } - public func onSignInPasswordStartError(error: MSAL.SignInPasswordStartError) { + public func onSignInStartError(error: MSAL.SignInStartError) { if let expectedError = expectedError { XCTAssertTrue(Thread.isMainThread) XCTAssertEqual(error.type, expectedError.type) @@ -133,9 +133,9 @@ final class SignInPasswordRequiredDelegateOptionalMethodsNotImplemented: SignInP } } -open class SignInPasswordStartDelegateFailureSpy: SignInPasswordStartDelegate { +open class SignInPasswordStartDelegateFailureSpy: SignInStartDelegate { - public func onSignInPasswordStartError(error: MSAL.SignInPasswordStartError) { + public func onSignInStartError(error: MSAL.SignInStartError) { XCTFail("This method should not be called") } @@ -385,18 +385,18 @@ final class SignInAfterSignUpDelegateOptionalMethodsNotImplemented: SignInAfterS } } -final class SignInPasswordStartDelegateOptionalMethodNotImplemented: SignInPasswordStartDelegate { +final class SignInPasswordStartDelegateOptionalMethodNotImplemented: SignInStartDelegate { private let expectation: XCTestExpectation - var expectedError: SignInPasswordStartError? + var expectedError: SignInStartError? var expectedUserAccountResult: MSALNativeAuthUserAccountResult? - init(expectation: XCTestExpectation, expectedError: SignInPasswordStartError? = nil, expectedUserAccountResult: MSALNativeAuthUserAccountResult? = nil) { + init(expectation: XCTestExpectation, expectedError: SignInStartError? = nil, expectedUserAccountResult: MSALNativeAuthUserAccountResult? = nil) { self.expectation = expectation self.expectedError = expectedError self.expectedUserAccountResult = expectedUserAccountResult } - func onSignInPasswordStartError(error: MSAL.SignInPasswordStartError) { + func onSignInStartError(error: MSAL.SignInStartError) { if let expectedError = expectedError { XCTAssertTrue(Thread.isMainThread) XCTAssertEqual(error.type, expectedError.type) diff --git a/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift b/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift index c5ed0d08fb..cb7027e163 100644 --- a/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift +++ b/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift @@ -27,17 +27,17 @@ import XCTest class SignInPasswordStartTestsValidatorHelper: SignInPasswordStartDelegateSpy { - func onSignInPasswordError(_ input: MSALNativeAuthSignInController.SignInPasswordControllerResponse) { + func onSignInPasswordError(_ input: MSALNativeAuthSignInController.SignInControllerResponse) { guard case let .error(error) = input.result else { expectation.fulfill() return XCTFail("input should be .error") } self.expectedError = error - Task { await self.onSignInPasswordStartError(error: error) } + Task { await self.onSignInStartError(error: error) } } - func onSignInCodeRequired(_ input: MSALNativeAuthSignInController.SignInPasswordControllerResponse) { + func onSignInCodeRequired(_ input: MSALNativeAuthSignInController.SignInControllerResponse) { guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input.result else { expectation.fulfill() @@ -47,7 +47,7 @@ class SignInPasswordStartTestsValidatorHelper: SignInPasswordStartDelegateSpy { Task { await self.onSignInCodeRequired(newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength) } } - func onSignInCompleted(_ input: MSALNativeAuthSignInController.SignInPasswordControllerResponse) { + func onSignInCompleted(_ input: MSALNativeAuthSignInController.SignInControllerResponse) { guard case let .completed(result) = input.result else { expectation.fulfill() return XCTFail("input should be .success") @@ -80,7 +80,7 @@ class SignInPasswordRequiredTestsValidatorHelper: SignInPasswordRequiredDelegate class SignInCodeStartTestsValidatorHelper: SignInCodeStartDelegateSpy { - func onSignInError(_ input: MSALNativeAuthSignInControlling.SignInCodeControllerResponse) { + func onSignInError(_ input: MSALNativeAuthSignInControlling.SignInControllerResponse) { guard case let .error(error) = input.result else { expectation.fulfill() return XCTFail("input should be .error") @@ -89,7 +89,7 @@ class SignInCodeStartTestsValidatorHelper: SignInCodeStartDelegateSpy { Task { await self.onSignInStartError(error: error) } } - func onSignInCodeRequired(_ input: MSALNativeAuthSignInControlling.SignInCodeControllerResponse) { + func onSignInCodeRequired(_ input: MSALNativeAuthSignInControlling.SignInControllerResponse) { guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input.result else { expectation.fulfill() return XCTFail("input should be .codeRequired") diff --git a/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift b/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift index 34d308a29b..5317727312 100644 --- a/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift +++ b/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift @@ -25,12 +25,12 @@ import XCTest @testable import MSAL -class SignUpPasswordStartDelegateSpy: SignUpPasswordStartDelegate { +class SignUpPasswordStartDelegateSpy: SignUpStartDelegate { let expectation: XCTestExpectation? private(set) var onSignUpPasswordErrorCalled = false private(set) var onSignUpCodeRequiredCalled = false private(set) var onSignUpAttributesInvalidCalled = false - private(set) var error: SignUpPasswordStartError? + private(set) var error: SignUpStartError? private(set) var newState: SignUpCodeRequiredState? private(set) var sentTo: String? private(set) var channelTargetType: MSALNativeAuthChannelType? @@ -41,7 +41,7 @@ class SignUpPasswordStartDelegateSpy: SignUpPasswordStartDelegate { self.expectation = expectation } - func onSignUpPasswordStartError(error: MSAL.SignUpPasswordStartError) { + func onSignUpStartError(error: MSAL.SignUpStartError) { onSignUpPasswordErrorCalled = true self.error = error @@ -337,16 +337,16 @@ class SignUpVerifyCodeDelegateOptionalMethodsNotImplemented: SignUpVerifyCodeDel } } -class SignUpPasswordStartDelegateOptionalMethodsNotImplemented: SignUpPasswordStartDelegate { +class SignUpPasswordStartDelegateOptionalMethodsNotImplemented: SignUpStartDelegate { private let expectation: XCTestExpectation? private(set) var onSignUpPasswordErrorCalled = false - private(set) var error: SignUpPasswordStartError? + private(set) var error: SignUpStartError? init(expectation: XCTestExpectation? = nil) { self.expectation = expectation } - func onSignUpPasswordStartError(error: MSAL.SignUpPasswordStartError) { + func onSignUpStartError(error: MSAL.SignUpStartError) { onSignUpPasswordErrorCalled = true self.error = error diff --git a/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift b/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift index a4274b7117..b61323877f 100644 --- a/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift +++ b/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift @@ -27,18 +27,18 @@ import XCTest class SignUpPasswordStartTestsValidatorHelper: SignUpPasswordStartDelegateSpy { - func onSignUpPasswordStartError(_ input: MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse) { + func onSignUpPasswordStartError(_ input: MSALNativeAuthSignUpControlling.SignUpStartControllerResponse) { guard case let .error(error) = input.result else { expectation?.fulfill() return XCTFail("Should be an .error") } Task { - await self.onSignUpPasswordStartError(error: error) + await self.onSignUpStartError(error: error) } } - func onSignUpCodeRequired(_ input: MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse) { + func onSignUpCodeRequired(_ input: MSALNativeAuthSignUpControlling.SignUpStartControllerResponse) { guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input.result else { expectation?.fulfill() return XCTFail("Should be .codeRequired") @@ -49,7 +49,7 @@ class SignUpPasswordStartTestsValidatorHelper: SignUpPasswordStartDelegateSpy { } } - func onSignUpAttributesInvalid(_ input: MSALNativeAuthSignUpControlling.SignUpStartPasswordControllerResponse) { + func onSignUpAttributesInvalid(_ input: MSALNativeAuthSignUpControlling.SignUpStartControllerResponse) { guard case let .attributesInvalid(attributes) = input.result else { expectation?.fulfill() return XCTFail("Should be .attributeValidationFailed") @@ -63,7 +63,7 @@ class SignUpPasswordStartTestsValidatorHelper: SignUpPasswordStartDelegateSpy { class SignUpCodeStartTestsValidatorHelper: SignUpCodeStartDelegateSpy { - func onSignUpStartError(_ input: MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse) { + func onSignUpStartError(_ input: MSALNativeAuthSignUpControlling.SignUpStartControllerResponse) { guard case let .error(error) = input.result else { expectation?.fulfill() return XCTFail("Should be an .error") @@ -74,7 +74,7 @@ class SignUpCodeStartTestsValidatorHelper: SignUpCodeStartDelegateSpy { } } - func onSignUpCodeRequired(_ input: MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse) { + func onSignUpCodeRequired(_ input: MSALNativeAuthSignUpControlling.SignUpStartControllerResponse) { guard case let .codeRequired(newState, sentTo, channelTargetType, codeLength) = input.result else { expectation?.fulfill() return XCTFail("Should be .codeRequired") @@ -85,7 +85,7 @@ class SignUpCodeStartTestsValidatorHelper: SignUpCodeStartDelegateSpy { } } - func onSignUpAttributesInvalid(_ input: MSALNativeAuthSignUpControlling.SignUpStartCodeControllerResponse) { + func onSignUpAttributesInvalid(_ input: MSALNativeAuthSignUpControlling.SignUpStartControllerResponse) { guard case let .attributesInvalid(attributes) = input.result else { expectation?.fulfill() return XCTFail("Should be .attributeValidationFailed") diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift index 47e52167b2..be12219c02 100644 --- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift @@ -30,24 +30,6 @@ final class MSALNativeAuthSignUpChallengeResponseErrorTests: XCTestCase { private var sut: MSALNativeAuthSignUpChallengeResponseError! private let testDescription = "testDescription" - // MARK: - to toSignUpPasswordStartPublicError tests - - func test_toSignUpPasswordStartPublicError_unauthorizedClient() { - testSignUpChallengeErrorToSignUpPasswordStart(code: .unauthorizedClient, description: testDescription, expectedErrorType: .generalError) - } - - func test_toSignUpPasswordStartPublicError_unsupportedChallengeType() { - testSignUpChallengeErrorToSignUpPasswordStart(code: .unsupportedChallengeType, description: "General error", expectedErrorType: .generalError) - } - - func test_toSignUpPasswordStartPublicError_expiredToken() { - testSignUpChallengeErrorToSignUpPasswordStart(code: .expiredToken, description: testDescription, expectedErrorType: .generalError) - } - - func test_toSignUpPasswordStartPublicError_invalidRequest() { - testSignUpChallengeErrorToSignUpPasswordStart(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError) - } - // MARK: - to SignUpCodeStartError tests func test_toSignUpCodeStartPublicError_unauthorizedClient() { @@ -104,13 +86,6 @@ final class MSALNativeAuthSignUpChallengeResponseErrorTests: XCTestCase { // MARK: private methods - private func testSignUpChallengeErrorToSignUpPasswordStart(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?, expectedErrorType: SignUpPasswordStartError.ErrorType) { - sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil) - let error = sut.toSignUpPasswordStartPublicError() - XCTAssertEqual(error.type, expectedErrorType) - XCTAssertEqual(error.errorDescription, description) - } - private func testSignUpChallengeErrorToSignUpStart(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?, expectedErrorType: SignUpStartError.ErrorType) { sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil) let error = sut.toSignUpStartPublicError() diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift index 1f0be321d8..96804ec7e2 100644 --- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift @@ -30,60 +30,6 @@ final class MSALNativeAuthSignUpStartResponseErrorTests: XCTestCase { private var sut: MSALNativeAuthSignUpStartResponseError! private let testDescription = "testDescription" - // MARK: - to toSignUpStartPasswordPublicError tests - - func test_toSignUpStartPasswordPublicError_invalidRequest() { - testSignUpStartErrorToSignUpStartPassword(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError) - } - - func test_toSignUpStartPasswordPublicError_unauthorizedClient() { - testSignUpStartErrorToSignUpStartPassword(code: .unauthorizedClient, description: testDescription, expectedErrorType: .generalError) - } - - func test_toSignUpStartPasswordPublicError_unsupportedChallengeType() { - testSignUpStartErrorToSignUpStartPassword(code: .unsupportedChallengeType, description: "General error", expectedErrorType: .generalError) - } - - func test_toSignUpStartPasswordPublicError_passwordTooWeak() { - testSignUpStartErrorToSignUpStartPassword(code: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword) - } - - func test_toSignUpStartPasswordPublicError_passwordTooShort() { - testSignUpStartErrorToSignUpStartPassword(code: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword) - } - - func test_toSignUpStartPasswordPublicError_passwordTooLong() { - testSignUpStartErrorToSignUpStartPassword(code: .passwordTooLong, description: testDescription, expectedErrorType: .invalidPassword) - } - - func test_toSignUpStartPasswordPublicError_passwordRecentlyUsed() { - testSignUpStartErrorToSignUpStartPassword(code: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword) - } - - func test_toSignUpStartPasswordPublicError_passwordBanned() { - testSignUpStartErrorToSignUpStartPassword(code: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword) - } - - func test_toSignUpStartPasswordPublicError_userAlreadyExists() { - testSignUpStartErrorToSignUpStartPassword(code: .userAlreadyExists, description: testDescription, expectedErrorType: .userAlreadyExists) - } - - func test_toSignUpStartPasswordPublicError_attributesRequired() { - testSignUpStartErrorToSignUpStartPassword(code: .attributesRequired, description: testDescription, expectedErrorType: .generalError) - } - - func test_toSignUpStartPasswordPublicError_verificationRequired() { - testSignUpStartErrorToSignUpStartPassword(code: .verificationRequired, description: testDescription, expectedErrorType: .generalError) - } - - func test_toSignUpStartPasswordPublicError_unsupportedAuthMethod() { - testSignUpStartErrorToSignUpStartPassword(code: .unsupportedAuthMethod, description: testDescription, expectedErrorType: .generalError) - } - - func test_toSignUpStartPasswordPublicError_attributeValidationFailed() { - testSignUpStartErrorToSignUpStartPassword(code: .attributeValidationFailed, description: testDescription, expectedErrorType: .generalError) - } - // MARK: - to toSignUpStartPublicError tests func test_toSignUpStartPublicError_invalidRequest() { @@ -99,23 +45,23 @@ final class MSALNativeAuthSignUpStartResponseErrorTests: XCTestCase { } func test_toSignUpStartPublicError_passwordTooWeak() { - testSignUpStartErrorToSignUpStart(code: .passwordTooWeak, description: testDescription, expectedErrorType: .generalError) + testSignUpStartErrorToSignUpStart(code: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword) } func test_toSignUpStartPublicError_passwordTooShort() { - testSignUpStartErrorToSignUpStart(code: .passwordTooShort, description: testDescription, expectedErrorType: .generalError) + testSignUpStartErrorToSignUpStart(code: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword) } func test_toSignUpStartPublicError_passwordTooLong() { - testSignUpStartErrorToSignUpStart(code: .passwordTooLong, description: testDescription, expectedErrorType: .generalError) + testSignUpStartErrorToSignUpStart(code: .passwordTooLong, description: testDescription, expectedErrorType: .invalidPassword) } func test_toSignUpStartPublicError_passwordRecentlyUsed() { - testSignUpStartErrorToSignUpStart(code: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .generalError) + testSignUpStartErrorToSignUpStart(code: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword) } func test_toSignUpStartPublicError_passwordBanned() { - testSignUpStartErrorToSignUpStart(code: .passwordBanned, description: testDescription, expectedErrorType: .generalError) + testSignUpStartErrorToSignUpStart(code: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword) } func test_toSignUpStartPublicError_userAlreadyExists() { @@ -140,13 +86,6 @@ final class MSALNativeAuthSignUpStartResponseErrorTests: XCTestCase { // MARK: private methods - private func testSignUpStartErrorToSignUpStartPassword(code: MSALNativeAuthSignUpStartOauth2ErrorCode, description: String?, expectedErrorType: SignUpPasswordStartError.ErrorType) { - sut = MSALNativeAuthSignUpStartResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, unverifiedAttributes: nil, invalidAttributes: nil) - let error = sut.toSignUpStartPasswordPublicError() - XCTAssertEqual(error.type, expectedErrorType) - XCTAssertEqual(error.errorDescription, description) - } - private func testSignUpStartErrorToSignUpStart(code: MSALNativeAuthSignUpStartOauth2ErrorCode, description: String?, expectedErrorType: SignUpStartError.ErrorType) { sut = MSALNativeAuthSignUpStartResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, unverifiedAttributes: nil, invalidAttributes: nil) let error = sut.toSignUpStartPublicError() diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift index 0f3b81beaa..faaf07c216 100644 --- a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift +++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift @@ -74,7 +74,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { func testSignUpPassword_delegate_whenInvalidUsernameUsed_shouldReturnCorrectError() { let exp = expectation(description: "sign-up public interface") let delegate = SignUpPasswordStartDelegateSpy(expectation: exp) - sut.signUpUsingPassword(username: "", password: "", delegate: delegate) + sut.signUp(username: "", password: "", delegate: delegate) wait(for: [exp], timeout: 1) XCTAssertEqual(delegate.error?.type, .invalidUsername) } @@ -82,7 +82,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { func testSignUpPassword_delegate_whenInvalidPasswordUsed_shouldReturnCorrectError() { let exp = expectation(description: "sign-up public interface") let delegate = SignUpPasswordStartDelegateSpy(expectation: exp) - sut.signUpUsingPassword(username: "correct", password: "", delegate: delegate) + sut.signUp(username: "correct", password: "", delegate: delegate) wait(for: [exp], timeout: 1) XCTAssertEqual(delegate.error?.type, .invalidPassword) } @@ -92,17 +92,17 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let exp2 = expectation(description: "sign-up public interface telemetry") let delegate = SignUpPasswordStartDelegateSpy(expectation: exp1) - let expectedResult: SignUpPasswordStartResult = .codeRequired( + let expectedResult: SignUpStartResult = .codeRequired( newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 ) - controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult, telemetryUpdate: { _ in + controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in exp2.fulfill() }) - sut.signUpUsingPassword(username: "correct", password: "correct", delegate: delegate) + sut.signUp(username: "correct", password: "correct", delegate: delegate) wait(for: [exp1, exp2]) @@ -115,17 +115,17 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let exp2 = expectation(description: "sign-up public interface telemetry") let delegate = SignUpPasswordStartDelegateOptionalMethodsNotImplemented(expectation: exp) - let expectedResult: SignUpPasswordStartResult = .codeRequired( + let expectedResult: SignUpStartResult = .codeRequired( newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 ) - controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult, telemetryUpdate: { _ in + controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in exp2.fulfill() }) - - sut.signUpUsingPassword(username: "correct", password: "correct", delegate: delegate) + + sut.signUp(username: "correct", password: "correct", delegate: delegate) wait(for: [exp, exp2]) @@ -142,12 +142,12 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignUpPasswordStartDelegateSpy(expectation: exp) let expectedInvalidAttributes = ["attribute"] - let expectedResult: SignUpPasswordStartResult = .attributesInvalid(expectedInvalidAttributes) - controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult, telemetryUpdate: { _ in + let expectedResult: SignUpStartResult = .attributesInvalid(expectedInvalidAttributes) + controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in exp2.fulfill() }) - sut.signUpUsingPassword(username: "correct", password: "correct", delegate: delegate) + sut.signUp(username: "correct", password: "correct", delegate: delegate) wait(for: [exp, exp2]) @@ -160,12 +160,12 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignUpPasswordStartDelegateOptionalMethodsNotImplemented(expectation: exp) let expectedInvalidAttributes = ["attribute"] - let expectedResult: SignUpPasswordStartResult = .attributesInvalid(expectedInvalidAttributes) - controllerFactoryMock.signUpController.startPasswordResult = .init(expectedResult, telemetryUpdate: { _ in + let expectedResult: SignUpStartResult = .attributesInvalid(expectedInvalidAttributes) + controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in exp2.fulfill() }) - sut.signUpUsingPassword(username: "correct", password: "correct", delegate: delegate) + sut.signUp(username: "correct", password: "correct", delegate: delegate) wait(for: [exp, exp2]) @@ -280,14 +280,14 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { func testSignInPassword_delegate_whenInvalidUsernameUsed_shouldReturnCorrectError() { let expectation = expectation(description: "sign-in public interface") let delegate = SignInPasswordStartDelegateSpy(expectation: expectation, expectedError: .init(type: .invalidUsername)) - sut.signInUsingPassword(username: "", password: "", delegate: delegate) + sut.signIn(username: "", password: "", delegate: delegate) wait(for: [expectation], timeout: 1) } func testSignInPassword_delegate_whenInvalidPasswordUsed_shouldReturnCorrectError() { let expectation = expectation(description: "sign-in public interface") let delegate = SignInPasswordStartDelegateSpy(expectation: expectation, expectedError: .init(type: .invalidCredentials)) - sut.signInUsingPassword(username: "correct", password: "", delegate: delegate) + sut.signIn(username: "correct", password: "", delegate: delegate) wait(for: [expectation], timeout: 1) } @@ -296,10 +296,10 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let exp2 = expectation(description: "expectation Telemetry") let delegate = SignInPasswordStartDelegateSpy(expectation: exp1, expectedUserAccountResult: MSALNativeAuthUserAccountResultStub.result) - controllerFactoryMock.signInController.signInPasswordStartResult = .init(.init(.completed(MSALNativeAuthUserAccountResultStub.result), telemetryUpdate: { _ in + controllerFactoryMock.signInController.signInStartResult = .init(.init(.completed(MSALNativeAuthUserAccountResultStub.result), telemetryUpdate: { _ in exp2.fulfill() })) - sut.signInUsingPassword(username: "correct", password: "correct", delegate: delegate) + sut.signIn(username: "correct", password: "correct", delegate: delegate) wait(for: [exp1, exp2], timeout: 1) } @@ -308,16 +308,16 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let exp = expectation(description: "sign-in public interface") let exp2 = expectation(description: "expectation Telemetry") - let expectedError = SignInPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted")) + let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted")) let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: exp, expectedError: expectedError) - let expectedResult: SignInPasswordStartResult = .completed(MSALNativeAuthUserAccountResultStub.result) + let expectedResult: SignInStartResult = .completed(MSALNativeAuthUserAccountResultStub.result) - controllerFactoryMock.signInController.signInPasswordStartResult = .init(expectedResult, telemetryUpdate: { _ in + controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in exp2.fulfill() }) - sut.signInUsingPassword(username: "correct", password: "correct", delegate: delegate) + sut.signIn(username: "correct", password: "correct", delegate: delegate) wait(for: [exp, exp2], timeout: 1) } @@ -331,18 +331,18 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { delegate.expectedCodeLength = 1 delegate.expectedChannelTargetType = .email - let expectedResult: SignInPasswordStartResult = .codeRequired( + let expectedResult: SignInStartResult = .codeRequired( newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 ) - controllerFactoryMock.signInController.signInPasswordStartResult = .init(expectedResult, telemetryUpdate: { _ in + controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in exp2.fulfill() }) - sut.signInUsingPassword(username: "correct", password: "correct", delegate: delegate) + sut.signIn(username: "correct", password: "correct", delegate: delegate) wait(for: [exp1, exp2], timeout: 1) } @@ -351,21 +351,21 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let exp = expectation(description: "sign-in public interface") let exp2 = expectation(description: "expectation Telemetry") - let expectedError = SignInPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired")) + let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired")) let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: exp, expectedError: expectedError) - let expectedResult: SignInPasswordStartResult = .codeRequired( + let expectedResult: SignInStartResult = .codeRequired( newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 ) - controllerFactoryMock.signInController.signInPasswordStartResult = .init(expectedResult, telemetryUpdate: { _ in + controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in exp2.fulfill() }) - sut.signInUsingPassword(username: "correct", password: "correct", delegate: delegate) + sut.signIn(username: "correct", password: "correct", delegate: delegate) wait(for: [exp, exp2], timeout: 1) } @@ -609,7 +609,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { // Correlation Id is validated internally against expectedStartRequestParameters and expectedChallengeRequestParameters in the // MSALNativeAuthSignUpRequestProviderMock class - checkStartParameters and checkChallengeParameters functions - sut.signUpUsingPassword(username: "username", password: "password", attributes: ["key": "value"], correlationId: correlationId, delegate: delegatePasswordStart) + sut.signUp(username: "username", password: "password", attributes: ["key": "value"], correlationId: correlationId, delegate: delegatePasswordStart) wait(for: [expectationPasswordStart]) @@ -801,7 +801,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { // Correlation Id is validated internally against contextMock on both initiate and challenge in the // MSALNativeAuthSignInRequestProviderMock class - checkContext function - sut.signInUsingPassword(username: "username", password: "password", scopes: ["scope1", "scope2"], correlationId: correlationId, delegate: delegatePasswordStart) + sut.signIn(username: "username", password: "password", scopes: ["scope1", "scope2"], correlationId: correlationId, delegate: delegatePasswordStart) wait(for: [expectationPasswordStart]) diff --git a/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift b/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift index 0e097e8dfa..b72ea24235 100644 --- a/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift @@ -68,8 +68,6 @@ final class DispatchAccessTokenRetrieveCompletedTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedResult = MSALNativeAuthUserAccountResultStub.result - await sut.dispatchAccessTokenRetrieveCompleted(accessToken: "token") await fulfillment(of: [telemetryExp, delegateExp]) diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift index 70a2985041..e4709a253e 100644 --- a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift @@ -29,7 +29,7 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase { private var telemetryExp: XCTestExpectation! private var delegateExp: XCTestExpectation! - private var sut: SignInPasswordStartDelegateDispatcher! + private var sut: SignInStartDelegateDispatcher! private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() private let correlationId = UUID() @@ -70,12 +70,12 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase { } func test_dispatchSignInCodeRequired_whenDelegateOptionalMethodsNotImplemented() async { - let expectedError = SignInPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired")) + let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired")) let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: delegateExp, expectedError: expectedError) sut = .init(delegate: delegate, telemetryUpdate: { result in - guard case let .failure(error) = result, let customError = error as? SignInPasswordStartError else { + guard case let .failure(error) = result, let customError = error as? SignInStartError else { return XCTFail("wrong result") } @@ -98,7 +98,7 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase { await fulfillment(of: [telemetryExp, delegateExp]) checkError(delegate.expectedError) - func checkError(_ error: SignInPasswordStartError?) { + func checkError(_ error: SignInStartError?) { XCTAssertEqual(error?.type, expectedError.type) XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) } @@ -123,12 +123,12 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase { } func test_dispatchSignInCompleted_whenDelegateOptionalMethodsNotImplemented() async { - let expectedError = SignInPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted")) + let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted")) let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: delegateExp, expectedError: expectedError) sut = .init(delegate: delegate, telemetryUpdate: { result in - guard case let .failure(error) = result, let customError = error as? SignInPasswordStartError else { + guard case let .failure(error) = result, let customError = error as? SignInStartError else { return XCTFail("wrong result") } @@ -143,7 +143,7 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase { await fulfillment(of: [telemetryExp, delegateExp]) checkError(delegate.expectedError) - func checkError(_ error: SignInPasswordStartError?) { + func checkError(_ error: SignInStartError?) { XCTAssertEqual(error?.type, expectedError.type) XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) } diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift index 0e0f7812a8..e8b8ec1b71 100644 --- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift @@ -29,7 +29,7 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase { private var telemetryExp: XCTestExpectation! private var delegateExp: XCTestExpectation! - private var sut: SignUpPasswordStartDelegateDispatcher! + private var sut: SignUpStartDelegateDispatcher! private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() private let correlationId = UUID() @@ -54,7 +54,7 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase { let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 - await sut.dispatchSignUpPasswordCodeRequired( + await sut.dispatchSignUpCodeRequired( newState: expectedState, sentTo: expectedSentTo, channelTargetType: expectedChannelTargetType, @@ -71,10 +71,10 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase { func test_dispatchSignUpPasswordCodeRequired_whenDelegateOptionalMethodsNotImplemented() async { let delegate = SignUpPasswordStartDelegateOptionalMethodsNotImplemented(expectation: delegateExp) - let expectedError = SignUpPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCodeRequired")) + let expectedError = SignUpStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCodeRequired")) sut = .init(delegate: delegate, telemetryUpdate: { result in - guard case let .failure(error) = result, let customError = error as? SignUpPasswordStartError else { + guard case let .failure(error) = result, let customError = error as? SignUpStartError else { return XCTFail("wrong result") } @@ -87,7 +87,7 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase { let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 - await sut.dispatchSignUpPasswordCodeRequired( + await sut.dispatchSignUpCodeRequired( newState: expectedState, sentTo: expectedSentTo, channelTargetType: expectedChannelTargetType, @@ -97,7 +97,7 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase { await fulfillment(of: [telemetryExp, delegateExp]) checkError(delegate.error) - func checkError(_ error: SignUpPasswordStartError?) { + func checkError(_ error: SignUpStartError?) { XCTAssertEqual(error?.type, expectedError.type) XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) } @@ -124,10 +124,10 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase { func test_dispatchSignUpAttributesInvalid_whenDelegateOptionalMethodsNotImplemented() async { let delegate = SignUpPasswordStartDelegateOptionalMethodsNotImplemented(expectation: delegateExp) - let expectedError = SignUpPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid")) + let expectedError = SignUpStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid")) sut = .init(delegate: delegate, telemetryUpdate: { result in - guard case let .failure(error) = result, let customError = error as? SignUpPasswordStartError else { + guard case let .failure(error) = result, let customError = error as? SignUpStartError else { return XCTFail("wrong result") } @@ -142,7 +142,7 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase { await fulfillment(of: [telemetryExp, delegateExp]) checkError(delegate.error) - func checkError(_ error: SignUpPasswordStartError?) { + func checkError(_ error: SignUpStartError?) { XCTAssertEqual(error?.type, expectedError.type) XCTAssertEqual(error?.errorDescription, expectedError.errorDescription) } diff --git a/MSAL/test/unit/native_auth/public/error/SignInPasswordStartErrorTests.swift b/MSAL/test/unit/native_auth/public/error/SignInPasswordStartErrorTests.swift deleted file mode 100644 index 0c3d0d6f32..0000000000 --- a/MSAL/test/unit/native_auth/public/error/SignInPasswordStartErrorTests.swift +++ /dev/null @@ -1,97 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. -// All rights reserved. -// -// This code is licensed under the MIT License. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import XCTest -@testable import MSAL - -final class SignInPasswordStartErrorTests: XCTestCase { - - private var sut: SignInPasswordStartError! - - func test_totalCases() { - XCTAssertEqual(SignInPasswordStartError.ErrorType.allCases.count, 5) - } - - func test_customErrorDescription() { - let expectedMessage = "Custom error message" - sut = .init(type: .generalError, message: expectedMessage) - XCTAssertEqual(sut.errorDescription, expectedMessage) - } - - func test_defaultErrorDescription() { - let sut: [SignInPasswordStartError] = [ - .init(type: .browserRequired), - .init(type: .userNotFound), - .init(type: .invalidCredentials), - .init(type: .invalidUsername), - .init(type: .generalError) - ] - - let expectedDescriptions = [ - MSALNativeAuthErrorMessage.browserRequired, - MSALNativeAuthErrorMessage.userNotFound, - MSALNativeAuthErrorMessage.invalidCredentials, - MSALNativeAuthErrorMessage.invalidUsername, - MSALNativeAuthErrorMessage.generalError - ] - - let errorDescriptions = sut.map { $0.errorDescription } - - zip(errorDescriptions, expectedDescriptions).forEach { - XCTAssertEqual($0, $1) - } - } - - func test_isBrowserRequired() { - sut = .init(type: .browserRequired) - XCTAssertTrue(sut.isBrowserRequired) - XCTAssertFalse(sut.isUserNotFound) - XCTAssertFalse(sut.isInvalidCredentials) - XCTAssertFalse(sut.isInvalidUsername) - } - - func test_isUserNotFound() { - sut = .init(type: .userNotFound) - XCTAssertTrue(sut.isUserNotFound) - XCTAssertFalse(sut.isBrowserRequired) - XCTAssertFalse(sut.isInvalidCredentials) - XCTAssertFalse(sut.isInvalidUsername) - } - - func test_isInvalidPassword() { - sut = .init(type: .invalidCredentials) - XCTAssertTrue(sut.isInvalidCredentials) - XCTAssertFalse(sut.isBrowserRequired) - XCTAssertFalse(sut.isUserNotFound) - XCTAssertFalse(sut.isInvalidUsername) - } - - func test_isInvalidUsername() { - sut = .init(type: .invalidUsername) - XCTAssertTrue(sut.isInvalidUsername) - XCTAssertFalse(sut.isBrowserRequired) - XCTAssertFalse(sut.isUserNotFound) - XCTAssertFalse(sut.isInvalidCredentials) - } -} diff --git a/MSAL/test/unit/native_auth/public/error/SignInStartErrorTests.swift b/MSAL/test/unit/native_auth/public/error/SignInStartErrorTests.swift index 3309c8bb6b..d6629f74a2 100644 --- a/MSAL/test/unit/native_auth/public/error/SignInStartErrorTests.swift +++ b/MSAL/test/unit/native_auth/public/error/SignInStartErrorTests.swift @@ -25,11 +25,12 @@ import XCTest @testable import MSAL -final class SignInStartErrorTests: XCTestCase { +final class SignInPasswordStartErrorTests: XCTestCase { + private var sut: SignInStartError! func test_totalCases() { - XCTAssertEqual(SignInStartError.ErrorType.allCases.count, 4) + XCTAssertEqual(SignInStartError.ErrorType.allCases.count, 5) } func test_customErrorDescription() { @@ -42,6 +43,7 @@ final class SignInStartErrorTests: XCTestCase { let sut: [SignInStartError] = [ .init(type: .browserRequired), .init(type: .userNotFound), + .init(type: .invalidCredentials), .init(type: .invalidUsername), .init(type: .generalError) ] @@ -49,6 +51,7 @@ final class SignInStartErrorTests: XCTestCase { let expectedDescriptions = [ MSALNativeAuthErrorMessage.browserRequired, MSALNativeAuthErrorMessage.userNotFound, + MSALNativeAuthErrorMessage.invalidCredentials, MSALNativeAuthErrorMessage.invalidUsername, MSALNativeAuthErrorMessage.generalError ] @@ -60,11 +63,11 @@ final class SignInStartErrorTests: XCTestCase { } } - func test_isBrowserRequired() { sut = .init(type: .browserRequired) XCTAssertTrue(sut.isBrowserRequired) XCTAssertFalse(sut.isUserNotFound) + XCTAssertFalse(sut.isInvalidCredentials) XCTAssertFalse(sut.isInvalidUsername) } @@ -72,6 +75,15 @@ final class SignInStartErrorTests: XCTestCase { sut = .init(type: .userNotFound) XCTAssertTrue(sut.isUserNotFound) XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isInvalidCredentials) + XCTAssertFalse(sut.isInvalidUsername) + } + + func test_isInvalidPassword() { + sut = .init(type: .invalidCredentials) + XCTAssertTrue(sut.isInvalidCredentials) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserNotFound) XCTAssertFalse(sut.isInvalidUsername) } @@ -80,5 +92,6 @@ final class SignInStartErrorTests: XCTestCase { XCTAssertTrue(sut.isInvalidUsername) XCTAssertFalse(sut.isBrowserRequired) XCTAssertFalse(sut.isUserNotFound) + XCTAssertFalse(sut.isInvalidCredentials) } } diff --git a/MSAL/test/unit/native_auth/public/error/SignUpPasswordStartErrorTests.swift b/MSAL/test/unit/native_auth/public/error/SignUpPasswordStartErrorTests.swift deleted file mode 100644 index 5215e34a28..0000000000 --- a/MSAL/test/unit/native_auth/public/error/SignUpPasswordStartErrorTests.swift +++ /dev/null @@ -1,97 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. -// All rights reserved. -// -// This code is licensed under the MIT License. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import XCTest -@testable import MSAL - -final class SignUpPasswordStartErrorTests: XCTestCase { - - private var sut: SignUpPasswordStartError! - - func test_totalCases() { - XCTAssertEqual(SignUpPasswordStartError.ErrorType.allCases.count, 5) - } - - func test_customErrorDescription() { - let expectedMessage = "Custom error message" - sut = .init(type: .generalError, message: expectedMessage) - XCTAssertEqual(sut.errorDescription, expectedMessage) - } - - func test_defaultErrorDescription() { - let sut: [SignUpPasswordStartError] = [ - .init(type: .browserRequired), - .init(type: .userAlreadyExists), - .init(type: .invalidPassword), - .init(type: .invalidUsername), - .init(type: .generalError) - ] - - let expectedDescriptions = [ - MSALNativeAuthErrorMessage.browserRequired, - MSALNativeAuthErrorMessage.userAlreadyExists, - MSALNativeAuthErrorMessage.invalidPassword, - MSALNativeAuthErrorMessage.invalidUsername, - MSALNativeAuthErrorMessage.generalError - ] - - let errorDescriptions = sut.map { $0.errorDescription } - - zip(errorDescriptions, expectedDescriptions).forEach { - XCTAssertEqual($0, $1) - } - } - - func test_isBrowserRequired() { - sut = .init(type: .browserRequired) - XCTAssertTrue(sut.isBrowserRequired) - XCTAssertFalse(sut.isUserAlreadyExists) - XCTAssertFalse(sut.isInvalidPassword) - XCTAssertFalse(sut.isInvalidUsername) - } - - func test_isUserAlreadyExists() { - sut = .init(type: .userAlreadyExists) - XCTAssertTrue(sut.isUserAlreadyExists) - XCTAssertFalse(sut.isBrowserRequired) - XCTAssertFalse(sut.isInvalidPassword) - XCTAssertFalse(sut.isInvalidUsername) - } - - func test_isInvalidPassword() { - sut = .init(type: .invalidPassword) - XCTAssertTrue(sut.isInvalidPassword) - XCTAssertFalse(sut.isBrowserRequired) - XCTAssertFalse(sut.isUserAlreadyExists) - XCTAssertFalse(sut.isInvalidUsername) - } - - func test_isInvalidUsername() { - sut = .init(type: .invalidUsername) - XCTAssertTrue(sut.isInvalidUsername) - XCTAssertFalse(sut.isBrowserRequired) - XCTAssertFalse(sut.isUserAlreadyExists) - XCTAssertFalse(sut.isInvalidPassword) - } -} diff --git a/MSAL/test/unit/native_auth/public/error/SignUpStartErrorTests.swift b/MSAL/test/unit/native_auth/public/error/SignUpStartErrorTests.swift index 7f94007f27..a455e8a00d 100644 --- a/MSAL/test/unit/native_auth/public/error/SignUpStartErrorTests.swift +++ b/MSAL/test/unit/native_auth/public/error/SignUpStartErrorTests.swift @@ -30,7 +30,7 @@ final class SignUpStartErrorTests: XCTestCase { private var sut: SignUpStartError! func test_totalCases() { - XCTAssertEqual(SignUpStartError.ErrorType.allCases.count, 4) + XCTAssertEqual(SignUpStartError.ErrorType.allCases.count, 5) } func test_customErrorDescription() { @@ -40,10 +40,11 @@ final class SignUpStartErrorTests: XCTestCase { } func test_defaultErrorDescription() { - let sut: [SignUpPasswordStartError] = [ + let sut: [SignUpStartError] = [ .init(type: .browserRequired), .init(type: .userAlreadyExists), .init(type: .invalidUsername), + .init(type: .invalidPassword), .init(type: .generalError) ] @@ -51,6 +52,7 @@ final class SignUpStartErrorTests: XCTestCase { MSALNativeAuthErrorMessage.browserRequired, MSALNativeAuthErrorMessage.userAlreadyExists, MSALNativeAuthErrorMessage.invalidUsername, + MSALNativeAuthErrorMessage.invalidPassword, MSALNativeAuthErrorMessage.generalError ] @@ -66,6 +68,7 @@ final class SignUpStartErrorTests: XCTestCase { XCTAssertTrue(sut.isBrowserRequired) XCTAssertFalse(sut.isUserAlreadyExists) XCTAssertFalse(sut.isInvalidUsername) + XCTAssertFalse(sut.isInvalidPassword) } func test_isUserAlreadyExists() { @@ -73,6 +76,7 @@ final class SignUpStartErrorTests: XCTestCase { XCTAssertTrue(sut.isUserAlreadyExists) XCTAssertFalse(sut.isBrowserRequired) XCTAssertFalse(sut.isInvalidUsername) + XCTAssertFalse(sut.isInvalidPassword) } func test_isInvalidUsername() { @@ -80,5 +84,14 @@ final class SignUpStartErrorTests: XCTestCase { XCTAssertTrue(sut.isInvalidUsername) XCTAssertFalse(sut.isBrowserRequired) XCTAssertFalse(sut.isUserAlreadyExists) + XCTAssertFalse(sut.isInvalidPassword) + } + + func test_isInvalidPassword() { + sut = .init(type: .invalidPassword) + XCTAssertTrue(sut.isInvalidPassword) + XCTAssertFalse(sut.isBrowserRequired) + XCTAssertFalse(sut.isUserAlreadyExists) + XCTAssertFalse(sut.isInvalidUsername) } } From 0fa51aea7f7e445a9c812761027098b4bfccb823 Mon Sep 17 00:00:00 2001 From: Silviu Petrescu Date: Mon, 8 Jan 2024 09:34:45 +0000 Subject: [PATCH 25/84] Capitalised logs, added context where missing, clarified them --- .../MSALNativeAuthResetPasswordController.swift | 14 +++++++------- ...LNativeAuthResetPasswordResponseValidator.swift | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift index 3faf8b0ea1..4e1b02c977 100644 --- a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift @@ -150,7 +150,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, - format: "redirect error in resetpassword/start request \(error.errorDescription ?? "No error description")") + format: "Redirect error in resetpassword/start request \(error.errorDescription ?? "No error description")") return .init(.error(error)) case .error(let apiError): let error = apiError.toResetPasswordStartPublicError() @@ -435,14 +435,14 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext ) async -> ResetPasswordSubmitPasswordControllerResponse { - MSALLogger.log(level: .verbose, context: context, format: "performing poll completion request...") + MSALLogger.log(level: .verbose, context: context, format: "Performing poll completion request") let pollCompletionResponse = await performPollCompletionRequest( passwordResetToken: passwordResetToken, context: context ) - MSALLogger.log(level: .verbose, context: context, format: "handling poll completion response...") + MSALLogger.log(level: .verbose, context: context, format: "Handling poll completion response") return await handlePollCompletionResponse( pollCompletionResponse, @@ -520,7 +520,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, case .failed: let error = PasswordRequiredError(type: .generalError) self.stopTelemetryEvent(event, context: context, error: error) - MSALLogger.log(level: .error, context: context, format: "password poll success returned status 'failed'") + MSALLogger.log(level: .error, context: context, format: "Password poll success returned status 'failed'") return .init(.error(error: error, newState: nil)) } @@ -571,7 +571,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, guard retriesRemaining > 0 else { let error = PasswordRequiredError(type: .generalError) self.stopTelemetryEvent(event, context: context, error: error) - MSALLogger.log(level: .error, context: context, format: "password poll completion did not complete in time") + MSALLogger.log(level: .error, context: context, format: "Password poll completion did not complete in time") return .init(.error(error: error, newState: nil)) } @@ -579,7 +579,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, MSALLogger.log( level: .info, context: context, - format: "resetpassword: waiting for \(pollInterval) seconds before retrying" + format: "Reset password: waiting for \(pollInterval) seconds before retrying" ) do { @@ -591,7 +591,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, MSALLogger.log( level: .error, context: context, - format: "resetpassword: Task.sleep unexpectedly threw an error: \(error). Ignoring..." + format: "Reset Password: Task.sleep unexpectedly threw an error: \(error). Ignoring" ) } diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift index e20fe2c21d..af862423ba 100644 --- a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift @@ -166,7 +166,7 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas private func handleContinueError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordContinueValidatedResponse { guard let apiError = error as? MSALNativeAuthResetPasswordContinueResponseError else { - MSALLogger.log(level: .error, context: context, format: "continue returned unexpected error type") + MSALLogger.log(level: .error, context: context, format: "resetpassword/continue returned unexpected error type") return .unexpectedError } @@ -209,7 +209,7 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas private func handleSubmitError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordSubmitValidatedResponse { guard let apiError = error as? MSALNativeAuthResetPasswordSubmitResponseError else { - MSALLogger.log(level: .error, context: context, format: "submit returned unexpected error type") + MSALLogger.log(level: .error, context: context, format: "resetpassword/submit returned unexpected error type") return .unexpectedError } From 68261d756e978f3ecb0dc9e32b1460ec1ae59cae Mon Sep 17 00:00:00 2001 From: Silviu Petrescu Date: Mon, 8 Jan 2024 10:47:04 +0000 Subject: [PATCH 26/84] PR comments --- .../reset_password/MSALNativeAuthResetPasswordController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift index 4e1b02c977..ecc1e7717e 100644 --- a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift @@ -520,7 +520,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, case .failed: let error = PasswordRequiredError(type: .generalError) self.stopTelemetryEvent(event, context: context, error: error) - MSALLogger.log(level: .error, context: context, format: "Password poll success returned status 'failed'") + MSALLogger.log(level: .error, context: context, format: "Password poll completion returned status 'failed'") return .init(.error(error: error, newState: nil)) } From 6239e74a2451dadb084aa419f50d56a0e9bbe392 Mon Sep 17 00:00:00 2001 From: Danilo Raspa <105228698+nilo-ms@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:40:46 +0000 Subject: [PATCH 27/84] Rename all tokens to continuation token (#1963) * rename various tokens to continuation token * rename some other tokens to continuation token * fix integration test * rename some more vars to continuation token * remove not needed coding keys and rename tokens * rename internal variable to avoid shadowing --- .../MSALNativeAuthTokenController.swift | 9 +- ...SALNativeAuthResetPasswordController.swift | 68 ++--- ...ALNativeAuthResetPasswordControlling.swift | 6 +- .../MSALNativeAuthSignInController.swift | 80 +++--- .../MSALNativeAuthSignInControlling.swift | 8 +- .../MSALNativeAuthSignUpController.swift | 117 ++++---- .../MSALNativeAuthSignUpControlling.swift | 13 +- .../network/MSALNativeAuthGrantType.swift | 2 +- .../MSALNativeAuthRequestParametersKey.swift | 7 +- ...thResetPasswordContinueResponseError.swift | 4 +- ...ativeAuthSignUpContinueResponseError.swift | 4 +- ...ALNativeAuthSignUpStartResponseError.swift | 4 +- .../MSALNativeAuthTokenResponseError.swift | 4 +- ...etPasswordChallengeRequestParameters.swift | 4 +- ...setPasswordContinueRequestParameters.swift | 4 +- ...swordPollCompletionRequestParameters.swift | 4 +- ...ResetPasswordSubmitRequestParameters.swift | 4 +- ...AuthSignInChallengeRequestParameters.swift | 4 +- ...AuthSignUpChallengeRequestParameters.swift | 4 +- ...eAuthSignUpContinueRequestParameters.swift | 4 +- ...MSALNativeAuthTokenRequestParameters.swift | 6 +- ...tiveAuthResetPasswordRequestProvider.swift | 2 +- ...LNativeAuthResendCodeRequestResponse.swift | 4 +- ...veAuthResetPasswordChallengeResponse.swift | 2 +- ...iveAuthResetPasswordContinueResponse.swift | 2 +- ...NativeAuthResetPasswordStartResponse.swift | 7 +- ...ativeAuthResetPasswordSubmitResponse.swift | 2 +- ...SALNativeAuthSignInChallengeResponse.swift | 2 +- ...MSALNativeAuthSignInInitiateResponse.swift | 7 +- ...SALNativeAuthSignUpChallengeResponse.swift | 8 +- ...MSALNativeAuthSignUpContinueResponse.swift | 9 +- .../MSALNativeAuthSignUpStartResponse.swift | 2 +- ...veAuthResetPasswordResponseValidator.swift | 12 +- ...eAuthResetPasswordValidatedResponses.swift | 6 +- ...SALNativeAuthSignInResponseValidator.swift | 16 +- ...AuthSignInChallengeValidatedResponse.swift | 4 +- ...eAuthSignInInitiateValidatedResponse.swift | 2 +- ...SALNativeAuthSignUpResponseValidator.swift | 45 ++-- ...ALNativeAuthSignUpValidatedResponses.swift | 10 +- ...hSignUpContinueRequestProviderParams.swift | 6 +- .../MSALNativeAuthSignUpRequestProvider.swift | 4 +- .../state/MSALNativeAuthBaseState.swift | 6 +- .../state/ResetPasswordStates+Internal.swift | 6 +- .../state/ResetPasswordStates.swift | 4 +- ...nAfterPreviousFlowBaseState+Internal.swift | 2 +- .../SignInAfterPreviousFlowBaseState.swift | 6 +- .../state/SignInStates+Internal.swift | 6 +- .../state_machine/state/SignInStates.swift | 12 +- .../state/SignUpStates+Internal.swift | 8 +- .../state_machine/state/SignUpStates.swift | 4 +- ...setPasswordChallengeIntegrationTests.swift | 6 +- ...esetPasswordContinueIntegrationTests.swift | 8 +- ...sswordPollCompletionIntegrationTests.swift | 2 +- ...thResetPasswordStartIntegrationTests.swift | 4 +- ...hResetPasswordSubmitIntegrationTests.swift | 4 +- ...eAuthSignInChallengeIntegrationTests.swift | 8 +- ...veAuthSignInInitiateIntegrationTests.swift | 4 +- ...eAuthSignUpChallengeIntegrationTests.swift | 6 +- ...veAuthSignUpContinueIntegrationTests.swift | 21 +- ...ativeAuthSignUpStartIntegrationTests.swift | 10 +- .../MSALNativeAuthTokenIntegrationTests.swift | 12 +- ...NativeAuthCredentialsControllerTests.swift | 2 +- ...tiveAuthResetPasswordControllerTests.swift | 116 ++++---- .../MSALNativeAuthSignInControllerTests.swift | 194 +++++++------- .../MSALNativeAuthSignUpControllerTests.swift | 252 +++++++++--------- .../mock/MSALNativeAuthNetworkMocks.swift | 14 +- ...ativeAuthResetPasswordControllerMock.swift | 6 +- .../MSALNativeAuthSignInControllerMock.swift | 16 +- .../MSALNativeAuthSignUpControllerMock.swift | 8 +- .../MSALNativeAuthSignUpControllerSpy.swift | 8 +- ...LNativeAuthSignUpRequestProviderMock.swift | 2 +- ...NativeAuthResetPasswordControllerSpy.swift | 14 +- ...AuthResetPasswordRequestProviderMock.swift | 6 +- ...ALNativeAuthRequestConfiguratorTests.swift | 37 ++- ...ALNativeAuthRequestErrorHandlerTests.swift | 4 +- ...NativeAuthSignUpRequestProviderTests.swift | 12 +- ...etPasswordContinueResponseErrorTests.swift | 12 +- ...AuthSignUpContinueResponseErrorTests.swift | 6 +- ...iveAuthSignUpStartResponseErrorTests.swift | 2 +- ...sswordChallengeRequestParametersTest.swift | 10 +- ...asswordContinueRequestParametersTest.swift | 10 +- ...dPollCompletionRequestParametersTest.swift | 6 +- ...tPasswordSubmitRequestParametersTest.swift | 6 +- ...SignInChallengeRequestParametersTest.swift | 10 +- ...SignUpChallengeRequestParametersTest.swift | 6 +- ...hSignUpContinueRequestParametersTest.swift | 6 +- ...NativeAuthTokenRequestParametersTest.swift | 12 +- ...hResetPasswordResponseValidatorTests.swift | 42 +-- ...ativeAuthSignInResponseValidatorTest.swift | 44 +-- ...tiveAuthSignUpResponseValidatorTests.swift | 130 ++++----- ...ativeAuthTokenResponseValidatorTests.swift | 14 +- ...ativeAuthPublicClientApplicationTest.swift | 104 ++++---- ...swordRequiredDelegateDispatcherTests.swift | 4 +- ...ordResendCodeDelegateDispatcherTests.swift | 4 +- ...PasswordStartDelegateDispatcherTests.swift | 4 +- ...ordVerifyCodeDelegateDispatcherTests.swift | 4 +- ...PasswordStartDelegateDispatcherTests.swift | 4 +- ...nInResendCodeDelegateDispatcherTests.swift | 4 +- .../SignInStartDelegateDispatcherTests.swift | 8 +- ...butesRequiredDelegateDispatcherTests.swift | 12 +- ...swordRequiredDelegateDispatcherTests.swift | 8 +- ...PasswordStartDelegateDispatcherTests.swift | 4 +- ...nUpResendCodeDelegateDispatcherTests.swift | 4 +- .../SignUpStartDelegateDispatcherTests.swift | 4 +- ...nUpVerifyCodeDelegateDispatcherTests.swift | 12 +- .../ResetPasswordCodeSentStateTests.swift | 16 +- .../ResetPasswordRequiredStateTests.swift | 14 +- .../SignInCodeRequiredStateTests.swift | 14 +- .../SignInPasswordRequiredStateTests.swift | 6 +- .../SignUpAttributesRequiredStateTests.swift | 14 +- .../sign_up/SignUpCodeSentStateTests.swift | 24 +- .../SignUpPasswordRequiredStateTests.swift | 14 +- 112 files changed, 973 insertions(+), 967 deletions(-) diff --git a/MSAL/src/native_auth/controllers/MSALNativeAuthTokenController.swift b/MSAL/src/native_auth/controllers/MSALNativeAuthTokenController.swift index 1c1fa765ec..9c19e1177a 100644 --- a/MSAL/src/native_auth/controllers/MSALNativeAuthTokenController.swift +++ b/MSAL/src/native_auth/controllers/MSALNativeAuthTokenController.swift @@ -77,9 +77,8 @@ class MSALNativeAuthTokenController: MSALNativeAuthBaseController { username: String? = nil, password: String? = nil, scopes: [String], - credentialToken: String? = nil, + continuationToken: String? = nil, oobCode: String? = nil, - signInSLT: String? = nil, grantType: MSALNativeAuthGrantType, includeChallengeType: Bool = true, context: MSIDRequestContext) -> MSIDHttpRequest? { @@ -87,8 +86,7 @@ class MSALNativeAuthTokenController: MSALNativeAuthBaseController { let params = MSALNativeAuthTokenRequestParameters( context: context, username: username, - credentialToken: credentialToken, - signInSLT: signInSLT, + continuationToken: continuationToken, grantType: grantType, scope: scopes.joinScopes(), password: password, @@ -114,8 +112,7 @@ class MSALNativeAuthTokenController: MSALNativeAuthBaseController { let params = MSALNativeAuthTokenRequestParameters( context: context, username: nil, - credentialToken: nil, - signInSLT: nil, + continuationToken: nil, grantType: .refreshToken, scope: scopes.joinScopes(), password: nil, diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift index ecc1e7717e..e290ce5338 100644 --- a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift @@ -66,49 +66,49 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, return await handleStartResponse(response, username: parameters.username, event: event, context: parameters.context) } - func resendCode(username: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { + func resendCode(username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordResendCode, context: context) - let response = await performChallengeRequest(passwordResetToken: passwordResetToken, context: context) + let response = await performChallengeRequest(continuationToken: continuationToken, context: context) return await handleResendCodeChallengeResponse(response, username: username, event: event, context: context) } func submitCode( code: String, username: String, - passwordResetToken: String, + continuationToken: String, context: MSIDRequestContext ) async -> ResetPasswordSubmitCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordSubmitCode, context: context) let params = MSALNativeAuthResetPasswordContinueRequestParameters( context: context, - passwordResetToken: passwordResetToken, + continuationToken: continuationToken, grantType: .oobCode, oobCode: code ) let response = await performContinueRequest(parameters: params) - return await handleSubmitCodeResponse(response, username: username, passwordResetToken: passwordResetToken, event: event, context: context) + return await handleSubmitCodeResponse(response, username: username, continuationToken: continuationToken, event: event, context: context) } func submitPassword( password: String, username: String, - passwordSubmitToken: String, + continuationToken: String, context: MSIDRequestContext ) async -> ResetPasswordSubmitPasswordControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordSubmit, context: context) let params = MSALNativeAuthResetPasswordSubmitRequestParameters( context: context, - passwordSubmitToken: passwordSubmitToken, + continuationToken: continuationToken, newPassword: password ) let submitRequestResponse = await performSubmitRequest(parameters: params) return await handleSubmitPasswordResponse( submitRequestResponse, username: username, - passwordSubmitToken: passwordSubmitToken, + continuationToken: continuationToken, event: event, context: context ) @@ -142,8 +142,8 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, MSALLogger.log(level: .verbose, context: context, format: "Finished resetpassword/start request") switch response { - case .success(let passwordResetToken): - let challengeResponse = await performChallengeRequest(passwordResetToken: passwordResetToken, context: context) + case .success(let continuationToken): + let challengeResponse = await performChallengeRequest(continuationToken: continuationToken, context: context) return await handleChallengeResponse(challengeResponse, username: username, event: event, context: context) case .redirect: let error = ResetPasswordStartError(type: .browserRequired, message: MSALNativeAuthErrorMessage.browserRequired) @@ -172,13 +172,13 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, // MARK: - Challenge Request handling private func performChallengeRequest( - passwordResetToken: String, + continuationToken: String, context: MSIDRequestContext ) async -> MSALNativeAuthResetPasswordChallengeValidatedResponse { let request: MSIDHttpRequest do { - request = try requestProvider.challenge(token: passwordResetToken, context: context) + request = try requestProvider.challenge(token: continuationToken, context: context) } catch { MSALLogger.log(level: .error, context: context, format: "Error creating Challenge Request: \(error)") return .unexpectedError @@ -204,7 +204,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, newState: ResetPasswordCodeRequiredState( controller: self, username: username, - flowToken: challengeToken, + continuationToken: challengeToken, correlationId: context.correlationId() ), sentTo: sentTo, @@ -250,7 +250,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, newState: ResetPasswordCodeRequiredState( controller: self, username: username, - flowToken: challengeToken, + continuationToken: challengeToken, correlationId: context.correlationId() ), sentTo: sentTo, @@ -300,17 +300,17 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, private func handleSubmitCodeResponse( _ response: MSALNativeAuthResetPasswordContinueValidatedResponse, username: String, - passwordResetToken: String, + continuationToken: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext ) async -> ResetPasswordSubmitCodeControllerResponse { switch response { - case .success(let passwordSubmitToken): + case .success(let newContinuationToken): MSALLogger.log(level: .info, context: context, format: "Successful resetpassword/continue request") let newState = ResetPasswordRequiredState( controller: self, username: username, - flowToken: passwordSubmitToken, + continuationToken: newContinuationToken, correlationId: context.correlationId() ) return .init(.passwordRequired(newState: newState), @@ -344,7 +344,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, let state = ResetPasswordCodeRequiredState( controller: self, username: username, - flowToken: passwordResetToken, + continuationToken: continuationToken, correlationId: context.correlationId() ) return .init(.error(error: error, newState: state)) @@ -374,17 +374,17 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, private func handleSubmitPasswordResponse( _ response: MSALNativeAuthResetPasswordSubmitValidatedResponse, username: String, - passwordSubmitToken: String, + continuationToken: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext ) async -> ResetPasswordSubmitPasswordControllerResponse { MSALLogger.log(level: .info, context: context, format: "Finished resetpassword/submit request") switch response { - case .success(let passwordResetToken, let pollInterval): + case .success(let newContinuationToken, let pollInterval): return await doPollCompletionLoop( username: username, - passwordResetToken: passwordResetToken, + continuationToken: newContinuationToken, pollInterval: pollInterval, retriesRemaining: kNumberOfTimesToRetryPollCompletionCall, event: event, @@ -400,7 +400,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, let newState = ResetPasswordRequiredState( controller: self, username: username, - flowToken: passwordSubmitToken, + continuationToken: continuationToken, correlationId: context.correlationId() ) return .init(.error(error: error, newState: newState)) @@ -429,7 +429,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, private func doPollCompletionLoop( username: String, - passwordResetToken: String, + continuationToken: String, pollInterval: Int, retriesRemaining: Int, event: MSIDTelemetryAPIEvent?, @@ -438,7 +438,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, MSALLogger.log(level: .verbose, context: context, format: "Performing poll completion request") let pollCompletionResponse = await performPollCompletionRequest( - passwordResetToken: passwordResetToken, + continuationToken: continuationToken, context: context ) @@ -449,19 +449,19 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, username: username, pollInterval: pollInterval, retriesRemaining: retriesRemaining, - passwordResetToken: passwordResetToken, + continuationToken: continuationToken, event: event, context: context ) } private func performPollCompletionRequest( - passwordResetToken: String, + continuationToken: String, context: MSIDRequestContext ) async -> MSALNativeAuthResetPasswordPollCompletionValidatedResponse { let parameters = MSALNativeAuthResetPasswordPollCompletionRequestParameters( context: context, - passwordResetToken: passwordResetToken + continuationToken: continuationToken ) let request: MSIDHttpRequest @@ -487,20 +487,20 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, username: String, pollInterval: Int, retriesRemaining: Int, - passwordResetToken: String, + continuationToken: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext ) async -> ResetPasswordSubmitPasswordControllerResponse { MSALLogger.log(level: .info, context: context, format: "Finished resetpassword/poll_completion") switch response { - case .success(let status, let continuationToken): + case .success(let status, let newContinuationToken): switch status { case .inProgress, .notStarted: return await retryPollCompletion( - passwordResetToken: passwordResetToken, + continuationToken: continuationToken, pollInterval: pollInterval, retriesRemaining: retriesRemaining, username: username, @@ -511,7 +511,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, let signInAfterResetPasswordState = SignInAfterResetPasswordState( controller: signInController, username: username, - slt: continuationToken, + continuationToken: newContinuationToken, correlationId: context.correlationId() ) return .init(.completed(signInAfterResetPasswordState), telemetryUpdate: { [weak self] result in @@ -534,7 +534,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, let newState = ResetPasswordRequiredState( controller: self, username: username, - flowToken: passwordResetToken, + continuationToken: continuationToken, correlationId: context.correlationId() ) return .init(.error(error: error, newState: newState)) @@ -561,7 +561,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, // swiftlint:enable function_body_length private func retryPollCompletion( - passwordResetToken: String, + continuationToken: String, pollInterval: Int, retriesRemaining: Int, username: String, @@ -597,7 +597,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, return await doPollCompletionLoop( username: username, - passwordResetToken: passwordResetToken, + continuationToken: continuationToken, pollInterval: pollInterval, retriesRemaining: retriesRemaining - 1, event: event, diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift index 8381c7e2fb..7e26f4c4f8 100644 --- a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift @@ -33,19 +33,19 @@ protocol MSALNativeAuthResetPasswordControlling: AnyObject { func resetPassword(parameters: MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartControllerResponse - func resendCode(username: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse + func resendCode(username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse func submitCode( code: String, username: String, - passwordResetToken: String, + continuationToken: String, context: MSIDRequestContext ) async -> ResetPasswordSubmitCodeControllerResponse func submitPassword( password: String, username: String, - passwordSubmitToken: String, + continuationToken: String, context: MSIDRequestContext ) async -> ResetPasswordSubmitPasswordControllerResponse } diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift index c205f3eb50..2a6f82f3ad 100644 --- a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift @@ -96,7 +96,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN func signIn( username: String, - slt: String?, + continuationToken: String?, scopes: [String]?, context: MSALNativeAuthRequestContext ) async -> SignInAfterPreviousFlowControllerResponse { @@ -105,8 +105,8 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN event: makeAndStartTelemetryEvent(id: .telemetryApiIdSignInAfterSignUp, context: context), context: context ) - guard let slt = slt else { - MSALLogger.log(level: .error, context: context, format: "SignIn after previous flow not available because signInSLT is nil") + guard let continuationToken = continuationToken else { + MSALLogger.log(level: .error, context: context, format: "SignIn after previous flow not available because continuationToken is nil") let error = SignInAfterSignUpError(message: MSALNativeAuthErrorMessage.signInNotAvailable) stopTelemetryEvent(telemetryInfo, error: error) return .init(.failure(error)) @@ -115,8 +115,8 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN guard let request = createTokenRequest( username: username, scopes: scopes, - signInSLT: slt, - grantType: .slt, + continuationToken: continuationToken, + grantType: .continuationToken, context: context ) else { let error = SignInAfterSignUpError() @@ -146,7 +146,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN // swiftlint:disable:next function_body_length func submitCode( _ code: String, - credentialToken: String, + continuationToken: String, context: MSALNativeAuthRequestContext, scopes: [String] ) async -> SignInSubmitCodeControllerResponse { @@ -156,7 +156,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN ) guard let request = createTokenRequest( scopes: scopes, - credentialToken: credentialToken, + continuationToken: continuationToken, oobCode: code, grantType: .oobCode, includeChallengeType: false, @@ -167,7 +167,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN errorType: .generalError, telemetryInfo: telemetryInfo, scopes: scopes, - credentialToken: credentialToken, + continuationToken: continuationToken, context: context ) } @@ -193,7 +193,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN errorType: .generalError, telemetryInfo: telemetryInfo, scopes: scopes, - credentialToken: credentialToken, + continuationToken: continuationToken, context: context )) } @@ -204,7 +204,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN errorType: errorType, telemetryInfo: telemetryInfo, scopes: scopes, - credentialToken: credentialToken, + continuationToken: continuationToken, context: context ) } @@ -214,7 +214,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN func submitPassword( _ password: String, username: String, - credentialToken: String, + continuationToken: String, context: MSALNativeAuthRequestContext, scopes: [String] ) async -> SignInSubmitPasswordControllerResponse { @@ -226,7 +226,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN username: username, password: password, scopes: scopes, - credentialToken: credentialToken, + continuationToken: continuationToken, grantType: .password, context: context) else { MSALLogger.log(level: .error, context: context, format: "SignIn, submit password: unable to create token request") @@ -234,7 +234,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN errorType: .generalError, telemetryInfo: telemetryInfo, username: username, - credentialToken: credentialToken, + continuationToken: continuationToken, scopes: scopes ) } @@ -260,7 +260,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN errorType: .generalError, telemetryInfo: telemetryInfo, username: username, - credentialToken: credentialToken, + continuationToken: continuationToken, scopes: scopes )) } @@ -272,19 +272,19 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN errorType: errorType, telemetryInfo: telemetryInfo, username: username, - credentialToken: credentialToken, + continuationToken: continuationToken, scopes: scopes ) } } func resendCode( - credentialToken: String, + continuationToken: String, context: MSALNativeAuthRequestContext, scopes: [String] ) async -> SignInResendCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignInResendCode, context: context) - let result = await performAndValidateChallengeRequest(credentialToken: credentialToken, context: context) + let result = await performAndValidateChallengeRequest(continuationToken: continuationToken, context: context) switch result { case .passwordRequired: let error = ResendCodeError() @@ -300,11 +300,16 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN newState: SignInCodeRequiredState( scopes: scopes, controller: self, - flowToken: credentialToken, + continuationToken: continuationToken, correlationId: context.correlationId())) ) - case .codeRequired(let credentialToken, let sentTo, let channelType, let codeLength): - let state = SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken, correlationId: context.correlationId()) + case .codeRequired(let newContinuationToken, let sentTo, let channelType, let codeLength): + let state = SignInCodeRequiredState( + scopes: scopes, + controller: self, + continuationToken: newContinuationToken, + correlationId: context.correlationId() + ) return .init( .codeRequired( newState: state, @@ -323,7 +328,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN errorType: MSALNativeAuthTokenValidatedErrorType, telemetryInfo: TelemetryInfo, scopes: [String], - credentialToken: String, + continuationToken: String, context: MSALNativeAuthRequestContext ) -> SignInSubmitCodeControllerResponse { MSALLogger.log( @@ -331,7 +336,12 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN context: context, format: "SignIn completed with errorType: \(errorType)") stopTelemetryEvent(telemetryInfo, error: errorType) - let state = SignInCodeRequiredState(scopes: scopes, controller: self, flowToken: credentialToken, correlationId: context.correlationId()) + let state = SignInCodeRequiredState( + scopes: scopes, + controller: self, + continuationToken: continuationToken, + correlationId: context.correlationId() + ) return .init(.error(error: errorType.convertToVerifyCodeError(), newState: state)) } @@ -339,7 +349,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN errorType: MSALNativeAuthTokenValidatedErrorType, telemetryInfo: TelemetryInfo, username: String, - credentialToken: String, + continuationToken: String, scopes: [String] ) -> SignInSubmitPasswordControllerResponse { MSALLogger.log( @@ -351,7 +361,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN scopes: scopes, username: username, controller: self, - flowToken: credentialToken, + continuationToken: continuationToken, correlationId: telemetryInfo.context.correlationId() ) return .init(.error(error: errorType.convertToPasswordRequiredError(), newState: state)) @@ -378,9 +388,9 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN telemetryInfo: TelemetryInfo ) async -> Result { switch validatedResponse { - case .success(let credentialToken): + case .success(let continuationToken): let challengeValidatedResponse = await performAndValidateChallengeRequest( - credentialToken: credentialToken, + continuationToken: continuationToken, context: telemetryInfo.context ) return .success(challengeValidatedResponse) @@ -458,13 +468,13 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN let scopes = joinScopes(params.scopes) let isSignInUsingPassword = params.password != nil switch validatedResponse { - case .passwordRequired(let credentialToken): + case .passwordRequired(let continuationToken): if isSignInUsingPassword { guard let request = createTokenRequest( username: params.username, password: params.password, scopes: scopes, - credentialToken: credentialToken, + continuationToken: continuationToken, grantType: .password, context: telemetryInfo.context ) else { @@ -495,7 +505,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN scopes: scopes, username: params.username, controller: self, - flowToken: credentialToken, + continuationToken: continuationToken, correlationId: params.context.correlationId() ) @@ -503,13 +513,13 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN self?.stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, delegateDispatcherResult: result) }) } - case .codeRequired(let credentialToken, let sentTo, let channelType, let codeLength): + case .codeRequired(let continuationToken, let sentTo, let channelType, let codeLength): if isSignInUsingPassword { MSALLogger.log(level: .warning, context: telemetryInfo.context, format: MSALNativeAuthErrorMessage.codeRequiredForPasswordUserLog) } let state = SignInCodeRequiredState(scopes: scopes, controller: self, - flowToken: credentialToken, + continuationToken: continuationToken, correlationId: params.context.correlationId()) return .init( .codeRequired( @@ -531,10 +541,10 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN } private func performAndValidateChallengeRequest( - credentialToken: String, + continuationToken: String, context: MSALNativeAuthRequestContext ) async -> MSALNativeAuthSignInChallengeValidatedResponse { - guard let challengeRequest = createChallengeRequest(credentialToken: credentialToken, context: context) else { + guard let challengeRequest = createChallengeRequest(continuationToken: continuationToken, context: context) else { MSALLogger.log(level: .error, context: context, format: "SignIn ResendCode: Cannot create Challenge request object") return .error(.invalidRequest(message: nil)) } @@ -553,13 +563,13 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN } private func createChallengeRequest( - credentialToken: String, + continuationToken: String, context: MSIDRequestContext ) -> MSIDHttpRequest? { do { let params = MSALNativeAuthSignInChallengeRequestParameters( context: context, - credentialToken: credentialToken + continuationToken: continuationToken ) return try signInRequestProvider.challenge(parameters: params, context: context) } catch { diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift index 3d58598c63..95de6fe52c 100644 --- a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift @@ -37,14 +37,14 @@ protocol MSALNativeAuthSignInControlling { func signIn( username: String, - slt: String?, + continuationToken: String?, scopes: [String]?, context: MSALNativeAuthRequestContext ) async -> SignInAfterPreviousFlowControllerResponse func submitCode( _ code: String, - credentialToken: String, + continuationToken: String, context: MSALNativeAuthRequestContext, scopes: [String] ) async -> SignInSubmitCodeControllerResponse @@ -52,10 +52,10 @@ protocol MSALNativeAuthSignInControlling { func submitPassword( _ password: String, username: String, - credentialToken: String, + continuationToken: String, context: MSALNativeAuthRequestContext, scopes: [String] ) async -> SignInSubmitPasswordControllerResponse - func resendCode(credentialToken: String, context: MSALNativeAuthRequestContext, scopes: [String]) async -> SignInResendCodeControllerResponse + func resendCode(continuationToken: String, context: MSALNativeAuthRequestContext, scopes: [String]) async -> SignInResendCodeControllerResponse } diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift index d8cc2c70f2..9c1de26f49 100644 --- a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift @@ -70,54 +70,70 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa return await handleSignUpStartResult(result, username: parameters.username, event: event, context: parameters.context) } - func resendCode(username: String, context: MSIDRequestContext, signUpToken: String) async -> SignUpResendCodeControllerResponse { + func resendCode(username: String, context: MSIDRequestContext, continuationToken: String) async -> SignUpResendCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpResendCode, context: context) - let challengeResult = await performAndValidateChallengeRequest(signUpToken: signUpToken, context: context) - return handleResendCodeResult(challengeResult, username: username, event: event, signupToken: signUpToken, context: context) + let challengeResult = await performAndValidateChallengeRequest(continuationToken: continuationToken, context: context) + return handleResendCodeResult(challengeResult, username: username, event: event, continuationToken: continuationToken, context: context) } - func submitCode(_ code: String, username: String, signUpToken: String, context: MSIDRequestContext) async -> SignUpSubmitCodeControllerResponse { + func submitCode( + _ code: String, + username: String, + continuationToken: String, + context: MSIDRequestContext + ) async -> SignUpSubmitCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpSubmitCode, context: context) - let params = MSALNativeAuthSignUpContinueRequestProviderParams(grantType: .oobCode, signUpToken: signUpToken, oobCode: code, context: context) + let params = MSALNativeAuthSignUpContinueRequestProviderParams( + grantType: .oobCode, + continuationToken: continuationToken, + oobCode: code, + context: context + ) let result = await performAndValidateContinueRequest(parameters: params) - return await handleSubmitCodeResult(result, username: username, signUpToken: signUpToken, event: event, context: context) + return await handleSubmitCodeResult(result, username: username, continuationToken: continuationToken, event: event, context: context) } func submitPassword( _ password: String, username: String, - signUpToken: String, + continuationToken: String, context: MSIDRequestContext ) async -> SignUpSubmitPasswordControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpSubmitPassword, context: context) let params = MSALNativeAuthSignUpContinueRequestProviderParams( grantType: .password, - signUpToken: signUpToken, + continuationToken: continuationToken, password: password, context: context ) let continueRequestResult = await performAndValidateContinueRequest(parameters: params) - return handleSubmitPasswordResult(continueRequestResult, username: username, signUpToken: signUpToken, event: event, context: context) + return handleSubmitPasswordResult( + continueRequestResult, + username: username, + continuationToken: continuationToken, + event: event, + context: context + ) } func submitAttributes( _ attributes: [String: Any], username: String, - signUpToken: String, + continuationToken: String, context: MSIDRequestContext ) async -> SignUpSubmitAttributesControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpSubmitAttributes, context: context) let params = MSALNativeAuthSignUpContinueRequestProviderParams( grantType: .attributes, - signUpToken: signUpToken, + continuationToken: continuationToken, attributes: attributes, context: context ) let result = await performAndValidateContinueRequest(parameters: params) - return handleSubmitAttributesResult(result, username: username, signUpToken: signUpToken, event: event, context: context) + return handleSubmitAttributesResult(result, username: username, continuationToken: continuationToken, event: event, context: context) } // MARK: - Start Request handling @@ -148,13 +164,13 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa context: MSIDRequestContext ) async -> SignUpStartControllerResponse { switch result { - case .verificationRequired(let signUpToken, let unverifiedAttributes): + case .verificationRequired(let continuationToken, let unverifiedAttributes): MSALLogger.log( level: .info, context: context, format: "verification_required received from signup/start request for attributes: \(unverifiedAttributes)" ) - let challengeResult = await performAndValidateChallengeRequest(signUpToken: signUpToken, context: context) + let challengeResult = await performAndValidateChallengeRequest(continuationToken: continuationToken, context: context) return handleSignUpChallengeResult(challengeResult, username: username, event: event, context: context) case .attributeValidationFailed(let invalidAttributes): MSALLogger.log( @@ -209,13 +225,13 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa // MARK: - Challenge Request handling private func performAndValidateChallengeRequest( - signUpToken: String, + continuationToken: String, context: MSIDRequestContext ) async -> MSALNativeAuthSignUpChallengeValidatedResponse { let request: MSIDHttpRequest do { - request = try requestProvider.challenge(token: signUpToken, context: context) + request = try requestProvider.challenge(token: continuationToken, context: context) } catch { MSALLogger.log(level: .error, context: context, format: "Error while creating Challenge Request: \(error)") return .unexpectedError @@ -234,13 +250,13 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa context: MSIDRequestContext ) -> SignUpStartControllerResponse { switch result { - case .codeRequired(let sentTo, let challengeType, let codeLength, let signUpToken): + case .codeRequired(let sentTo, let challengeType, let codeLength, let continuationToken): MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge request") return SignUpStartControllerResponse( .codeRequired( newState: SignUpCodeRequiredState(controller: self, username: username, - flowToken: signUpToken, + continuationToken: continuationToken, correlationId: context.correlationId()), sentTo: sentTo, channelTargetType: challengeType, @@ -278,17 +294,17 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa _ result: MSALNativeAuthSignUpChallengeValidatedResponse, username: String, event: MSIDTelemetryAPIEvent?, - signupToken: String, + continuationToken: String, context: MSIDRequestContext ) -> SignUpResendCodeControllerResponse { switch result { - case .codeRequired(let sentTo, let challengeType, let codeLength, let signUpToken): + case .codeRequired(let sentTo, let challengeType, let codeLength, let newContinuationToken): MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge resendCode request") return .init(.codeRequired( newState: SignUpCodeRequiredState( controller: self, username: username, - flowToken: signUpToken, + continuationToken: newContinuationToken, correlationId: context.correlationId() ), sentTo: sentTo, @@ -306,7 +322,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa let newState = SignUpCodeRequiredState( controller: self, username: username, - flowToken: signupToken, + continuationToken: continuationToken, correlationId: context.correlationId() ) return .init(.error(error: error, newState: newState)) @@ -330,12 +346,12 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa context: MSIDRequestContext ) -> SignUpSubmitCodeControllerResponse { switch result { - case .passwordRequired(let signUpToken): + case .passwordRequired(let continuationToken): MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge request after credential_required") let state = SignUpPasswordRequiredState(controller: self, username: username, - flowToken: signUpToken, + continuationToken: continuationToken, correlationId: context.correlationId()) return .init(.passwordRequired(state), telemetryUpdate: { [weak self] result in @@ -383,13 +399,13 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa private func handleSubmitCodeResult( _ result: MSALNativeAuthSignUpContinueValidatedResponse, username: String, - signUpToken: String, + continuationToken: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext ) async -> SignUpSubmitCodeControllerResponse { switch result { - case .success(let slt): - let state = createSignInAfterSignUpStateUsingSLT(slt, username: username, event: event, context: context) + case .success(let newContinuationToken): + let state = createSignInAfterSignUpStateUsingContinuationToken(newContinuationToken, username: username, event: event, context: context) return .init(.completed(state), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) @@ -398,19 +414,24 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa let error = VerifyCodeError(type: .invalidCode) stopTelemetryEvent(event, context: context, error: error) - let state = SignUpCodeRequiredState(controller: self, username: username, flowToken: signUpToken, correlationId: context.correlationId()) + let state = SignUpCodeRequiredState( + controller: self, + username: username, + continuationToken: continuationToken, + correlationId: context.correlationId() + ) return .init(.error(error: error, newState: state)) - case .credentialRequired(let signUpToken): + case .credentialRequired(let newContinuationToken): MSALLogger.log(level: .verbose, context: context, format: "credential_required received in signup/continue request") - let result = await performAndValidateChallengeRequest(signUpToken: signUpToken, context: context) + let result = await performAndValidateChallengeRequest(continuationToken: newContinuationToken, context: context) return handlePerformChallengeAfterContinueRequest(result, username: username, event: event, context: context) - case .attributesRequired(let signUpToken, let attributes): + case .attributesRequired(let newContinuationToken, let attributes): MSALLogger.log(level: .verbose, context: context, format: "attributes_required received in signup/continue request: \(attributes)") let state = SignUpAttributesRequiredState(controller: self, username: username, - flowToken: signUpToken, + continuationToken: newContinuationToken, correlationId: context.correlationId()) return .init(.attributesRequired(attributes: attributes, newState: state), telemetryUpdate: { [weak self] result in @@ -437,13 +458,13 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa private func handleSubmitPasswordResult( _ result: MSALNativeAuthSignUpContinueValidatedResponse, username: String, - signUpToken: String, + continuationToken: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext ) -> SignUpSubmitPasswordControllerResponse { switch result { - case .success(let slt): - let state = createSignInAfterSignUpStateUsingSLT(slt, username: username, event: event, context: context) + case .success(let newContinuationToken): + let state = createSignInAfterSignUpStateUsingContinuationToken(newContinuationToken, username: username, event: event, context: context) return .init(.completed(state), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) @@ -458,16 +479,16 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa let state = SignUpPasswordRequiredState(controller: self, username: username, - flowToken: signUpToken, + continuationToken: continuationToken, correlationId: context.correlationId()) return .init(.error(error: error, newState: state)) - case .attributesRequired(let signUpToken, let attributes): + case .attributesRequired(let newContinuationToken, let attributes): MSALLogger.log(level: .verbose, context: context, format: "attributes_required received in signup/continue request: \(attributes)") let state = SignUpAttributesRequiredState(controller: self, username: username, - flowToken: signUpToken, + continuationToken: newContinuationToken, correlationId: context.correlationId()) return .init(.attributesRequired(attributes: attributes, newState: state), telemetryUpdate: { [weak self] result in @@ -496,17 +517,17 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa private func handleSubmitAttributesResult( _ result: MSALNativeAuthSignUpContinueValidatedResponse, username: String, - signUpToken: String, + continuationToken: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext ) -> SignUpSubmitAttributesControllerResponse { switch result { - case .success(let slt): - let state = createSignInAfterSignUpStateUsingSLT(slt, username: username, event: event, context: context) + case .success(let newContinuationToken): + let state = createSignInAfterSignUpStateUsingContinuationToken(newContinuationToken, username: username, event: event, context: context) return .init(.completed(state), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) - case .attributesRequired(let signUpToken, let attributes): + case .attributesRequired(let newContinuationToken, let attributes): let error = AttributesRequiredError() MSALLogger.log(level: .error, context: context, @@ -514,14 +535,14 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa let state = SignUpAttributesRequiredState( controller: self, username: username, - flowToken: signUpToken, + continuationToken: newContinuationToken, correlationId: context.correlationId() ) return .init(.attributesRequired(attributes: attributes, state: state), telemetryUpdate: { [weak self] result in // The telemetry event always fails because more attributes are required (we consider this an error after having sent attributes) self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result, controllerError: error) }) - case .attributeValidationFailed(let signUpToken, let invalidAttributes): + case .attributeValidationFailed(let newContinuationToken, let invalidAttributes): let message = "attribute_validation_failed from signup/continue submitAttributes request. Make sure these attributes are correct: \(invalidAttributes)" // swiftlint:disable:this line_length MSALLogger.log(level: .error, context: context, format: message) @@ -531,7 +552,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa let state = SignUpAttributesRequiredState( controller: self, username: username, - flowToken: signUpToken, + continuationToken: newContinuationToken, correlationId: context.correlationId() ) return .init(.attributesInvalid(attributes: invalidAttributes, newState: state), telemetryUpdate: { [weak self] result in @@ -557,8 +578,8 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa } } - private func createSignInAfterSignUpStateUsingSLT( - _ slt: String?, + private func createSignInAfterSignUpStateUsingContinuationToken( + _ continuationToken: String?, username: String, event: MSIDTelemetryAPIEvent?, context: MSIDRequestContext @@ -568,7 +589,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa return SignInAfterSignUpState( controller: signInController, username: username, - slt: slt, + continuationToken: continuationToken, correlationId: context.correlationId() ) } diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift index f1af75660e..d0f4dce645 100644 --- a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift @@ -34,21 +34,26 @@ protocol MSALNativeAuthSignUpControlling: AnyObject { func signUpStart(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) async -> SignUpStartControllerResponse - func resendCode(username: String, context: MSIDRequestContext, signUpToken: String) async -> SignUpResendCodeControllerResponse + func resendCode(username: String, context: MSIDRequestContext, continuationToken: String) async -> SignUpResendCodeControllerResponse - func submitCode(_ code: String, username: String, signUpToken: String, context: MSIDRequestContext) async -> SignUpSubmitCodeControllerResponse + func submitCode( + _ code: String, + username: String, + continuationToken: String, + context: MSIDRequestContext + ) async -> SignUpSubmitCodeControllerResponse func submitPassword( _ password: String, username: String, - signUpToken: String, + continuationToken: String, context: MSIDRequestContext ) async -> SignUpSubmitPasswordControllerResponse func submitAttributes( _ attributes: [String: Any], username: String, - signUpToken: String, + continuationToken: String, context: MSIDRequestContext ) async -> SignUpSubmitAttributesControllerResponse } diff --git a/MSAL/src/native_auth/network/MSALNativeAuthGrantType.swift b/MSAL/src/native_auth/network/MSALNativeAuthGrantType.swift index c14e1a7864..a792cf4e28 100644 --- a/MSAL/src/native_auth/network/MSALNativeAuthGrantType.swift +++ b/MSAL/src/native_auth/network/MSALNativeAuthGrantType.swift @@ -27,6 +27,6 @@ enum MSALNativeAuthGrantType: String { case otp = "passwordless_otp" case oobCode = "oob" case refreshToken = "refresh_token" - case slt + case continuationToken = "continuation_token" case attributes } diff --git a/MSAL/src/native_auth/network/MSALNativeAuthRequestParametersKey.swift b/MSAL/src/native_auth/network/MSALNativeAuthRequestParametersKey.swift index 73646795a2..a4dc10590d 100644 --- a/MSAL/src/native_auth/network/MSALNativeAuthRequestParametersKey.swift +++ b/MSAL/src/native_auth/network/MSALNativeAuthRequestParametersKey.swift @@ -32,16 +32,11 @@ enum MSALNativeAuthRequestParametersKey: String { case email case password case scope - case credentialToken = "credential_token" - case flowToken + case continuationToken = "continuation_token" case oobCode = "oob" case otp case customAttributes - case signInSLT = "signin_slt" case attributes - case signUpToken = "signup_token" - case passwordResetToken = "password_reset_token" - case passwordSubmitToken = "password_submit_token" case newPassword = "new_password" case clientInfo = "client_info" case refreshToken = "refresh_token" diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift index 3db3d0f7f5..0ca07d8271 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift @@ -32,7 +32,7 @@ struct MSALNativeAuthResetPasswordContinueResponseError: MSALNativeAuthResponseE let errorURI: String? let innerErrors: [MSALNativeAuthInnerError]? let target: String? - let passwordResetToken: String? + let continuationToken: String? enum CodingKeys: String, CodingKey { case error @@ -41,7 +41,7 @@ struct MSALNativeAuthResetPasswordContinueResponseError: MSALNativeAuthResponseE case errorURI = "error_uri" case innerErrors = "inner_errors" case target - case passwordResetToken = "password_reset_token" + case continuationToken = "continuation_token" } } diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift index 1e63957eb9..2d1a1c0819 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift @@ -30,7 +30,7 @@ struct MSALNativeAuthSignUpContinueResponseError: MSALNativeAuthResponseError { let errorCodes: [Int]? let errorURI: String? let innerErrors: [MSALNativeAuthInnerError]? - let signUpToken: String? + let continuationToken: String? let requiredAttributes: [MSALNativeAuthRequiredAttributesInternal]? let unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes]? let invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? @@ -41,7 +41,7 @@ struct MSALNativeAuthSignUpContinueResponseError: MSALNativeAuthResponseError { case errorCodes = "error_codes" case errorURI = "error_uri" case innerErrors = "inner_errors" - case signUpToken = "signup_token" + case continuationToken = "continuation_token" case requiredAttributes = "required_attributes" case unverifiedAttributes = "unverified_attributes" case invalidAttributes = "invalid_attributes" diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift index c67be5a79c..aee5f45a26 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift @@ -31,7 +31,7 @@ struct MSALNativeAuthSignUpStartResponseError: MSALNativeAuthResponseError { let errorCodes: [Int]? let errorURI: String? let innerErrors: [MSALNativeAuthInnerError]? - let signUpToken: String? + let continuationToken: String? let unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes]? let invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? @@ -41,7 +41,7 @@ struct MSALNativeAuthSignUpStartResponseError: MSALNativeAuthResponseError { case errorCodes = "error_codes" case errorURI = "error_uri" case innerErrors = "inner_errors" - case signUpToken = "signup_token" + case continuationToken = "continuation_token" case unverifiedAttributes = "unverified_attributes" case invalidAttributes = "invalid_attributes" } diff --git a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift index 2c1ee53590..83bacdea16 100644 --- a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift +++ b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift @@ -31,7 +31,7 @@ struct MSALNativeAuthTokenResponseError: MSALNativeAuthResponseError { let errorCodes: [Int]? let errorURI: String? let innerErrors: [MSALNativeAuthInnerError]? - let credentialToken: String? + let continuationToken: String? enum CodingKeys: String, CodingKey { case error @@ -39,6 +39,6 @@ struct MSALNativeAuthTokenResponseError: MSALNativeAuthResponseError { case errorCodes = "error_codes" case errorURI = "error_uri" case innerErrors = "inner_errors" - case credentialToken = "credential_token" + case continuationToken = "continuation_token" } } diff --git a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParameters.swift b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParameters.swift index 4368cb7430..5209677c2b 100644 --- a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParameters.swift @@ -27,14 +27,14 @@ struct MSALNativeAuthResetPasswordChallengeRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .resetPasswordChallenge let context: MSIDRequestContext - let passwordResetToken: String + let continuationToken: String func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { typealias Key = MSALNativeAuthRequestParametersKey return [ Key.clientId.rawValue: config.clientId, - Key.passwordResetToken.rawValue: passwordResetToken, + Key.continuationToken.rawValue: continuationToken, Key.challengeType.rawValue: config.challengeTypesString ].compactMapValues { $0 } } diff --git a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParameters.swift b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParameters.swift index d2021a03a8..375a7b70aa 100644 --- a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParameters.swift @@ -27,7 +27,7 @@ struct MSALNativeAuthResetPasswordContinueRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .resetPasswordContinue let context: MSIDRequestContext - let passwordResetToken: String + let continuationToken: String let grantType: MSALNativeAuthGrantType let oobCode: String? @@ -36,7 +36,7 @@ struct MSALNativeAuthResetPasswordContinueRequestParameters: MSALNativeAuthReque return [ Key.clientId.rawValue: config.clientId, - Key.passwordResetToken.rawValue: passwordResetToken, + Key.continuationToken.rawValue: continuationToken, Key.grantType.rawValue: grantType.rawValue, Key.oobCode.rawValue: oobCode ].compactMapValues { $0 } diff --git a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift index 1f2a10f01e..e93629836f 100644 --- a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift @@ -27,14 +27,14 @@ struct MSALNativeAuthResetPasswordPollCompletionRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .resetpasswordPollCompletion let context: MSIDRequestContext - let passwordResetToken: String + let continuationToken: String func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { typealias Key = MSALNativeAuthRequestParametersKey return [ Key.clientId.rawValue: config.clientId, - Key.passwordResetToken.rawValue: passwordResetToken + Key.continuationToken.rawValue: continuationToken ] } } diff --git a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordSubmitRequestParameters.swift b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordSubmitRequestParameters.swift index 13bb4dd1f6..54691135e6 100644 --- a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordSubmitRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordSubmitRequestParameters.swift @@ -27,7 +27,7 @@ struct MSALNativeAuthResetPasswordSubmitRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .resetPasswordSubmit let context: MSIDRequestContext - let passwordSubmitToken: String + let continuationToken: String let newPassword: String func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { @@ -35,7 +35,7 @@ struct MSALNativeAuthResetPasswordSubmitRequestParameters: MSALNativeAuthRequest return [ Key.clientId.rawValue: config.clientId, - Key.passwordSubmitToken.rawValue: passwordSubmitToken, + Key.continuationToken.rawValue: continuationToken, Key.newPassword.rawValue: newPassword ] } diff --git a/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParameters.swift b/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParameters.swift index d372563f3d..4079d2bc55 100644 --- a/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParameters.swift @@ -27,14 +27,14 @@ struct MSALNativeAuthSignInChallengeRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .signInChallenge let context: MSIDRequestContext - let credentialToken: String + let continuationToken: String func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { typealias Key = MSALNativeAuthRequestParametersKey return [ Key.clientId.rawValue: config.clientId, - Key.credentialToken.rawValue: credentialToken, + Key.continuationToken.rawValue: continuationToken, Key.challengeType.rawValue: config.challengeTypesString ].compactMapValues { $0 } } diff --git a/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParameters.swift b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParameters.swift index a4c0f98db9..ae276d486d 100644 --- a/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParameters.swift @@ -26,7 +26,7 @@ struct MSALNativeAuthSignUpChallengeRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .signUpChallenge - let signUpToken: String + let continuationToken: String let context: MSIDRequestContext func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { @@ -34,7 +34,7 @@ struct MSALNativeAuthSignUpChallengeRequestParameters: MSALNativeAuthRequestable return [ Key.clientId.rawValue: config.clientId, - Key.signUpToken.rawValue: signUpToken, + Key.continuationToken.rawValue: continuationToken, Key.challengeType.rawValue: config.challengeTypesString ].compactMapValues { $0 } } diff --git a/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParameters.swift b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParameters.swift index 880e673a67..62359a996c 100644 --- a/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParameters.swift @@ -27,7 +27,7 @@ struct MSALNativeAuthSignUpContinueRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .signUpContinue let grantType: MSALNativeAuthGrantType - let signUpToken: String + let continuationToken: String let password: String? let oobCode: String? let attributes: String? @@ -39,7 +39,7 @@ struct MSALNativeAuthSignUpContinueRequestParameters: MSALNativeAuthRequestable return [ Key.clientId.rawValue: config.clientId, Key.grantType.rawValue: grantType.rawValue, - Key.signUpToken.rawValue: signUpToken, + Key.continuationToken.rawValue: continuationToken, Key.password.rawValue: password, Key.oobCode.rawValue: oobCode, Key.attributes.rawValue: attributes diff --git a/MSAL/src/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParameters.swift b/MSAL/src/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParameters.swift index a053878c2c..96315a1b89 100644 --- a/MSAL/src/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParameters.swift @@ -28,8 +28,7 @@ struct MSALNativeAuthTokenRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .token let context: MSIDRequestContext let username: String? - let credentialToken: String? - let signInSLT: String? + let continuationToken: String? let grantType: MSALNativeAuthGrantType let scope: String? let password: String? @@ -43,8 +42,7 @@ struct MSALNativeAuthTokenRequestParameters: MSALNativeAuthRequestable { var parameters = [ Key.clientId.rawValue: config.clientId, Key.username.rawValue: username, - Key.credentialToken.rawValue: credentialToken, - Key.signInSLT.rawValue: signInSLT, + Key.continuationToken.rawValue: continuationToken, Key.grantType.rawValue: grantType.rawValue, Key.scope.rawValue: scope, Key.password.rawValue: password, diff --git a/MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordRequestProvider.swift b/MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordRequestProvider.swift index 4b678432ae..438d823155 100644 --- a/MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordRequestProvider.swift +++ b/MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordRequestProvider.swift @@ -86,7 +86,7 @@ final class MSALNativeAuthResetPasswordRequestProvider: MSALNativeAuthResetPassw func challenge(token: String, context: MSIDRequestContext) throws -> MSIDHttpRequest { let requestParams = MSALNativeAuthResetPasswordChallengeRequestParameters( context: context, - passwordResetToken: token + continuationToken: token ) let request = MSIDHttpRequest() diff --git a/MSAL/src/native_auth/network/responses/MSALNativeAuthResendCodeRequestResponse.swift b/MSAL/src/native_auth/network/responses/MSALNativeAuthResendCodeRequestResponse.swift index 36fc3360f4..ecd7c76a60 100644 --- a/MSAL/src/native_auth/network/responses/MSALNativeAuthResendCodeRequestResponse.swift +++ b/MSAL/src/native_auth/network/responses/MSALNativeAuthResendCodeRequestResponse.swift @@ -27,9 +27,9 @@ import Foundation struct MSALNativeAuthResendCodeRequestResponse: Decodable { // MARK: - Variables - let credentialToken: String + let continuationToken: String enum CodingKeys: String, CodingKey { - case credentialToken = "flowToken" + case continuationToken } } diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordChallengeResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordChallengeResponse.swift index 3c352b2454..bfccddd1aa 100644 --- a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordChallengeResponse.swift +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordChallengeResponse.swift @@ -31,6 +31,6 @@ struct MSALNativeAuthResetPasswordChallengeResponse: Decodable { let bindingMethod: String? let challengeTargetLabel: String? let challengeChannel: MSALNativeAuthInternalChannelType? - let passwordResetToken: String? + let continuationToken: String? let codeLength: Int? } diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordContinueResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordContinueResponse.swift index 8576d31b66..10fd7c241f 100644 --- a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordContinueResponse.swift +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordContinueResponse.swift @@ -27,6 +27,6 @@ import Foundation struct MSALNativeAuthResetPasswordContinueResponse: Decodable { // MARK: - Variables - let passwordSubmitToken: String + let continuationToken: String let expiresIn: Int } diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift index a47968e180..38a4122209 100644 --- a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift @@ -27,11 +27,6 @@ import Foundation struct MSALNativeAuthResetPasswordStartResponse: Decodable { // MARK: - Variables - let passwordResetToken: String? + let continuationToken: String? let challengeType: MSALNativeAuthInternalChallengeType? - - enum CodingKeys: String, CodingKey { - case passwordResetToken - case challengeType - } } diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordSubmitResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordSubmitResponse.swift index 9aaece1819..f61c83927b 100644 --- a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordSubmitResponse.swift +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordSubmitResponse.swift @@ -27,6 +27,6 @@ import Foundation struct MSALNativeAuthResetPasswordSubmitResponse: Decodable { // MARK: - Variables - let passwordResetToken: String + let continuationToken: String let pollInterval: Int } diff --git a/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInChallengeResponse.swift b/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInChallengeResponse.swift index 029cf29c68..4f969080b1 100644 --- a/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInChallengeResponse.swift +++ b/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInChallengeResponse.swift @@ -27,7 +27,7 @@ import Foundation struct MSALNativeAuthSignInChallengeResponse: Decodable { // MARK: - Variables - let credentialToken: String? + let continuationToken: String? let challengeType: MSALNativeAuthInternalChallengeType let bindingMethod: String? let challengeTargetLabel: String? diff --git a/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInInitiateResponse.swift b/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInInitiateResponse.swift index 4f26b545b9..3329b7a562 100644 --- a/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInInitiateResponse.swift +++ b/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInInitiateResponse.swift @@ -27,11 +27,6 @@ import Foundation struct MSALNativeAuthSignInInitiateResponse: Decodable { // MARK: - Variables - let credentialToken: String? + let continuationToken: String? let challengeType: MSALNativeAuthInternalChallengeType? - - enum CodingKeys: String, CodingKey { - case credentialToken - case challengeType - } } diff --git a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpChallengeResponse.swift b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpChallengeResponse.swift index ed62bb1bc8..ea8339b5be 100644 --- a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpChallengeResponse.swift +++ b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpChallengeResponse.swift @@ -30,12 +30,6 @@ struct MSALNativeAuthSignUpChallengeResponse: Decodable { let interval: Int? let challengeTargetLabel: String? let challengeChannel: MSALNativeAuthInternalChannelType? - let signUpToken: String? + let continuationToken: String? let codeLength: Int? - - enum CodingKeys: String, CodingKey { - case challengeType, bindingMethod, interval, challengeTargetLabel, challengeChannel, codeLength - // API returns signup_token not sign_up_token - case signUpToken = "signupToken" - } } diff --git a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpContinueResponse.swift b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpContinueResponse.swift index e43999f7fb..cba35c6f01 100644 --- a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpContinueResponse.swift +++ b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpContinueResponse.swift @@ -25,13 +25,6 @@ import Foundation struct MSALNativeAuthSignUpContinueResponse: Decodable { - let signinSLT: String? + let continuationToken: String? let expiresIn: Int? - let signupToken: String? - - enum CodingKeys: String, CodingKey { - case expiresIn, signupToken - // API returns signin_slt not sign_in_slt - case signinSLT = "signinSlt" - } } diff --git a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpStartResponse.swift b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpStartResponse.swift index 27702343d3..0846bc4108 100644 --- a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpStartResponse.swift +++ b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpStartResponse.swift @@ -25,6 +25,6 @@ import Foundation struct MSALNativeAuthSignUpStartResponse: Decodable { - let signupToken: String? + let continuationToken: String? let challengeType: MSALNativeAuthInternalChallengeType? } diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift index af862423ba..7a374c964c 100644 --- a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift @@ -55,8 +55,8 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordStartValidatedResponse { if response.challengeType == .redirect { return .redirect - } else if let passwordResetToken = response.passwordResetToken { - return .success(passwordResetToken: passwordResetToken) + } else if let continuationToken = response.continuationToken { + return .success(continuationToken: continuationToken) } else { MSALLogger.log(level: .error, context: context, @@ -117,12 +117,12 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas if let sentTo = response.challengeTargetLabel, let channelTargetType = response.challengeChannel?.toPublicChannelType(), let codeLength = response.codeLength, - let passwordResetToken = response.passwordResetToken { + let continuationToken = response.continuationToken { return .success( sentTo, channelTargetType, codeLength, - passwordResetToken + continuationToken ) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields from backend") @@ -161,7 +161,7 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas private func handleContinueSuccess( _ response: MSALNativeAuthResetPasswordContinueResponse ) -> MSALNativeAuthResetPasswordContinueValidatedResponse { - return .success(passwordSubmitToken: response.passwordSubmitToken) + return .success(continuationToken: response.continuationToken) } private func handleContinueError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordContinueValidatedResponse { @@ -202,7 +202,7 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas _ response: MSALNativeAuthResetPasswordSubmitResponse ) -> MSALNativeAuthResetPasswordSubmitValidatedResponse { return .success( - passwordResetToken: response.passwordResetToken, + continuationToken: response.continuationToken, pollInterval: response.pollInterval ) } diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift index d581ac7ecd..5d0074ec64 100644 --- a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift +++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift @@ -23,7 +23,7 @@ // THE SOFTWARE. enum MSALNativeAuthResetPasswordStartValidatedResponse { - case success(passwordResetToken: String) + case success(continuationToken: String) case redirect case error(MSALNativeAuthResetPasswordStartValidatedErrorType) case unexpectedError @@ -58,14 +58,14 @@ enum MSALNativeAuthResetPasswordChallengeValidatedResponse: Equatable { } enum MSALNativeAuthResetPasswordContinueValidatedResponse: Equatable { - case success(passwordSubmitToken: String) + case success(continuationToken: String) case invalidOOB case error(MSALNativeAuthResetPasswordContinueResponseError) case unexpectedError } enum MSALNativeAuthResetPasswordSubmitValidatedResponse: Equatable { - case success(passwordResetToken: String, pollInterval: Int) + case success(continuationToken: String, pollInterval: Int) case passwordError(error: MSALNativeAuthResetPasswordSubmitResponseError) case error(MSALNativeAuthResetPasswordSubmitResponseError) case unexpectedError diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift index 78673d87c2..8a916b1181 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift @@ -67,10 +67,10 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV if initiateResponse.challengeType == .redirect { return .error(.redirect) } - if let credentialToken = initiateResponse.credentialToken { - return .success(credentialToken: credentialToken) + if let continuationToken = initiateResponse.continuationToken { + return .success(continuationToken: continuationToken) } - MSALLogger.log(level: .error, context: context, format: "SignIn Initiate: challengeType and credential token empty") + MSALLogger.log(level: .error, context: context, format: "SignIn Initiate: challengeType and continuation token empty") return .error(.invalidServerResponse) case .failure(let responseError): guard let initiateResponseError = responseError as? MSALNativeAuthSignInInitiateResponseError else { @@ -97,7 +97,7 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV format: "SignIn Challenge: Received unexpected challenge type: \(response.challengeType)") return .error(.invalidServerResponse) case .oob: - guard let credentialToken = response.credentialToken, + guard let continuationToken = response.continuationToken, let targetLabel = response.challengeTargetLabel, let codeLength = response.codeLength, let channelType = response.challengeChannel else { @@ -108,19 +108,19 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV return .error(.invalidServerResponse) } return .codeRequired( - credentialToken: credentialToken, + continuationToken: continuationToken, sentTo: targetLabel, channelType: channelType.toPublicChannelType(), codeLength: codeLength) case .password: - guard let credentialToken = response.credentialToken else { + guard let continuationToken = response.continuationToken else { MSALLogger.log( level: .error, context: context, - format: "SignIn Challenge: Expected credential token not nil with credential type password") + format: "SignIn Challenge: Expected continuation token not nil with credential type password") return .error(.invalidServerResponse) } - return .passwordRequired(credentialToken: credentialToken) + return .passwordRequired(continuationToken: continuationToken) case .redirect: return .error(.redirect) } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift index af0c5c2c99..a0f446cb14 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift @@ -25,8 +25,8 @@ import Foundation enum MSALNativeAuthSignInChallengeValidatedResponse { - case codeRequired(credentialToken: String, sentTo: String, channelType: MSALNativeAuthChannelType, codeLength: Int) - case passwordRequired(credentialToken: String) + case codeRequired(continuationToken: String, sentTo: String, channelType: MSALNativeAuthChannelType, codeLength: Int) + case passwordRequired(continuationToken: String) case error(MSALNativeAuthSignInChallengeValidatedErrorType) } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift index 37744f6956..45d6cb274e 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift @@ -25,7 +25,7 @@ import Foundation enum MSALNativeAuthSignInInitiateValidatedResponse { - case success(credentialToken: String) + case success(continuationToken: String) case error(MSALNativeAuthSignInInitiateValidatedErrorType) } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift index b78496043a..c3b46024bd 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift @@ -75,8 +75,13 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV switch apiError.error { case .verificationRequired: - if let signUpToken = apiError.signUpToken, let unverifiedAttributes = apiError.unverifiedAttributes, !unverifiedAttributes.isEmpty { - return .verificationRequired(signUpToken: signUpToken, unverifiedAttributes: extractAttributeNames(from: unverifiedAttributes)) + if let continuationToken = apiError.continuationToken, + let unverifiedAttributes = apiError.unverifiedAttributes, + !unverifiedAttributes.isEmpty { + return .verificationRequired( + continuationToken: continuationToken, + unverifiedAttributes: extractAttributeNames(from: unverifiedAttributes) + ) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/start for verification_required error") return .unexpectedError @@ -135,15 +140,15 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV if let sentTo = response.challengeTargetLabel, let channelType = response.challengeChannel?.toPublicChannelType(), let codeLength = response.codeLength, - let signUpChallengeToken = response.signUpToken { - return .codeRequired(sentTo, channelType, codeLength, signUpChallengeToken) + let continuationToken = response.continuationToken { + return .codeRequired(sentTo, channelType, codeLength, continuationToken) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/challenge with challenge_type = oob") return .unexpectedError } case .password: - if let signUpToken = response.signUpToken { - return .passwordRequired(signUpToken) + if let continuationToken = response.continuationToken { + return .passwordRequired(continuationToken) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/challenge with challenge_type = password") return .unexpectedError @@ -171,14 +176,14 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV ) -> MSALNativeAuthSignUpContinueValidatedResponse { switch result { case .success(let response): - // Even if the `signInSLT` is nil, the signUp flow is considered successfully completed - return .success(response.signinSLT) + // Even if the `continuationToken` is nil, the signUp flow is considered successfully completed + return .success(response.continuationToken) case .failure(let error): return handleContinueError(error, with: context) } } - // swiftlint:disable:next cyclomatic_complexity + // swiftlint:disable:next cyclomatic_complexity function_body_length private func handleContinueError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthSignUpContinueValidatedResponse { guard let apiError = error as? MSALNativeAuthSignUpContinueResponseError else { return .unexpectedError @@ -193,8 +198,11 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV .passwordBanned: return .invalidUserInput(apiError) case .attributeValidationFailed: - if let signUpToken = apiError.signUpToken, let invalidAttributes = apiError.invalidAttributes, !invalidAttributes.isEmpty { - return .attributeValidationFailed(signUpToken: signUpToken, invalidAttributes: extractAttributeNames(from: invalidAttributes)) + if let continuationToken = apiError.continuationToken, let invalidAttributes = apiError.invalidAttributes, !invalidAttributes.isEmpty { + return .attributeValidationFailed( + continuationToken: continuationToken, + invalidAttributes: extractAttributeNames(from: invalidAttributes) + ) } else { MSALLogger.log( level: .error, @@ -204,15 +212,20 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV return .unexpectedError } case .credentialRequired: - if let signUpToken = apiError.signUpToken { - return .credentialRequired(signUpToken: signUpToken) + if let continuationToken = apiError.continuationToken { + return .credentialRequired(continuationToken: continuationToken) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/continue for credential_required error") return .unexpectedError } case .attributesRequired: - if let signUpToken = apiError.signUpToken, let requiredAttributes = apiError.requiredAttributes, !requiredAttributes.isEmpty { - return .attributesRequired(signUpToken: signUpToken, requiredAttributes: requiredAttributes.map { $0.toRequiredAttributesPublic() }) + if let continuationToken = apiError.continuationToken, + let requiredAttributes = apiError.requiredAttributes, + !requiredAttributes.isEmpty { + return .attributesRequired( + continuationToken: continuationToken, + requiredAttributes: requiredAttributes.map { $0.toRequiredAttributesPublic() } + ) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/continue for attributes_required error") return .unexpectedError @@ -246,7 +259,7 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV errorCodes: error.errorCodes, errorURI: error.errorURI, innerErrors: error.innerErrors, - signUpToken: error.signUpToken, + continuationToken: error.continuationToken, requiredAttributes: error.requiredAttributes, unverifiedAttributes: error.unverifiedAttributes, invalidAttributes: error.invalidAttributes)) diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift index 44be0edbbf..d657f14906 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift @@ -23,7 +23,7 @@ // THE SOFTWARE. enum MSALNativeAuthSignUpStartValidatedResponse: Equatable { - case verificationRequired(signUpToken: String, unverifiedAttributes: [String]) + case verificationRequired(continuationToken: String, unverifiedAttributes: [String]) case attributeValidationFailed(invalidAttributes: [String]) case redirect case error(MSALNativeAuthSignUpStartResponseError) @@ -42,12 +42,12 @@ enum MSALNativeAuthSignUpChallengeValidatedResponse: Equatable { } enum MSALNativeAuthSignUpContinueValidatedResponse: Equatable { - case success(_ signInSLT: String?) + case success(_ continuationToken: String?) /// error that represents invalidOOB or invalidPassword, depending on which State the input comes from. case invalidUserInput(_ error: MSALNativeAuthSignUpContinueResponseError) - case credentialRequired(signUpToken: String) - case attributesRequired(signUpToken: String, requiredAttributes: [MSALNativeAuthRequiredAttributes]) - case attributeValidationFailed(signUpToken: String, invalidAttributes: [String]) + case credentialRequired(continuationToken: String) + case attributesRequired(continuationToken: String, requiredAttributes: [MSALNativeAuthRequiredAttributes]) + case attributeValidationFailed(continuationToken: String, invalidAttributes: [String]) case error(MSALNativeAuthSignUpContinueResponseError) case unexpectedError } diff --git a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpContinueRequestProviderParams.swift b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpContinueRequestProviderParams.swift index 3b6baeed14..46af3ec74c 100644 --- a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpContinueRequestProviderParams.swift +++ b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpContinueRequestProviderParams.swift @@ -26,7 +26,7 @@ struct MSALNativeAuthSignUpContinueRequestProviderParams { let grantType: MSALNativeAuthGrantType - let signUpToken: String + let continuationToken: String let password: String? let oobCode: String? let attributes: [String: Any]? @@ -34,14 +34,14 @@ struct MSALNativeAuthSignUpContinueRequestProviderParams { init( grantType: MSALNativeAuthGrantType, - signUpToken: String, + continuationToken: String, password: String? = nil, oobCode: String? = nil, attributes: [String: Any]? = nil, context: MSIDRequestContext ) { self.grantType = grantType - self.signUpToken = signUpToken + self.continuationToken = continuationToken self.password = password self.oobCode = oobCode self.attributes = attributes diff --git a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift index 3517fab078..dffb9953f6 100644 --- a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift +++ b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift @@ -59,7 +59,7 @@ final class MSALNativeAuthSignUpRequestProvider: MSALNativeAuthSignUpRequestProv func challenge(token: String, context: MSIDRequestContext) throws -> MSIDHttpRequest { let params = MSALNativeAuthSignUpChallengeRequestParameters( - signUpToken: token, + continuationToken: token, context: context ) @@ -75,7 +75,7 @@ final class MSALNativeAuthSignUpRequestProvider: MSALNativeAuthSignUpRequestProv let params = MSALNativeAuthSignUpContinueRequestParameters( grantType: parameters.grantType, - signUpToken: parameters.signUpToken, + continuationToken: parameters.continuationToken, password: parameters.password, oobCode: parameters.oobCode, attributes: formattedAttributes, diff --git a/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift b/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift index f0261cbf08..1dc39b1258 100644 --- a/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift +++ b/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift @@ -26,11 +26,11 @@ import Foundation @objc public class MSALNativeAuthBaseState: NSObject { - let flowToken: String + let continuationToken: String let correlationId: UUID - init(flowToken: String, correlationId: UUID) { - self.flowToken = flowToken + init(continuationToken: String, correlationId: UUID) { + self.continuationToken = continuationToken self.correlationId = correlationId } } diff --git a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift index d47174612c..583456bb8b 100644 --- a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift +++ b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift @@ -28,7 +28,7 @@ extension ResetPasswordCodeRequiredState { func resendCodeInternal() async -> MSALNativeAuthResetPasswordControlling.ResetPasswordResendCodeControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) - return await controller.resendCode(username: username, passwordResetToken: flowToken, context: context) + return await controller.resendCode(username: username, continuationToken: continuationToken, context: context) } func submitCodeInternal(code: String) async -> MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitCodeControllerResponse { @@ -39,7 +39,7 @@ extension ResetPasswordCodeRequiredState { return .init(.error(error: VerifyCodeError(type: .invalidCode), newState: self)) } - return await controller.submitCode(code: code, username: username, passwordResetToken: flowToken, context: context) + return await controller.submitCode(code: code, username: username, continuationToken: continuationToken, context: context) } } @@ -53,6 +53,6 @@ extension ResetPasswordRequiredState { return .init(.error(error: PasswordRequiredError(type: .invalidPassword), newState: self)) } - return await controller.submitPassword(password: password, username: username, passwordSubmitToken: flowToken, context: context) + return await controller.submitPassword(password: password, username: username, continuationToken: continuationToken, context: context) } } diff --git a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift index 1625bf9826..3a243d7870 100644 --- a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift +++ b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift @@ -33,14 +33,14 @@ public class ResetPasswordBaseState: MSALNativeAuthBaseState { init( controller: MSALNativeAuthResetPasswordControlling, username: String, - flowToken: String, + continuationToken: String, inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator(), correlationId: UUID ) { self.controller = controller self.username = username self.inputValidator = inputValidator - super.init(flowToken: flowToken, correlationId: correlationId) + super.init(continuationToken: continuationToken, correlationId: correlationId) } } diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState+Internal.swift index 26f45254fc..f7e20ccc77 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState+Internal.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState+Internal.swift @@ -28,6 +28,6 @@ extension SignInAfterPreviousFlowBaseState { func signInInternal(scopes: [String]?) async -> MSALNativeAuthSignInControlling.SignInAfterPreviousFlowControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) - return await controller.signIn(username: username, slt: slt, scopes: scopes, context: context) + return await controller.signIn(username: username, continuationToken: continuationToken, scopes: scopes, context: context) } } diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState.swift index 4a2c0171e8..87816a2b4f 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState.swift @@ -27,13 +27,13 @@ import Foundation @objcMembers public class SignInAfterPreviousFlowBaseState: NSObject { let controller: MSALNativeAuthSignInControlling let username: String - let slt: String? // TODO: Update to continuation_token + let continuationToken: String? let correlationId: UUID - init(controller: MSALNativeAuthSignInControlling, username: String, slt: String?, correlationId: UUID) { + init(controller: MSALNativeAuthSignInControlling, username: String, continuationToken: String?, correlationId: UUID) { self.username = username self.controller = controller - self.slt = slt + self.continuationToken = continuationToken self.correlationId = correlationId } } diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift index dda4c7d034..a4e78052d0 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift @@ -34,14 +34,14 @@ extension SignInCodeRequiredState { return .init(.error(error: VerifyCodeError(type: .invalidCode), newState: self)) } - return await controller.submitCode(code, credentialToken: flowToken, context: context, scopes: scopes) + return await controller.submitCode(code, continuationToken: continuationToken, context: context, scopes: scopes) } func resendCodeInternal() async -> MSALNativeAuthSignInControlling.SignInResendCodeControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) MSALLogger.log(level: .verbose, context: context, format: "SignIn flow, resend code requested") - return await controller.resendCode(credentialToken: flowToken, context: context, scopes: scopes) + return await controller.resendCode(continuationToken: continuationToken, context: context, scopes: scopes) } } @@ -56,6 +56,6 @@ extension SignInPasswordRequiredState { return .init(.error(error: PasswordRequiredError(type: .invalidPassword), newState: self)) } - return await controller.submitPassword(password, username: username, credentialToken: flowToken, context: context, scopes: scopes) + return await controller.submitPassword(password, username: username, continuationToken: continuationToken, context: context, scopes: scopes) } } diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift b/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift index 9022ea051c..6c83b3c484 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift @@ -31,11 +31,11 @@ import Foundation init( controller: MSALNativeAuthSignInControlling, inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator(), - flowToken: String, + continuationToken: String, correlationId: UUID) { self.controller = controller self.inputValidator = inputValidator - super.init(flowToken: flowToken, correlationId: correlationId) + super.init(continuationToken: continuationToken, correlationId: correlationId) } } @@ -48,10 +48,10 @@ import Foundation scopes: [String], controller: MSALNativeAuthSignInControlling, inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator(), - flowToken: String, + continuationToken: String, correlationId: UUID) { self.scopes = scopes - super.init(controller: controller, inputValidator: inputValidator, flowToken: flowToken, correlationId: correlationId) + super.init(controller: controller, inputValidator: inputValidator, continuationToken: continuationToken, correlationId: correlationId) } /// Requests the server to resend the verification code to the user. @@ -105,11 +105,11 @@ import Foundation username: String, controller: MSALNativeAuthSignInControlling, inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator(), - flowToken: String, + continuationToken: String, correlationId: UUID) { self.scopes = scopes self.username = username - super.init(controller: controller, inputValidator: inputValidator, flowToken: flowToken, correlationId: correlationId) + super.init(controller: controller, inputValidator: inputValidator, continuationToken: continuationToken, correlationId: correlationId) } /// Submits the password to the server for verification. diff --git a/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift index c053ea7d84..3ac4affea0 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift @@ -28,7 +28,7 @@ extension SignUpCodeRequiredState { func resendCodeInternal() async -> MSALNativeAuthSignUpControlling.SignUpResendCodeControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) - return await controller.resendCode(username: username, context: context, signUpToken: flowToken) + return await controller.resendCode(username: username, context: context, continuationToken: continuationToken) } func submitCodeInternal(code: String) async -> MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse { @@ -39,7 +39,7 @@ extension SignUpCodeRequiredState { return .init(.error(error: VerifyCodeError(type: .invalidCode), newState: self)) } - return await controller.submitCode(code, username: username, signUpToken: flowToken, context: context) + return await controller.submitCode(code, username: username, continuationToken: continuationToken, context: context) } } @@ -53,7 +53,7 @@ extension SignUpPasswordRequiredState { return .init(.error(error: PasswordRequiredError(type: .invalidPassword), newState: self)) } - return await controller.submitPassword(password, username: username, signUpToken: flowToken, context: context) + return await controller.submitPassword(password, username: username, continuationToken: continuationToken, context: context) } } @@ -61,6 +61,6 @@ extension SignUpAttributesRequiredState { func submitAttributesInternal(attributes: [String: Any]) async -> MSALNativeAuthSignUpControlling.SignUpSubmitAttributesControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) - return await controller.submitAttributes(attributes, username: username, signUpToken: flowToken, context: context) + return await controller.submitAttributes(attributes, username: username, continuationToken: continuationToken, context: context) } } diff --git a/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift b/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift index 1f3108e31e..4cd97e330a 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift @@ -33,14 +33,14 @@ public class SignUpBaseState: MSALNativeAuthBaseState { init( controller: MSALNativeAuthSignUpControlling, username: String, - flowToken: String, + continuationToken: String, inputValidator: MSALNativeAuthInputValidating = MSALNativeAuthInputValidator(), correlationId: UUID ) { self.controller = controller self.username = username self.inputValidator = inputValidator - super.init(flowToken: flowToken, correlationId: correlationId) + super.init(continuationToken: continuationToken, correlationId: correlationId) } } diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift index c6f55c8bff..ecec0c1ddb 100644 --- a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift @@ -39,7 +39,7 @@ final class MSALNativeAuthResetPasswordChallengeIntegrationTests: MSALNativeAuth ) sut = try provider.challenge( - token: "", + token: "", context: MSALNativeAuthRequestContext(correlationId: correlationId) ) } @@ -57,7 +57,7 @@ final class MSALNativeAuthResetPasswordChallengeIntegrationTests: MSALNativeAuth XCTAssertNotNil(response?.bindingMethod) XCTAssertNotNil(response?.challengeTargetLabel) XCTAssertNotNil(response?.challengeChannel) - XCTAssertNotNil(response?.passwordResetToken) + XCTAssertNotNil(response?.continuationToken) XCTAssertNotNil(response?.codeLength) } @@ -70,7 +70,7 @@ final class MSALNativeAuthResetPasswordChallengeIntegrationTests: MSALNativeAuth XCTAssertNil(response?.bindingMethod) XCTAssertNil(response?.challengeTargetLabel) XCTAssertNil(response?.challengeChannel) - XCTAssertNil(response?.passwordResetToken) + XCTAssertNil(response?.continuationToken) XCTAssertNil(response?.codeLength) } diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift index f5688cd309..7478d13e19 100644 --- a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift @@ -42,7 +42,7 @@ final class MSALNativeAuthResetPasswordContinueIntegrationTests: MSALNativeAuthI sut = try provider.continue( parameters: MSALNativeAuthResetPasswordContinueRequestParameters(context: context, - passwordResetToken: "", + continuationToken: "", grantType: .oobCode, oobCode: "0000") ) @@ -57,7 +57,7 @@ final class MSALNativeAuthResetPasswordContinueIntegrationTests: MSALNativeAuthI let response: MSALNativeAuthResetPasswordContinueResponse? = try await performTestSucceed() - XCTAssertNotNil(response?.passwordSubmitToken) + XCTAssertNotNil(response?.continuationToken) XCTAssertNotNil(response?.expiresIn) } @@ -116,7 +116,7 @@ final class MSALNativeAuthResetPasswordContinueIntegrationTests: MSALNativeAuthI errorURI: String? = nil, innerErrors: [MSALNativeAuthInnerError]? = nil, target: String? = nil, - passwordResetToken: String? = nil + continuationToken: String? = nil ) -> MSALNativeAuthResetPasswordContinueResponseError { .init( error: error, @@ -125,7 +125,7 @@ final class MSALNativeAuthResetPasswordContinueIntegrationTests: MSALNativeAuthI errorURI: errorURI, innerErrors: innerErrors, target: target, - passwordResetToken: passwordResetToken + continuationToken: continuationToken ) } } diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift index 40cc3776cc..449d3b63ac 100644 --- a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift @@ -42,7 +42,7 @@ final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativ sut = try provider.pollCompletion( parameters: MSALNativeAuthResetPasswordPollCompletionRequestParameters(context: context, - passwordResetToken: "", + continuationToken: "", newPassword:"new-password") ) } @@ -56,7 +56,7 @@ final class MSALNativeAuthResetPasswordSubmitIntegrationTests: MSALNativeAuthInt let response: MSALNativeAuthResetPasswordSubmitResponse? = try await performTestSucceed() - XCTAssertNotNil(response?.passwordResetToken) + XCTAssertNotNil(response?.continuationToken) XCTAssertNotNil(response?.pollInterval) } diff --git a/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInChallengeIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInChallengeIntegrationTests.swift index e3880ebb2c..ad0d1a50c8 100644 --- a/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInChallengeIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInChallengeIntegrationTests.swift @@ -40,7 +40,7 @@ class MSALNativeAuthSignInChallengeIntegrationTests: MSALNativeAuthIntegrationBa sut = try provider.challenge( parameters: .init( context: context, - credentialToken: "Test Credential Token" + continuationToken: "Test Credential Token" ), context: context ) @@ -51,7 +51,7 @@ class MSALNativeAuthSignInChallengeIntegrationTests: MSALNativeAuthIntegrationBa let response: MSALNativeAuthSignInChallengeResponse? = try await performTestSucceed() XCTAssertTrue(response?.challengeType == .password) - XCTAssertNotNil(response?.credentialToken) + XCTAssertNotNil(response?.continuationToken) } func test_succeedRequest_challengeTypeOOB() async throws { @@ -59,7 +59,7 @@ class MSALNativeAuthSignInChallengeIntegrationTests: MSALNativeAuthIntegrationBa let response: MSALNativeAuthSignInChallengeResponse? = try await performTestSucceed() XCTAssertTrue(response?.challengeType == .oob) - XCTAssertNotNil(response?.credentialToken) + XCTAssertNotNil(response?.continuationToken) XCTAssertNotNil(response?.bindingMethod) XCTAssertNotNil(response?.challengeTargetLabel) XCTAssertNotNil(response?.codeLength) @@ -71,7 +71,7 @@ class MSALNativeAuthSignInChallengeIntegrationTests: MSALNativeAuthIntegrationBa let response: MSALNativeAuthSignInChallengeResponse? = try await performTestSucceed() XCTAssertEqual(response?.challengeType, .redirect) - XCTAssertNil(response?.credentialToken) + XCTAssertNil(response?.continuationToken) } diff --git a/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift index 53a9da5392..a31be910ee 100644 --- a/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift @@ -53,14 +53,14 @@ class MSALNativeAuthSignInInitiateIntegrationTests: MSALNativeAuthIntegrationBas responses: [] ) let response: MSALNativeAuthSignInInitiateResponse? = try await performTestSucceed() - XCTAssertNotNil(response?.credentialToken) + XCTAssertNotNil(response?.continuationToken) } func test_succeedRequest_challengeTypeRedirect() async throws { try await mockResponse(.challengeTypeRedirect, endpoint: .signInInitiate) let response: MSALNativeAuthSignInInitiateResponse? = try await performTestSucceed() - XCTAssertNil(response?.credentialToken) + XCTAssertNil(response?.continuationToken) XCTAssertEqual(response?.challengeType, .redirect) } diff --git a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift index 2c8abdafde..a4a5bb8a65 100644 --- a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift @@ -49,7 +49,7 @@ final class MSALNativeAuthSignUpChallengeIntegrationTests: MSALNativeAuthIntegra let response: MSALNativeAuthSignUpChallengeResponse? = try await performTestSucceed() XCTAssertEqual(response?.challengeType, .password) - XCTAssertNotNil(response?.signUpToken) + XCTAssertNotNil(response?.continuationToken) } func test_whenSignUpChallengeOOB_succeeds() async throws { @@ -57,7 +57,7 @@ final class MSALNativeAuthSignUpChallengeIntegrationTests: MSALNativeAuthIntegra let response: MSALNativeAuthSignUpChallengeResponse? = try await performTestSucceed() XCTAssertEqual(response?.challengeType, .oob) - XCTAssertNotNil(response?.signUpToken) + XCTAssertNotNil(response?.continuationToken) XCTAssertNotNil(response?.bindingMethod) XCTAssertNotNil(response?.challengeTargetLabel) XCTAssertNotNil(response?.codeLength) @@ -69,7 +69,7 @@ final class MSALNativeAuthSignUpChallengeIntegrationTests: MSALNativeAuthIntegra let response: MSALNativeAuthSignUpChallengeResponse? = try await performTestSucceed() XCTAssertEqual(response?.challengeType, .redirect) - XCTAssertNil(response?.signUpToken) + XCTAssertNil(response?.continuationToken) } func test_signUpChallenge_unauthorizedClient() async throws { diff --git a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift index de89ecaa85..b6ad194afb 100644 --- a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift @@ -43,7 +43,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat let params = MSALNativeAuthSignUpContinueRequestProviderParams( grantType: .password, - signUpToken: "", + continuationToken: "", password: "12345", context: context ) @@ -54,7 +54,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat func test_signUpContinue_withPassword_succeeds() async throws { let params = MSALNativeAuthSignUpContinueRequestProviderParams( grantType: .password, - signUpToken: "", + continuationToken: "", password: "12345", context: context ) @@ -65,7 +65,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat func test_signUpContinue_withOOB_succeeds() async throws { let params = MSALNativeAuthSignUpContinueRequestProviderParams( grantType: .oobCode, - signUpToken: "", + continuationToken: "", oobCode: "1234", context: context ) @@ -76,7 +76,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat func test_signUpContinue_withAttributes_succeeds() async throws { let params = MSALNativeAuthSignUpContinueRequestProviderParams( grantType: .attributes, - signUpToken: "", + continuationToken: "", attributes: ["key": "value"], context: context ) @@ -181,7 +181,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat expectedError: createError(.attributesRequired) ) - XCTAssertNotNil(response.signUpToken) + XCTAssertNotNil(response.continuationToken) } func test_signUpContinue_verificationRequired() async throws { @@ -191,7 +191,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat expectedError: createError(.verificationRequired) ) - XCTAssertNotNil(response.signUpToken) + XCTAssertNotNil(response.continuationToken) XCTAssertNotNil(response.unverifiedAttributes) } @@ -202,7 +202,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat expectedError: createError(.attributeValidationFailed) ) - XCTAssertNotNil(response.signUpToken) + XCTAssertNotNil(response.continuationToken) } func test_signUpContinue_credentialRequired() async throws { @@ -212,7 +212,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat expectedError: createError(.credentialRequired) ) - XCTAssertNotNil(response.signUpToken) + XCTAssertNotNil(response.continuationToken) } func performSuccessfulTestCase(with params: MSALNativeAuthSignUpContinueRequestProviderParams) async throws { @@ -221,8 +221,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat let response: MSALNativeAuthSignUpContinueResponse? = try await performTestSucceed() - XCTAssertNotNil(response?.signinSLT) - XCTAssertNil(response?.signupToken) + XCTAssertNil(response?.continuationToken) } private func createError(_ error: MSALNativeAuthSignUpContinueOauth2ErrorCode) -> MSALNativeAuthSignUpContinueResponseError { @@ -232,7 +231,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat errorCodes: nil, errorURI: nil, innerErrors: nil, - signUpToken: nil, + continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil diff --git a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift index 6beee3c552..ca2758b48e 100644 --- a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift @@ -52,7 +52,7 @@ final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegration try await mockResponse(.challengeTypeRedirect, endpoint: .signUpStart) let response: MSALNativeAuthSignUpStartResponse? = try await performTestSucceed() - XCTAssertNil(response?.signupToken) + XCTAssertNil(response?.continuationToken) XCTAssertEqual(response?.challengeType, .redirect) } @@ -129,7 +129,7 @@ final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegration expectedError: createError(.attributesRequired) ) - XCTAssertNotNil(response.signUpToken) + XCTAssertNotNil(response.continuationToken) } func test_signUpStart_verificationRequired() async throws { @@ -139,7 +139,7 @@ final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegration expectedError: createError(.verificationRequired) ) - XCTAssertNotNil(response.signUpToken) + XCTAssertNotNil(response.continuationToken) XCTAssertNotNil(response.unverifiedAttributes) } @@ -150,7 +150,7 @@ final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegration expectedError: createError(.attributeValidationFailed) ) - XCTAssertNotNil(response.signUpToken) + XCTAssertNotNil(response.continuationToken) } func test_signUpStart_unsupportedAuthMethod() async throws { @@ -180,7 +180,7 @@ final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegration errorCodes: nil, errorURI: nil, innerErrors: nil, - signUpToken: nil, + continuationToken: nil, unverifiedAttributes: nil, invalidAttributes: nil ) diff --git a/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift index 8f09632c26..209a22c4ff 100644 --- a/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift @@ -40,8 +40,7 @@ class MSALNativeAuthTokenIntegrationTests: MSALNativeAuthIntegrationBaseTests { parameters: .init( context: context, username: "test@contoso.com", - credentialToken: nil, - signInSLT: nil, + continuationToken: nil, grantType: .otp, scope: nil, password: nil, @@ -71,8 +70,7 @@ class MSALNativeAuthTokenIntegrationTests: MSALNativeAuthIntegrationBaseTests { let context = MSALNativeAuthRequestContext(correlationId: correlationId) let parameters = MSALNativeAuthTokenRequestParameters(context: context, username: "test@contoso.com", - credentialToken: nil, - signInSLT: nil, + continuationToken: nil, grantType: .otp, scope: "test & alt test", password: nil, @@ -122,7 +120,7 @@ class MSALNativeAuthTokenIntegrationTests: MSALNativeAuthIntegrationBaseTests { try await perform_testFail( endpoint: .signInToken, response: .invalidPassword, - expectedError: Error(error: .invalidGrant, errorDescription: nil, errorCodes: [MSALNativeAuthESTSApiErrorCodes.invalidCredentials.rawValue], errorURI: nil, innerErrors: nil, credentialToken: nil) + expectedError: Error(error: .invalidGrant, errorDescription: nil, errorCodes: [MSALNativeAuthESTSApiErrorCodes.invalidCredentials.rawValue], errorURI: nil, innerErrors: nil, continuationToken: nil) ) } @@ -130,7 +128,7 @@ class MSALNativeAuthTokenIntegrationTests: MSALNativeAuthIntegrationBaseTests { try await perform_testFail( endpoint: .signInToken, response: .invalidOOBValue, - expectedError: Error(error: .invalidGrant, errorDescription: nil, errorCodes: [MSALNativeAuthESTSApiErrorCodes.invalidOTP.rawValue], errorURI: nil, innerErrors: nil, credentialToken: nil) + expectedError: Error(error: .invalidGrant, errorDescription: nil, errorCodes: [MSALNativeAuthESTSApiErrorCodes.invalidOTP.rawValue], errorURI: nil, innerErrors: nil, continuationToken: nil) ) } @@ -176,6 +174,6 @@ class MSALNativeAuthTokenIntegrationTests: MSALNativeAuthIntegrationBaseTests { } private func createError(_ code: MSALNativeAuthTokenOauth2ErrorCode) -> Error { - .init(error: code, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, credentialToken: nil) + .init(error: code, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil) } } diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift index 30f0614b45..314695362f 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift @@ -114,7 +114,7 @@ final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase { let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let authTokens = MSALNativeAuthUserAccountResultStub.authTokens - requestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, credentialToken: nil, signInSLT: nil, grantType: MSALNativeAuthGrantType.refreshToken, scope: "" , password: nil, oobCode: nil, includeChallengeType: true, refreshToken: "refreshToken") + requestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, continuationToken: nil, grantType: MSALNativeAuthGrantType.refreshToken, scope: "" , password: nil, oobCode: nil, includeChallengeType: true, refreshToken: "refreshToken") requestProviderMock.throwingRefreshTokenError = ErrorMock.error let helper = CredentialsTestValidatorHelper(expectation: expectation, expectedError: RetrieveAccessTokenError(type: .generalError)) diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift index 42c515a535..716889d2e7 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift @@ -82,7 +82,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenResetPasswordStart_returnsSuccess_it_callsChallenge() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams - validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) + validatorMock.mockValidateResetPasswordStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError) @@ -164,7 +164,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenResetPasswordStart_challenge_cantCreateRequest_it_returns_unexpectedError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams - validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) + validatorMock.mockValidateResetPasswordStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() @@ -188,10 +188,10 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenResetPasswordStart_challenge_succeeds_it_returnsCorrectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams - validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) + validatorMock.mockValidateResetPasswordStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() - validatorMock.mockValidateResetPasswordChallengeFunc(.success("sentTo", .email, 4, "resetPasswordToken")) + validatorMock.mockValidateResetPasswordChallengeFunc(.success("sentTo", .email, 4, "continuationToken")) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordStartValidatorHelper(exp) @@ -202,7 +202,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { await fulfillment(of: [exp]) XCTAssertTrue(helper.onResetPasswordCodeRequiredCalled) - XCTAssertEqual(helper.newState?.flowToken, "resetPasswordToken") + XCTAssertEqual(helper.newState?.continuationToken, "continuationToken") XCTAssertEqual(helper.sentTo, "sentTo") XCTAssertEqual(helper.channelTargetType, .email) XCTAssertEqual(helper.codeLength, 4) @@ -214,7 +214,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenResetPasswordStart_challenge_returns_redirect_it_returnsRedirectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams - validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) + validatorMock.mockValidateResetPasswordStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateResetPasswordChallengeFunc(.redirect) @@ -239,7 +239,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenResetPasswordStart_challenge_returns_error_it_returnsCorrectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams - validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) + validatorMock.mockValidateResetPasswordStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() let error : MSALNativeAuthResetPasswordChallengeValidatedResponse = .error( @@ -272,7 +272,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenValidatorInResetPasswordStart_challenge_returns_unexpectedError_it_returnsGeneralError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams - validatorMock.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) + validatorMock.mockValidateResetPasswordStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError) @@ -303,7 +303,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordResendCodeValidatorHelper(exp) - let result = await sut.resendCode(username: "", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.resendCode(username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordResendCodeError(result) await fulfillment(of: [exp]) @@ -320,18 +320,18 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() - validatorMock.mockValidateResetPasswordChallengeFunc(.success("sentTo", .email, 4, "flowToken response")) + validatorMock.mockValidateResetPasswordChallengeFunc(.success("sentTo", .email, 4, "continuationToken response")) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordResendCodeValidatorHelper(exp) - let result = await sut.resendCode(username: "", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.resendCode(username: "", continuationToken: "continuationToken", context: contextMock) result.telemetryUpdate?(.success(())) helper.onResetPasswordResendCodeRequired(result) await fulfillment(of: [exp]) XCTAssertTrue(helper.onResetPasswordResendCodeRequiredCalled) - XCTAssertEqual(helper.newState?.flowToken, "flowToken response") + XCTAssertEqual(helper.newState?.continuationToken, "continuationToken response") XCTAssertEqual(helper.sentTo, "sentTo") XCTAssertEqual(helper.channelTargetType, .email) XCTAssertEqual(helper.codeLength, 4) @@ -355,7 +355,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordResendCodeValidatorHelper(exp) - let result = await sut.resendCode(username: "", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.resendCode(username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordResendCodeError(result) await fulfillment(of: [exp]) @@ -376,7 +376,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordResendCodeValidatorHelper(exp) - let result = await sut.resendCode(username: "", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.resendCode(username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordResendCodeError(result) await fulfillment(of: [exp]) @@ -397,7 +397,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordResendCodeValidatorHelper(exp) - let result = await sut.resendCode(username: "", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.resendCode(username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordResendCodeError(result) await fulfillment(of: [exp]) @@ -419,7 +419,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode(code: "1234", username: "", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.submitCode(code: "1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordVerifyCodeError(result) await fulfillment(of: [exp]) @@ -434,12 +434,12 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenResetPasswordSubmitCode_succeeds_it_returnsPasswordRequired() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() - validatorMock.mockValidateResetPasswordContinueFunc(.success(passwordSubmitToken: "")) + validatorMock.mockValidateResetPasswordContinueFunc(.success(continuationToken: "")) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode(code: "1234", username: "", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.submitCode(code: "1234", username: "", continuationToken: "continuationToken", context: contextMock) result.telemetryUpdate?(.success(())) helper.onPasswordRequired(result) @@ -460,12 +460,12 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode(code: "1234", username: "", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.submitCode(code: "1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordVerifyCodeError(result) await fulfillment(of: [exp]) XCTAssertTrue(helper.onResetPasswordVerifyCodeErrorCalled) - XCTAssertEqual(helper.newCodeRequiredState?.flowToken, "passwordResetToken") + XCTAssertEqual(helper.newCodeRequiredState?.continuationToken, "continuationToken") XCTAssertNil(helper.newPasswordRequiredState) XCTAssertEqual(helper.error?.type, .invalidCode) @@ -482,18 +482,18 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { errorURI: nil, innerErrors: nil, target: nil, - passwordResetToken: nil)) + continuationToken: nil)) validatorMock.mockValidateResetPasswordContinueFunc(error) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode(code: "1234", username: "", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.submitCode(code: "1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordVerifyCodeError(result) await fulfillment(of: [exp]) XCTAssertTrue(helper.onResetPasswordVerifyCodeErrorCalled) - XCTAssertNil(helper.newCodeRequiredState?.flowToken) + XCTAssertNil(helper.newCodeRequiredState?.continuationToken) XCTAssertNil(helper.newPasswordRequiredState) XCTAssertEqual(helper.error?.type, .generalError) @@ -508,12 +508,12 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode(code: "1234", username: "", passwordResetToken: "passwordResetToken", context: contextMock) + let result = await sut.submitCode(code: "1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordVerifyCodeError(result) await fulfillment(of: [exp]) XCTAssertTrue(helper.onResetPasswordVerifyCodeErrorCalled) - XCTAssertNil(helper.newCodeRequiredState?.flowToken) + XCTAssertNil(helper.newCodeRequiredState?.continuationToken) XCTAssertNil(helper.newPasswordRequiredState) XCTAssertEqual(helper.error?.type, .generalError) @@ -529,7 +529,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -543,7 +543,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenSubmitPassword_succeeds_it_returnsCompleted() async { requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() - validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + validatorMock.mockValidateResetPasswordSubmitFunc(.success(continuationToken: "continuationToken", pollInterval: 0)) requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .succeeded, continuationToken: nil)) @@ -551,7 +551,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", continuationToken: "continuationToken", context: contextMock) result.telemetryUpdate?(.success(())) helper.onResetPasswordCompleted(result) @@ -578,12 +578,12 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) - XCTAssertEqual(helper.newPasswordRequiredState?.flowToken, "passwordSubmitToken") + XCTAssertEqual(helper.newPasswordRequiredState?.continuationToken, "continuationToken") XCTAssertEqual(helper.error?.type, .invalidPassword) XCTAssertEqual(helper.error?.errorDescription, "Password too weak") @@ -605,7 +605,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -624,7 +624,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -640,7 +640,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenSubmitPassword_pollCompletion_returns_failed_it_returnsResetPasswordRequiredError() async { requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() - validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + validatorMock.mockValidateResetPasswordSubmitFunc(.success(continuationToken: "continuationToken", pollInterval: 0)) requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() validatorMock.mockValidateResetPasswordPollCompletionFunc(.unexpectedError) @@ -648,7 +648,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -661,7 +661,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenSubmitPassword_pollCompletion_returns_unexpectedError_it_returnsCorrectError() async { requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() - validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + validatorMock.mockValidateResetPasswordSubmitFunc(.success(continuationToken: "continuationToken", pollInterval: 0)) requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() validatorMock.mockValidateResetPasswordPollCompletionFunc(.unexpectedError) @@ -669,7 +669,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -682,7 +682,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenSubmitPassword_pollCompletion_returns_passwordError_it_returnsCorrectError() async { requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() - validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + validatorMock.mockValidateResetPasswordSubmitFunc(.success(continuationToken: "continuationToken", pollInterval: 0)) requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() let error : MSALNativeAuthResetPasswordPollCompletionValidatedResponse = @@ -699,12 +699,12 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) - XCTAssertEqual(helper.newPasswordRequiredState?.flowToken, "passwordResetToken") + XCTAssertEqual(helper.newPasswordRequiredState?.continuationToken, "continuationToken") XCTAssertEqual(helper.error?.type, .invalidPassword) XCTAssertEqual(helper.error?.errorDescription, "Password banned") @@ -714,7 +714,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenSubmitPassword_pollCompletion_returns_error_it_returnsCorrectError() async { requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() - validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + validatorMock.mockValidateResetPasswordSubmitFunc(.success(continuationToken: "continuationToken", pollInterval: 0)) requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() let error : MSALNativeAuthResetPasswordPollCompletionValidatedResponse = .error( @@ -729,7 +729,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -743,7 +743,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenSubmitPassword_pollCompletion_returns_notStarted_it_returnsCorrectErrorAfterRetries() async { requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() - validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 1)) + validatorMock.mockValidateResetPasswordSubmitFunc(.success(continuationToken: "continuationToken", pollInterval: 1)) requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() @@ -754,7 +754,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -767,7 +767,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenSubmitPassword_pollCompletion_returns_failed_it_returnsError() async { requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() - validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + validatorMock.mockValidateResetPasswordSubmitFunc(.success(continuationToken: "continuationToken", pollInterval: 0)) requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .failed, continuationToken: "")) @@ -777,7 +777,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -790,7 +790,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenSubmitPassword_pollCompletion_returns_inProgress_it_returnsErrorAfterRetries() async { requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() - validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + validatorMock.mockValidateResetPasswordSubmitFunc(.success(continuationToken: "continuationToken", pollInterval: 0)) requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .inProgress, continuationToken: "")) @@ -800,7 +800,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", username: "", passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onResetPasswordRequiredError(result) await fulfillment(of: [exp]) @@ -831,7 +831,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() - validatorMock.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken", pollInterval: 0)) + validatorMock.mockValidateResetPasswordSubmitFunc(.success(continuationToken: "continuationToken", pollInterval: 0)) requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() validatorMock.mockValidateResetPasswordPollCompletionFunc(.success(status: .succeeded, continuationToken: continuationToken)) @@ -839,7 +839,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword(password: "password", username: username, passwordSubmitToken: "passwordSubmitToken", context: contextMock) + let result = await sut.submitPassword(password: "password", username: username, continuationToken: "continuationToken", context: contextMock) result.telemetryUpdate?(.success(())) helper.onResetPasswordCompleted(result) @@ -851,13 +851,13 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { let exp2 = expectation(description: "SignInAfterResetPassword expectation") signInControllerMock.expectation = exp2 - signInControllerMock.signInSLTResult = .init(.failure(.init())) + signInControllerMock.continuationTokenResult = .init(.failure(.init())) helper.signInAfterResetPasswordState?.signIn(delegate: SignInAfterResetPasswordDelegateStub()) await fulfillment(of: [exp2], timeout: 1) XCTAssertEqual(signInControllerMock.username, username) - XCTAssertEqual(signInControllerMock.slt, continuationToken) + XCTAssertEqual(signInControllerMock.continuationToken, continuationToken) } // MARK: - Common Methods @@ -927,39 +927,39 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { return helper } - private func expectedChallengeParams(token: String = "passwordResetToken") -> (token: String, context: MSIDRequestContext) { + private func expectedChallengeParams(token: String = "continuationToken") -> (token: String, context: MSIDRequestContext) { return (token: token, context: contextMock) } private func expectedContinueParams( grantType: MSALNativeAuthGrantType = .oobCode, - token: String = "passwordResetToken", + token: String = "continuationToken", oobCode: String? = "1234" ) -> MSALNativeAuthResetPasswordContinueRequestParameters { .init( context: contextMock, - passwordResetToken: token, + continuationToken: token, grantType: grantType, oobCode: oobCode ) } private func expectedSubmitParams( - token: String = "passwordSubmitToken", + token: String = "continuationToken", password: String = "password" ) -> MSALNativeAuthResetPasswordSubmitRequestParameters { .init( context: contextMock, - passwordSubmitToken: token, + continuationToken: token, newPassword: password) } private func expectedPollCompletionParameters( - token: String = "passwordResetToken" + token: String = "continuationToken" ) -> MSALNativeAuthResetPasswordPollCompletionRequestParameters { .init( context: contextMock, - passwordResetToken: token) + continuationToken: token) } private func prepareMockRequestsForPollCompletionRetries(_ count: Int) { diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift index d7b6d882f7..060ca42f0b 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift @@ -98,18 +98,18 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectedScopes = "scope1 scope2 openid profile offline_access" - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) - signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: continuationToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(continuationToken: continuationToken) signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername - signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedCredentialToken = continuationToken signInRequestProviderMock.expectedContext = expectedContext tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: expectedScopes, password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, continuationToken: continuationToken, grantType: MSALNativeAuthGrantType.password, scope: expectedScopes, password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError)) @@ -127,17 +127,17 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectedScopes = "scope1 openid profile offline_access" - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) - signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: continuationToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(continuationToken: continuationToken) signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername - signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedCredentialToken = continuationToken signInRequestProviderMock.expectedContext = expectedContext - tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: expectedScopes, password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, continuationToken: continuationToken, grantType: MSALNativeAuthGrantType.password, scope: expectedScopes, password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) tokenRequestProviderMock.throwingTokenError = ErrorMock.error let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError)) @@ -153,17 +153,17 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectedUsername = "username" let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" let expectation = expectation(description: "SignInController") - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) - signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: continuationToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(continuationToken: continuationToken) signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername - signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedCredentialToken = continuationToken signInRequestProviderMock.expectedContext = expectedContext tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) @@ -190,17 +190,17 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectedUsername = "username" let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" let expectation = expectation(description: "SignInController") - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) - signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: continuationToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(continuationToken: continuationToken) signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername - signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedCredentialToken = continuationToken signInRequestProviderMock.expectedContext = expectedContext tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) @@ -226,11 +226,11 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectedUsername = "username" let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let credentialToken = "invalid token" + let continuationToken = "invalid token" let expectation = expectation(description: "SignInController") - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: continuationToken) signInResponseValidatorMock.challengeValidatedResponse = .error(.invalidToken(message: nil)) signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) @@ -274,19 +274,19 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectedUsername = "username" let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) - signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: continuationToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(continuationToken: continuationToken) signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername - signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedCredentialToken = continuationToken signInRequestProviderMock.expectedContext = expectedContext tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - tokenRequestProviderMock.expectedCredentialToken = credentialToken + tokenRequestProviderMock.expectedCredentialToken = continuationToken let expectation = expectation(description: "SignInController") @@ -309,17 +309,17 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" let expectation = expectation(description: "SignInController") - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) - signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: expectedSentTo, channelType: expectedChannelTargetType, codeLength: expectedCodeLength) + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: continuationToken) + signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(continuationToken: continuationToken, sentTo: expectedSentTo, channelType: expectedChannelTargetType, codeLength: expectedCodeLength) signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername - signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedCredentialToken = continuationToken signInRequestProviderMock.expectedContext = expectedContext let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation) @@ -343,17 +343,17 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" let expectation = expectation(description: "SignInController") - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) - signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: expectedSentTo, channelType: expectedChannelTargetType, codeLength: expectedCodeLength) + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: continuationToken) + signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(continuationToken: continuationToken, sentTo: expectedSentTo, channelType: expectedChannelTargetType, codeLength: expectedCodeLength) signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername - signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedCredentialToken = continuationToken signInRequestProviderMock.expectedContext = expectedContext let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation) @@ -377,7 +377,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let sentTo = "sentTo" let channelTargetType = MSALNativeAuthChannelType.email let codeLength = 4 - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectation = expectation(description: "SignInController") @@ -385,13 +385,13 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername - signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedCredentialToken = continuationToken signInRequestProviderMock.expectedContext = expectedContext let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedSentTo: sentTo, expectedChannelTargetType: channelTargetType, expectedCodeLength: codeLength) - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) - signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: sentTo, channelType: channelTargetType, codeLength: codeLength) + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: continuationToken) + signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(continuationToken: continuationToken, sentTo: sentTo, channelType: channelTargetType, codeLength: codeLength) let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: nil, context: expectedContext, scopes: nil)) result.telemetryUpdate?(.success(())) @@ -403,21 +403,21 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_afterSignInWithCodeSubmitCode_signInShouldCompleteSuccessfully() { - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectation = expectation(description: "SignInController") tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext - tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.oobCode, scope: defaultScopes, password: nil, oobCode: "code", includeChallengeType: false, refreshToken: nil) + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, continuationToken: continuationToken, grantType: MSALNativeAuthGrantType.oobCode, scope: defaultScopes, password: nil, oobCode: "code", includeChallengeType: false, refreshToken: nil) let userAccountResult = MSALNativeAuthUserAccountResultStub.result tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) cacheAccessorMock.mockUserAccounts = [MSALNativeAuthUserAccountResultStub.account] cacheAccessorMock.expectedMSIDTokenResult = tokenResult - let state = SignInCodeRequiredState(scopes: ["openid","profile","offline_access"], controller: sut, inputValidator: MSALNativeAuthInputValidator(), flowToken: credentialToken, correlationId: defaultUUID) + let state = SignInCodeRequiredState(scopes: ["openid","profile","offline_access"], controller: sut, inputValidator: MSALNativeAuthInputValidator(), continuationToken: continuationToken, correlationId: defaultUUID) state.submitCode(code: "code", delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedUserAccountResult: userAccountResult)) wait(for: [expectation], timeout: 1) @@ -427,19 +427,19 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_afterSignInWithCodeSubmitCode_whenTokenCacheIsNotValid_it_shouldReturnCorrectError() { - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectation = expectation(description: "SignInController") tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext - tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.oobCode, scope: defaultScopes, password: nil, oobCode: "code", includeChallengeType: false, refreshToken: nil) + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, continuationToken: continuationToken, grantType: MSALNativeAuthGrantType.oobCode, scope: defaultScopes, password: nil, oobCode: "code", includeChallengeType: false, refreshToken: nil) tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) cacheAccessorMock.expectedMSIDTokenResult = nil - let state = SignInCodeRequiredState(scopes: ["openid","profile","offline_access"], controller: sut, inputValidator: MSALNativeAuthInputValidator(), flowToken: credentialToken, correlationId: defaultUUID) + let state = SignInCodeRequiredState(scopes: ["openid","profile","offline_access"], controller: sut, inputValidator: MSALNativeAuthInputValidator(), continuationToken: continuationToken, correlationId: defaultUUID) state.submitCode(code: "code", delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedError: VerifyCodeError(type: .generalError))) wait(for: [expectation], timeout: 1) @@ -484,7 +484,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.throwingChallengeError = MSALNativeAuthError(message: nil) - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: "credentialToken") + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: "continuationToken") let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError)) @@ -509,15 +509,15 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { func test_whenSignInWithCodePasswordIsRequired_newStateIsPropagatedToUser() async { let expectedUsername = "username" - let expectedCredentialToken = "credentialToken" + let expectedCredentialToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectation = expectation(description: "SignInController") signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: expectedCredentialToken) - signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: expectedCredentialToken) + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: expectedCredentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(continuationToken: expectedCredentialToken) let helper = SignInCodeStartWithPasswordRequiredTestsValidatorHelper(expectation: expectation) @@ -528,20 +528,20 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { await fulfillment(of: [expectation], timeout: 1) checkTelemetryEventResult(id: .telemetryApiIdSignInWithCodeStart, isSuccessful: true) - XCTAssertEqual(helper.passwordRequiredState?.flowToken, expectedCredentialToken) + XCTAssertEqual(helper.passwordRequiredState?.continuationToken, expectedCredentialToken) } func test_whenSignInWithCodePasswordIsRequired_newStateIsPropagatedToUser_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { let expectedUsername = "username" - let expectedCredentialToken = "credentialToken" + let expectedCredentialToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectation = expectation(description: "SignInController") signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: expectedCredentialToken) - signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: expectedCredentialToken) + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: expectedCredentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(continuationToken: expectedCredentialToken) let helper = SignInCodeStartWithPasswordRequiredTestsValidatorHelper(expectation: expectation) @@ -552,20 +552,20 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { await fulfillment(of: [expectation], timeout: 1) checkTelemetryEventResult(id: .telemetryApiIdSignInWithCodeStart, isSuccessful: false) - XCTAssertEqual(helper.passwordRequiredState?.flowToken, expectedCredentialToken) + XCTAssertEqual(helper.passwordRequiredState?.continuationToken, expectedCredentialToken) } func test_whenSignInWithCodeSubmitPassword_signInIsCompletedSuccessfully() async { let expectedUsername = "username" let expectedPassword = "password" - let expectedCredentialToken = "credentialToken" + let expectedCredentialToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let exp = expectation(description: "SignInController") tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext - tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: expectedCredentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: "", password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, continuationToken: expectedCredentialToken, grantType: MSALNativeAuthGrantType.password, scope: "", password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedUserAccountResult: MSALNativeAuthUserAccountResultStub.result) tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) @@ -573,7 +573,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { cacheAccessorMock.mockUserAccounts = [MSALNativeAuthUserAccountResultStub.account] cacheAccessorMock.expectedMSIDTokenResult = tokenResult - let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken, correlationId: defaultUUID) + let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, continuationToken: expectedCredentialToken, correlationId: defaultUUID) state.submitPassword(password: expectedPassword, delegate: mockDelegate) await fulfillment(of: [exp], timeout: 1) @@ -586,21 +586,21 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { func test_whenSignInWithCodeSubmitPassword_whenTokenCacheIsNotValid_it_shouldReturnCorrectError() async { let expectedUsername = "username" let expectedPassword = "password" - let expectedCredentialToken = "credentialToken" + let expectedCredentialToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let exp = expectation(description: "SignInController") tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext - tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: expectedCredentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: "", password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, continuationToken: expectedCredentialToken, grantType: MSALNativeAuthGrantType.password, scope: "", password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: PasswordRequiredError(type: .generalError)) tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) tokenResponseValidatorMock.expectedTokenResponse = tokenResponse cacheAccessorMock.expectedMSIDTokenResult = nil - let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken, correlationId: defaultUUID) + let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, continuationToken: expectedCredentialToken, correlationId: defaultUUID) state.submitPassword(password: expectedPassword, delegate: mockDelegate) await fulfillment(of: [exp], timeout: 1) @@ -610,7 +610,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { func test_whenSignInWithCodeSubmitPasswordTokenRequestCreationFail_errorShouldBeReturned() async { let expectedUsername = "username" let expectedPassword = "password" - let expectedCredentialToken = "credentialToken" + let expectedCredentialToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let exp = expectation(description: "SignInController") @@ -620,7 +620,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: PasswordRequiredError(type: .generalError)) - let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken, correlationId: defaultUUID) + let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, continuationToken: expectedCredentialToken, correlationId: defaultUUID) state.submitPassword(password: expectedPassword, delegate: mockDelegate) await fulfillment(of: [exp], timeout: 1) @@ -646,7 +646,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_signInWithCodeSubmitCodeTokenRequestFailCreation_errorShouldBeReturned() { - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectation = expectation(description: "SignInController") @@ -654,7 +654,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { signInRequestProviderMock.expectedContext = expectedContext tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError(message: nil) - let state = SignInCodeRequiredState(scopes: [], controller: sut, flowToken: credentialToken, correlationId: defaultUUID) + let state = SignInCodeRequiredState(scopes: [], controller: sut, continuationToken: continuationToken, correlationId: defaultUUID) state.submitCode(code: "code", delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedError: VerifyCodeError(type: .generalError))) wait(for: [expectation], timeout: 1) @@ -683,21 +683,21 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let sentTo = "sentTo" let channelTargetType = MSALNativeAuthChannelType.email let codeLength = 4 - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectation = expectation(description: "SignInController") signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signInRequestProviderMock.expectedUsername = expectedUsername - signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedCredentialToken = continuationToken signInRequestProviderMock.expectedContext = expectedContext let helper = SignInResendCodeTestsValidatorHelper(expectation: expectation, expectedSentTo: sentTo, expectedChannelTargetType: channelTargetType, expectedCodeLength: codeLength) - signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: sentTo, channelType: channelTargetType, codeLength: codeLength) + signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(continuationToken: continuationToken, sentTo: sentTo, channelType: channelTargetType, codeLength: codeLength) - let result = await sut.resendCode(credentialToken: credentialToken, context: expectedContext, scopes: []) + let result = await sut.resendCode(continuationToken: continuationToken, context: expectedContext, scopes: []) result.telemetryUpdate?(.success(())) helper.onSignInResendCodeCodeRequired(result) @@ -715,7 +715,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let helper = SignInResendCodeTestsValidatorHelper(expectation: expectation) - let result = await sut.resendCode(credentialToken: "credentialToken", context: expectedContext, scopes: []) + let result = await sut.resendCode(continuationToken: "continuationToken", context: expectedContext, scopes: []) helper.onSignInResendCodeError(result) @@ -725,7 +725,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_signInWithCodeResendCodePasswordRequired_shouldReturnAnError() async { - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectation = expectation(description: "SignInController") @@ -735,9 +735,9 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let helper = SignInResendCodeTestsValidatorHelper(expectation: expectation) - signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(continuationToken: continuationToken) - let result = await sut.resendCode(credentialToken: credentialToken, context: expectedContext, scopes: []) + let result = await sut.resendCode(continuationToken: continuationToken, context: expectedContext, scopes: []) helper.onSignInResendCodeError(result) @@ -747,7 +747,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { } func test_signInWithCodeResendCodeChallengeReturnError_shouldReturnAnError() async { - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectation = expectation(description: "SignInController") @@ -759,27 +759,27 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { signInResponseValidatorMock.challengeValidatedResponse = .error(.userNotFound(message: nil)) - let result = await sut.resendCode(credentialToken: credentialToken, context: expectedContext, scopes: []) + let result = await sut.resendCode(continuationToken: continuationToken, context: expectedContext, scopes: []) helper.onSignInResendCodeError(result) await fulfillment(of: [expectation], timeout: 1) XCTAssertNotNil(helper.newSignInCodeRequiredState) - XCTAssertEqual(helper.newSignInCodeRequiredState?.flowToken, credentialToken) + XCTAssertEqual(helper.newSignInCodeRequiredState?.continuationToken, continuationToken) checkTelemetryEventResult(id: .telemetryApiIdSignInResendCode, isSuccessful: false) } - // MARK: signIn using SLT + // MARK: signIn using ContinuationToken - func test_whenSignInWithSLT_signInIsCompletedSuccessfully() { - let slt = "signInSLT" + func test_whenSignInWithContinuationToken_signInIsCompletedSuccessfully() { + let continuationToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectation = expectation(description: "SignInController") tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext - tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: "", credentialToken: nil, signInSLT: slt, grantType: .slt, scope: defaultScopes, password: nil, oobCode: nil, includeChallengeType: false, refreshToken: nil) + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: "", continuationToken: continuationToken, grantType: .continuationToken, scope: defaultScopes, password: nil, oobCode: nil, includeChallengeType: false, refreshToken: nil) let userAccountResult = MSALNativeAuthUserAccountResultStub.result let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: expectation, expectedUserAccountResult: userAccountResult) @@ -788,7 +788,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { cacheAccessorMock.expectedMSIDTokenResult = tokenResult - let state = SignInAfterSignUpState(controller: sut, username: "", slt: slt, correlationId: defaultUUID) + let state = SignInAfterSignUpState(controller: sut, username: "", continuationToken: continuationToken, correlationId: defaultUUID) state.signIn(delegate: mockDelegate) wait(for: [expectation], timeout: 1) @@ -796,8 +796,8 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { checkTelemetryEventResult(id: .telemetryApiIdSignInAfterSignUp, isSuccessful: true) } - func test_whenSignInWithSLTTokenRequestCreationFail_errorShouldBeReturned() { - let slt = "signInSLT" + func test_whenSignInWithContinuationTokenTokenRequestCreationFail_errorShouldBeReturned() { + let continuationToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let exp = expectation(description: "SignInController") @@ -807,7 +807,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: exp, expectedError: SignInAfterSignUpError()) - let state = SignInAfterSignUpState(controller: sut, username: "", slt: slt, correlationId: defaultUUID) + let state = SignInAfterSignUpState(controller: sut, username: "", continuationToken: continuationToken, correlationId: defaultUUID) state.signIn(delegate: mockDelegate) wait(for: [exp], timeout: 1) @@ -815,8 +815,8 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { checkTelemetryEventResult(id: .telemetryApiIdSignInAfterSignUp, isSuccessful: false) } - func test_whenSignInWithSLTTokenReturnError_shouldReturnAnError() { - let slt = "signInSLT" + func test_whenSignInWithContinuationTokenTokenReturnError_shouldReturnAnError() { + let continuationToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let expectation = expectation(description: "SignInController") @@ -828,7 +828,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { tokenResponseValidatorMock.tokenValidatedResponse = .error(.invalidClient(message: "Invalid Client ID")) - let state = SignInAfterSignUpState(controller: sut, username: "", slt: slt, correlationId: defaultUUID) + let state = SignInAfterSignUpState(controller: sut, username: "", continuationToken: continuationToken, correlationId: defaultUUID) state.signIn(delegate: mockDelegate) wait(for: [expectation], timeout: 1) @@ -836,12 +836,12 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { checkTelemetryEventResult(id: .telemetryApiIdSignInAfterSignUp, isSuccessful: false) } - func test_whenSignInWithSLTHaveTokenNil_shouldReturnAnError() { + func test_whenSignInWithContinuationTokenHaveTokenNil_shouldReturnAnError() { let expectation = expectation(description: "SignInController") let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: expectation, expectedError: SignInAfterSignUpError(message: "Sign In is not available at this point, please use the standalone sign in methods")) - let state = SignInAfterSignUpState(controller: sut, username: "username", slt: nil, correlationId: defaultUUID) + let state = SignInAfterSignUpState(controller: sut, username: "username", continuationToken: nil, correlationId: defaultUUID) state.signIn(delegate: mockDelegate) wait(for: [expectation], timeout: 1) @@ -853,7 +853,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { // MARK: private methods private func checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: VerifyCodeError.ErrorType, validatorError: MSALNativeAuthTokenValidatedErrorType) { - let expectedCredentialToken = "credentialToken" + let expectedCredentialToken = "continuationToken" let expectedOOBCode = "code" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) @@ -861,11 +861,11 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext - tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, credentialToken: expectedCredentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.oobCode, scope: "", password: nil, oobCode: expectedOOBCode, includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, continuationToken: expectedCredentialToken, grantType: MSALNativeAuthGrantType.oobCode, scope: "", password: nil, oobCode: expectedOOBCode, includeChallengeType: true, refreshToken: nil) let mockDelegate = SignInVerifyCodeDelegateSpy(expectation: exp, expectedError: VerifyCodeError(type: delegateError)) tokenResponseValidatorMock.tokenValidatedResponse = .error(validatorError) - let state = SignInCodeRequiredState(scopes: [], controller: sut, flowToken: expectedCredentialToken, correlationId: defaultUUID) + let state = SignInCodeRequiredState(scopes: [], controller: sut, continuationToken: expectedCredentialToken, correlationId: defaultUUID) state.submitCode(code: expectedOOBCode, delegate: mockDelegate) wait(for: [exp], timeout: 1) @@ -877,18 +877,18 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { private func checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError, validatorError: MSALNativeAuthTokenValidatedErrorType) async { let expectedUsername = "username" let expectedPassword = "password" - let expectedCredentialToken = "credentialToken" + let expectedCredentialToken = "continuationToken" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) let exp = expectation(description: "SignInController") tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) tokenRequestProviderMock.expectedContext = expectedContext - tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, credentialToken: expectedCredentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.password, scope: "", password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, continuationToken: expectedCredentialToken, grantType: MSALNativeAuthGrantType.password, scope: "", password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil) let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: publicError) tokenResponseValidatorMock.tokenValidatedResponse = .error(validatorError) - let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, flowToken: expectedCredentialToken, correlationId: defaultUUID) + let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, continuationToken: expectedCredentialToken, correlationId: defaultUUID) state.submitPassword(password: expectedPassword, delegate: mockDelegate) await fulfillment(of: [exp], timeout: 1) @@ -905,7 +905,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { signInRequestProviderMock.mockInitiateRequestFunc((MSALNativeAuthHTTPRequestMock.prepareMockRequest())) signInRequestProviderMock.mockChallengeRequestFunc((MSALNativeAuthHTTPRequestMock.prepareMockRequest())) - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: "credentialToken") + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: "continuationToken") signInResponseValidatorMock.challengeValidatedResponse = .error(validatorError) let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: delegateError) @@ -945,15 +945,15 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let expectedUsername = "username" let expectedPassword = "password" let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) - signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(credentialToken: credentialToken) + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: continuationToken) + signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(continuationToken: continuationToken) signInRequestProviderMock.mockInitiateRequestFunc((MSALNativeAuthHTTPRequestMock.prepareMockRequest())) signInRequestProviderMock.mockChallengeRequestFunc((MSALNativeAuthHTTPRequestMock.prepareMockRequest())) signInRequestProviderMock.expectedUsername = expectedUsername - signInRequestProviderMock.expectedCredentialToken = credentialToken + signInRequestProviderMock.expectedCredentialToken = continuationToken signInRequestProviderMock.expectedContext = expectedContext let expectation = expectation(description: "SignInController") diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift index f41bd08fa1..b7d39458d8 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift @@ -96,7 +96,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartPassword_returnsVerificationRequired_it_returnsChallenge() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -192,7 +192,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { errorCodes: nil, errorURI: nil, innerErrors: nil, - signUpToken: nil, + continuationToken: nil, unverifiedAttributes: nil, invalidAttributes: nil)) validatorMock.mockValidateSignUpStartFunc(error) @@ -223,7 +223,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { errorCodes: nil, errorURI: nil, innerErrors: nil, - signUpToken: nil, + continuationToken: nil, unverifiedAttributes: nil, invalidAttributes: nil)) validatorMock.mockValidateSignUpStartFunc(invalidUsername) @@ -254,7 +254,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { errorCodes: nil, errorURI: nil, innerErrors: nil, - signUpToken: nil, + continuationToken: nil, unverifiedAttributes: nil, invalidAttributes: nil)) validatorMock.mockValidateSignUpStartFunc(invalidClientId) @@ -303,7 +303,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartPassword_challenge_cantCreateRequest_it_returns_unexpectedError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() @@ -327,10 +327,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartPassword_challenge_succeeds_it_continuesTheFlow() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() - validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "signUpToken 2")) + validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "continuationToken 2")) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) @@ -341,7 +341,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpCodeRequiredCalled) - XCTAssertEqual(helper.newState?.flowToken, "signUpToken 2") + XCTAssertEqual(helper.newState?.continuationToken, "continuationToken 2") XCTAssertEqual(helper.sentTo, "sentTo") XCTAssertEqual(helper.channelTargetType, .email) XCTAssertEqual(helper.codeLength, 4) @@ -353,7 +353,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartPassword_challenge_returns_passwordRequired_it_returnsCorrectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("")) @@ -378,7 +378,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartPassword_challenge_returns_redirect_it_returnsCorrectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.redirect) @@ -403,7 +403,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartPassword_challenge_returns_error_it_returnsCorrectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() let error : MSALNativeAuthSignUpChallengeValidatedResponse = .error( @@ -435,7 +435,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenValidatorInSignUpStartPassword_challenge_returns_unexpectedError_it_returnsGeneralError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -483,7 +483,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartCode_returnsVerificationRequired_it_returnsChallenge() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -577,7 +577,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { errorCodes: nil, errorURI: nil, innerErrors: nil, - signUpToken: nil, + continuationToken: nil, unverifiedAttributes: nil, invalidAttributes: nil)) validatorMock.mockValidateSignUpStartFunc(error) @@ -608,7 +608,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { errorCodes: nil, errorURI: nil, innerErrors: nil, - signUpToken: nil, + continuationToken: nil, unverifiedAttributes: nil, invalidAttributes: nil)) validatorMock.mockValidateSignUpStartFunc(invalidUsername) @@ -639,7 +639,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { errorCodes: nil, errorURI: nil, innerErrors: nil, - signUpToken: nil, + continuationToken: nil, unverifiedAttributes: nil, invalidAttributes: nil)) validatorMock.mockValidateSignUpStartFunc(invalidClientId) @@ -688,7 +688,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartCode_challenge_cantCreateRequest_it_returns_unexpectedError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() @@ -712,10 +712,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartCode_challenge_succeeds_it_continuesTheFlow() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken 1", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken 1", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 1") - validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "signUpToken 2")) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 1") + validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "continuationToken 2")) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) @@ -726,7 +726,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpCodeRequiredCalled) - XCTAssertEqual(helper.newState?.flowToken, "signUpToken 2") + XCTAssertEqual(helper.newState?.continuationToken, "continuationToken 2") XCTAssertEqual(helper.sentTo, "sentTo") XCTAssertEqual(helper.channelTargetType, .email) XCTAssertEqual(helper.codeLength, 4) @@ -738,7 +738,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartCode_challenge_succeedsPassword_it_returnsCorrectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("")) @@ -763,7 +763,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartCode_challenge_returns_redirect_it_returnsCorrectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.redirect) @@ -788,7 +788,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartCode_challenge_returns_error_it_returnsCorrectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() let error : MSALNativeAuthSignUpChallengeValidatedResponse = .error( @@ -820,7 +820,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenValidatorInSignUpStartCode_challenge_it_returns_unexpectedError_returnsGeneralError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -851,7 +851,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpResendCodeValidatorHelper(exp) - let result = await sut.resendCode(username: "", context: contextMock, signUpToken: "signUpToken") + let result = await sut.resendCode(username: "", context: contextMock, continuationToken: "continuationToken") helper.onSignUpResendCodeError(result) await fulfillment(of: [exp], timeout: 1) @@ -867,18 +867,18 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpResendCode_succeeds_it_continuesTheFlow() async { requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() - validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "signUpToken")) + validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "continuationToken")) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpResendCodeValidatorHelper(exp) - let result = await sut.resendCode(username: "", context: contextMock, signUpToken: "signUpToken") + let result = await sut.resendCode(username: "", context: contextMock, continuationToken: "continuationToken") result.telemetryUpdate?(.success(())) helper.onSignUpResendCodeCodeRequired(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpResendCodeCodeRequiredCalled) - XCTAssertEqual(helper.newState?.flowToken, "signUpToken") + XCTAssertEqual(helper.newState?.continuationToken, "continuationToken") XCTAssertEqual(helper.sentTo, "sentTo") XCTAssertEqual(helper.channelTargetType, .email) XCTAssertEqual(helper.codeLength, 4) @@ -889,13 +889,13 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpResendCode_succeedsPassword_it_returnsCorrectError() async { requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") - validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("signUpToken 1")) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2") + validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("continuationToken 1")) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpResendCodeValidatorHelper(exp) - let result = await sut.resendCode(username: "", context: contextMock, signUpToken: "signUpToken 2") + let result = await sut.resendCode(username: "", context: contextMock, continuationToken: "continuationToken 2") helper.onSignUpResendCodeError(result) await fulfillment(of: [exp], timeout: 1) @@ -922,7 +922,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpResendCodeValidatorHelper(exp) - let result = await sut.resendCode(username: "", context: contextMock, signUpToken: "signUpToken") + let result = await sut.resendCode(username: "", context: contextMock, continuationToken: "continuationToken") helper.onSignUpResendCodeError(result) await fulfillment(of: [exp], timeout: 1) @@ -943,7 +943,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpResendCodeValidatorHelper(exp) - let result = await sut.resendCode(username: "", context: contextMock, signUpToken: "signUpToken") + let result = await sut.resendCode(username: "", context: contextMock, continuationToken: "continuationToken") helper.onSignUpResendCodeError(result) await fulfillment(of: [exp], timeout: 1) @@ -964,7 +964,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpResendCodeValidatorHelper(exp) - let result = await sut.resendCode(username: "", context: contextMock, signUpToken: "signUpToken") + let result = await sut.resendCode(username: "", context: contextMock, continuationToken: "continuationToken") helper.onSignUpResendCodeError(result) await fulfillment(of: [exp], timeout: 1) @@ -986,7 +986,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpVerifyCodeError(result) await fulfillment(of: [exp], timeout: 1) @@ -1007,7 +1007,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpCompleted(result) await fulfillment(of: [exp], timeout: 1) @@ -1028,7 +1028,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { errorCodes: nil, errorURI: nil, innerErrors: nil, - signUpToken: nil, + continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil)) @@ -1038,13 +1038,13 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpVerifyCodeError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpVerifyCodeErrorCalled) XCTAssertNil(helper.newAttributesRequiredState) - XCTAssertEqual(helper.newCodeRequiredState?.flowToken, "signUpToken") + XCTAssertEqual(helper.newCodeRequiredState?.continuationToken, "continuationToken") XCTAssertNil(helper.newPasswordRequiredState) XCTAssertEqual(helper.error?.type, .invalidCode) @@ -1053,20 +1053,20 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitCode_returns_attributesRequired_it_returnsAttributesRequired() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(signUpToken: "signUpToken", requiredAttributes: [])) + validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken", requiredAttributes: [])) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) result.telemetryUpdate?(.success(())) helper.onSignUpAttributesRequired(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpAttributesRequiredCalled) - XCTAssertEqual(helper.newAttributesRequiredState?.flowToken, "signUpToken") + XCTAssertEqual(helper.newAttributesRequiredState?.continuationToken, "continuationToken") XCTAssertNil(helper.newCodeRequiredState) XCTAssertNil(helper.newPasswordRequiredState) XCTAssertNil(helper.error) @@ -1076,20 +1076,20 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitCode_returns_attributesRequired_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(signUpToken: "signUpToken", requiredAttributes: [])) + validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken", requiredAttributes: [])) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) result.telemetryUpdate?(.failure(.init(message: "error"))) helper.onSignUpAttributesRequired(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpAttributesRequiredCalled) - XCTAssertEqual(helper.newAttributesRequiredState?.flowToken, "signUpToken") + XCTAssertEqual(helper.newAttributesRequiredState?.continuationToken, "continuationToken") XCTAssertNil(helper.newCodeRequiredState) XCTAssertNil(helper.newPasswordRequiredState) XCTAssertNil(helper.error) @@ -1100,12 +1100,12 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitCode_returns_attributeValidationFailed_returnsCorrectError() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() - validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(signUpToken: "signUpToken 2", invalidAttributes: ["name"])) + validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(continuationToken: "continuationToken 2", invalidAttributes: ["name"])) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) result.telemetryUpdate?(.success(())) helper.onSignUpVerifyCodeError(result) @@ -1127,7 +1127,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { errorCodes: nil, errorURI: nil, innerErrors: nil, - signUpToken: nil, + continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil)) @@ -1136,13 +1136,13 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpVerifyCodeError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpVerifyCodeErrorCalled) XCTAssertNil(helper.newAttributesRequiredState) - XCTAssertNil(helper.newCodeRequiredState?.flowToken) + XCTAssertNil(helper.newCodeRequiredState?.continuationToken) XCTAssertNil(helper.newPasswordRequiredState) XCTAssertEqual(helper.error?.type, .generalError) @@ -1157,13 +1157,13 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpVerifyCodeError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpVerifyCodeErrorCalled) XCTAssertNil(helper.newAttributesRequiredState) - XCTAssertNil(helper.newCodeRequiredState?.flowToken) + XCTAssertNil(helper.newCodeRequiredState?.continuationToken) XCTAssertNil(helper.newPasswordRequiredState) XCTAssertEqual(helper.error?.type, .generalError) @@ -1175,9 +1175,9 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() - validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2") validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) XCTAssertFalse(requestProviderMock.challengeCalled) @@ -1185,7 +1185,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpVerifyCodeError(result) await fulfillment(of: [exp], timeout: 1) @@ -1197,14 +1197,14 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andCantCreateRequest() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() - validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2")) requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) - requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2") let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpVerifyCodeError(result) await fulfillment(of: [exp], timeout: 1) @@ -1220,17 +1220,17 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andSucceeds() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() - validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") - validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("signUpToken 3")) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2") + validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("continuationToken 3")) XCTAssertFalse(requestProviderMock.challengeCalled) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) result.telemetryUpdate?(.success(())) helper.onSignUpPasswordRequired(result) @@ -1240,7 +1240,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { XCTAssertTrue(helper.onSignUpPasswordRequiredCalled) XCTAssertNil(helper.newAttributesRequiredState) XCTAssertNil(helper.newCodeRequiredState) - XCTAssertEqual(helper.newPasswordRequiredState?.flowToken, "signUpToken 3") + XCTAssertEqual(helper.newPasswordRequiredState?.continuationToken, "continuationToken 3") XCTAssertNil(helper.error) checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: true) @@ -1249,17 +1249,17 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() - validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") - validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("signUpToken 3")) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2") + validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("continuationToken 3")) XCTAssertFalse(requestProviderMock.challengeCalled) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) result.telemetryUpdate?(.failure(.init(message: "error"))) helper.onSignUpPasswordRequired(result) @@ -1269,7 +1269,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { XCTAssertTrue(helper.onSignUpPasswordRequiredCalled) XCTAssertNil(helper.newAttributesRequiredState) XCTAssertNil(helper.newCodeRequiredState) - XCTAssertEqual(helper.newPasswordRequiredState?.flowToken, "signUpToken 3") + XCTAssertEqual(helper.newPasswordRequiredState?.continuationToken, "continuationToken 3") XCTAssertNil(helper.error) checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) @@ -1277,18 +1277,18 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andSucceedOOB_returnsCorrectError() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2")) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") - validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("", .email, 4, "signUpToken 3")) + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2") + validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("", .email, 4, "continuationToken 3")) XCTAssertFalse(requestProviderMock.challengeCalled) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpVerifyCodeError(result) await fulfillment(of: [exp], timeout: 1) @@ -1301,9 +1301,9 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andRedirects() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() - validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2") validatorMock.mockValidateSignUpChallengeFunc(.redirect) XCTAssertFalse(requestProviderMock.challengeCalled) @@ -1311,7 +1311,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpVerifyCodeError(result) await fulfillment(of: [exp], timeout: 1) @@ -1327,9 +1327,9 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andReturnsError() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() - validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2") let error : MSALNativeAuthSignUpChallengeValidatedResponse = .error( MSALNativeAuthSignUpChallengeResponseError(error: .expiredToken, errorDescription: nil, @@ -1343,7 +1343,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpVerifyCodeError(result) await fulfillment(of: [exp], timeout: 1) @@ -1359,9 +1359,9 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andReturnsUnexpectedError() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() - validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "signUpToken 2") + requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2") validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) XCTAssertFalse(requestProviderMock.challengeCalled) @@ -1369,7 +1369,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) - let result = await sut.submitCode("1234", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpVerifyCodeError(result) await fulfillment(of: [exp], timeout: 1) @@ -1391,7 +1391,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitPassword("password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpPasswordRequiredError(result) await fulfillment(of: [exp], timeout: 1) @@ -1406,12 +1406,12 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSubmitPassword_succeeds_it_continuesTheFlow() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) - validatorMock.mockValidateSignUpContinueFunc(.success("signInSLT")) + validatorMock.mockValidateSignUpContinueFunc(.success("continuationToken")) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitPassword("password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpCompleted(result) await fulfillment(of: [exp], timeout: 1) @@ -1432,7 +1432,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { errorCodes: nil, errorURI: nil, innerErrors: nil, - signUpToken: nil, + continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil)) @@ -1441,13 +1441,13 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitPassword("password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpPasswordRequiredError(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpPasswordRequiredErrorCalled) XCTAssertNil(helper.newAttributesRequiredState) - XCTAssertEqual(helper.newPasswordRequiredState?.flowToken, "signUpToken") + XCTAssertEqual(helper.newPasswordRequiredState?.continuationToken, "continuationToken") XCTAssertEqual(helper.error?.type, .invalidPassword) XCTAssertEqual(helper.error?.errorDescription, "Password too weak") @@ -1457,19 +1457,19 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitPassword_returns_attributesRequired_it_returnsCorrectError() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) - validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(signUpToken: "signUpToken 2", requiredAttributes: [])) + validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken 2", requiredAttributes: [])) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitPassword("password", username: "", continuationToken: "continuationToken", context: contextMock) result.telemetryUpdate?(.success(())) helper.onSignUpAttributesRequired(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpAttributesRequiredCalled) - XCTAssertEqual(helper.newAttributesRequiredState?.flowToken, "signUpToken 2") + XCTAssertEqual(helper.newAttributesRequiredState?.continuationToken, "continuationToken 2") XCTAssertNil(helper.newPasswordRequiredState) XCTAssertNil(helper.error) @@ -1479,19 +1479,19 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitPassword_returns_attributesRequired_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) - validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(signUpToken: "signUpToken 2", requiredAttributes: [])) + validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken 2", requiredAttributes: [])) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitPassword("password", username: "", continuationToken: "continuationToken", context: contextMock) result.telemetryUpdate?(.failure(.init(message: "error"))) helper.onSignUpAttributesRequired(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpAttributesRequiredCalled) - XCTAssertEqual(helper.newAttributesRequiredState?.flowToken, "signUpToken 2") + XCTAssertEqual(helper.newAttributesRequiredState?.continuationToken, "continuationToken 2") XCTAssertNil(helper.newPasswordRequiredState) XCTAssertNil(helper.error) @@ -1507,7 +1507,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { errorCodes: nil, errorURI: nil, innerErrors: nil, - signUpToken: nil, + continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil)) @@ -1516,7 +1516,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitPassword("password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpPasswordRequiredError(result) await fulfillment(of: [exp], timeout: 1) @@ -1531,12 +1531,12 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitPassword_returns_credentialRequired_it_returnsCorrectError() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) - validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2")) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitPassword("password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpPasswordRequiredError(result) await fulfillment(of: [exp], timeout: 1) @@ -1556,7 +1556,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitPassword("password", username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpPasswordRequiredError(result) await fulfillment(of: [exp], timeout: 1) @@ -1571,12 +1571,12 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitPassword_returns_attributeValidationFailed_it_returnsCorrectError() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) - validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(signUpToken: "signUpToken 2", invalidAttributes: ["key"])) + validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(continuationToken: "continuationToken 2", invalidAttributes: ["key"])) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword("password", username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitPassword("password", username: "", continuationToken: "continuationToken", context: contextMock) result.telemetryUpdate?(.success(())) helper.onSignUpPasswordRequiredError(result) @@ -1602,7 +1602,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) - let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitAttributes(["key": "value"], username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpAttributesRequiredError(result) await fulfillment(of: [exp], timeout: 1) @@ -1624,7 +1624,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) - let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitAttributes(["key": "value"], username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpCompleted(result) await fulfillment(of: [exp], timeout: 1) @@ -1648,7 +1648,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { errorCodes: nil, errorURI: nil, innerErrors: nil, - signUpToken: nil, + continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil)) @@ -1657,7 +1657,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) - let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitAttributes(["key": "value"], username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpAttributesRequiredError(result) await fulfillment(of: [exp], timeout: 1) @@ -1680,7 +1680,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { errorCodes: nil, errorURI: nil, innerErrors: nil, - signUpToken: nil, + continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil)) @@ -1689,7 +1689,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) - let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitAttributes(["key": "value"], username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpAttributesRequiredError(result) await fulfillment(of: [exp], timeout: 1) @@ -1706,18 +1706,18 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { oobCode: nil, attributes: ["key": "value"] ) - validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(signUpToken: "signUpToken 2", requiredAttributes: [])) + validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken 2", requiredAttributes: [])) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) - let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitAttributes(["key": "value"], username: "", continuationToken: "continuationToken", context: contextMock) result.telemetryUpdate?(.success(())) helper.onSignUpAttributesRequired(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpAttributesRequiredCalled) - XCTAssertEqual(helper.newState?.flowToken, "signUpToken 2") + XCTAssertEqual(helper.newState?.continuationToken, "continuationToken 2") checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitAttributes, isSuccessful: false) } @@ -1729,12 +1729,12 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { oobCode: nil, attributes: ["key": "value"] ) - validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(signUpToken: "signUpToken 2")) + validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2")) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) - let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitAttributes(["key": "value"], username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpAttributesRequiredError(result) await fulfillment(of: [exp], timeout: 1) @@ -1756,7 +1756,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) - let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitAttributes(["key": "value"], username: "", continuationToken: "continuationToken", context: contextMock) helper.onSignUpAttributesRequiredError(result) await fulfillment(of: [exp], timeout: 1) @@ -1773,28 +1773,28 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { oobCode: nil, attributes: ["key": "value"] ) - validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(signUpToken: "signUpToken 2", invalidAttributes: ["attribute"])) + validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(continuationToken: "continuationToken 2", invalidAttributes: ["attribute"])) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) - let result = await sut.submitAttributes(["key": "value"], username: "", signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitAttributes(["key": "value"], username: "", continuationToken: "continuationToken", context: contextMock) result.telemetryUpdate?(.success(())) helper.onSignUpAttributesValidationFailed(result) await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpInvalidAttributesCalled) - XCTAssertEqual(helper.newState?.flowToken, "signUpToken 2") + XCTAssertEqual(helper.newState?.continuationToken, "continuationToken 2") XCTAssertEqual(helper.invalidAttributes, ["attribute"]) checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitAttributes, isSuccessful: false) } - // MARK: - Sign-in with SLT (Short-Lived Token) + // MARK: - Sign-in with ContinuationToken - func test_whenSignUpSucceeds_and_userCallsSignInWithSLT_signUpControllerPassesCorrectParams() async { + func test_whenSignUpSucceeds_and_userCallsSignInWithContinuationToken_signUpControllerPassesCorrectParams() async { let username = "username" - let slt = "signInSLT" + let continuationToken = "continuationToken" class SignInAfterSignUpDelegateStub: SignInAfterSignUpDelegate { func onSignInAfterSignUpError(error: MSAL.SignInAfterSignUpError) {} @@ -1803,12 +1803,12 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) - validatorMock.mockValidateSignUpContinueFunc(.success(slt)) + validatorMock.mockValidateSignUpContinueFunc(.success(continuationToken)) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) - let result = await sut.submitPassword("password", username: username, signUpToken: "signUpToken", context: contextMock) + let result = await sut.submitPassword("password", username: username, continuationToken: "continuationToken", context: contextMock) helper.onSignUpCompleted(result) await fulfillment(of: [exp], timeout: 1) @@ -1821,12 +1821,12 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { let exp2 = expectation(description: "SignInAfterSignUp expectation") signInControllerMock.expectation = exp2 - signInControllerMock.signInSLTResult = .init(.failure(.init())) + signInControllerMock.continuationTokenResult = .init(.failure(.init())) helper.signInAfterSignUpState?.signIn(delegate: SignInAfterSignUpDelegateStub()) await fulfillment(of: [exp2], timeout: 1) XCTAssertEqual(signInControllerMock.username, username) - XCTAssertEqual(signInControllerMock.slt, slt) + XCTAssertEqual(signInControllerMock.continuationToken, continuationToken) } // MARK: - Common Methods @@ -1924,20 +1924,20 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { return helper } - private func expectedChallengeParams(token: String = "signUpToken") -> (token: String, context: MSIDRequestContext) { + private func expectedChallengeParams(token: String = "continuationToken") -> (token: String, context: MSIDRequestContext) { return (token: token, context: contextMock) } private func expectedContinueParams( grantType: MSALNativeAuthGrantType = .oobCode, - token: String = "signUpToken", + token: String = "continuationToken", password: String? = nil, oobCode: String? = "1234", attributes: [String: Any]? = nil ) -> MSALNativeAuthSignUpContinueRequestProviderParams { .init( grantType: grantType, - signUpToken: token, + continuationToken: token, password: password, oobCode: oobCode, attributes: attributes, diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift index 21ce6dd4d7..ec56f1292d 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift @@ -90,7 +90,7 @@ class MSALNativeAuthSignInResponseValidatorMock: MSALNativeAuthSignInResponseVal checkConfAndContext(context) if case .success(let successChallengeResponse) = result, let expectedChallengeResponse = expectedChallengeResponse { XCTAssertEqual(successChallengeResponse.challengeType, expectedChallengeResponse.challengeType) - XCTAssertEqual(successChallengeResponse.credentialToken, expectedChallengeResponse.credentialToken) + XCTAssertEqual(successChallengeResponse.continuationToken, expectedChallengeResponse.continuationToken) XCTAssertEqual(successChallengeResponse.challengeTargetLabel, expectedChallengeResponse.challengeTargetLabel) XCTAssertEqual(successChallengeResponse.challengeChannel, expectedChallengeResponse.challengeChannel) XCTAssertEqual(successChallengeResponse.codeLength, expectedChallengeResponse.codeLength) @@ -106,7 +106,7 @@ class MSALNativeAuthSignInResponseValidatorMock: MSALNativeAuthSignInResponseVal checkConfAndContext(context) if case .success(let successInitiateResponse) = result, let expectedInitiateResponse = expectedInitiateResponse { XCTAssertEqual(successInitiateResponse.challengeType, expectedInitiateResponse.challengeType) - XCTAssertEqual(successInitiateResponse.credentialToken, expectedInitiateResponse.credentialToken) + XCTAssertEqual(successInitiateResponse.continuationToken, expectedInitiateResponse.continuationToken) } if case .failure(let initiateResponseError) = result, let expectedInitiateResponseError = expectedResponseError { XCTAssertTrue(type(of: initiateResponseError) == type(of: expectedInitiateResponseError)) @@ -202,7 +202,7 @@ class MSALNativeAuthSignInRequestProviderMock: MSALNativeAuthSignInRequestProvid func challenge(parameters: MSAL.MSALNativeAuthSignInChallengeRequestParameters, context: MSIDRequestContext) throws -> MSIDHttpRequest { checkContext(context) if let expectedCredentialToken = expectedCredentialToken { - XCTAssertEqual(expectedCredentialToken, parameters.credentialToken) + XCTAssertEqual(expectedCredentialToken, parameters.continuationToken) } if let request = requestChallenge { return request @@ -240,8 +240,8 @@ class MSALNativeAuthTokenRequestProviderMock: MSALNativeAuthTokenRequestProvidin checkContext(context) if let expectedTokenParams = expectedTokenParams { XCTAssertEqual(expectedTokenParams.username, parameters.username) - XCTAssertEqual(expectedTokenParams.credentialToken, parameters.credentialToken) - XCTAssertEqual(expectedTokenParams.signInSLT, parameters.signInSLT) + XCTAssertEqual(expectedTokenParams.continuationToken, parameters.continuationToken) + XCTAssertEqual(expectedTokenParams.continuationToken, parameters.continuationToken) XCTAssertEqual(expectedTokenParams.grantType, parameters.grantType) XCTAssertEqual(expectedTokenParams.scope, parameters.scope) XCTAssertEqual(expectedTokenParams.password, parameters.password) @@ -266,8 +266,8 @@ class MSALNativeAuthTokenRequestProviderMock: MSALNativeAuthTokenRequestProvidin checkContext(context) if let expectedTokenParams = expectedTokenParams { XCTAssertEqual(expectedTokenParams.username, parameters.username) - XCTAssertEqual(expectedTokenParams.credentialToken, parameters.credentialToken) - XCTAssertEqual(expectedTokenParams.signInSLT, parameters.signInSLT) + XCTAssertEqual(expectedTokenParams.continuationToken, parameters.continuationToken) + XCTAssertEqual(expectedTokenParams.continuationToken, parameters.continuationToken) XCTAssertEqual(expectedTokenParams.grantType, parameters.grantType) XCTAssertEqual(expectedTokenParams.scope, parameters.scope) XCTAssertEqual(expectedTokenParams.password, parameters.password) diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift index a71bcd8a4e..90cb8f8fcb 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift @@ -37,15 +37,15 @@ class MSALNativeAuthResetPasswordControllerMock: MSALNativeAuthResetPasswordCont return resetPasswordResponse } - func resendCode(username: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { + func resendCode(username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { return resendCodeResponse } - func submitCode(code: String, username: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse { + func submitCode(code: String, username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse { return submitCodeResponse } - func submitPassword(password: String, username: String, passwordSubmitToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitPasswordControllerResponse { + func submitPassword(password: String, username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitPasswordControllerResponse { return submitPasswordResponse } } diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift index e71850b5dc..a70be9799a 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignInControllerMock.swift @@ -28,11 +28,11 @@ import XCTest class MSALNativeAuthSignInControllerMock: MSALNativeAuthSignInControlling { private(set) var username: String? - private(set) var slt: String? + private(set) var continuationToken: String? var expectation: XCTestExpectation? var signInStartResult: MSALNativeAuthSignInControlling.SignInControllerResponse! - var signInSLTResult: SignInAfterPreviousFlowControllerResponse! + var continuationTokenResult: SignInAfterPreviousFlowControllerResponse! var submitCodeResult: SignInSubmitCodeControllerResponse! var submitPasswordResult: SignInSubmitPasswordControllerResponse! var resendCodeResult: SignInResendCodeControllerResponse! @@ -41,23 +41,23 @@ class MSALNativeAuthSignInControllerMock: MSALNativeAuthSignInControlling { return signInStartResult } - func signIn(username: String, slt: String?, scopes: [String]?, context: MSAL.MSALNativeAuthRequestContext) async -> SignInAfterPreviousFlowControllerResponse { + func signIn(username: String, continuationToken: String?, scopes: [String]?, context: MSAL.MSALNativeAuthRequestContext) async -> SignInAfterPreviousFlowControllerResponse { self.username = username - self.slt = slt + self.continuationToken = continuationToken expectation?.fulfill() - return signInSLTResult + return continuationTokenResult } - func submitCode(_ code: String, credentialToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInSubmitCodeControllerResponse { + func submitCode(_ code: String, continuationToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInSubmitCodeControllerResponse { submitCodeResult } - func submitPassword(_ password: String, username: String, credentialToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInSubmitPasswordControllerResponse { + func submitPassword(_ password: String, username: String, continuationToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInSubmitPasswordControllerResponse { return submitPasswordResult } - func resendCode(credentialToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInResendCodeControllerResponse { + func resendCode(continuationToken: String, context: MSAL.MSALNativeAuthRequestContext, scopes: [String]) async -> SignInResendCodeControllerResponse { return resendCodeResult } } diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift index 7ebaca6a9f..33482b7c89 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift @@ -40,19 +40,19 @@ class MSALNativeAuthSignUpControllerMock: MSALNativeAuthSignUpControlling { return startResult } - func resendCode(username: String, context: MSIDRequestContext, signUpToken: String) async -> SignUpResendCodeControllerResponse { + func resendCode(username: String, context: MSIDRequestContext, continuationToken: String) async -> SignUpResendCodeControllerResponse { return resendCodeResult } - func submitCode(_ code: String, username: String, signUpToken: String, context: MSIDRequestContext) async -> MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse { + func submitCode(_ code: String, username: String, continuationToken: String, context: MSIDRequestContext) async -> MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse { return submitCodeResult } - func submitPassword(_ password: String, username: String, signUpToken: String, context: MSIDRequestContext) async -> MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse { + func submitPassword(_ password: String, username: String, continuationToken: String, context: MSIDRequestContext) async -> MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse { return submitPasswordResult } - func submitAttributes(_ attributes: [String : Any], username: String, signUpToken: String, context: MSIDRequestContext) async -> SignUpSubmitAttributesControllerResponse { + func submitAttributes(_ attributes: [String : Any], username: String, continuationToken: String, context: MSIDRequestContext) async -> SignUpSubmitAttributesControllerResponse { return submitAttributesResult } } diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift index 1d021ac41c..d64ae99fe1 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift @@ -61,7 +61,7 @@ class MSALNativeAuthSignUpControllerSpy: MSALNativeAuthSignUpControlling { func resendCode( username: String, context: MSIDRequestContext, - signUpToken: String + continuationToken: String ) async -> SignUpResendCodeControllerResponse { self.context = context resendCodeCalled = true @@ -72,7 +72,7 @@ class MSALNativeAuthSignUpControllerSpy: MSALNativeAuthSignUpControlling { func submitCode( _ code: String, username: String, - signUpToken: String, + continuationToken: String, context: MSIDRequestContext ) async -> MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse { self.context = context @@ -84,7 +84,7 @@ class MSALNativeAuthSignUpControllerSpy: MSALNativeAuthSignUpControlling { func submitPassword( _ password: String, username: String, - signUpToken: String, + continuationToken: String, context: MSIDRequestContext ) async -> MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse { self.context = context @@ -96,7 +96,7 @@ class MSALNativeAuthSignUpControllerSpy: MSALNativeAuthSignUpControlling { func submitAttributes( _ attributes: [String: Any], username: String, - signUpToken: String, + continuationToken: String, context: MSIDRequestContext ) async -> SignUpSubmitAttributesControllerResponse { self.context = context diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift index 23992d63a9..6219473797 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift @@ -109,7 +109,7 @@ class MSALNativeAuthSignUpRequestProviderMock: MSALNativeAuthSignUpRequestProvid private func checkContinueParameters(_ params: MSALNativeAuthSignUpContinueRequestProviderParams) { XCTAssertEqual(params.grantType, expectedContinueRequestParameters.grantType) - XCTAssertEqual(params.signUpToken, expectedContinueRequestParameters.signUpToken) + XCTAssertEqual(params.continuationToken, expectedContinueRequestParameters.continuationToken) XCTAssertEqual(params.password, expectedContinueRequestParameters.password) XCTAssertEqual(params.oobCode, expectedContinueRequestParameters.oobCode) XCTAssertEqual(params.attributes?["key"] as? String, expectedContinueRequestParameters.attributes?["key"] as? String) diff --git a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift index 2ca3c5af24..46217c1c3b 100644 --- a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift +++ b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift @@ -29,7 +29,7 @@ import XCTest class MSALNativeAuthResetPasswordControllerSpy: MSALNativeAuthResetPasswordControlling { private let expectation: XCTestExpectation private(set) var context: MSIDRequestContext? - private(set) var flowToken: String? + private(set) var continuationToken: String? private(set) var resetPasswordCalled = false private(set) var resendCodeCalled = false private(set) var submitCodeCalled = false @@ -48,8 +48,8 @@ class MSALNativeAuthResetPasswordControllerSpy: MSALNativeAuthResetPasswordContr return .init(.error(.init(type: .generalError))) } - func resendCode(username: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { - self.flowToken = passwordResetToken + func resendCode(username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { + self.continuationToken = continuationToken self.username = username self.context = context resendCodeCalled = true @@ -58,8 +58,8 @@ class MSALNativeAuthResetPasswordControllerSpy: MSALNativeAuthResetPasswordContr return .init(.error(error: .init(), newState: nil)) } - func submitCode(code: String, username: String, passwordResetToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse { - self.flowToken = passwordResetToken + func submitCode(code: String, username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse { + self.continuationToken = continuationToken self.username = username self.context = context submitCodeCalled = true @@ -68,8 +68,8 @@ class MSALNativeAuthResetPasswordControllerSpy: MSALNativeAuthResetPasswordContr return .init(.error(error: .init(type: .generalError), newState: nil)) } - func submitPassword(password: String, username: String, passwordSubmitToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitPasswordControllerResponse { - self.flowToken = passwordSubmitToken + func submitPassword(password: String, username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitPasswordControllerResponse { + self.continuationToken = continuationToken self.username = username self.context = context submitPasswordCalled = true diff --git a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordRequestProviderMock.swift b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordRequestProviderMock.swift index 4c876637d3..c5fbd5d2ee 100644 --- a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordRequestProviderMock.swift +++ b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordRequestProviderMock.swift @@ -114,7 +114,7 @@ class MSALNativeAuthResetPasswordRequestProviderMock: MSALNativeAuthResetPasswor private func checkParameters(_ params: MSALNativeAuthResetPasswordContinueRequestParameters) { XCTAssertEqual(params.grantType, expectedContinueRequestParameters.grantType) - XCTAssertEqual(params.passwordResetToken, expectedContinueRequestParameters.passwordResetToken) + XCTAssertEqual(params.continuationToken, expectedContinueRequestParameters.continuationToken) XCTAssertEqual(params.oobCode, expectedContinueRequestParameters.oobCode) XCTAssertEqual(params.context.correlationId(), expectedContinueRequestParameters.context.correlationId()) } @@ -145,7 +145,7 @@ class MSALNativeAuthResetPasswordRequestProviderMock: MSALNativeAuthResetPasswor } private func checkParameters(_ params: MSALNativeAuthResetPasswordSubmitRequestParameters) { - XCTAssertEqual(params.passwordSubmitToken, expectedSubmitRequestParameters.passwordSubmitToken) + XCTAssertEqual(params.continuationToken, expectedSubmitRequestParameters.continuationToken) XCTAssertEqual(params.newPassword, expectedSubmitRequestParameters.newPassword) XCTAssertEqual(params.context.correlationId(), expectedSubmitRequestParameters.context.correlationId()) } @@ -176,7 +176,7 @@ class MSALNativeAuthResetPasswordRequestProviderMock: MSALNativeAuthResetPasswor } private func checkParameters(_ params: MSALNativeAuthResetPasswordPollCompletionRequestParameters) { - XCTAssertEqual(params.passwordResetToken, expectedPollCompletionParameters.passwordResetToken) + XCTAssertEqual(params.continuationToken, expectedPollCompletionParameters.continuationToken) XCTAssertEqual(params.context.correlationId(), expectedPollCompletionParameters.context.correlationId()) } } diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift index 950f058e90..cb07889a84 100644 --- a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift @@ -75,7 +75,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { let request = MSIDHttpRequest() let params = MSALNativeAuthSignInChallengeRequestParameters(context: context, - credentialToken: "Test Credential Token") + continuationToken: "Test Credential Token") let sut = MSALNativeAuthRequestConfigurator(config: config) try sut.configure(configuratorType: .signIn(.challenge(params)), request: request, @@ -83,7 +83,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, - "credential_token": "Test Credential Token", + "continuation_token": "Test Credential Token", "challenge_type": "otp" ] @@ -103,8 +103,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { let request = MSIDHttpRequest() let params = MSALNativeAuthTokenRequestParameters(context: context, username: DEFAULT_TEST_ID_TOKEN_USERNAME, - credentialToken: "Test Credential Token", - signInSLT: "Test SignIn SLT", + continuationToken: "Test Continuation Token", grantType: .password, scope: "", password: "password", @@ -120,8 +119,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, "username": DEFAULT_TEST_ID_TOKEN_USERNAME, - "credential_token": "Test Credential Token", - "signin_slt": "Test SignIn SLT", + "continuation_token": "Test Continuation Token", "grant_type": "password", "challenge_type": "password", "scope": "", @@ -176,7 +174,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { ) let request = MSIDHttpRequest() - let params = MSALNativeAuthSignUpChallengeRequestParameters(signUpToken: "", + let params = MSALNativeAuthSignUpChallengeRequestParameters(continuationToken: "", context: context) let sut = MSALNativeAuthRequestConfigurator(config: config) @@ -186,7 +184,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, - "signup_token": "", + "continuation_token": "", "challenge_type": "password oob redirect" ] @@ -205,7 +203,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { let request = MSIDHttpRequest() let params = MSALNativeAuthSignUpContinueRequestParameters(grantType: .oobCode, - signUpToken: "", + continuationToken: "", password: "", oobCode: "0000", attributes: "", @@ -218,7 +216,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, - "signup_token": "", + "continuation_token": "", "password": "", "oob": "0000", "grant_type": "oob", @@ -269,7 +267,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { let request = MSIDHttpRequest() let params = MSALNativeAuthResetPasswordChallengeRequestParameters(context: context, - passwordResetToken: "") + continuationToken: "") let sut = MSALNativeAuthRequestConfigurator(config: config) try sut.configure(configuratorType: .resetPassword(.challenge(params)), @@ -278,7 +276,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, - "password_reset_token": "", + "continuation_token": "", "challenge_type": "password oob redirect" ] @@ -297,7 +295,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { let request = MSIDHttpRequest() let params = MSALNativeAuthResetPasswordContinueRequestParameters(context: context, - passwordResetToken: "", + continuationToken: "", grantType: .oobCode, oobCode: "0000") @@ -308,7 +306,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, - "password_reset_token": "", + "continuation_token": "", "grant_type": "oob", "oob": "0000" ] @@ -328,7 +326,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { let request = MSIDHttpRequest() let params = MSALNativeAuthResetPasswordSubmitRequestParameters(context: context, - passwordSubmitToken: "", + continuationToken: "", newPassword:"new-password") let sut = MSALNativeAuthRequestConfigurator(config: config) @@ -338,7 +336,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, - "password_submit_token": "", + "continuation_token": "", "new_password": "new-password" ] @@ -357,7 +355,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { let request = MSIDHttpRequest() let params = MSALNativeAuthResetPasswordPollCompletionRequestParameters(context: context, - passwordResetToken: "", password: nil, diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift index 85e7051d9c..735ab2f31a 100644 --- a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift @@ -230,7 +230,7 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { dictionary["error"] = "verification_required" dictionary["error_description"] = "AADSTS55102: Verification required." dictionary["error_uri"] = HttpModuleMockConfigurator.baseUrl.absoluteString - dictionary["signup_token"] = "abcdef" + dictionary["continuation_token"] = "abcdef" let data = try JSONSerialization.data(withJSONObject: dictionary) @@ -252,7 +252,7 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { XCTAssertEqual(error.error, MSALNativeAuthSignUpStartOauth2ErrorCode.verificationRequired) XCTAssertEqual(error.errorDescription, "AADSTS55102: Verification required.") XCTAssertEqual(error.errorURI, HttpModuleMockConfigurator.baseUrl.absoluteString) - XCTAssertEqual(error.signUpToken, "abcdef") + XCTAssertEqual(error.continuationToken, "abcdef") expectation.fulfill() } wait(for: [expectation], timeout: 1) diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift index b20a7de987..8d533fe0fc 100644 --- a/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift @@ -87,7 +87,7 @@ final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase { } func test_signUpChallengeRequest_is_created_successfully() throws { - let request = try sut.challenge(token: "sign-up-token", context: context) + let request = try sut.challenge(token: "continuation-token", context: context) checkBodyParams(request.parameters, for: .signUpChallenge) checkUrlRequest(request.urlRequest!, for: .signUpChallenge) @@ -99,7 +99,7 @@ final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase { func test_signUpContinueRequest_is_created_successfully() throws { let parameters = MSALNativeAuthSignUpContinueRequestProviderParams( grantType: .password, - signUpToken: "sign-up-token", + continuationToken: "continuation-token", password: "1234", oobCode: nil, attributes: ["city": "dublin"], @@ -118,7 +118,7 @@ final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase { func test_signUpContinueRequestWithNoAttributes_is_created_successfully() throws { let parameters = MSALNativeAuthSignUpContinueRequestProviderParams( grantType: .password, - signUpToken: "sign-up-token", + continuationToken: "continuation-token", password: "1234", oobCode: nil, attributes: nil, @@ -137,7 +137,7 @@ final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase { func test_signUpContinueRequestWithInvalidAttributes_throwAnError() throws { let parameters = MSALNativeAuthSignUpContinueRequestProviderParams( grantType: .password, - signUpToken: "sign-up-token", + continuationToken: "continuation-token", password: "1234", oobCode: nil, attributes: ["invalid attribute": Data()], @@ -166,14 +166,14 @@ final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase { case .signUpChallenge: expectedBodyParams = [ Key.clientId.rawValue: DEFAULT_TEST_CLIENT_ID, - Key.signUpToken.rawValue: "sign-up-token", + Key.continuationToken.rawValue: "continuation-token", Key.challengeType.rawValue: "redirect" ] case .signUpContinue: expectedBodyParams = [ Key.clientId.rawValue: DEFAULT_TEST_CLIENT_ID, Key.grantType.rawValue: "password", - Key.signUpToken.rawValue: "sign-up-token", + Key.continuationToken.rawValue: "continuation-token", Key.password.rawValue: "1234" ] if expectAttributes { diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift index ad627538a5..b19dee8fb9 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift @@ -33,42 +33,42 @@ final class MSALNativeAuthResetPasswordContinueResponseErrorTests: XCTestCase { // MARK: - to toVerifyCodePublicError tests func test_toResetPasswordStartPublicError_invalidRequest() { - sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidRequest, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, passwordResetToken: nil) + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidRequest, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, .generalError) XCTAssertNotNil(error.errorDescription) } func test_toResetPasswordStartPublicError_invalidClient() { - sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidClient, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, passwordResetToken: nil) + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidClient, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, .generalError) XCTAssertEqual(error.errorDescription, testDescription) } func test_toResetPasswordStartPublicError_invalidGrant() { - sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidGrant, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, passwordResetToken: nil) + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidGrant, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, .generalError) XCTAssertEqual(error.errorDescription, testDescription) } func test_toResetPasswordStartPublicError_expiredToken() { - sut = MSALNativeAuthResetPasswordContinueResponseError(error: .expiredToken, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, passwordResetToken: nil) + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .expiredToken, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, .generalError) XCTAssertEqual(error.errorDescription, testDescription) } func test_toResetPasswordStartPublicError_unsupportedChallengeType() { - sut = MSALNativeAuthResetPasswordContinueResponseError(error: .verificationRequired, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, passwordResetToken: nil) + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .verificationRequired, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, .generalError) XCTAssertNotNil(error.errorDescription) } func test_toResetPasswordStartPublicError_invalidOOBValue() { - sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidOOBValue, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, passwordResetToken: nil) + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidOOBValue, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, .invalidCode) XCTAssertNotNil(error.errorDescription) diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift index 3f81cdfcdd..663e2e4628 100644 --- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift @@ -219,21 +219,21 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase { // MARK: private methods private func testSignUpContinueErrorToVerifyCode(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, description: String?, expectedErrorType: VerifyCodeError.ErrorType) { - sut = MSALNativeAuthSignUpContinueResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) + sut = MSALNativeAuthSignUpContinueResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, expectedErrorType) XCTAssertEqual(error.errorDescription, description) } private func testSignUpContinueErrorToPasswordRequired(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) { - sut = MSALNativeAuthSignUpContinueResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) + sut = MSALNativeAuthSignUpContinueResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) let error = sut.toPasswordRequiredPublicError() XCTAssertEqual(error.type, expectedErrorType) XCTAssertEqual(error.errorDescription, description) } private func testSignUpContinueErrorToAttributesRequired(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, description: String?) { - sut = MSALNativeAuthSignUpContinueResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) + sut = MSALNativeAuthSignUpContinueResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) let error = sut.toAttributesRequiredPublicError() XCTAssertEqual(error.errorDescription, description) } diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift index 96804ec7e2..3f5ec7d6e3 100644 --- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift @@ -87,7 +87,7 @@ final class MSALNativeAuthSignUpStartResponseErrorTests: XCTestCase { // MARK: private methods private func testSignUpStartErrorToSignUpStart(code: MSALNativeAuthSignUpStartOauth2ErrorCode, description: String?, expectedErrorType: SignUpStartError.ErrorType) { - sut = MSALNativeAuthSignUpStartResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, signUpToken: nil, unverifiedAttributes: nil, invalidAttributes: nil) + sut = MSALNativeAuthSignUpStartResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, unverifiedAttributes: nil, invalidAttributes: nil) let error = sut.toSignUpStartPublicError() XCTAssertEqual(error.type, expectedErrorType) XCTAssertEqual(error.errorDescription, description) diff --git a/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift index a2684f4cb6..4d67746045 100644 --- a/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift +++ b/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift @@ -40,7 +40,7 @@ final class MSALNativeAuthResetPasswordChallengeRequestParametersTest: XCTestCas XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .oob, .redirect])) let parameters = MSALNativeAuthResetPasswordChallengeRequestParameters( context: MSALNativeAuthRequestContextMock(), - passwordResetToken: "" + continuationToken: "" ) var resultUrl: URL? = nil @@ -52,14 +52,14 @@ final class MSALNativeAuthResetPasswordChallengeRequestParametersTest: XCTestCas XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .oob, .redirect])) let params = MSALNativeAuthResetPasswordChallengeRequestParameters( context: MSALNativeAuthRequestContextMock(), - passwordResetToken: "" + continuationToken: "" ) let body = params.makeRequestBody(config: config) let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, - "password_reset_token": "", + "continuation_token": "", "challenge_type": "password oob redirect" ] @@ -70,14 +70,14 @@ final class MSALNativeAuthResetPasswordChallengeRequestParametersTest: XCTestCas XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .redirect])) let params = MSALNativeAuthResetPasswordChallengeRequestParameters( context: MSALNativeAuthRequestContextMock(), - passwordResetToken: "" + continuationToken: "" ) let body = params.makeRequestBody(config: config) let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, - "password_reset_token": "", + "continuation_token": "", "challenge_type": "password redirect" ] diff --git a/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParametersTest.swift index f342ed3801..e6351837a2 100644 --- a/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParametersTest.swift +++ b/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParametersTest.swift @@ -40,7 +40,7 @@ final class MSALNativeAuthResetPasswordContinueRequestParametersTest: XCTestCase XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) let parameters = MSALNativeAuthResetPasswordContinueRequestParameters( context: context, - passwordResetToken: "", + continuationToken: "", grantType: .oobCode, oobCode: "0000" ) @@ -54,7 +54,7 @@ final class MSALNativeAuthResetPasswordContinueRequestParametersTest: XCTestCase XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) let params = MSALNativeAuthResetPasswordContinueRequestParameters( context: context, - passwordResetToken: "", + continuationToken: "", grantType: .oobCode, oobCode: "0000" ) @@ -63,7 +63,7 @@ final class MSALNativeAuthResetPasswordContinueRequestParametersTest: XCTestCase let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, - "password_reset_token": "", + "continuation_token": "", "grant_type": "oob", "oob": "0000" ] @@ -75,7 +75,7 @@ final class MSALNativeAuthResetPasswordContinueRequestParametersTest: XCTestCase XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) let params = MSALNativeAuthResetPasswordContinueRequestParameters( context: context, - passwordResetToken: "", + continuationToken: "", grantType: .oobCode, oobCode: nil ) @@ -84,7 +84,7 @@ final class MSALNativeAuthResetPasswordContinueRequestParametersTest: XCTestCase let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, - "password_reset_token": "", + "continuation_token": "", "grant_type": "oob" ] diff --git a/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift index f8b9daa70a..fbcfd9848e 100644 --- a/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift +++ b/MSAL/test/unit/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift @@ -40,7 +40,7 @@ final class MSALNativeAuthResetPasswordPollCompletionRequestParametersTest: XCTe XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) let parameters = MSALNativeAuthResetPasswordPollCompletionRequestParameters( context: context, - passwordResetToken: "", + continuationToken: "", newPassword:"new-password" ) @@ -53,7 +53,7 @@ final class MSALNativeAuthResetPasswordSubmitRequestParametersTest: XCTestCase { XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) let params = MSALNativeAuthResetPasswordSubmitRequestParameters( context: context, - passwordSubmitToken: "", + continuationToken: "", newPassword:"new-password" ) @@ -61,7 +61,7 @@ final class MSALNativeAuthResetPasswordSubmitRequestParametersTest: XCTestCase { let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, - "password_submit_token": "", + "continuation_token": "", "new_password": "new-password" ] diff --git a/MSAL/test/unit/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParametersTest.swift index dc833456b6..d35d597762 100644 --- a/MSAL/test/unit/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParametersTest.swift +++ b/MSAL/test/unit/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParametersTest.swift @@ -39,7 +39,7 @@ final class MSALNativeAuthSignInChallengeRequestParametersTest: XCTestCase { func testMakeEndpointUrl_whenRightUrlStringIsUsed_noExceptionThrown() { XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password])) let parameters = MSALNativeAuthSignInChallengeRequestParameters(context: MSALNativeAuthRequestContextMock(), - credentialToken: "Test Credential Token") + continuationToken: "Test Credential Token") var resultUrl: URL? = nil XCTAssertNoThrow(resultUrl = try parameters.makeEndpointUrl(config: config)) XCTAssertEqual(resultUrl?.absoluteString, "https://login.microsoftonline.com/common/oauth2/v2.0/challenge") @@ -49,14 +49,14 @@ final class MSALNativeAuthSignInChallengeRequestParametersTest: XCTestCase { XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.otp])) let params = MSALNativeAuthSignInChallengeRequestParameters( context: context, - credentialToken: "Test Credential Token" + continuationToken: "Test Credential Token" ) let body = params.makeRequestBody(config: config) let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, - "credential_token": "Test Credential Token", + "continuation_token": "Test Credential Token", "challenge_type": "otp" ] @@ -67,14 +67,14 @@ final class MSALNativeAuthSignInChallengeRequestParametersTest: XCTestCase { XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .redirect])) let params = MSALNativeAuthSignInChallengeRequestParameters( context: context, - credentialToken: "Test Credential Token" + continuationToken: "Test Credential Token" ) let body = params.makeRequestBody(config: config) let expectedBodyParams = [ "client_id": config.clientId, - "credential_token": params.credentialToken, + "continuation_token": params.continuationToken, "challenge_type": "password redirect", ] diff --git a/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParametersTest.swift index c1e63091a5..8028e9355b 100644 --- a/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParametersTest.swift +++ b/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParametersTest.swift @@ -39,7 +39,7 @@ final class MSALNativeAuthSignUpChallengeRequestParametersTest: XCTestCase { func testMakeEndpointUrl_whenRightUrlStringIsUsed_noExceptionThrown() { XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.redirect])) let parameters = MSALNativeAuthSignUpChallengeRequestParameters( - signUpToken: "token", + continuationToken: "token", context: MSALNativeAuthRequestContextMock() ) var resultUrl: URL? = nil @@ -50,7 +50,7 @@ final class MSALNativeAuthSignUpChallengeRequestParametersTest: XCTestCase { func test_allChallengeTypes_shouldCreateCorrectBodyRequest() throws { XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password, .oob, .redirect])) let params = MSALNativeAuthSignUpChallengeRequestParameters( - signUpToken: "", + continuationToken: "", context: context ) @@ -58,7 +58,7 @@ final class MSALNativeAuthSignUpChallengeRequestParametersTest: XCTestCase { let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, - "signup_token": "", + "continuation_token": "", "challenge_type": "password oob redirect" ] diff --git a/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParametersTest.swift index 522a72d330..f7bbf0c73e 100644 --- a/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParametersTest.swift +++ b/MSAL/test/unit/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParametersTest.swift @@ -40,7 +40,7 @@ final class MSALNativeAuthSignUpContinueRequestParametersTest: XCTestCase { XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) let parameters = MSALNativeAuthSignUpContinueRequestParameters( grantType: .oobCode, - signUpToken: "token", + continuationToken: "token", password: nil, oobCode: "1234", attributes: nil, @@ -55,7 +55,7 @@ final class MSALNativeAuthSignUpContinueRequestParametersTest: XCTestCase { XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [])) let params = MSALNativeAuthSignUpContinueRequestParameters( grantType: .oobCode, - signUpToken: "", + continuationToken: "", password: "", oobCode: "0000", attributes: "", @@ -66,7 +66,7 @@ final class MSALNativeAuthSignUpContinueRequestParametersTest: XCTestCase { let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, - "signup_token": "", + "continuation_token": "", "password": "", "oob": "0000", "grant_type": "oob", diff --git a/MSAL/test/unit/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParametersTest.swift b/MSAL/test/unit/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParametersTest.swift index 974589b14a..bf2a4b9501 100644 --- a/MSAL/test/unit/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParametersTest.swift +++ b/MSAL/test/unit/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParametersTest.swift @@ -39,8 +39,7 @@ final class MSALNativeAuthTokenRequestParametersTest: XCTestCase { XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password])) let parameters = MSALNativeAuthTokenRequestParameters(context: MSALNativeAuthRequestContextMock(), username: "username", - credentialToken: "Test Credential Token", - signInSLT: "Test SignIn SLT", + continuationToken: "Test Credential Token", grantType: .password, scope: "scope", password: "password", @@ -57,8 +56,7 @@ final class MSALNativeAuthTokenRequestParametersTest: XCTestCase { let params = MSALNativeAuthTokenRequestParameters( context: context, username: DEFAULT_TEST_ID_TOKEN_USERNAME, - credentialToken: "Test Credential Token", - signInSLT: "Test SignIn SLT", + continuationToken: "Test continuation Token", grantType: .password, scope: "", password: "password", @@ -72,8 +70,7 @@ final class MSALNativeAuthTokenRequestParametersTest: XCTestCase { let expectedBodyParams = [ "client_id": DEFAULT_TEST_CLIENT_ID, "username": DEFAULT_TEST_ID_TOKEN_USERNAME, - "credential_token": "Test Credential Token", - "signin_slt": "Test SignIn SLT", + "continuation_token": "Test continuation Token", "grant_type": "password", "challenge_type": "password", "scope": "", @@ -90,8 +87,7 @@ final class MSALNativeAuthTokenRequestParametersTest: XCTestCase { let params = MSALNativeAuthTokenRequestParameters( context: context, username: nil, - credentialToken: nil, - signInSLT: nil, + continuationToken: nil, grantType: .password, scope: nil, password: nil, diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift index b44ed52204..5e3d92b524 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift @@ -42,7 +42,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { func test_whenResetPasswordStartSuccessResponseContainsRedirect_itReturnsRedirect() { let response: Result = .success( - .init(passwordResetToken: nil, challengeType: .redirect) + .init(continuationToken: nil, challengeType: .redirect) ) let result = sut.validate(response, with: context) @@ -53,7 +53,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { func test_whenResetPasswordStartSuccessResponseDoesNotContainsTokenOrRedirect_itReturnsUnexpectedError() { let response: Result = .success( - .init(passwordResetToken: nil, challengeType: .otp) + .init(continuationToken: nil, challengeType: .otp) ) let result = sut.validate(response, with: context) @@ -64,16 +64,16 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { func test_whenResetPasswordStartSuccessResponseContainsToken_itReturnsSuccess() { let response: Result = .success( - .init(passwordResetToken: "passwordResetToken", challengeType: .otp) + .init(continuationToken: "continuationToken", challengeType: .otp) ) let result = sut.validate(response, with: context) - guard case .success(let passwordResetToken) = result else { + guard case .success(let continuationToken) = result else { return XCTFail("Unexpected response") } - XCTAssertEqual(passwordResetToken, "passwordResetToken") + XCTAssertEqual(continuationToken, "continuationToken") } func test_whenResetPasswordStartErrorResponseIsNotExpected_itReturnsUnexpectedError() { @@ -153,7 +153,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { bindingMethod: nil, challengeTargetLabel: "challenge-type-label", challengeChannel: .email, - passwordResetToken: "token", + continuationToken: "token", codeLength: nil) ) @@ -167,20 +167,20 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { bindingMethod: nil, challengeTargetLabel: "challenge-type-label", challengeChannel: .email, - passwordResetToken: "token", + continuationToken: "token", codeLength: 6) ) let result = sut.validate(response, with: context) - guard case .success(let sentTo, let channelTargetType, let codeLength, let passwordResetToken) = result else { + guard case .success(let sentTo, let channelTargetType, let codeLength, let continuationToken) = result else { return XCTFail("Unexpected response") } XCTAssertEqual(sentTo, "challenge-type-label") XCTAssertEqual(channelTargetType, .email) XCTAssertEqual(codeLength, 6) - XCTAssertEqual(passwordResetToken, "token") + XCTAssertEqual(continuationToken, "token") } func test_whenResetPasswordChallengeSuccessResponseOmitsSomeAttributes_itReturnsUnexpectedError() { @@ -189,7 +189,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { bindingMethod: nil, challengeTargetLabel: "challenge-type-label", challengeChannel: .email, - passwordResetToken: nil, + continuationToken: nil, codeLength: 6) ) @@ -203,7 +203,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { bindingMethod: nil, challengeTargetLabel: "challenge-type-label", challengeChannel: .none, - passwordResetToken: nil, + continuationToken: nil, codeLength: 6) ) @@ -235,15 +235,15 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { // MARK: - Continue Response func test_whenResetPasswordContinueSuccessResponseContainsValidAttributesAndOOB_itReturnsSuccess() { - let response: Result = .success(.init(passwordSubmitToken: "passwordSubmitToken", expiresIn: 300)) + let response: Result = .success(.init(continuationToken: "continuationToken", expiresIn: 300)) let result = sut.validate(response, with: context) - guard case .success(let passwordSubmitToken) = result else { + guard case .success(let continuationToken) = result else { return XCTFail("Unexpected response") } - XCTAssertEqual(passwordSubmitToken, "passwordSubmitToken") + XCTAssertEqual(continuationToken, "continuationToken") } func test_whenResetPasswordContinueErrorResponseIsNotExpected_itReturnsUnexpectedError() { @@ -312,15 +312,15 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { // MARK: - Submit Response func test_whenResetPasswordSubmitSuccessResponseContainsToken_itReturnsSuccess() { - let response: Result = .success(.init(passwordResetToken: "passwordResetToken", pollInterval: 1)) + let response: Result = .success(.init(continuationToken: "continuationToken", pollInterval: 1)) let result = sut.validate(response, with: context) - guard case .success(let passwordResetToken, let pollInterval) = result else { + guard case .success(let continuationToken, let pollInterval) = result else { return XCTFail("Unexpected response") } - XCTAssertEqual(passwordResetToken, "passwordResetToken") + XCTAssertEqual(continuationToken, "continuationToken") XCTAssertEqual(pollInterval, 1) } @@ -533,12 +533,12 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { private func buildContinueErrorResponse( expectedError: MSALNativeAuthResetPasswordContinueOauth2ErrorCode, - expectedPasswordResetToken: String? = nil + expectedContinuationToken: String? = nil ) -> MSALNativeAuthResetPasswordContinueValidatedResponse { let response: Result = .failure( createResetPasswordContinueError( error: expectedError, - passwordResetToken: expectedPasswordResetToken + continuationToken: expectedContinuationToken ) ) @@ -612,7 +612,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { errorURI: String? = nil, innerErrors: [MSALNativeAuthInnerError]? = nil, target: String? = nil, - passwordResetToken: String? = nil + continuationToken: String? = nil ) -> MSALNativeAuthResetPasswordContinueResponseError { .init( error: error, @@ -621,7 +621,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { errorURI: errorURI, innerErrors: innerErrors, target: target, - passwordResetToken: passwordResetToken + continuationToken: continuationToken ) } diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift index 7172554a98..b23b3ef261 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift @@ -45,7 +45,7 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase { func test_whenChallengeTypeRedirect_validationShouldReturnRedirectError() { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let challengeResponse = MSALNativeAuthSignInChallengeResponse(credentialToken: nil, challengeType: .redirect, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: nil, codeLength: nil, interval: nil) + let challengeResponse = MSALNativeAuthSignInChallengeResponse(continuationToken: nil, challengeType: .redirect, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: nil, codeLength: nil, interval: nil) let result = sut.validate(context: context, result: .success(challengeResponse)) if case .error(.redirect) = result {} else { XCTFail("Unexpected result: \(result)") @@ -54,17 +54,17 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase { func test_whenChallengeTypePassword_validationShouldReturnPasswordRequired() { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let credentialToken = "credentialToken" - let challengeResponse = MSALNativeAuthSignInChallengeResponse(credentialToken: credentialToken, challengeType: .password, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: nil, codeLength: nil, interval: nil) + let continuationToken = "continuationToken" + let challengeResponse = MSALNativeAuthSignInChallengeResponse(continuationToken: continuationToken, challengeType: .password, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: nil, codeLength: nil, interval: nil) let result = sut.validate(context: context, result: .success(challengeResponse)) - if case .passwordRequired(credentialToken: credentialToken) = result {} else { + if case .passwordRequired(continuationToken: continuationToken) = result {} else { XCTFail("Unexpected result: \(result)") } } func test_whenChallengeTypePasswordAndNoCredentialToken_validationShouldFail() { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let challengeResponse = MSALNativeAuthSignInChallengeResponse(credentialToken: nil, challengeType: .password, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: nil, codeLength: nil, interval: nil) + let challengeResponse = MSALNativeAuthSignInChallengeResponse(continuationToken: nil, challengeType: .password, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: nil, codeLength: nil, interval: nil) let result = sut.validate(context: context, result: .success(challengeResponse)) if case .error(.invalidServerResponse) = result {} else { XCTFail("Unexpected result: \(result)") @@ -73,39 +73,39 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase { func test_whenChallengeTypeOOB_validationShouldReturnCodeRequired() { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" let targetLabel = "targetLabel" let codeLength = 4 let channelType = MSALNativeAuthInternalChannelType.email - let challengeResponse = MSALNativeAuthSignInChallengeResponse(credentialToken: credentialToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: channelType, codeLength: codeLength, interval: nil) + let challengeResponse = MSALNativeAuthSignInChallengeResponse(continuationToken: continuationToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: channelType, codeLength: codeLength, interval: nil) let result = sut.validate(context: context, result: .success(challengeResponse)) - if case .codeRequired(credentialToken: credentialToken, sentTo: targetLabel, channelType: .email, codeLength: codeLength) = result {} else { + if case .codeRequired(continuationToken: continuationToken, sentTo: targetLabel, channelType: .email, codeLength: codeLength) = result {} else { XCTFail("Unexpected result: \(result)") } } func test_whenChallengeTypeOOBButMissingAttributes_validationShouldFail() { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let credentialToken = "credentialToken" + let continuationToken = "continuationToken" let targetLabel = "targetLabel" let codeLength = 4 let channelType = MSALNativeAuthInternalChannelType.email - let missingCredentialToken = MSALNativeAuthSignInChallengeResponse(credentialToken: nil, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: channelType, codeLength: codeLength, interval: nil) + let missingCredentialToken = MSALNativeAuthSignInChallengeResponse(continuationToken: nil, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: channelType, codeLength: codeLength, interval: nil) var result = sut.validate(context: context, result: .success(missingCredentialToken)) if case .error(.invalidServerResponse) = result {} else { XCTFail("Unexpected result: \(result)") } - let missingTargetLabel = MSALNativeAuthSignInChallengeResponse(credentialToken: credentialToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: channelType, codeLength: codeLength, interval: nil) + let missingTargetLabel = MSALNativeAuthSignInChallengeResponse(continuationToken: continuationToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: channelType, codeLength: codeLength, interval: nil) result = sut.validate(context: context, result: .success(missingTargetLabel)) if case .error(.invalidServerResponse) = result {} else { XCTFail("Unexpected result: \(result)") } - let missingChannelType = MSALNativeAuthSignInChallengeResponse(credentialToken: credentialToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: nil, codeLength: codeLength, interval: nil) + let missingChannelType = MSALNativeAuthSignInChallengeResponse(continuationToken: continuationToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: nil, codeLength: codeLength, interval: nil) result = sut.validate(context: context, result: .success(missingChannelType)) if case .error(.invalidServerResponse) = result {} else { XCTFail("Unexpected result: \(result)") } - let missingCodeLength = MSALNativeAuthSignInChallengeResponse(credentialToken: credentialToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: channelType, codeLength: nil, interval: nil) + let missingCodeLength = MSALNativeAuthSignInChallengeResponse(continuationToken: continuationToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: channelType, codeLength: nil, interval: nil) result = sut.validate(context: context, result: .success(missingCodeLength)) if case .error(.invalidServerResponse) = result {} else { XCTFail("Unexpected result: \(result)") @@ -114,7 +114,7 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase { func test_whenChallengeTypeOTP_validationShouldFail() { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let challengeResponse = MSALNativeAuthSignInChallengeResponse(credentialToken: "something", challengeType: .otp, bindingMethod: nil, challengeTargetLabel: "some", challengeChannel: .email, codeLength: 2, interval: nil) + let challengeResponse = MSALNativeAuthSignInChallengeResponse(continuationToken: "something", challengeType: .otp, bindingMethod: nil, challengeTargetLabel: "some", challengeChannel: .email, codeLength: 2, interval: nil) let result = sut.validate(context: context, result: .success(challengeResponse)) if case .error(.invalidServerResponse) = result {} else { XCTFail("Unexpected result: \(result)") @@ -125,17 +125,17 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase { func test_whenInitiateResponseIsValid_validationShouldBeSuccessful() { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let credentialToken = "credentialToken" - let initiateResponse = MSALNativeAuthSignInInitiateResponse(credentialToken: credentialToken, challengeType: nil) + let continuationToken = "continuationToken" + let initiateResponse = MSALNativeAuthSignInInitiateResponse(continuationToken: continuationToken, challengeType: nil) let result = sut.validate(context: context, result: .success(initiateResponse)) - if case .success(credentialToken: credentialToken) = result {} else { + if case .success(continuationToken: continuationToken) = result {} else { XCTFail("Unexpected result: \(result)") } } func test_whenInitiateResponseIsInvalid_validationShouldFail() { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let initiateResponse = MSALNativeAuthSignInInitiateResponse(credentialToken: nil, challengeType: nil) + let initiateResponse = MSALNativeAuthSignInInitiateResponse(continuationToken: nil, challengeType: nil) let result = sut.validate(context: context, result: .success(initiateResponse)) if case .error(.invalidServerResponse) = result {} else { XCTFail("Unexpected result: \(result)") @@ -144,7 +144,7 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase { func test_whenInitiateChallengeTypeIsRedirect_validationShouldReturnRedirectError() { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let initiateResponse = MSALNativeAuthSignInInitiateResponse(credentialToken: nil, challengeType: .redirect) + let initiateResponse = MSALNativeAuthSignInInitiateResponse(continuationToken: nil, challengeType: .redirect) let result = sut.validate(context: context, result: .success(initiateResponse)) if case .error(.redirect) = result {} else { XCTFail("Unexpected result: \(result)") @@ -153,17 +153,17 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase { func test_whenInitiateChallengeTypeIsInvalid_validationShouldFail() { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) - var initiateResponse = MSALNativeAuthSignInInitiateResponse(credentialToken: nil, challengeType: .oob) + var initiateResponse = MSALNativeAuthSignInInitiateResponse(continuationToken: nil, challengeType: .oob) var result = sut.validate(context: context, result: .success(initiateResponse)) if case .error(.invalidServerResponse) = result {} else { XCTFail("Unexpected result: \(result)") } - initiateResponse = MSALNativeAuthSignInInitiateResponse(credentialToken: nil, challengeType: .otp) + initiateResponse = MSALNativeAuthSignInInitiateResponse(continuationToken: nil, challengeType: .otp) result = sut.validate(context: context, result: .success(initiateResponse)) if case .error(.invalidServerResponse) = result {} else { XCTFail("Unexpected result: \(result)") } - initiateResponse = MSALNativeAuthSignInInitiateResponse(credentialToken: nil, challengeType: .password) + initiateResponse = MSALNativeAuthSignInInitiateResponse(continuationToken: nil, challengeType: .password) result = sut.validate(context: context, result: .success(initiateResponse)) if case .error(.invalidServerResponse) = result {} else { XCTFail("Unexpected result: \(result)") diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift index 863d7318a5..79a4963a5a 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift @@ -42,7 +42,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { func test_whenSignUpStartSuccessResponseContainsRedirect_it_returns_redirect() { let response: Result = .success( - .init(signupToken: nil, challengeType: .redirect) + .init(continuationToken: nil, challengeType: .redirect) ) let result = sut.validate(response, with: context) @@ -51,7 +51,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { func test_whenSignUpStartSuccessResponseDoesNotContainsTokenOrRedirect_it_returns_unexpectedError() { let response: Result = .success( - .init(signupToken: nil, challengeType: .otp) + .init(continuationToken: nil, challengeType: .otp) ) let result = sut.validate(response, with: context) @@ -68,25 +68,25 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { func test_whenSignUpStart_verificationRequiredErrorWithSignUpTokenAndUnverifiedAttributes_it_returns_verificationRequired() { let error = createSignUpStartError( error: .verificationRequired, - signUpToken: "sign-up token", + continuationToken: "continuation-token", unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes(name: "username")] ) let response: Result = .failure(error) let result = sut.validate(response, with: context) - guard case .verificationRequired(let signUpToken, let unverifiedAttributes) = result else { + guard case .verificationRequired(let continuationToken, let unverifiedAttributes) = result else { return XCTFail("Unexpected response") } - XCTAssertEqual(signUpToken, "sign-up token") + XCTAssertEqual(continuationToken, "continuation-token") XCTAssertEqual(unverifiedAttributes.first, "username") } func test_whenSignUpStart_verificationRequiredErrorWithSignUpToken_but_unverifiedAttributesIsEmpty_it_returns_unexpectedError() { let error = createSignUpStartError( error: .verificationRequired, - signUpToken: "sign-up token", + continuationToken: "continuation-token", unverifiedAttributes: [] ) let response: Result = .failure(error) @@ -98,7 +98,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { func test_whenSignUpStart_verificationRequiredErrorWithSignUpToken_but_unverifiedAttributesIsNil_it_returns_unexpectedError() { let error = createSignUpStartError( error: .verificationRequired, - signUpToken: "sign-up token", + continuationToken: "continuation-token", unverifiedAttributes: nil ) let response: Result = .failure(error) @@ -146,7 +146,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpStart_expectedVerificationRequiredErrorWithoutSignUpToken_it_returns_unexpectedError() { - let error = createSignUpStartError(error: .verificationRequired, signUpToken: nil) + let error = createSignUpStartError(error: .verificationRequired, continuationToken: nil) let response: Result = .failure(error) let result = sut.validate(response, with: context) @@ -175,7 +175,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { errorDescription: "username parameter is empty or not valid", errorCodes: errorCodes, errorURI: "aURI", - signUpToken: "aToken", + continuationToken: "aToken", unverifiedAttributes: attributes, invalidAttributes: attributes ) @@ -198,7 +198,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { errorDescription: "client_id parameter is empty or not valid", errorCodes: errorCodes, errorURI: "aURI", - signUpToken: "aToken", + continuationToken: "aToken", unverifiedAttributes: attributes, invalidAttributes: attributes ) @@ -221,7 +221,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { errorDescription: "aDescription", errorCodes: errorCodes, errorURI: "aURI", - signUpToken: "aToken", + continuationToken: "aToken", unverifiedAttributes: attributes, invalidAttributes: attributes ) @@ -237,7 +237,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { XCTAssertEqual(resultError.errorDescription, "aDescription") XCTAssertEqual(resultError.errorCodes, errorCodes) XCTAssertEqual(resultError.errorURI, "aURI") - XCTAssertEqual(resultError.signUpToken, "aToken") + XCTAssertEqual(resultError.continuationToken, "aToken") XCTAssertEqual(resultError.unverifiedAttributes, attributes) XCTAssertEqual(resultError.invalidAttributes, attributes) } @@ -251,7 +251,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { interval: nil, challengeTargetLabel: "challenge-type-label", challengeChannel: nil, - signUpToken: "token", + continuationToken: "token", codeLength: nil) ) @@ -266,7 +266,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { interval: nil, challengeTargetLabel: "challenge-type-label", challengeChannel: nil, - signUpToken: "token", + continuationToken: "token", codeLength: nil) ) @@ -281,20 +281,20 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { interval: nil, challengeTargetLabel: "challenge-type-label", challengeChannel: .email, - signUpToken: "token", + continuationToken: "token", codeLength: 6) ) let result = sut.validate(response, with: context) - guard case .codeRequired(let displayName, let displayType, let codeLength, let signUpToken) = result else { + guard case .codeRequired(let displayName, let displayType, let codeLength, let continuationToken) = result else { return XCTFail("Unexpected response") } XCTAssertEqual(displayName, "challenge-type-label") XCTAssertEqual(displayType, .email) XCTAssertEqual(codeLength, 6) - XCTAssertEqual(signUpToken, "token") + XCTAssertEqual(continuationToken, "token") } func test_whenSignUpChallengeSuccessResponseContainsValidAttributesAndPassword_it_returns_success() { @@ -304,17 +304,17 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { interval: nil, challengeTargetLabel: "challenge-type-label", challengeChannel: .email, - signUpToken: "token", + continuationToken: "token", codeLength: nil) ) let result = sut.validate(response, with: context) - guard case .passwordRequired(let signUpToken) = result else { + guard case .passwordRequired(let continuationToken) = result else { return XCTFail("Unexpected response") } - XCTAssertEqual(signUpToken, "token") + XCTAssertEqual(continuationToken, "token") } func test_whenSignUpChallengeSuccessResponseContainsPassword_but_noToken_it_returns_unexpectedError() { @@ -324,7 +324,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { interval: nil, challengeTargetLabel: "challenge-type-label", challengeChannel: .email, - signUpToken: nil, + continuationToken: nil, codeLength: nil) ) @@ -339,7 +339,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { interval: nil, challengeTargetLabel: "challenge-type-label", challengeChannel: nil, - signUpToken: "token", + continuationToken: "token", codeLength: 6) ) @@ -354,7 +354,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { interval: nil, challengeTargetLabel: "challenge-type-label", challengeChannel: nil, - signUpToken: nil, + continuationToken: nil, codeLength: 6) ) @@ -385,18 +385,18 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { // MARK: - Continue Response - func test_whenSignUpStartSuccessResponseContainsSLT_it_returns_success() { + func test_whenSignUpStartSuccessResponseContainsContinuationToken_it_returns_success() { let response: Result = .success( - .init(signinSLT: "", expiresIn: nil, signupToken: nil) + .init(continuationToken: "", expiresIn: nil) ) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .success("")) + XCTAssertEqual(result, .success("")) } - func test_whenSignUpStartSuccessResponseButDoesNotContainSLT_it_returns_successWithNoSLT() throws { + func test_whenSignUpStartSuccessResponseButDoesNotContainContinuationToken_it_returns_successWithNoContinuationToken() throws { let response: Result = .success( - .init(signinSLT: nil, expiresIn: nil, signupToken: nil) + .init(continuationToken: nil, expiresIn: nil) ) let result = sut.validate(response, with: context) @@ -411,7 +411,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpContinueErrorResponseIs_invalidOOBValue_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .invalidOOBValue, expectedSignUpToken: "sign-up-token") + let result = buildContinueErrorResponse(expectedError: .invalidOOBValue, expectedContinuationToken: "continuation-token") guard case .invalidUserInput(let error) = result else { return XCTFail("Unexpected response") @@ -422,7 +422,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpContinueErrorResponseIs_passwordTooWeak_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .passwordTooWeak, expectedSignUpToken: "sign-up-token") + let result = buildContinueErrorResponse(expectedError: .passwordTooWeak, expectedContinuationToken: "continuation-token") guard case .invalidUserInput(let error) = result else { return XCTFail("Unexpected response") @@ -433,7 +433,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpContinueErrorResponseIs_passwordTooShort_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .passwordTooShort, expectedSignUpToken: "sign-up-token") + let result = buildContinueErrorResponse(expectedError: .passwordTooShort, expectedContinuationToken: "continuation-token") guard case .invalidUserInput(let error) = result else { return XCTFail("Unexpected response") @@ -444,7 +444,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpContinueErrorResponseIs_passwordTooLong_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .passwordTooLong, expectedSignUpToken: "sign-up-token") + let result = buildContinueErrorResponse(expectedError: .passwordTooLong, expectedContinuationToken: "continuation-token") guard case .invalidUserInput(let error) = result else { return XCTFail("Unexpected response") @@ -455,7 +455,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpContinueErrorResponseIs_passwordRecentlyUsed_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .passwordRecentlyUsed, expectedSignUpToken: "sign-up-token") + let result = buildContinueErrorResponse(expectedError: .passwordRecentlyUsed, expectedContinuationToken: "continuation-token") guard case .invalidUserInput(let error) = result else { return XCTFail("Unexpected response") @@ -466,7 +466,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpContinueErrorResponseIs_passwordBanned_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .passwordBanned, expectedSignUpToken: "sign-up-token") + let result = buildContinueErrorResponse(expectedError: .passwordBanned, expectedContinuationToken: "continuation-token") guard case .invalidUserInput(let error) = result else { return XCTFail("Unexpected response") @@ -477,26 +477,26 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .attributeValidationFailed, expectedSignUpToken: "sign-up-token", invalidAttributes: [MSALNativeAuthErrorBasicAttributes(name: "email")]) + let result = buildContinueErrorResponse(expectedError: .attributeValidationFailed, expectedContinuationToken: "continuation-token", invalidAttributes: [MSALNativeAuthErrorBasicAttributes(name: "email")]) - guard case .attributeValidationFailed(let signUpToken, let invalidAttributes) = result else { + guard case .attributeValidationFailed(let continuationToken, let invalidAttributes) = result else { return XCTFail("Unexpected response") } - XCTAssertEqual(signUpToken, "sign-up-token") + XCTAssertEqual(continuationToken, "continuation-token") XCTAssertEqual(invalidAttributes.first, "email") } func test_whenSignUpContinueErrorResponseIs_invalidRequestWithInvalidOTPErrorCode_it_returns_expectedError() { - let signUpToken = "sign-up-token" + let continuationToken = "continuation-token" var errorCodes = [MSALNativeAuthESTSApiErrorCodes.invalidOTP.rawValue, Int.max] - var result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedSignUpToken: signUpToken, errorCodes: errorCodes) + var result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedContinuationToken: continuationToken, errorCodes: errorCodes) checkInvalidOOBValue() errorCodes = [MSALNativeAuthESTSApiErrorCodes.incorrectOTP.rawValue] - result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedSignUpToken: signUpToken, errorCodes: errorCodes) + result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedContinuationToken: continuationToken, errorCodes: errorCodes) checkInvalidOOBValue() errorCodes = [MSALNativeAuthESTSApiErrorCodes.OTPNoCacheEntryForUser.rawValue] - result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedSignUpToken: signUpToken, errorCodes: errorCodes) + result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedContinuationToken: continuationToken, errorCodes: errorCodes) checkInvalidOOBValue() func checkInvalidOOBValue() { guard case .invalidUserInput(let error) = result else { @@ -508,7 +508,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { XCTAssertNil(error.errorDescription) XCTAssertNil(error.errorURI) XCTAssertNil(error.innerErrors) - XCTAssertEqual(error.signUpToken, signUpToken) + XCTAssertEqual(error.continuationToken, continuationToken) XCTAssertNil(error.requiredAttributes) XCTAssertNil(error.unverifiedAttributes) XCTAssertNil(error.invalidAttributes) @@ -517,11 +517,11 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpContinueErrorResponseIs_invalidRequestWithGenericErrorCode_it_returns_expectedError() { - var result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedSignUpToken: "sign-up-token", errorCodes: [MSALNativeAuthESTSApiErrorCodes.strongAuthRequired.rawValue]) + var result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedContinuationToken: "continuation-token", errorCodes: [MSALNativeAuthESTSApiErrorCodes.strongAuthRequired.rawValue]) checkValidatedErrorResult() - result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedSignUpToken: "sign-up-token", errorCodes: [Int.max]) + result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedContinuationToken: "continuation-token", errorCodes: [Int.max]) checkValidatedErrorResult() - result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedSignUpToken: "sign-up-token", errorCodes: [MSALNativeAuthESTSApiErrorCodes.userNotHaveAPassword.rawValue]) + result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedContinuationToken: "continuation-token", errorCodes: [MSALNativeAuthESTSApiErrorCodes.userNotHaveAPassword.rawValue]) checkValidatedErrorResult() func checkValidatedErrorResult() { guard case .error(let error) = result else { @@ -534,8 +534,8 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } - func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_but_signUpTokenIsNil_it_returns_unexpectedError() { - let result = buildContinueErrorResponse(expectedError: .attributeValidationFailed, expectedSignUpToken: nil, invalidAttributes: [MSALNativeAuthErrorBasicAttributes(name: "email")]) + func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_but_continuationTokenIsNil_it_returns_unexpectedError() { + let result = buildContinueErrorResponse(expectedError: .attributeValidationFailed, expectedContinuationToken: nil, invalidAttributes: [MSALNativeAuthErrorBasicAttributes(name: "email")]) XCTAssertEqual(result, .unexpectedError) } @@ -553,47 +553,47 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpContinueErrorResponseIs_credentialRequired_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .credentialRequired, expectedSignUpToken: "sign-up-token") + let result = buildContinueErrorResponse(expectedError: .credentialRequired, expectedContinuationToken: "continuation-token") - guard case .credentialRequired(let signUpToken) = result else { + guard case .credentialRequired(let continuationToken) = result else { return XCTFail("Unexpected response") } - XCTAssertEqual(signUpToken, "sign-up-token") + XCTAssertEqual(continuationToken, "continuation-token") } - func test_whenSignUpContinueErrorResponseIs_credentialRequired_but_signUpToken_isNil_it_returns_unexpectedError() { - let result = buildContinueErrorResponse(expectedError: .credentialRequired, expectedSignUpToken: nil) + func test_whenSignUpContinueErrorResponseIs_credentialRequired_but_continuationToken_isNil_it_returns_unexpectedError() { + let result = buildContinueErrorResponse(expectedError: .credentialRequired, expectedContinuationToken: nil) XCTAssertEqual(result, .unexpectedError) } func test_whenSignUpContinueErrorResponseIs_attributesRequired_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedSignUpToken: "sign-up-token", requiredAttributes: [.init(name: "email", type: "", required: true), .init(name: "city", type: "", required: false)]) + let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedContinuationToken: "continuation-token", requiredAttributes: [.init(name: "email", type: "", required: true), .init(name: "city", type: "", required: false)]) - guard case .attributesRequired(let signUpToken, let requiredAttributes) = result else { + guard case .attributesRequired(let continuationToken, let requiredAttributes) = result else { return XCTFail("Unexpected response") } - XCTAssertEqual(signUpToken, "sign-up-token") + XCTAssertEqual(continuationToken, "continuation-token") XCTAssertEqual(requiredAttributes.count, 2) XCTAssertEqual(requiredAttributes[0].name, "email") XCTAssertEqual(requiredAttributes[1].name, "city") } - func test_whenSignUpContinueErrorResponseIs_attributesRequired_but_signUpToken_IsNil_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedSignUpToken: nil, requiredAttributes: [.init(name: "email", type: "", required: true), .init(name: "city", type: "", required: false)]) + func test_whenSignUpContinueErrorResponseIs_attributesRequired_but_continuationToken_IsNil_it_returns_expectedError() { + let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedContinuationToken: nil, requiredAttributes: [.init(name: "email", type: "", required: true), .init(name: "city", type: "", required: false)]) XCTAssertEqual(result, .unexpectedError) } func test_whenSignUpContinueErrorResponseIs_attributesRequired_but_requiredAttributesIsNil_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedSignUpToken: "sign-up-token", requiredAttributes: nil) + let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedContinuationToken: "continuation-token", requiredAttributes: nil) XCTAssertEqual(result, .unexpectedError) } func test_whenSignUpContinueErrorResponseIs_attributesRequired_but_requiredAttributes_IsEmpty_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedSignUpToken: "sign-up-token", requiredAttributes: []) + let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedContinuationToken: "continuation-token", requiredAttributes: []) XCTAssertEqual(result, .unexpectedError) } @@ -660,7 +660,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { private func buildContinueErrorResponse( expectedError: MSALNativeAuthSignUpContinueOauth2ErrorCode, - expectedSignUpToken: String? = nil, + expectedContinuationToken: String? = nil, requiredAttributes: [MSALNativeAuthRequiredAttributesInternal]? = nil, invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil, errorCodes: [Int]? = nil @@ -669,7 +669,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { createSignUpContinueError( error: expectedError, errorCodes: errorCodes, - signUpToken: expectedSignUpToken, + continuationToken: expectedContinuationToken, requiredAttributes: requiredAttributes, invalidAttributes: invalidAttributes ) @@ -684,7 +684,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { errorCodes: [Int]? = nil, errorURI: String? = nil, innerErrors: [MSALNativeAuthInnerError]? = nil, - signUpToken: String? = nil, + continuationToken: String? = nil, unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil, invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil ) -> MSALNativeAuthSignUpStartResponseError { @@ -694,7 +694,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { errorCodes: errorCodes, errorURI: errorURI, innerErrors: innerErrors, - signUpToken: signUpToken, + continuationToken: continuationToken, unverifiedAttributes: unverifiedAttributes, invalidAttributes: invalidAttributes ) @@ -722,7 +722,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { errorCodes: [Int]? = nil, errorURI: String? = nil, innerErrors: [MSALNativeAuthInnerError]? = nil, - signUpToken: String? = nil, + continuationToken: String? = nil, requiredAttributes: [MSALNativeAuthRequiredAttributesInternal]? = nil, unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil, invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil @@ -733,7 +733,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { errorCodes: errorCodes, errorURI: errorURI, innerErrors: innerErrors, - signUpToken: signUpToken, + continuationToken: continuationToken, requiredAttributes: requiredAttributes, unverifiedAttributes: unverifiedAttributes, invalidAttributes: invalidAttributes diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift index 090928c208..cc335bf46e 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift @@ -88,7 +88,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { let errorCodes: [Int] = [unknownErrorCode1, unknownErrorCode2] - let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, errorDescription: nil, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, credentialToken: nil) + let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, errorDescription: nil, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil) let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) @@ -103,7 +103,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { } func test_invalidClient_isProperlyHandled() { - let error = MSALNativeAuthTokenResponseError(error: .invalidClient, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, credentialToken: nil) + let error = MSALNativeAuthTokenResponseError(error: .invalidClient, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil) let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) @@ -118,7 +118,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { } func test_unauthorizedClient_isProperlyHandled() { - let error = MSALNativeAuthTokenResponseError(error: .unauthorizedClient, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, credentialToken: nil) + let error = MSALNativeAuthTokenResponseError(error: .unauthorizedClient, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil) let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) @@ -171,7 +171,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { return XCTFail("Unexpected Error") } func checkErrorCodes() -> MSALNativeAuthTokenValidatedErrorType? { - let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, credentialToken: nil) + let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil) let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) @@ -191,7 +191,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { let errorCodes: [Int] = [unknownErrorCode1, knownErrorCode, unknownErrorCode2] - let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, errorDescription: nil, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, credentialToken: nil) + let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, errorDescription: nil, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil) let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) @@ -214,7 +214,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { checkErrorCodes() func checkErrorCodes() { let description = "description" - let error = MSALNativeAuthTokenResponseError(error: .invalidRequest, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, credentialToken: nil) + let error = MSALNativeAuthTokenResponseError(error: .invalidRequest, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil) let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) @@ -239,7 +239,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { errorCodes = [MSALNativeAuthESTSApiErrorCodes.userNotFound.rawValue] checkErrorCodes() func checkErrorCodes() { - let error = MSALNativeAuthTokenResponseError(error: .invalidRequest, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, credentialToken: nil) + let error = MSALNativeAuthTokenResponseError(error: .invalidRequest, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil) let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift index faaf07c216..6c6f53539c 100644 --- a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift +++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift @@ -93,7 +93,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignUpPasswordStartDelegateSpy(expectation: exp1) let expectedResult: SignUpStartResult = .codeRequired( - newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId), + newState: .init(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -116,7 +116,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignUpPasswordStartDelegateOptionalMethodsNotImplemented(expectation: exp) let expectedResult: SignUpStartResult = .codeRequired( - newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId), + newState: .init(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -192,7 +192,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignUpCodeStartDelegateSpy(expectation: exp) let expectedResult: SignUpStartResult = .codeRequired( - newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId), + newState: .init(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -215,7 +215,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignUpStartDelegateOptionalMethodsNotImplemented(expectation: exp) let expectedResult: SignUpStartResult = .codeRequired( - newState: .init(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId), + newState: .init(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -332,7 +332,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { delegate.expectedChannelTargetType = .email let expectedResult: SignInStartResult = .codeRequired( - newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "", correlationId: correlationId), + newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, continuationToken: "", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -355,7 +355,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: exp, expectedError: expectedError) let expectedResult: SignInStartResult = .codeRequired( - newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "", correlationId: correlationId), + newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, continuationToken: "", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -388,7 +388,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { delegate.expectedChannelTargetType = .email let expectedResult: SignInStartResult = .codeRequired( - newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "", correlationId: correlationId), + newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, continuationToken: "", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -410,7 +410,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignInCodeStartDelegateOptionalMethodNotImplemented(expectation: exp, expectedError: expectedError) let expectedResult: SignInStartResult = .codeRequired( - newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "", correlationId: correlationId), + newState: SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, continuationToken: "", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -431,7 +431,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignInCodeStartDelegateWithPasswordRequiredSpy(expectation: exp1) - let expectedState = SignInPasswordRequiredState(scopes: [], username: "", controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignInPasswordRequiredState(scopes: [], username: "", controller: controllerFactoryMock.signInController, continuationToken: "continuationToken", correlationId: correlationId) let expectedResult: SignInStartResult = .passwordRequired(newState: expectedState) controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in @@ -442,7 +442,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { wait(for: [exp1, exp2], timeout: 1) - XCTAssertEqual(delegate.passwordRequiredState?.flowToken, expectedState.flowToken) + XCTAssertEqual(delegate.passwordRequiredState?.continuationToken, expectedState.continuationToken) } func testSignIn_delegate_whenPasswordIsRequiredButUserHasNotImplementedOptionalDelegate_shouldReturnError() { @@ -453,7 +453,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = SignInCodeStartDelegateSpy(expectation: exp, expectedError: expectedError) let expectedResult: SignInStartResult = .passwordRequired( - newState: SignInPasswordRequiredState(scopes: [], username: "", controller: controllerFactoryMock.signInController, flowToken: "", correlationId: correlationId) + newState: SignInPasswordRequiredState(scopes: [], username: "", controller: controllerFactoryMock.signInController, continuationToken: "", correlationId: correlationId) ) controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in @@ -481,7 +481,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = ResetPasswordStartDelegateSpy(expectation: exp1) let expectedResult: ResetPasswordStartResult = .codeRequired( - newState: .init(controller: controllerFactoryMock.resetPasswordController, username: "username", flowToken: "flowToken", correlationId: correlationId), + newState: .init(controller: controllerFactoryMock.resetPasswordController, username: "username", continuationToken: "continuationToken", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -494,7 +494,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { wait(for: [exp1, exp2], timeout: 1) - XCTAssertEqual(delegate.newState?.flowToken, "flowToken") + XCTAssertEqual(delegate.newState?.continuationToken, "continuationToken") XCTAssertEqual(delegate.newState?.username, "username") XCTAssertEqual(delegate.sentTo, "sentTo") XCTAssertEqual(delegate.channelTargetType, .email) @@ -507,7 +507,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { let delegate = ResetPasswordStartDelegateOptionalMethodsNotImplemented(expectation: exp) let expectedResult: ResetPasswordStartResult = .codeRequired( - newState: .init(controller: controllerFactoryMock.resetPasswordController, username: "username", flowToken: "flowToken", correlationId: correlationId), + newState: .init(controller: controllerFactoryMock.resetPasswordController, username: "username", continuationToken: "continuationToken", correlationId: correlationId), sentTo: "sentTo", channelTargetType: .email, codeLength: 1 @@ -546,12 +546,12 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { signUpRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signUpRequestProviderMock.expectedChallengeRequestParameters = expectedSignUpChallengeParams() signUpRequestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - signUpRequestProviderMock.expectedContinueRequestParameters = expectedSignUpContinueParams(token: "signUpToken 2") + signUpRequestProviderMock.expectedContinueRequestParameters = expectedSignUpContinueParams(token: "continuationToken 2") let signUpResponseValidatorMock = MSALNativeAuthSignUpResponseValidatorMock() - signUpResponseValidatorMock.mockValidateSignUpStartFunc((.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""]))) - signUpResponseValidatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "signUpToken 2")) - signUpResponseValidatorMock.mockValidateSignUpContinueFunc(.success("signInSLT")) + signUpResponseValidatorMock.mockValidateSignUpStartFunc((.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""]))) + signUpResponseValidatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "continuationToken 2")) + signUpResponseValidatorMock.mockValidateSignUpContinueFunc(.success("continuationToken")) let signInRequestProviderMock = MSALNativeAuthSignInRequestProviderMock() @@ -565,7 +565,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { tokenResponse.refreshToken = "refreshToken" let tokenRequestProviderMock = MSALNativeAuthTokenRequestProviderMock() - tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: expectedUsername, credentialToken: nil, signInSLT: "signInSLT", grantType: MSALNativeAuthGrantType.slt, scope: expectedScopes, password: nil, oobCode: nil, includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: expectedUsername, continuationToken: "continuationToken", grantType: MSALNativeAuthGrantType.continuationToken, scope: expectedScopes, password: nil, oobCode: nil, includeChallengeType: true, refreshToken: nil) tokenRequestProviderMock.expectedContext = contextMock tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) @@ -647,12 +647,12 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { signUpRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) signUpRequestProviderMock.expectedChallengeRequestParameters = expectedSignUpChallengeParams() signUpRequestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - signUpRequestProviderMock.expectedContinueRequestParameters = expectedSignUpContinueParams(token: "signUpToken 2") + signUpRequestProviderMock.expectedContinueRequestParameters = expectedSignUpContinueParams(token: "continuationToken 2") let signUpResponseValidatorMock = MSALNativeAuthSignUpResponseValidatorMock() - signUpResponseValidatorMock.mockValidateSignUpStartFunc((.verificationRequired(signUpToken: "signUpToken", unverifiedAttributes: [""]))) - signUpResponseValidatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "signUpToken 2")) - signUpResponseValidatorMock.mockValidateSignUpContinueFunc(.success("signInSLT")) + signUpResponseValidatorMock.mockValidateSignUpStartFunc((.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""]))) + signUpResponseValidatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "continuationToken 2")) + signUpResponseValidatorMock.mockValidateSignUpContinueFunc(.success("continuationToken")) let signInRequestProviderMock = MSALNativeAuthSignInRequestProviderMock() @@ -666,7 +666,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { tokenResponse.refreshToken = "refreshToken" let tokenRequestProviderMock = MSALNativeAuthTokenRequestProviderMock() - tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: expectedUsername, credentialToken: nil, signInSLT: "signInSLT", grantType: MSALNativeAuthGrantType.slt, scope: expectedScopes, password: nil, oobCode: nil, includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: expectedUsername, continuationToken: "continuationToken", grantType: MSALNativeAuthGrantType.continuationToken, scope: expectedScopes, password: nil, oobCode: nil, includeChallengeType: true, refreshToken: nil) tokenRequestProviderMock.expectedContext = contextMock tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) @@ -745,13 +745,13 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { signInRequestProviderMock.expectedUsername = "username" signInRequestProviderMock.expectedContext = contextMock - let credentialToken = "" + let continuationToken = "" let expectedSentTo = "sentTo" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 let signInResponseValidatorMock = MSALNativeAuthSignInResponseValidatorMock() - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) - signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: expectedSentTo, channelType: expectedChannelTargetType, codeLength: expectedCodeLength) + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: continuationToken) + signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(continuationToken: continuationToken, sentTo: expectedSentTo, channelType: expectedChannelTargetType, codeLength: expectedCodeLength) let expectedScopes = "scope1 scope2 openid profile offline_access" @@ -762,7 +762,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { tokenResponse.refreshToken = "refreshToken" let tokenRequestProviderMock = MSALNativeAuthTokenRequestProviderMock() - tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: nil, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.oobCode, scope: expectedScopes, password: nil, oobCode: "1234", includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: nil, continuationToken: continuationToken, grantType: MSALNativeAuthGrantType.oobCode, scope: expectedScopes, password: nil, oobCode: "1234", includeChallengeType: true, refreshToken: nil) tokenRequestProviderMock.expectedContext = contextMock tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) @@ -830,7 +830,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { signInRequestProviderMock.expectedUsername = "username" signInRequestProviderMock.expectedContext = contextMock - let credentialToken = "" + let continuationToken = "" let expectedSentTo = "sentTo" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 @@ -839,8 +839,8 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { delegateCodeStart.expectedCodeLength = expectedCodeLength let signInResponseValidatorMock = MSALNativeAuthSignInResponseValidatorMock() - signInResponseValidatorMock.initiateValidatedResponse = .success(credentialToken: credentialToken) - signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(credentialToken: credentialToken, sentTo: expectedSentTo, channelType: expectedChannelTargetType, codeLength: expectedCodeLength) + signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: continuationToken) + signInResponseValidatorMock.challengeValidatedResponse = .codeRequired(continuationToken: continuationToken, sentTo: expectedSentTo, channelType: expectedChannelTargetType, codeLength: expectedCodeLength) let expectedScopes = "scope1 scope2 openid profile offline_access" @@ -851,7 +851,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { tokenResponse.refreshToken = "refreshToken" let tokenRequestProviderMock = MSALNativeAuthTokenRequestProviderMock() - tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: nil, credentialToken: credentialToken, signInSLT: nil, grantType: MSALNativeAuthGrantType.oobCode, scope: expectedScopes, password: nil, oobCode: "1234", includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: nil, continuationToken: continuationToken, grantType: MSALNativeAuthGrantType.oobCode, scope: expectedScopes, password: nil, oobCode: "1234", includeChallengeType: true, refreshToken: nil) tokenRequestProviderMock.expectedContext = contextMock tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) @@ -920,20 +920,20 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { resetPasswordRequestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) resetPasswordRequestProviderMock.expectedStartRequestParameters = expectedResetPasswordStartParams resetPasswordRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - resetPasswordRequestProviderMock.expectedChallengeRequestParameters = expectedResetPasswordChallengeParams(token: "passwordResetToken") + resetPasswordRequestProviderMock.expectedChallengeRequestParameters = expectedResetPasswordChallengeParams(token: "continuationToken") resetPasswordRequestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - resetPasswordRequestProviderMock.expectedContinueRequestParameters = expectedResetPasswordContinueParams(token: "passwordResetToken 2") + resetPasswordRequestProviderMock.expectedContinueRequestParameters = expectedResetPasswordContinueParams(token: "continuationToken 2") resetPasswordRequestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - resetPasswordRequestProviderMock.expectedSubmitRequestParameters = expectedResetPasswordSubmitParams(token: "passwordSubmitToken") + resetPasswordRequestProviderMock.expectedSubmitRequestParameters = expectedResetPasswordSubmitParams(token: "continuationToken") resetPasswordRequestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) - resetPasswordRequestProviderMock.expectedPollCompletionParameters = expectedResetPasswordPollCompletionParameters(token: "passwordResetToken 3") + resetPasswordRequestProviderMock.expectedPollCompletionParameters = expectedResetPasswordPollCompletionParameters(token: "continuationToken 3") let resetPasswordResponseValidator = MSALNativeAuthResetPasswordResponseValidatorMock() - resetPasswordResponseValidator.mockValidateResetPasswordStartFunc(.success(passwordResetToken: "passwordResetToken")) - resetPasswordResponseValidator.mockValidateResetPasswordChallengeFunc(.success("sentTo", .email, 4, "passwordResetToken 2")) - resetPasswordResponseValidator.mockValidateResetPasswordContinueFunc(.success(passwordSubmitToken: "passwordSubmitToken")) - resetPasswordResponseValidator.mockValidateResetPasswordSubmitFunc(.success(passwordResetToken: "passwordResetToken 3", pollInterval: 0)) - resetPasswordResponseValidator.mockValidateResetPasswordPollCompletionFunc(.success(status: .succeeded, continuationToken: "slt")) + resetPasswordResponseValidator.mockValidateResetPasswordStartFunc(.success(continuationToken: "continuationToken")) + resetPasswordResponseValidator.mockValidateResetPasswordChallengeFunc(.success("sentTo", .email, 4, "continuationToken 2")) + resetPasswordResponseValidator.mockValidateResetPasswordContinueFunc(.success(continuationToken: "continuationToken")) + resetPasswordResponseValidator.mockValidateResetPasswordSubmitFunc(.success(continuationToken: "continuationToken 3", pollInterval: 0)) + resetPasswordResponseValidator.mockValidateResetPasswordPollCompletionFunc(.success(status: .succeeded, continuationToken: "continuationToken")) let expectedUsername = "username" let expectedScopes = "scope1 scope2 openid profile offline_access" @@ -944,7 +944,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { cacheAccessorMock.expectedMSIDTokenResult = tokenResult let tokenRequestProviderMock = MSALNativeAuthTokenRequestProviderMock() - tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: expectedUsername, credentialToken: nil, signInSLT: "slt", grantType: .slt, scope: expectedScopes, password: nil, oobCode: nil, includeChallengeType: true, refreshToken: nil) + tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: contextMock, username: expectedUsername, continuationToken: "continuationToken", grantType: .continuationToken, scope: expectedScopes, password: nil, oobCode: nil, includeChallengeType: true, refreshToken: nil) tokenRequestProviderMock.expectedContext = contextMock tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) @@ -1038,20 +1038,20 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { ) } - private func expectedSignUpChallengeParams(token: String = "signUpToken") -> (token: String, context: MSIDRequestContext) { + private func expectedSignUpChallengeParams(token: String = "continuationToken") -> (token: String, context: MSIDRequestContext) { return (token: token, context: contextMock) } private func expectedSignUpContinueParams( grantType: MSALNativeAuthGrantType = .oobCode, - token: String = "signUpToken", + token: String = "continuationToken", password: String? = nil, oobCode: String? = "1234", attributes: [String: Any]? = nil ) -> MSALNativeAuthSignUpContinueRequestProviderParams { .init( grantType: grantType, - signUpToken: token, + continuationToken: token, password: password, oobCode: oobCode, attributes: attributes, @@ -1066,38 +1066,38 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { ) } - private func expectedResetPasswordChallengeParams(token: String = "passwordResetToken") -> (token: String, context: MSIDRequestContext) { + private func expectedResetPasswordChallengeParams(token: String = "continuationToken") -> (token: String, context: MSIDRequestContext) { return (token: token, context: contextMock) } private func expectedResetPasswordContinueParams( grantType: MSALNativeAuthGrantType = .oobCode, - token: String = "passwordResetToken", + token: String = "continuationToken", oobCode: String? = "1234" ) -> MSALNativeAuthResetPasswordContinueRequestParameters { .init( context: contextMock, - passwordResetToken: token, + continuationToken: token, grantType: grantType, oobCode: oobCode ) } private func expectedResetPasswordSubmitParams( - token: String = "passwordSubmitToken", + token: String = "continuationToken", password: String = "password" ) -> MSALNativeAuthResetPasswordSubmitRequestParameters { .init( context: contextMock, - passwordSubmitToken: token, + continuationToken: token, newPassword: password) } private func expectedResetPasswordPollCompletionParameters( - token: String = "passwordResetToken" + token: String = "continuationToken" ) -> MSALNativeAuthResetPasswordPollCompletionRequestParameters { .init( context: contextMock, - passwordResetToken: token) + continuationToken: token) } } diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift index 3d93a1bd5d..b7b8e0d0d9 100644 --- a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift @@ -52,7 +52,7 @@ final class ResetPasswordRequiredDelegateDispatcherTests: XCTestCase { let expectedState = SignInAfterResetPasswordState( controller: signInControllerMock, username: "username", - slt: "slt", + continuationToken: "continuationToken", correlationId: correlationId ) @@ -80,7 +80,7 @@ final class ResetPasswordRequiredDelegateDispatcherTests: XCTestCase { let expectedState = SignInAfterResetPasswordState( controller: signInControllerMock, username: "username", - slt: "slt", + continuationToken: "continuationToken", correlationId: correlationId ) diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift index 664eee0e4a..be7c261f60 100644 --- a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift @@ -49,7 +49,7 @@ final class ResetPasswordResendCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 @@ -82,7 +82,7 @@ final class ResetPasswordResendCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift index 242d797d82..f595aa02e9 100644 --- a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift @@ -49,7 +49,7 @@ final class ResetPasswordStartDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "username", flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "username", continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 @@ -82,7 +82,7 @@ final class ResetPasswordStartDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "username", flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "username", continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift index 78807a3b5d..aa7ee163da 100644 --- a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift @@ -49,7 +49,7 @@ final class ResetPasswordVerifyCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = ResetPasswordRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "username", flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "username", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchPasswordRequired(newState: expectedState) @@ -71,7 +71,7 @@ final class ResetPasswordVerifyCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = ResetPasswordRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "username", flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "username", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchPasswordRequired(newState: expectedState) diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift index e4709a253e..8c1fecae3b 100644 --- a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift @@ -49,7 +49,7 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 @@ -83,7 +83,7 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInResendCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInResendCodeDelegateDispatcherTests.swift index 97662b0692..61f5fead5e 100644 --- a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInResendCodeDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInResendCodeDelegateDispatcherTests.swift @@ -40,7 +40,7 @@ final class SignInResendCodeDelegateDispatcherTests: XCTestCase { } func test_dispatchSignInResendCodeCodeRequired_whenDelegateMethodsAreImplemented() async { - let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 @@ -79,7 +79,7 @@ final class SignInResendCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInStartDelegateDispatcherTests.swift index b1ab94b081..c7047a70b8 100644 --- a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInStartDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInStartDelegateDispatcherTests.swift @@ -39,7 +39,7 @@ final class SignInStartDelegateDispatcherTests: XCTestCase { } func test_dispatchSignInCodeRequired_whenDelegateMethodsAreImplemented() async { - let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 @@ -82,7 +82,7 @@ final class SignInStartDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignInCodeRequiredState(scopes: [], controller: controllerFactoryMock.signInController, continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 @@ -113,7 +113,7 @@ final class SignInStartDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignInPasswordRequiredState(scopes: [], username: "username", controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignInPasswordRequiredState(scopes: [], username: "username", controller: controllerFactoryMock.signInController, continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignInPasswordRequired(newState: expectedState) @@ -136,7 +136,7 @@ final class SignInStartDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignInPasswordRequiredState(scopes: [], username: "username", controller: controllerFactoryMock.signInController, flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignInPasswordRequiredState(scopes: [], username: "username", controller: controllerFactoryMock.signInController, continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignInPasswordRequired(newState: expectedState) diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift index 308695294e..c82b2eea67 100644 --- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift @@ -54,7 +54,7 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase { .init(name: "attribute2", type: "", required: true), ] - let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState) @@ -82,7 +82,7 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase { .init(name: "attribute2", type: "", required: true), ] - let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState) @@ -106,7 +106,7 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase { let expectedAttributeNames = ["attribute1", "attribute2"] - let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames, newState: expectedState) @@ -131,7 +131,7 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase { let expectedAttributeNames = ["attribute1", "attribute2"] - let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames, newState: expectedState) @@ -153,7 +153,7 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", slt: "flowToken", correlationId: correlationId) + let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpCompleted(newState: expectedState) @@ -175,7 +175,7 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", slt: "flowToken", correlationId: correlationId) + let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpCompleted(newState: expectedState) diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift index 60c432f233..33b7315b23 100644 --- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift @@ -54,7 +54,7 @@ final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase { .init(name: "attribute2", type: "", required: true), ] - let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState) @@ -82,7 +82,7 @@ final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase { .init(name: "attribute2", type: "", required: true), ] - let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState) @@ -105,7 +105,7 @@ final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", slt: "flowToken", correlationId: correlationId) + let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpCompleted(newState: expectedState) @@ -127,7 +127,7 @@ final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", slt: "flowToken", correlationId: correlationId) + let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpCompleted(newState: expectedState) diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift index e8b8ec1b71..810ee5a175 100644 --- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift @@ -49,7 +49,7 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 @@ -82,7 +82,7 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpResendCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpResendCodeDelegateDispatcherTests.swift index f06109b86f..edfe6906ca 100644 --- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpResendCodeDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpResendCodeDelegateDispatcherTests.swift @@ -49,7 +49,7 @@ final class SignUpResendCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 @@ -82,7 +82,7 @@ final class SignUpResendCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpStartDelegateDispatcherTests.swift index afe28bab45..c5d1ba7bc9 100644 --- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpStartDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpStartDelegateDispatcherTests.swift @@ -49,7 +49,7 @@ final class SignUpStartDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 @@ -82,7 +82,7 @@ final class SignUpStartDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpCodeRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedSentTo = "user@contoso.com" let expectedChannelTargetType = MSALNativeAuthChannelType.email let expectedCodeLength = 4 diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift index 9c07d3173f..12c5d24144 100644 --- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift @@ -54,7 +54,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase { .init(name: "attribute2", type: "", required: true), ] - let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState) @@ -82,7 +82,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase { .init(name: "attribute2", type: "", required: true), ] - let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState) @@ -105,7 +105,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignUpPasswordRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpPasswordRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpPasswordRequired(newState: expectedState) @@ -127,7 +127,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignUpPasswordRequiredState(controller: controllerFactoryMock.signUpController, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = SignUpPasswordRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpPasswordRequired(newState: expectedState) @@ -150,7 +150,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", slt: "flowToken", correlationId: correlationId) + let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpCompleted(newState: expectedState) @@ -172,7 +172,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", slt: "flowToken", correlationId: correlationId) + let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", continuationToken: "continuationToken", correlationId: correlationId) await sut.dispatchSignUpCompleted(newState: expectedState) diff --git a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift index a8b849af51..73f82de377 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift @@ -36,7 +36,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { try super.setUpWithError() controller = .init() - sut = ResetPasswordCodeRequiredState(controller: controller, username: "username", flowToken: "", correlationId: correlationId) + sut = ResetPasswordCodeRequiredState(controller: controller, username: "username", continuationToken: "", correlationId: correlationId) } // MARK: - Delegates @@ -45,7 +45,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { func test_resendCode_delegate_whenError_shouldReturnCorrectError() { let expectedError = ResendCodeError(message: "test error") - let expectedState = ResetPasswordCodeRequiredState(controller: controller, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controller, username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedResult: ResetPasswordResendCodeResult = .error(error: expectedError, newState: expectedState) controller.resendCodeResponse = .init(expectedResult) @@ -63,7 +63,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { func test_resendCode_delegate_success_shouldReturnCodeRequired() { let exp = expectation(description: "reset password states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = ResetPasswordCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId) let expectedResult: ResetPasswordResendCodeResult = .codeRequired( newState: expectedState, @@ -80,7 +80,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { sut.resendCode(delegate: delegate) wait(for: [exp, exp2]) - XCTAssertEqual(delegate.newState?.flowToken, expectedState.flowToken) + XCTAssertEqual(delegate.newState?.continuationToken, expectedState.continuationToken) XCTAssertEqual(delegate.sentTo, "sentTo") XCTAssertEqual(delegate.channelTargetType, .email) XCTAssertEqual(delegate.codeLength, 1) @@ -89,7 +89,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { func test_resendCode_delegate_success_whenOptionalMethodNotImplemented_shouldReturnCorrectError() { let exp = expectation(description: "reset password states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = ResetPasswordCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId) let expectedResult: ResetPasswordResendCodeResult = .codeRequired( newState: expectedState, @@ -113,7 +113,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { func test_submitCode_delegate_whenError_shouldReturnCorrectError() { let expectedError = VerifyCodeError(type: .invalidCode) - let expectedState = ResetPasswordCodeRequiredState(controller: controller, username: "", flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordCodeRequiredState(controller: controller, username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedResult: ResetPasswordSubmitCodeResult = .error(error: expectedError, newState: expectedState) controller.submitCodeResponse = .init(expectedResult) @@ -131,7 +131,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { func test_submitCode_delegate_success_shouldReturnPasswordRequired() { let exp = expectation(description: "reset password states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = ResetPasswordRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = ResetPasswordRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId) let expectedResult: ResetPasswordSubmitCodeResult = .passwordRequired(newState: expectedState) controller.submitCodeResponse = .init(expectedResult, telemetryUpdate: { _ in @@ -149,7 +149,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase { func test_submitCode_delegate_success_whenOptionalMethodsNotImplemented_shouldReturnCorrectError() { let exp = expectation(description: "reset password states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = ResetPasswordRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = ResetPasswordRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId) let expectedResult: ResetPasswordSubmitCodeResult = .passwordRequired(newState: expectedState) controller.submitCodeResponse = .init(expectedResult, telemetryUpdate: { _ in diff --git a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift index 717200d92a..9685650ede 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift @@ -42,7 +42,7 @@ final class ResetPasswordRequiredStateTests: XCTestCase { XCTAssertNil(controllerSpy.context) XCTAssertFalse(controllerSpy.submitPasswordCalled) - let sut = ResetPasswordRequiredState(controller: controllerSpy, username: "username", flowToken: "", correlationId: correlationId) + let sut = ResetPasswordRequiredState(controller: controllerSpy, username: "username", continuationToken: "", correlationId: correlationId) sut.submitPassword(password: "1234", delegate: ResetPasswordRequiredDelegateSpy()) wait(for: [exp], timeout: 1) @@ -53,10 +53,10 @@ final class ResetPasswordRequiredStateTests: XCTestCase { func test_submitPassword_delegate_whenError_shouldReturnCorrectError() { controllerMock = MSALNativeAuthResetPasswordControllerMock() - let sut = ResetPasswordRequiredState(controller: controllerMock, username: "username", flowToken: "", correlationId: correlationId) + let sut = ResetPasswordRequiredState(controller: controllerMock, username: "username", continuationToken: "", correlationId: correlationId) let expectedError = PasswordRequiredError(type: .invalidPassword, message: nil) - let expectedState = ResetPasswordRequiredState(controller: controllerMock, username: "username", flowToken: "flowToken", correlationId: correlationId) + let expectedState = ResetPasswordRequiredState(controller: controllerMock, username: "username", continuationToken: "continuationToken", correlationId: correlationId) let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.error(error: expectedError, newState: expectedState)) controllerMock.submitPasswordResponse = expectedResult @@ -75,8 +75,8 @@ final class ResetPasswordRequiredStateTests: XCTestCase { let exp = expectation(description: "reset password states") let exp2 = expectation(description: "telemetry expectation") controllerMock = MSALNativeAuthResetPasswordControllerMock() - let sut = ResetPasswordRequiredState(controller: controllerMock, username: "", flowToken: "", correlationId: correlationId) - let expectedState = SignInAfterResetPasswordState(controller: controllerFactoryMock.signInController, username: "", slt: nil, correlationId: correlationId) + let sut = ResetPasswordRequiredState(controller: controllerMock, username: "", continuationToken: "", correlationId: correlationId) + let expectedState = SignInAfterResetPasswordState(controller: controllerFactoryMock.signInController, username: "", continuationToken: nil, correlationId: correlationId) let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.completed(expectedState), telemetryUpdate: { _ in exp2.fulfill() @@ -96,8 +96,8 @@ final class ResetPasswordRequiredStateTests: XCTestCase { let exp = expectation(description: "reset password states") let exp2 = expectation(description: "telemetry expectation") controllerMock = MSALNativeAuthResetPasswordControllerMock() - let sut = ResetPasswordRequiredState(controller: controllerMock, username: "", flowToken: "", correlationId: correlationId) - let state = SignInAfterResetPasswordState(controller: controllerFactoryMock.signInController, username: "", slt: nil, correlationId: correlationId) + let sut = ResetPasswordRequiredState(controller: controllerMock, username: "", continuationToken: "", correlationId: correlationId) + let state = SignInAfterResetPasswordState(controller: controllerFactoryMock.signInController, username: "", continuationToken: nil, correlationId: correlationId) let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.completed(state), telemetryUpdate: { _ in exp2.fulfill() diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift index a184bb5950..6a422fbd3b 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift @@ -35,7 +35,7 @@ final class SignInCodeRequiredStateTests: XCTestCase { super.setUp() controller = .init() - sut = .init(scopes: [], controller: controller, flowToken: "flowToken", correlationId: correlationId) + sut = .init(scopes: [], controller: controller, continuationToken: "continuationToken", correlationId: correlationId) } // MARK: - Delegates @@ -46,7 +46,7 @@ final class SignInCodeRequiredStateTests: XCTestCase { let exp = expectation(description: "sign-in states") let expectedError = ResendCodeError(message: "test error") - let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, continuationToken: "continuationToken 2", correlationId: correlationId) let expectedResult: SignInResendCodeResult = .error( error: expectedError, @@ -60,13 +60,13 @@ final class SignInCodeRequiredStateTests: XCTestCase { wait(for: [exp]) XCTAssertEqual(delegate.newSignInResendCodeError, expectedError) - XCTAssertEqual(delegate.newSignInCodeRequiredState?.flowToken, expectedState.flowToken) + XCTAssertEqual(delegate.newSignInCodeRequiredState?.continuationToken, expectedState.continuationToken) } func test_resendCode_delegate_success_shouldReturnSignInResendCodeCodeRequired() { let exp = expectation(description: "sign-in states") let exp2 = expectation(description: "expectation Telemetry") - let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, continuationToken: "continuationToken 2", correlationId: correlationId) let expectedResult: SignInResendCodeResult = .codeRequired( newState: expectedState, @@ -82,13 +82,13 @@ final class SignInCodeRequiredStateTests: XCTestCase { sut.resendCode(delegate: delegate) wait(for: [exp, exp2]) - XCTAssertEqual(delegate.newSignInCodeRequiredState?.flowToken, expectedState.flowToken) + XCTAssertEqual(delegate.newSignInCodeRequiredState?.continuationToken, expectedState.continuationToken) } func test_resendCode_delegate_success_butMethodNotImplemented_shouldReturnCorrectError() { let exp = expectation(description: "sign-in states") let exp2 = expectation(description: "expectation Telemetry") - let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2", correlationId: UUID()) + let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, continuationToken: "continuationToken 2", correlationId: UUID()) let expectedResult: SignInResendCodeResult = .codeRequired( newState: expectedState, @@ -112,7 +112,7 @@ final class SignInCodeRequiredStateTests: XCTestCase { func test_submitCode_delegate_withError_shouldReturnSignInVerifyCodeError() { let exp = expectation(description: "sign-in states") let expectedError = VerifyCodeError(type: .invalidCode) - let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, continuationToken: "continuationToken 2", correlationId: correlationId) let expectedResult: SignInVerifyCodeResult = .error( error: expectedError, diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift index 8723bb832f..478103f312 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift @@ -35,14 +35,14 @@ final class SignInPasswordRequiredStateTests: XCTestCase { super.setUp() controller = .init() - sut = .init(scopes: [], username: "username", controller: controller, flowToken: "flowToken", correlationId: correlationId) + sut = .init(scopes: [], username: "username", controller: controller, continuationToken: "continuationToken", correlationId: correlationId) } // MARK: - Delegates func test_submitPassword_delegate_withError_shouldReturnError() { let expectedError = PasswordRequiredError(type: .invalidPassword) - let expectedState = SignInPasswordRequiredState(scopes: [], username: "", controller: controller, flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = SignInPasswordRequiredState(scopes: [], username: "", controller: controller, continuationToken: "continuationToken 2", correlationId: correlationId) let expectedResult: SignInPasswordRequiredResult = .error( error: expectedError, @@ -56,7 +56,7 @@ final class SignInPasswordRequiredStateTests: XCTestCase { sut.submitPassword(password: "invalid password", delegate: delegate) wait(for: [exp]) - XCTAssertEqual(delegate.newPasswordRequiredState?.flowToken, expectedState.flowToken) + XCTAssertEqual(delegate.newPasswordRequiredState?.continuationToken, expectedState.continuationToken) } func test_submitPassword_delegate_success_shouldReturnSuccess() { diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift index b8e887eeb8..dc63bb1f1c 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift @@ -37,7 +37,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase { try super.setUpWithError() controller = .init() - sut = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "", correlationId: correlationId) + sut = SignUpAttributesRequiredState(controller: controller, username: "", continuationToken: "", correlationId: correlationId) } // MARK: - Delegate @@ -60,7 +60,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase { func test_submitPassword_delegate_whenSuccess_shouldReturnCompleted() { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: correlationId) + let expectedState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedResult: SignUpAttributesRequiredResult = .completed(expectedState) controller.submitAttributesResult = .init(expectedResult, telemetryUpdate: { _ in @@ -78,7 +78,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase { func test_submitPassword_delegate_whenSuccess_butMethodNotImplemented_shouldReturnCorrectError() { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: UUID()) + let expectedState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", continuationToken: "continuationToken", correlationId: UUID()) let expectedResult: SignUpAttributesRequiredResult = .completed(expectedState) controller.submitAttributesResult = .init(expectedResult, telemetryUpdate: { _ in @@ -96,7 +96,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase { func test_submitPassword_delegate_whenAttributesRequired_shouldReturnAttributesRequired() { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", flowToken: "slt", correlationId: correlationId) + let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ .init(name: "anAttribute", type: "aType", required: true) ] @@ -118,7 +118,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase { func test_submitPassword_delegate_whenAttributesRequired_butMethodNotImplemented_shouldReturnCorrectError() { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", flowToken: "slt", correlationId: correlationId) + let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ .init(name: "anAttribute", type: "aType", required: true) ] @@ -139,7 +139,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase { func test_submitPassword_delegate_whenAttributesAreInvalid_shouldReturnAttributesInvalid() { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", flowToken: "slt", correlationId: correlationId) + let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedAttributes = ["anAttribute"] let expectedResult: SignUpAttributesRequiredResult = .attributesInvalid(attributes: expectedAttributes, newState: expectedState) @@ -159,7 +159,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase { func test_submitPassword_delegate_whenAttributesAreInvalid_butMethodNotImplemented_shouldReturnCorrectError() { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", flowToken: "slt", correlationId: correlationId) + let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedAttributes = ["anAttribute"] let expectedResult: SignUpAttributesRequiredResult = .attributesInvalid(attributes: expectedAttributes, newState: expectedState) diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift index c50df1be0d..ddc9fe8237 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift @@ -36,7 +36,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { try super.setUpWithError() controller = .init() - sut = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "", correlationId: correlationId) + sut = SignUpCodeRequiredState(controller: controller, username: "", continuationToken: "", correlationId: correlationId) } // MARK: - Delegates @@ -61,7 +61,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { func test_resendCode_delegate_success_shouldReturnCodeRequired() { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = SignUpCodeRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId) let expectedResult: SignUpResendCodeResult = .codeRequired( newState: expectedState, @@ -78,7 +78,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { sut.resendCode(delegate: delegate) wait(for: [exp, exp2]) - XCTAssertEqual(delegate.newState?.flowToken, expectedState.flowToken) + XCTAssertEqual(delegate.newState?.continuationToken, expectedState.continuationToken) XCTAssertEqual(delegate.sentTo, "sentTo") XCTAssertEqual(delegate.channelTargetType, .email) XCTAssertEqual(delegate.codeLength, 1) @@ -87,7 +87,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { func test_resendCode_delegate_success_butMethodNotImplemented() { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "telemetry expectation") - let expectedState = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = SignUpCodeRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId) let expectedResult: SignUpResendCodeResult = .codeRequired( newState: expectedState, @@ -111,7 +111,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { func test_submitCode_delegate_whenError_shouldReturnCorrectError() { let expectedError = VerifyCodeError(type: .invalidCode) - let expectedState = SignUpCodeRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = SignUpCodeRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId) let expectedResult: SignUpVerifyCodeResult = .error( error: expectedError, @@ -126,11 +126,11 @@ final class SignUpCodeRequiredStateTests: XCTestCase { wait(for: [exp]) XCTAssertEqual(delegate.error, expectedError) - XCTAssertEqual(delegate.newCodeRequiredState?.flowToken, expectedState.flowToken) + XCTAssertEqual(delegate.newCodeRequiredState?.continuationToken, expectedState.continuationToken) } func test_submitCode_delegate_whenPasswordRequired_AndUserHasImplementedOptionalDelegate_shouldReturnPasswordRequired() { - let expectedPasswordRequiredState = SignUpPasswordRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) + let expectedPasswordRequiredState = SignUpPasswordRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId) let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "exp telemetry is called") @@ -152,7 +152,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "exp telemetry is called") - let expectedResult: SignUpVerifyCodeResult = .passwordRequired(.init(controller: controller, username: "", flowToken: "", correlationId: correlationId)) + let expectedResult: SignUpVerifyCodeResult = .passwordRequired(.init(controller: controller, username: "", continuationToken: "", correlationId: correlationId)) controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in exp2.fulfill() }) @@ -170,7 +170,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { } func test_submitCode_delegate_whenAttributesRequired_AndUserHasImplementedOptionalDelegate_shouldReturnAttributesRequired() { - let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) + let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId) let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "exp telemetry is called") @@ -192,7 +192,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "exp telemetry is called") - let expectedResult: SignUpVerifyCodeResult = .attributesRequired(attributes: [], newState: .init(controller: controller, username: "", flowToken: "", correlationId: correlationId)) + let expectedResult: SignUpVerifyCodeResult = .attributesRequired(attributes: [], newState: .init(controller: controller, username: "", continuationToken: "", correlationId: correlationId)) controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in exp2.fulfill() }) @@ -212,7 +212,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { func test_submitCode_delegate_whenSuccess_shouldReturnAccountResult() { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "telemetry expectation") - let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: correlationId) + let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", continuationToken: "continuationToken", correlationId: correlationId) let expectedResult: SignUpVerifyCodeResult = .completed(expectedSignInAfterSignUpState) controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in @@ -230,7 +230,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase { func test_submitCode_delegate_whenSuccess_ButUserHasNotImplementedOptionalDelegate_shouldReturnCorrectError() { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "telemetry expectation") - let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: correlationId) + let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", continuationToken: "continuationToken", correlationId: correlationId) let result: SignUpVerifyCodeResult = .completed(expectedSignInAfterSignUpState) controller.submitCodeResult = .init(result, telemetryUpdate: { _ in exp2.fulfill() diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift index fad873c340..22ea5cfb5f 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift @@ -37,14 +37,14 @@ final class SignUpPasswordRequiredStateTests: XCTestCase { try super.setUpWithError() controller = .init() - sut = SignUpPasswordRequiredState(controller: controller, username: "", flowToken: "", correlationId: correlationId) + sut = SignUpPasswordRequiredState(controller: controller, username: "", continuationToken: "", correlationId: correlationId) } // MARK: - Delegate func test_submitPassword_delegate_whenError_shouldReturnPasswordRequiredError() { let expectedError = PasswordRequiredError(type: .invalidPassword) - let expectedState = SignUpPasswordRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) + let expectedState = SignUpPasswordRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId) let expectedResult: SignUpPasswordRequiredResult = .error(error: expectedError, newState: expectedState) controller.submitPasswordResult = .init(expectedResult) @@ -56,11 +56,11 @@ final class SignUpPasswordRequiredStateTests: XCTestCase { wait(for: [exp]) XCTAssertEqual(delegate.error, expectedError) - XCTAssertEqual(delegate.newPasswordRequiredState?.flowToken, expectedState.flowToken) + XCTAssertEqual(delegate.newPasswordRequiredState?.continuationToken, expectedState.continuationToken) } func test_submitCode_delegate_whenAttributesRequired_AndUserHasImplementedOptionalDelegate_shouldReturnAttributesRequired() { - let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) + let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId) let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "exp telemetry is called") @@ -79,7 +79,7 @@ final class SignUpPasswordRequiredStateTests: XCTestCase { } func test_submitCode_delegate_whenAttributesRequired_ButUserHasNotImplementedOptionalDelegate_shouldReturnPasswordRequiredError() { - let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", flowToken: "flowToken 2", correlationId: correlationId) + let expectedAttributesRequiredState = SignUpAttributesRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId) let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "exp telemetry is called") @@ -99,7 +99,7 @@ final class SignUpPasswordRequiredStateTests: XCTestCase { } func test_submitCode_delegate_whenSuccess_shouldReturnSignUpCompleted() { - let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: correlationId) + let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", continuationToken: "continuationToken", correlationId: correlationId) let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "telemetry expectation") @@ -118,7 +118,7 @@ final class SignUpPasswordRequiredStateTests: XCTestCase { } func test_submitCode_delegate_whenSuccess_ButUserHasNotImplementedOptionalDelegate_shouldReturnCorrectError() { - let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", slt: "slt", correlationId: correlationId) + let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", continuationToken: "continuationToken", correlationId: correlationId) let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "telemetry expectation") From 0ba3ed4aacddcd2c28713c9e905ac368f8d2e40f Mon Sep 17 00:00:00 2001 From: Diego Jerez <109726904+diegojerezba@users.noreply.github.com> Date: Thu, 11 Jan 2024 16:45:31 +0000 Subject: [PATCH 28/84] Update api errors (#1943) * Update api errors * PR comments. Remove invalid_grant error handling from signin/initiate --- MSAL/MSAL.xcodeproj/project.pbxproj | 12 +- .../MSALNativeAuthSignUpController.swift | 12 +- .../MSALNativeAuthESTSApiErrorCodes.swift | 3 - .../errors/MSALNativeAuthSubErrorCode.swift | 51 ++++++ ...ResetPasswordContinueOauth2ErrorCode.swift | 1 - ...thResetPasswordContinueResponseError.swift | 8 +- ...asswordPollCompletionOauth2ErrorCode.swift | 6 +- ...tPasswordPollCompletionResponseError.swift | 14 +- ...thResetPasswordSubmitOauth2ErrorCode.swift | 6 +- ...AuthResetPasswordSubmitResponseError.swift | 14 +- ...iveAuthSignInInitiateOauth2ErrorCode.swift | 2 +- ...iveAuthSignUpContinueOauth2ErrorCode.swift | 7 - ...ativeAuthSignUpContinueResponseError.swift | 33 ++-- ...NativeAuthSignUpStartOauth2ErrorCode.swift | 8 +- ...ALNativeAuthSignUpStartResponseError.swift | 20 +- .../MSALNativeAuthTokenOauth2ErrorCode.swift | 1 + .../MSALNativeAuthTokenResponseError.swift | 2 + ...veAuthResetPasswordResponseValidator.swift | 29 ++- ...SALNativeAuthSignInResponseValidator.swift | 2 +- ...SALNativeAuthSignUpResponseValidator.swift | 106 ++++------- ...ALNativeAuthSignUpValidatedResponses.swift | 4 +- ...MSALNativeAuthTokenResponseValidator.swift | 16 +- .../native_auth/common/Model.swift | 8 +- ...gnUpUsernameAndPasswordEndToEndTests.swift | 12 +- ...ativeAuthSignUpUsernameEndToEndTests.swift | 10 +- ...setPasswordChallengeIntegrationTests.swift | 6 +- ...esetPasswordContinueIntegrationTests.swift | 14 +- ...sswordPollCompletionIntegrationTests.swift | 22 ++- ...thResetPasswordStartIntegrationTests.swift | 2 +- ...hResetPasswordSubmitIntegrationTests.swift | 19 +- ...veAuthSignInInitiateIntegrationTests.swift | 2 +- ...eAuthSignUpChallengeIntegrationTests.swift | 6 +- ...veAuthSignUpContinueIntegrationTests.swift | 32 ++-- ...ativeAuthSignUpStartIntegrationTests.swift | 41 ++--- .../MSALNativeAuthTokenIntegrationTests.swift | 8 +- ...tiveAuthResetPasswordControllerTests.swift | 9 +- .../MSALNativeAuthSignUpControllerTests.swift | 60 +++--- ...ALNativeAuthRequestErrorHandlerTests.swift | 10 +- .../MSALNativeAuthSubErrorCodeTests.swift | 66 +++++++ ...PasswordContinueOauth2ErrorCodeTests.swift | 6 +- ...etPasswordContinueResponseErrorTests.swift | 12 +- ...rdPollCompletionOauth2ErrorCodeTests.swift | 26 +-- ...wordPollCompletionResponseErrorTests.swift | 14 +- ...etPasswordSubmitOauth2ErrorCodeTests.swift | 24 +-- ...esetPasswordSubmitResponseErrorTests.swift | 14 +- ...thSignUpContinueOauth2ErrorCodeTests.swift | 30 +-- ...AuthSignUpContinueResponseErrorTests.swift | 54 +++--- ...eAuthSignUpStartOauth2ErrorCodeTests.swift | 34 +--- ...iveAuthSignUpStartResponseErrorTests.swift | 20 +- ...hResetPasswordResponseValidatorTests.swift | 62 ++++--- ...tiveAuthSignUpResponseValidatorTests.swift | 172 ++++++------------ ...ativeAuthTokenResponseValidatorTests.swift | 59 ++---- ...ativeAuthPublicClientApplicationTest.swift | 4 +- 53 files changed, 569 insertions(+), 646 deletions(-) create mode 100644 MSAL/src/native_auth/network/errors/MSALNativeAuthSubErrorCode.swift create mode 100644 MSAL/test/unit/native_auth/network/errors/MSALNativeAuthSubErrorCodeTests.swift diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index b2ddfbbec3..293f5f833a 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -1014,6 +1014,8 @@ DEFB46ED2A52BA3700DBC006 /* MSALNativeAuthSignOutEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFB46EC2A52BA3700DBC006 /* MSALNativeAuthSignOutEndToEndTests.swift */; }; DEFB46F22A52C11400DBC006 /* MSALNativeAuthResetPasswordEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFB46F12A52C11400DBC006 /* MSALNativeAuthResetPasswordEndToEndTests.swift */; }; DEFB46F42A52C28100DBC006 /* ResetPasswordDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFB46F32A52C28100DBC006 /* ResetPasswordDelegateSpies.swift */; }; + E2025CC92B2A182200E32871 /* MSALNativeAuthSubErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2025CC82B2A182200E32871 /* MSALNativeAuthSubErrorCode.swift */; }; + E2025D202B2B8EEA00E32871 /* MSALNativeAuthSubErrorCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2025D1F2B2B8EEA00E32871 /* MSALNativeAuthSubErrorCodeTests.swift */; }; E205D62E29B783FF003887BC /* MSALNativeAuthConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = E205D62D29B783FF003887BC /* MSALNativeAuthConfiguration.swift */; }; E206FC5F296D65DE00AF4400 /* MSALNativeAuthInternalError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E206FC5E296D65DE00AF4400 /* MSALNativeAuthInternalError.swift */; }; E206FCEF2979BC4600AF4400 /* MSALNativeAuthSignInController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E206FCEE2979BC4600AF4400 /* MSALNativeAuthSignInController.swift */; }; @@ -2023,6 +2025,8 @@ DEFB46F12A52C11400DBC006 /* MSALNativeAuthResetPasswordEndToEndTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordEndToEndTests.swift; sourceTree = ""; }; DEFB46F32A52C28100DBC006 /* ResetPasswordDelegateSpies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordDelegateSpies.swift; sourceTree = ""; }; E02396F31E79E2F4004D6278 /* MSALTelemetryApiId.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALTelemetryApiId.h; sourceTree = ""; }; + E2025CC82B2A182200E32871 /* MSALNativeAuthSubErrorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSubErrorCode.swift; sourceTree = ""; }; + E2025D1F2B2B8EEA00E32871 /* MSALNativeAuthSubErrorCodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSubErrorCodeTests.swift; sourceTree = ""; }; E205D62D29B783FF003887BC /* MSALNativeAuthConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthConfiguration.swift; sourceTree = ""; }; E206FC5E296D65DE00AF4400 /* MSALNativeAuthInternalError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthInternalError.swift; sourceTree = ""; }; E206FCEE2979BC4600AF4400 /* MSALNativeAuthSignInController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInController.swift; sourceTree = ""; }; @@ -3587,11 +3591,11 @@ DE8EC8762A026C2E003FA561 /* reset_password */ = { isa = PBXGroup; children = ( - DE8EC8772A026C2E003FA561 /* MSALNativeAuthResetPasswordChallengeIntegrationTests.swift */, - DE8EC8782A026C2E003FA561 /* MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift */, DE8EC8792A026C2E003FA561 /* MSALNativeAuthResetPasswordStartIntegrationTests.swift */, + DE8EC8772A026C2E003FA561 /* MSALNativeAuthResetPasswordChallengeIntegrationTests.swift */, DE8EC87A2A026C2E003FA561 /* MSALNativeAuthResetPasswordContinueIntegrationTests.swift */, DE8EC87B2A026C2E003FA561 /* MSALNativeAuthResetPasswordSubmitIntegrationTests.swift */, + DE8EC8782A026C2E003FA561 /* MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift */, ); path = reset_password; sourceTree = ""; @@ -3669,6 +3673,7 @@ DE0D65BE29D30BAE005798B1 /* MSALNativeAuthResponseError.swift */, DE8EC8B52A053D80003FA561 /* MSALNativeAuthESTSApiErrorCodes.swift */, DEF1DD312AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift */, + E2025CC82B2A182200E32871 /* MSALNativeAuthSubErrorCode.swift */, E2C61FD829DECE8900F15203 /* sign_up */, DEDB29A329DDA99C008DA85B /* sign_in */, DEE34F5DD170B71C00BC302A /* reset_password */, @@ -3975,6 +3980,7 @@ E2960A0F2A1F4D18000F441B /* sign_up */, 9B2BBA252A3291DD0075F702 /* reset_password */, DEF1DD3B2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift */, + E2025D1F2B2B8EEA00E32871 /* MSALNativeAuthSubErrorCodeTests.swift */, ); path = errors; sourceTree = ""; @@ -5619,6 +5625,7 @@ E26097C32948FC4D0060DD7C /* MSALNativeAuthLogging.swift in Sources */, 232D614C2248484C00260C42 /* MSALClaimsRequest.m in Sources */, B203459621AF77FB00B221AA /* MSALRedirectUri.m in Sources */, + E2025CC92B2A182200E32871 /* MSALNativeAuthSubErrorCode.swift in Sources */, DEE34F7BD170B71C00BC302A /* MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift in Sources */, DEE34F7FD170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitResponse.swift in Sources */, E284F5D929F28B4200DBED7D /* MSALNativeAuthSignUpController.swift in Sources */, @@ -5966,6 +5973,7 @@ E22428072B0676970006C55E /* DispatchAccessTokenRetrieveCompletedTests.swift in Sources */, A0274CBE24B432B100BD198D /* MSALAuthSchemeTests.m in Sources */, E22427F22B0668910006C55E /* SignInPasswordStartDelegateDispatcherTests.swift in Sources */, + E2025D202B2B8EEA00E32871 /* MSALNativeAuthSubErrorCodeTests.swift in Sources */, B286BA00238A08F6007833AD /* MSALB2CPolicyTests.m in Sources */, E22428012B0673290006C55E /* ResetPasswordResendCodeDelegateDispatcherTests.swift in Sources */, 9B2BBA2F2A3293330075F702 /* MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift in Sources */, diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift index 9c1de26f49..7475e39850 100644 --- a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift @@ -164,12 +164,8 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa context: MSIDRequestContext ) async -> SignUpStartControllerResponse { switch result { - case .verificationRequired(let continuationToken, let unverifiedAttributes): - MSALLogger.log( - level: .info, - context: context, - format: "verification_required received from signup/start request for attributes: \(unverifiedAttributes)" - ) + case .success(let continuationToken): + MSALLogger.log(level: .info, context: context, format: "Successful signup/start request") let challengeResult = await performAndValidateChallengeRequest(continuationToken: continuationToken, context: context) return handleSignUpChallengeResult(challengeResult, username: username, event: event, context: context) case .attributeValidationFailed(let invalidAttributes): @@ -542,7 +538,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa // The telemetry event always fails because more attributes are required (we consider this an error after having sent attributes) self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result, controllerError: error) }) - case .attributeValidationFailed(let newContinuationToken, let invalidAttributes): + case .attributeValidationFailed(let invalidAttributes): let message = "attribute_validation_failed from signup/continue submitAttributes request. Make sure these attributes are correct: \(invalidAttributes)" // swiftlint:disable:this line_length MSALLogger.log(level: .error, context: context, format: message) @@ -552,7 +548,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa let state = SignUpAttributesRequiredState( controller: self, username: username, - continuationToken: newContinuationToken, + continuationToken: continuationToken, correlationId: context.correlationId() ) return .init(.attributesInvalid(attributes: invalidAttributes, newState: state), telemetryUpdate: { [weak self] result in diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorCodes.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorCodes.swift index 32210dd480..381b72d684 100644 --- a/MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorCodes.swift +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorCodes.swift @@ -26,9 +26,6 @@ enum MSALNativeAuthESTSApiErrorCodes: Int { case userNotFound = 50034 case invalidCredentials = 50126 - case invalidOTP = 50181 - case incorrectOTP = 501811 - case OTPNoCacheEntryForUser = 50184 case strongAuthRequired = 50076 case userNotHaveAPassword = 500222 case invalidRequestParameter = 90100 diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthSubErrorCode.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthSubErrorCode.swift new file mode 100644 index 0000000000..ff9687addd --- /dev/null +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthSubErrorCode.swift @@ -0,0 +1,51 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +enum MSALNativeAuthSubErrorCode: String, Decodable, CaseIterable, Equatable { + case passwordTooWeak = "password_too_weak" + case passwordTooShort = "password_too_short" + case passwordTooLong = "password_too_long" + case passwordInvalid = "password_is_invalid" + case passwordRecentlyUsed = "password_recently_used" + case passwordBanned = "password_banned" + case attributeValidationFailed = "attribute_validation_failed" + case invalidOOBValue = "invalid_oob_value" + + var isAnyPasswordError: Bool { + switch self { + case .passwordTooWeak, + .passwordTooShort, + .passwordTooLong, + .passwordInvalid, + .passwordRecentlyUsed, + .passwordBanned: + return true + case .attributeValidationFailed, + .invalidOOBValue: + return false + } + } +} diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift index 27fec6c774..59b7d23abf 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift @@ -30,5 +30,4 @@ enum MSALNativeAuthResetPasswordContinueOauth2ErrorCode: String, Decodable, Case case invalidGrant = "invalid_grant" case expiredToken = "expired_token" case verificationRequired = "verification_required" - case invalidOOBValue = "invalid_oob_value" } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift index 0ca07d8271..123b244863 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift @@ -27,6 +27,7 @@ import Foundation struct MSALNativeAuthResetPasswordContinueResponseError: MSALNativeAuthResponseError { let error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode + let subError: MSALNativeAuthSubErrorCode? let errorDescription: String? let errorCodes: [Int]? let errorURI: String? @@ -36,6 +37,7 @@ struct MSALNativeAuthResetPasswordContinueResponseError: MSALNativeAuthResponseE enum CodingKeys: String, CodingKey { case error + case subError = "suberror" case errorDescription = "error_description" case errorCodes = "error_codes" case errorURI = "error_uri" @@ -49,12 +51,12 @@ extension MSALNativeAuthResetPasswordContinueResponseError { func toVerifyCodePublicError() -> VerifyCodeError { switch error { - case .invalidOOBValue: - return .init(type: .invalidCode, message: errorDescription) + case .invalidGrant: + return subError == .invalidOOBValue ? .init(type: .invalidCode, message: errorDescription) + : .init(type: .generalError, message: errorDescription) case .invalidClient, .expiredToken, .invalidRequest, - .invalidGrant, .verificationRequired: return .init(type: .generalError, message: errorDescription) } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift index aec42a88d2..effb36081e 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift @@ -25,13 +25,9 @@ import Foundation enum MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode: String, Decodable, CaseIterable { + case invalidGrant = "invalid_grant" case invalidRequest = "invalid_request" case invalidClient = "invalid_client" case expiredToken = "expired_token" - case passwordTooWeak = "password_too_weak" - case passwordTooShort = "password_too_short" - case passwordTooLong = "password_too_long" - case passwordRecentlyUsed = "password_recently_used" - case passwordBanned = "password_banned" case userNotFound = "user_not_found" } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift index e96898b754..3a674ab01a 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift @@ -27,6 +27,7 @@ import Foundation struct MSALNativeAuthResetPasswordPollCompletionResponseError: MSALNativeAuthResponseError { let error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode + let subError: MSALNativeAuthSubErrorCode? let errorDescription: String? let errorCodes: [Int]? let errorURI: String? @@ -35,6 +36,7 @@ struct MSALNativeAuthResetPasswordPollCompletionResponseError: MSALNativeAuthRes enum CodingKeys: String, CodingKey { case error + case subError = "suberror" case errorDescription = "error_description" case errorCodes = "error_codes" case errorURI = "error_uri" @@ -47,12 +49,12 @@ extension MSALNativeAuthResetPasswordPollCompletionResponseError { func toPasswordRequiredPublicError() -> PasswordRequiredError { switch error { - case .passwordTooWeak, - .passwordTooShort, - .passwordTooLong, - .passwordRecentlyUsed, - .passwordBanned: - return .init(type: .invalidPassword, message: errorDescription) + case .invalidGrant: + if let subError, subError.isAnyPasswordError { + return .init(type: .invalidPassword, message: errorDescription) + } else { + return .init(type: .generalError, message: errorDescription) + } case .invalidClient, .expiredToken, .invalidRequest, diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift index de0e3d1724..0037eda721 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift @@ -28,9 +28,5 @@ enum MSALNativeAuthResetPasswordSubmitOauth2ErrorCode: String, Decodable, CaseIt case invalidRequest = "invalid_request" case invalidClient = "invalid_client" case expiredToken = "expired_token" - case passwordTooWeak = "password_too_weak" - case passwordTooShort = "password_too_short" - case passwordTooLong = "password_too_long" - case passwordRecentlyUsed = "password_recently_used" - case passwordBanned = "password_banned" + case invalidGrant = "invalid_grant" } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift index 96c473bca1..15452206d5 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift @@ -27,6 +27,7 @@ import Foundation struct MSALNativeAuthResetPasswordSubmitResponseError: MSALNativeAuthResponseError { let error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode + let subError: MSALNativeAuthSubErrorCode? let errorDescription: String? let errorCodes: [Int]? let errorURI: String? @@ -35,6 +36,7 @@ struct MSALNativeAuthResetPasswordSubmitResponseError: MSALNativeAuthResponseErr enum CodingKeys: String, CodingKey { case error + case subError = "suberror" case errorDescription = "error_description" case errorCodes = "error_codes" case errorURI = "error_uri" @@ -47,12 +49,12 @@ extension MSALNativeAuthResetPasswordSubmitResponseError { func toPasswordRequiredPublicError() -> PasswordRequiredError { switch error { - case .passwordTooWeak, - .passwordTooShort, - .passwordTooLong, - .passwordRecentlyUsed, - .passwordBanned: - return .init(type: .invalidPassword, message: errorDescription) + case .invalidGrant: + if let subError, subError.isAnyPasswordError { + return .init(type: .invalidPassword, message: errorDescription) + } else { + return .init(type: .generalError, message: errorDescription) + } case .invalidClient, .expiredToken, .invalidRequest: diff --git a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateOauth2ErrorCode.swift index 57c98fdb65..3dab73e028 100644 --- a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateOauth2ErrorCode.swift +++ b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateOauth2ErrorCode.swift @@ -27,6 +27,6 @@ import Foundation enum MSALNativeAuthSignInInitiateOauth2ErrorCode: String, Decodable, CaseIterable { case invalidRequest = "invalid_request" case unauthorizedClient = "unauthorized_client" - case invalidGrant = "invalid_grant" + case userNotFound = "user_not_found" case unsupportedChallengeType = "unsupported_challenge_type" } diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCode.swift index 7a60eabc2f..80c8f9789f 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCode.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCode.swift @@ -29,15 +29,8 @@ enum MSALNativeAuthSignUpContinueOauth2ErrorCode: String, Decodable, CaseIterabl case unauthorizedClient = "unauthorized_client" case invalidGrant = "invalid_grant" case expiredToken = "expired_token" - case passwordTooWeak = "password_too_weak" - case passwordTooShort = "password_too_short" - case passwordTooLong = "password_too_long" - case passwordRecentlyUsed = "password_recently_used" - case passwordBanned = "password_banned" case userAlreadyExists = "user_already_exists" case attributesRequired = "attributes_required" case verificationRequired = "verification_required" - case attributeValidationFailed = "attribute_validation_failed" case credentialRequired = "credential_required" - case invalidOOBValue = "invalid_oob_value" } diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift index 2d1a1c0819..57cbd610aa 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift @@ -26,6 +26,7 @@ import Foundation struct MSALNativeAuthSignUpContinueResponseError: MSALNativeAuthResponseError { let error: MSALNativeAuthSignUpContinueOauth2ErrorCode + let subError: MSALNativeAuthSubErrorCode? let errorDescription: String? let errorCodes: [Int]? let errorURI: String? @@ -37,6 +38,7 @@ struct MSALNativeAuthSignUpContinueResponseError: MSALNativeAuthResponseError { enum CodingKeys: String, CodingKey { case error + case subError = "suberror" case errorDescription = "error_description" case errorCodes = "error_codes" case errorURI = "error_uri" @@ -52,44 +54,35 @@ extension MSALNativeAuthSignUpContinueResponseError { func toVerifyCodePublicError() -> VerifyCodeError { switch error { - case .invalidOOBValue: - return .init(type: .invalidCode, message: errorDescription) + case .invalidGrant: + return subError == .invalidOOBValue ? .init(type: .invalidCode, message: errorDescription) + : .init(type: .generalError, message: errorDescription) case .unauthorizedClient, .expiredToken, .invalidRequest, - .invalidGrant, - .passwordTooWeak, - .passwordTooShort, - .passwordTooLong, - .passwordRecentlyUsed, - .passwordBanned, .userAlreadyExists, .attributesRequired, .verificationRequired, - .credentialRequired, - .attributeValidationFailed: + .credentialRequired: return .init(type: .generalError, message: errorDescription) } } func toPasswordRequiredPublicError() -> PasswordRequiredError { switch error { - case .passwordTooWeak, - .passwordTooShort, - .passwordTooLong, - .passwordRecentlyUsed, - .passwordBanned: - return .init(type: .invalidPassword, message: errorDescription) + case .invalidGrant: + if let subError, subError.isAnyPasswordError { + return .init(type: .invalidPassword, message: errorDescription) + } else { + return .init(type: .generalError, message: errorDescription) + } case .unauthorizedClient, .expiredToken, .invalidRequest, - .invalidGrant, .userAlreadyExists, .attributesRequired, .verificationRequired, - .credentialRequired, - .attributeValidationFailed, - .invalidOOBValue: + .credentialRequired: return .init(type: .generalError, message: errorDescription) } } diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCode.swift index 92c97f8831..4997bcd815 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCode.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCode.swift @@ -25,17 +25,11 @@ import Foundation enum MSALNativeAuthSignUpStartOauth2ErrorCode: String, Decodable, CaseIterable, Equatable { + case invalidGrant = "invalid_grant" case invalidRequest = "invalid_request" case unauthorizedClient = "unauthorized_client" case unsupportedChallengeType = "unsupported_challenge_type" - case passwordTooWeak = "password_too_weak" - case passwordTooShort = "password_too_short" - case passwordTooLong = "password_too_long" - case passwordRecentlyUsed = "password_recently_used" - case passwordBanned = "password_banned" case userAlreadyExists = "user_already_exists" case attributesRequired = "attributes_required" - case verificationRequired = "verification_required" case unsupportedAuthMethod = "unsupported_auth_method" - case attributeValidationFailed = "attribute_validation_failed" } diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift index aee5f45a26..4d7cbf15cb 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift @@ -27,6 +27,7 @@ import Foundation struct MSALNativeAuthSignUpStartResponseError: MSALNativeAuthResponseError { let error: MSALNativeAuthSignUpStartOauth2ErrorCode + let subError: MSALNativeAuthSubErrorCode? let errorDescription: String? let errorCodes: [Int]? let errorURI: String? @@ -37,6 +38,7 @@ struct MSALNativeAuthSignUpStartResponseError: MSALNativeAuthResponseError { enum CodingKeys: String, CodingKey { case error + case subError = "suberror" case errorDescription = "error_description" case errorCodes = "error_codes" case errorURI = "error_uri" @@ -51,21 +53,19 @@ extension MSALNativeAuthSignUpStartResponseError { func toSignUpStartPublicError() -> SignUpStartError { switch error { - case .passwordTooWeak, - .passwordTooShort, - .passwordTooLong, - .passwordRecentlyUsed, - .passwordBanned: - return .init(type: .invalidPassword, message: errorDescription) + case .invalidGrant: + if let subError, subError.isAnyPasswordError { + return .init(type: .invalidPassword, message: errorDescription) + } else { + return .init(type: .generalError, message: errorDescription) + } case .userAlreadyExists: return .init(type: .userAlreadyExists, message: errorDescription) - case .attributeValidationFailed, - .attributesRequired, + case .attributesRequired, .unauthorizedClient, .unsupportedChallengeType, .unsupportedAuthMethod, - .invalidRequest, - .verificationRequired: /// .verificationRequired is not supported by the API team yet. We treat it as an unexpectedError in the validator + .invalidRequest: return .init(type: .generalError, message: errorDescription) } } diff --git a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenOauth2ErrorCode.swift index f5709b3f9b..5b98c1b08f 100644 --- a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenOauth2ErrorCode.swift +++ b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenOauth2ErrorCode.swift @@ -35,4 +35,5 @@ enum MSALNativeAuthTokenOauth2ErrorCode: String, Decodable { case invalidScope = "invalid_scope" case authorizationPending = "authorization_pending" case slowDown = "slow_down" + case userNotFound = "user_not_found" } diff --git a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift index 83bacdea16..1b88e7cb77 100644 --- a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift +++ b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift @@ -27,6 +27,7 @@ import Foundation struct MSALNativeAuthTokenResponseError: MSALNativeAuthResponseError { let error: MSALNativeAuthTokenOauth2ErrorCode + let subError: MSALNativeAuthSubErrorCode? let errorDescription: String? let errorCodes: [Int]? let errorURI: String? @@ -35,6 +36,7 @@ struct MSALNativeAuthTokenResponseError: MSALNativeAuthResponseError { enum CodingKeys: String, CodingKey { case error + case subError = "suberror" case errorDescription = "error_description" case errorCodes = "error_codes" case errorURI = "error_uri" diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift index 7a374c964c..44ef1db68d 100644 --- a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift @@ -171,10 +171,9 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas } switch apiError.error { - case .invalidOOBValue: - return .invalidOOB + case .invalidGrant: + return apiError.subError == .invalidOOBValue ? .invalidOOB : .error(apiError) case .invalidClient, - .invalidGrant, .expiredToken, .invalidRequest: return .error(apiError) @@ -214,12 +213,12 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas } switch apiError.error { - case .passwordTooWeak, - .passwordTooShort, - .passwordTooLong, - .passwordRecentlyUsed, - .passwordBanned: - return .passwordError(error: apiError) + case .invalidGrant: + if let subError = apiError.subError, subError.isAnyPasswordError { + return .passwordError(error: apiError) + } else { + return .error(apiError) + } case .invalidRequest, .invalidClient, .expiredToken: @@ -258,12 +257,12 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas } switch apiError.error { - case .passwordTooWeak, - .passwordTooShort, - .passwordTooLong, - .passwordRecentlyUsed, - .passwordBanned: - return .passwordError(error: apiError) + case .invalidGrant: + if let subError = apiError.subError, subError.isAnyPasswordError { + return .passwordError(error: apiError) + } else { + return .error(apiError) + } case .userNotFound, .invalidRequest, .invalidClient, diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift index 8a916b1181..3aa93dbdc7 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift @@ -153,7 +153,7 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV return .error(.invalidClient(message: error.errorDescription)) case .unsupportedChallengeType: return .error(.unsupportedChallengeType(message: error.errorDescription)) - case .invalidGrant: + case .userNotFound: return .error(.userNotFound(message: error.errorDescription)) } } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift index c3b46024bd..0379cc971f 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift @@ -53,16 +53,15 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV } private func handleStartSuccess( - _ response: MSALNativeAuthSignUpStartResponse, with context: MSIDRequestContext + _ response: MSALNativeAuthSignUpStartResponse, + with context: MSIDRequestContext ) -> MSALNativeAuthSignUpStartValidatedResponse { if response.challengeType == .redirect { return .redirect + } else if let continuationToken = response.continuationToken { + return .success(continuationToken: continuationToken) } else { - MSALLogger.log( - level: .error, - context: context, - format: "Unexpected response in signup/start. SDK expects only 200 with redirect challenge_type" - ) + MSALLogger.log(level: .error, context: context, format: "signup/start returned success with unexpected response body") return .unexpectedError } } @@ -74,19 +73,7 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV } switch apiError.error { - case .verificationRequired: - if let continuationToken = apiError.continuationToken, - let unverifiedAttributes = apiError.unverifiedAttributes, - !unverifiedAttributes.isEmpty { - return .verificationRequired( - continuationToken: continuationToken, - unverifiedAttributes: extractAttributeNames(from: unverifiedAttributes) - ) - } else { - MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/start for verification_required error") - return .unexpectedError - } - case .attributeValidationFailed: + case .invalidGrant where apiError.subError == .attributeValidationFailed: if let invalidAttributes = apiError.invalidAttributes, !invalidAttributes.isEmpty { return .attributeValidationFailed(invalidAttributes: extractAttributeNames(from: invalidAttributes)) } else { @@ -183,34 +170,14 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV } } - // swiftlint:disable:next cyclomatic_complexity function_body_length private func handleContinueError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthSignUpContinueValidatedResponse { guard let apiError = error as? MSALNativeAuthSignUpContinueResponseError else { return .unexpectedError } switch apiError.error { - case .invalidOOBValue, - .passwordTooWeak, - .passwordTooShort, - .passwordTooLong, - .passwordRecentlyUsed, - .passwordBanned: - return .invalidUserInput(apiError) - case .attributeValidationFailed: - if let continuationToken = apiError.continuationToken, let invalidAttributes = apiError.invalidAttributes, !invalidAttributes.isEmpty { - return .attributeValidationFailed( - continuationToken: continuationToken, - invalidAttributes: extractAttributeNames(from: invalidAttributes) - ) - } else { - MSALLogger.log( - level: .error, - context: context, - format: "Missing expected fields in signup/continue for attribute_validation_failed error" - ) - return .unexpectedError - } + case .invalidGrant: + return handleInvalidGrantError(apiError, with: context) case .credentialRequired: if let continuationToken = apiError.continuationToken { return .credentialRequired(continuationToken: continuationToken) @@ -235,40 +202,41 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV MSALLogger.log(level: .error, context: context, format: "verificationRequired is not supported yet") return .unexpectedError case .unauthorizedClient, - .invalidGrant, .expiredToken, - .userAlreadyExists: + .userAlreadyExists, + .invalidRequest: return .error(apiError) - case .invalidRequest: - return handleInvalidRequestError(apiError) } } - private func handleInvalidRequestError(_ error: MSALNativeAuthSignUpContinueResponseError) -> MSALNativeAuthSignUpContinueValidatedResponse { - guard let errorCode = error.errorCodes?.first, let knownErrorCode = MSALNativeAuthESTSApiErrorCodes(rawValue: errorCode) else { - return .error(error) + private func handleInvalidGrantError( + _ apiError: MSALNativeAuthSignUpContinueResponseError, + with context: MSIDRequestContext + ) -> MSALNativeAuthSignUpContinueValidatedResponse { + guard let subError = apiError.subError else { + return .error(apiError) } - switch knownErrorCode { - case .invalidOTP, - .incorrectOTP, - .OTPNoCacheEntryForUser: - return .invalidUserInput( - MSALNativeAuthSignUpContinueResponseError( - error: .invalidOOBValue, - errorDescription: error.errorDescription, - errorCodes: error.errorCodes, - errorURI: error.errorURI, - innerErrors: error.innerErrors, - continuationToken: error.continuationToken, - requiredAttributes: error.requiredAttributes, - unverifiedAttributes: error.unverifiedAttributes, - invalidAttributes: error.invalidAttributes)) - case .userNotFound, - .invalidCredentials, - .strongAuthRequired, - .userNotHaveAPassword, - .invalidRequestParameter: - return .error(error) + + switch subError { + case .invalidOOBValue, + .passwordTooWeak, + .passwordTooShort, + .passwordTooLong, + .passwordInvalid, + .passwordRecentlyUsed, + .passwordBanned: + return .invalidUserInput(apiError) + case .attributeValidationFailed: + if let invalidAttributes = apiError.invalidAttributes, !invalidAttributes.isEmpty { + return .attributeValidationFailed(invalidAttributes: extractAttributeNames(from: invalidAttributes)) + } else { + MSALLogger.log( + level: .error, + context: context, + format: "Missing expected fields in signup/continue for attribute_validation_failed error" + ) + return .unexpectedError + } } } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift index d657f14906..37c819a7cb 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift @@ -23,7 +23,7 @@ // THE SOFTWARE. enum MSALNativeAuthSignUpStartValidatedResponse: Equatable { - case verificationRequired(continuationToken: String, unverifiedAttributes: [String]) + case success(continuationToken: String) case attributeValidationFailed(invalidAttributes: [String]) case redirect case error(MSALNativeAuthSignUpStartResponseError) @@ -47,7 +47,7 @@ enum MSALNativeAuthSignUpContinueValidatedResponse: Equatable { case invalidUserInput(_ error: MSALNativeAuthSignUpContinueResponseError) case credentialRequired(continuationToken: String) case attributesRequired(continuationToken: String, requiredAttributes: [MSALNativeAuthRequiredAttributes]) - case attributeValidationFailed(continuationToken: String, invalidAttributes: [String]) + case attributeValidationFailed(invalidAttributes: [String]) case error(MSALNativeAuthSignUpContinueResponseError) case unexpectedError } diff --git a/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift index 826fa7ec48..a856880c81 100644 --- a/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift @@ -99,7 +99,11 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal .unauthorizedClient: return .error(.invalidClient(message: responseError.errorDescription)) case .invalidGrant: - return handleInvalidGrantErrorCodes(responseError.errorCodes, errorDescription: responseError.errorDescription, context: context) + if responseError.subError == .invalidOOBValue { + return .error(.invalidOOBCode(message: responseError.errorDescription)) + } else { + return handleInvalidGrantErrorCodes(responseError.errorCodes, errorDescription: responseError.errorDescription, context: context) + } case .expiredToken: return .error(.expiredToken(message: responseError.errorDescription)) case .expiredRefreshToken: @@ -112,6 +116,8 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal return .error(.authorizationPending(message: responseError.errorDescription)) case .slowDown: return .error(.slowDown(message: responseError.errorDescription)) + case .userNotFound: + return .error(.userNotFound(message: responseError.errorDescription)) } } @@ -190,10 +196,6 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal return .userNotFound(message: errorDescription) case .invalidCredentials: return .invalidPassword(message: errorDescription) - case .invalidOTP, - .incorrectOTP, - .OTPNoCacheEntryForUser: - return .invalidOOBCode(message: errorDescription) case .strongAuthRequired: return .strongAuthRequired(message: errorDescription) case .userNotHaveAPassword, @@ -207,10 +209,6 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal errorDescription: String? ) -> MSALNativeAuthTokenValidatedErrorType { switch errorCode { - case .invalidOTP, - .incorrectOTP, - .OTPNoCacheEntryForUser: - return .invalidOOBCode(message: errorDescription) case .userNotFound, .invalidCredentials, .strongAuthRequired, diff --git a/MSAL/test/integration/native_auth/common/Model.swift b/MSAL/test/integration/native_auth/common/Model.swift index 822c709cc5..870d7b5dc6 100644 --- a/MSAL/test/integration/native_auth/common/Model.swift +++ b/MSAL/test/integration/native_auth/common/Model.swift @@ -45,6 +45,7 @@ enum MockAPIEndpoint: String { } enum MockAPIResponse: String { + case signUpStartSuccess = "SignUpStartSuccess" case invalidRequest = "InvalidRequest" case invalidToken = "InvalidToken" case invalidClient = "InvalidClient" @@ -52,10 +53,9 @@ enum MockAPIResponse: String { case invalidScope = "InvalidScope" case expiredToken = "ExpiredToken" case invalidPurposeToken = "InvalidPurposeToken" - case unsupportedAuthMethod = "UnsupportedAuthMethod" + case authNotSupported = "AuthNotSupported" case userAlreadyExists = "UserAlreadyExists" case userNotFound = "UserNotFound" - case explicityUserNotFound = "ExplicityUserNotFound" case slowDown = "SlowDown" case invalidPassword = "InvalidPassword" case invalidOOBValue = "InvalidOOBValue" @@ -76,9 +76,7 @@ enum MockAPIResponse: String { case invalidAttributes = "InvalidAttributes" case verificationRequired = "VerificationRequired" case attributeValidationFailed = "AttributeValidationFailed" - case invalidSignUpToken = "InvalidSignupToken" - case explicitInvalidOOBValue = "ExplicitInvalidOOBValue" - case invalidPasswordResetToken = "InvalidPasswordResetToken" + case invalidContinuationToken = "InvalidContinuationToken" case ssprStartSuccess = "SSPRStartSuccess" case ssprContinueSuccess = "SSPRContinueSuccess" case ssprSubmitSuccess = "SSPRSubmitSuccess" diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift index 9366c4f30a..3505dff41d 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift @@ -41,7 +41,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth let signUpStartDelegate = SignUpPasswordStartDelegateSpy(expectation: codeRequiredExp) if usingMockAPI { - try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.signUpStartSuccess, endpoint: .signUpStart) try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } @@ -90,7 +90,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth let signUpStartDelegate = SignUpPasswordStartDelegateSpy(expectation: codeRequiredExp) if usingMockAPI { - try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.signUpStartSuccess, endpoint: .signUpStart) try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } @@ -140,7 +140,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth let signUpStartDelegate = SignUpPasswordStartDelegateSpy(expectation: codeRequiredExp) if usingMockAPI { - try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.signUpStartSuccess, endpoint: .signUpStart) try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } @@ -207,7 +207,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth let signUpStartDelegate = SignUpPasswordStartDelegateSpy(expectation: codeRequiredExp) if usingMockAPI { - try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.signUpStartSuccess, endpoint: .signUpStart) try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } @@ -291,7 +291,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth let signUpStartDelegate = SignUpPasswordStartDelegateSpy(expectation: codeRequiredExp) if usingMockAPI { - try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.signUpStartSuccess, endpoint: .signUpStart) try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } @@ -392,7 +392,7 @@ final class MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests: MSALNativeAuth let signUpStartDelegate = SignUpPasswordStartDelegateSpy(expectation: codeRequiredExp) if usingMockAPI { - try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.signUpStartSuccess, endpoint: .signUpStart) try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameEndToEndTests.swift b/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameEndToEndTests.swift index a49b951761..6af5c2631f 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameEndToEndTests.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_up/MSALNativeAuthSignUpUsernameEndToEndTests.swift @@ -41,7 +41,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas let signUpStartDelegate = SignUpStartDelegateSpy(expectation: codeRequiredExp) if usingMockAPI { - try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.signUpStartSuccess, endpoint: .signUpStart) try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } @@ -85,7 +85,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas let signUpStartDelegate = SignUpStartDelegateSpy(expectation: codeRequiredExp) if usingMockAPI { - try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.signUpStartSuccess, endpoint: .signUpStart) try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } @@ -129,7 +129,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas let signUpStartDelegate = SignUpStartDelegateSpy(expectation: codeRequiredExp) if usingMockAPI { - try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.signUpStartSuccess, endpoint: .signUpStart) try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } @@ -190,7 +190,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas let signUpStartDelegate = SignUpStartDelegateSpy(expectation: codeRequiredExp) if usingMockAPI { - try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.signUpStartSuccess, endpoint: .signUpStart) try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } @@ -268,7 +268,7 @@ final class MSALNativeAuthSignUpUsernameEndToEndTests: MSALNativeAuthEndToEndBas let signUpStartDelegate = SignUpStartDelegateSpy(expectation: codeRequiredExp) if usingMockAPI { - try await mockResponse(.verificationRequired, endpoint: .signUpStart) + try await mockResponse(.signUpStartSuccess, endpoint: .signUpStart) try await mockResponse(.challengeTypeOOB, endpoint: .signUpChallenge) } diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift index ecec0c1ddb..31f7b2f5d9 100644 --- a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift @@ -90,10 +90,12 @@ final class MSALNativeAuthResetPasswordChallengeIntegrationTests: MSALNativeAuth ) } - func test_resetPasswordChallenge_invalidPasswordResetToken() async throws { + func test_resetPasswordChallenge_invalidContinuationToken() async throws { + throw XCTSkip() + try await perform_testFail( endpoint: .resetPasswordChallenge, - response: .invalidPasswordResetToken, + response: .invalidContinuationToken, expectedError: createError(.invalidRequest) ) } diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift index 7478d13e19..b59ca975ff 100644 --- a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift @@ -77,10 +77,12 @@ final class MSALNativeAuthResetPasswordContinueIntegrationTests: MSALNativeAuthI ) } - func test_resetPasswordContinue_invalidPasswordResetToken() async throws { + func test_resetPasswordContinue_invalidContinuationToken() async throws { + throw XCTSkip() + try await perform_testFail( endpoint: .resetPasswordContinue, - response: .invalidPasswordResetToken, + response: .invalidContinuationToken, expectedError: createResetPasswordContinueError(error: .invalidRequest) ) } @@ -96,12 +98,14 @@ final class MSALNativeAuthResetPasswordContinueIntegrationTests: MSALNativeAuthI func test_resetPasswordContinue_invalidOOB() async throws { try await perform_testFail( endpoint: .resetPasswordContinue, - response: .explicitInvalidOOBValue, - expectedError: createResetPasswordContinueError(error: .invalidOOBValue) + response: .invalidOOBValue, + expectedError: createResetPasswordContinueError(error: .invalidGrant, subError: .invalidOOBValue) ) } func test_resetPasswordContinue_verificationRequired() async throws { + throw XCTSkip() + try await perform_testFail( endpoint: .resetPasswordContinue, response: .verificationRequired, @@ -111,6 +115,7 @@ final class MSALNativeAuthResetPasswordContinueIntegrationTests: MSALNativeAuthI private func createResetPasswordContinueError( error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode, + subError: MSALNativeAuthSubErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, errorURI: String? = nil, @@ -120,6 +125,7 @@ final class MSALNativeAuthResetPasswordContinueIntegrationTests: MSALNativeAuthI ) -> MSALNativeAuthResetPasswordContinueResponseError { .init( error: error, + subError: subError, errorDescription: errorDescription, errorCodes: errorCodes, errorURI: errorURI, diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift index 449d3b63ac..dc00bcfb82 100644 --- a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift @@ -57,7 +57,7 @@ final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativ let response: MSALNativeAuthResetPasswordPollCompletionResponse? = try await performTestSucceed() XCTAssertNotNil(response?.status) - XCTAssertNil(response?.continuationToken) + XCTAssertNotNil(response?.continuationToken) XCTAssertNil(response?.expiresIn) } @@ -111,10 +111,12 @@ final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativ ) } - func test_resetPasswordPollCompletion_invalidPasswordResetToken() async throws { + func test_resetPasswordPollCompletion_invalidContinuationToken() async throws { + throw XCTSkip() + try await perform_testFail( endpoint: .resetPasswordPollCompletion, - response: .invalidPasswordResetToken, + response: .invalidContinuationToken, expectedError: createResetPasswordPollCompletionError(error: .invalidRequest) ) } @@ -131,7 +133,7 @@ final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativ try await perform_testFail( endpoint: .resetPasswordPollCompletion, response: .passwordTooWeak, - expectedError: createResetPasswordPollCompletionError(error: .passwordTooWeak) + expectedError: createResetPasswordPollCompletionError(error: .invalidGrant, subError: .passwordTooWeak) ) } @@ -139,7 +141,7 @@ final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativ try await perform_testFail( endpoint: .resetPasswordPollCompletion, response: .passwordTooShort, - expectedError: createResetPasswordPollCompletionError(error: .passwordTooShort) + expectedError: createResetPasswordPollCompletionError(error: .invalidGrant, subError: .passwordTooShort) ) } @@ -147,7 +149,7 @@ final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativ try await perform_testFail( endpoint: .resetPasswordPollCompletion, response: .passwordTooLong, - expectedError: createResetPasswordPollCompletionError(error: .passwordTooLong) + expectedError: createResetPasswordPollCompletionError(error: .invalidGrant, subError: .passwordTooLong) ) } @@ -155,7 +157,7 @@ final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativ try await perform_testFail( endpoint: .resetPasswordPollCompletion, response: .passwordRecentlyUsed, - expectedError: createResetPasswordPollCompletionError(error: .passwordRecentlyUsed) + expectedError: createResetPasswordPollCompletionError(error: .invalidGrant, subError: .passwordRecentlyUsed) ) } @@ -163,20 +165,21 @@ final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativ try await perform_testFail( endpoint: .resetPasswordPollCompletion, response: .passwordBanned, - expectedError: createResetPasswordPollCompletionError(error: .passwordBanned) + expectedError: createResetPasswordPollCompletionError(error: .invalidGrant, subError: .passwordBanned) ) } func test_resetPasswordPollCompletion_userNotFound() async throws { try await perform_testFail( endpoint: .resetPasswordPollCompletion, - response: .explicityUserNotFound, + response: .userNotFound, expectedError: createResetPasswordPollCompletionError(error: .userNotFound) ) } private func createResetPasswordPollCompletionError( error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode, + subError: MSALNativeAuthSubErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, errorURI: String? = nil, @@ -185,6 +188,7 @@ final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativ ) -> MSALNativeAuthResetPasswordPollCompletionResponseError { .init( error: error, + subError: subError, errorDescription: errorDescription, errorCodes: errorCodes, errorURI: errorURI, diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordStartIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordStartIntegrationTests.swift index 318782806c..22a066a145 100644 --- a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordStartIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordStartIntegrationTests.swift @@ -80,7 +80,7 @@ final class MSALNativeAuthResetPasswordStartIntegrationTests: MSALNativeAuthInte func test_resetPasswordStart_userNotFound() async throws { try await perform_testFail( endpoint: .resetPasswordStart, - response: .explicityUserNotFound, + response: .userNotFound, expectedError: createResetPasswordStartError(error: .userNotFound) ) } diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordSubmitIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordSubmitIntegrationTests.swift index fa2a92df9a..b33419728b 100644 --- a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordSubmitIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordSubmitIntegrationTests.swift @@ -68,10 +68,12 @@ final class MSALNativeAuthResetPasswordSubmitIntegrationTests: MSALNativeAuthInt ) } - func test_resetPasswordSubmit_invalidPasswordResetToken() async throws { + func test_resetPasswordSubmit_invalidContinuationToken() async throws { + throw XCTSkip() + try await perform_testFail( endpoint: .resetPasswordSubmit, - response: .invalidPasswordResetToken, + response: .invalidContinuationToken, expectedError: createError(.invalidRequest) ) } @@ -88,7 +90,7 @@ final class MSALNativeAuthResetPasswordSubmitIntegrationTests: MSALNativeAuthInt try await perform_testFail( endpoint: .resetPasswordSubmit, response: .passwordTooWeak, - expectedError: createError(.passwordTooWeak) + expectedError: createError(.invalidGrant, subError: .passwordTooWeak) ) } @@ -96,7 +98,7 @@ final class MSALNativeAuthResetPasswordSubmitIntegrationTests: MSALNativeAuthInt try await perform_testFail( endpoint: .resetPasswordSubmit, response: .passwordTooShort, - expectedError: createError(.passwordTooShort) + expectedError: createError(.invalidGrant, subError: .passwordTooShort) ) } @@ -104,7 +106,7 @@ final class MSALNativeAuthResetPasswordSubmitIntegrationTests: MSALNativeAuthInt try await perform_testFail( endpoint: .resetPasswordSubmit, response: .passwordTooLong, - expectedError: createError(.passwordTooLong) + expectedError: createError(.invalidGrant, subError: .passwordTooLong) ) } @@ -112,7 +114,7 @@ final class MSALNativeAuthResetPasswordSubmitIntegrationTests: MSALNativeAuthInt try await perform_testFail( endpoint: .resetPasswordSubmit, response: .passwordRecentlyUsed, - expectedError: createError(.passwordRecentlyUsed) + expectedError: createError(.invalidGrant, subError: .passwordRecentlyUsed) ) } @@ -120,13 +122,14 @@ final class MSALNativeAuthResetPasswordSubmitIntegrationTests: MSALNativeAuthInt try await perform_testFail( endpoint: .resetPasswordSubmit, response: .passwordBanned, - expectedError: createError(.passwordBanned) + expectedError: createError(.invalidGrant, subError: .passwordBanned) ) } - private func createError(_ error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode) -> MSALNativeAuthResetPasswordSubmitResponseError { + private func createError(_ error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil) -> MSALNativeAuthResetPasswordSubmitResponseError { .init( error: error, + subError: subError, errorDescription: nil, errorCodes: nil, errorURI: nil, diff --git a/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift index a31be910ee..679b9bb1f0 100644 --- a/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift @@ -78,7 +78,7 @@ class MSALNativeAuthSignInInitiateIntegrationTests: MSALNativeAuthIntegrationBas try await perform_testFail( endpoint: .signInInitiate, response: .userNotFound, - expectedError: Error(error: .invalidGrant, errorDescription: nil, errorCodes:[MSALNativeAuthESTSApiErrorCodes.userNotFound.rawValue], errorURI: nil, innerErrors: nil) + expectedError: Error(error: .userNotFound, errorDescription: nil, errorCodes:[MSALNativeAuthESTSApiErrorCodes.userNotFound.rawValue], errorURI: nil, innerErrors: nil) ) } diff --git a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift index a4a5bb8a65..6278a999dc 100644 --- a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift @@ -98,10 +98,12 @@ final class MSALNativeAuthSignUpChallengeIntegrationTests: MSALNativeAuthIntegra ) } - func test_signUpChallenge_invalidSignUpToken() async throws { + func test_signUpChallenge_invalidContinuationToken() async throws { + throw XCTSkip() + try await perform_testFail( endpoint: .signUpChallenge, - response: .invalidSignUpToken, + response: .invalidContinuationToken, expectedError: createError(.invalidRequest) ) } diff --git a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift index b6ad194afb..9ba5e81ad2 100644 --- a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift @@ -102,10 +102,12 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat ) } - func test_signUpContinue_invalidSignUpToken() async throws { + func test_signUpContinue_invalidContinuationToken() async throws { + throw XCTSkip() + try await perform_testFail( endpoint: .signUpContinue, - response: .invalidSignUpToken, + response: .invalidContinuationToken, expectedError: createError(.invalidRequest) ) } @@ -118,11 +120,11 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat ) } - func test_signUpContinue_explicitInvalidOOBValue() async throws { + func test_signUpContinue_invalidOOBValue() async throws { try await perform_testFail( endpoint: .signUpContinue, - response: .explicitInvalidOOBValue, - expectedError: createError(.invalidOOBValue) + response: .invalidOOBValue, + expectedError: createError(.invalidGrant, subError: .invalidOOBValue) ) } @@ -130,7 +132,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat try await perform_testFail( endpoint: .signUpContinue, response: .passwordTooWeak, - expectedError: createError(.passwordTooWeak) + expectedError: createError(.invalidGrant, subError: .passwordTooWeak) ) } @@ -138,7 +140,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat try await perform_testFail( endpoint: .signUpContinue, response: .passwordTooShort, - expectedError: createError(.passwordTooShort) + expectedError: createError(.invalidGrant, subError: .passwordTooShort) ) } @@ -146,7 +148,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat try await perform_testFail( endpoint: .signUpContinue, response: .passwordTooLong, - expectedError: createError(.passwordTooLong) + expectedError: createError(.invalidGrant, subError: .passwordTooLong) ) } @@ -154,7 +156,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat try await perform_testFail( endpoint: .signUpContinue, response: .passwordRecentlyUsed, - expectedError: createError(.passwordRecentlyUsed) + expectedError: createError(.invalidGrant, subError: .passwordRecentlyUsed) ) } @@ -162,7 +164,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat try await perform_testFail( endpoint: .signUpContinue, response: .passwordBanned, - expectedError: createError(.passwordBanned) + expectedError: createError(.invalidGrant, subError: .passwordBanned) ) } @@ -196,13 +198,16 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat } func test_signUpContinue_validationFailed() async throws { + throw XCTSkip() + let response = try await perform_testFail( endpoint: .signUpContinue, response: .attributeValidationFailed, - expectedError: createError(.attributeValidationFailed) + expectedError: createError(.invalidGrant, subError: .attributeValidationFailed) ) XCTAssertNotNil(response.continuationToken) + XCTAssertNotNil(response.invalidAttributes) } func test_signUpContinue_credentialRequired() async throws { @@ -221,12 +226,13 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat let response: MSALNativeAuthSignUpContinueResponse? = try await performTestSucceed() - XCTAssertNil(response?.continuationToken) + XCTAssertNotNil(response?.continuationToken) } - private func createError(_ error: MSALNativeAuthSignUpContinueOauth2ErrorCode) -> MSALNativeAuthSignUpContinueResponseError { + private func createError(_ error: MSALNativeAuthSignUpContinueOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil) -> MSALNativeAuthSignUpContinueResponseError { .init( error: error, + subError: subError, errorDescription: nil, errorCodes: nil, errorURI: nil, diff --git a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift index ca2758b48e..8090acf4f1 100644 --- a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift @@ -48,6 +48,13 @@ final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegration ) } + func test_whenSignUpStart_succeeds() async throws { + try await mockResponse(.signUpStartSuccess, endpoint: .signUpStart) + let response: MSALNativeAuthSignUpStartResponse? = try await performTestSucceed() + + XCTAssertNotNil(response?.continuationToken) + } + func test_whenSignUpStart_redirects() async throws { try await mockResponse(.challengeTypeRedirect, endpoint: .signUpStart) let response: MSALNativeAuthSignUpStartResponse? = try await performTestSucceed() @@ -78,7 +85,7 @@ final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegration try await perform_testFail( endpoint: .signUpStart, response: .passwordTooWeak, - expectedError: createError(.passwordTooWeak) + expectedError: createError(.invalidGrant, subError: .passwordTooWeak) ) } @@ -86,7 +93,7 @@ final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegration try await perform_testFail( endpoint: .signUpStart, response: .passwordTooShort, - expectedError: createError(.passwordTooShort) + expectedError: createError(.invalidGrant, subError: .passwordTooShort) ) } @@ -94,7 +101,7 @@ final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegration try await perform_testFail( endpoint: .signUpStart, response: .passwordTooLong, - expectedError: createError(.passwordTooLong) + expectedError: createError(.invalidGrant, subError: .passwordTooLong) ) } @@ -102,7 +109,7 @@ final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegration try await perform_testFail( endpoint: .signUpStart, response: .passwordRecentlyUsed, - expectedError: createError(.passwordRecentlyUsed) + expectedError: createError(.invalidGrant, subError: .passwordRecentlyUsed) ) } @@ -110,7 +117,7 @@ final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegration try await perform_testFail( endpoint: .signUpStart, response: .passwordBanned, - expectedError: createError(.passwordBanned) + expectedError: createError(.invalidGrant, subError: .passwordBanned) ) } @@ -132,40 +139,25 @@ final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegration XCTAssertNotNil(response.continuationToken) } - func test_signUpStart_verificationRequired() async throws { - let response = try await perform_testFail( - endpoint: .signUpStart, - response: .verificationRequired, - expectedError: createError(.verificationRequired) - ) - - XCTAssertNotNil(response.continuationToken) - XCTAssertNotNil(response.unverifiedAttributes) - } - func test_signUpStart_validationFailed() async throws { let response = try await perform_testFail( endpoint: .signUpStart, response: .attributeValidationFailed, - expectedError: createError(.attributeValidationFailed) + expectedError: createError(.invalidGrant, subError: .attributeValidationFailed) ) - XCTAssertNotNil(response.continuationToken) + XCTAssertNotNil(response.invalidAttributes) } func test_signUpStart_unsupportedAuthMethod() async throws { - throw XCTSkip() - try await perform_testFail( endpoint: .signUpStart, - response: .unsupportedAuthMethod, + response: .authNotSupported, expectedError: createError(.unsupportedAuthMethod) ) } func test_signUpStart_invalidRequest_withESTSErrorInvalidEmail() async throws { - throw XCTSkip() - try await perform_testFail( endpoint: .signUpStart, response: .invalidUsername, @@ -173,9 +165,10 @@ final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegration ) } - private func createError(_ error: MSALNativeAuthSignUpStartOauth2ErrorCode, errorCodes: [Int]? = nil) -> MSALNativeAuthSignUpStartResponseError { + private func createError(_ error: MSALNativeAuthSignUpStartOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, errorCodes: [Int]? = nil) -> MSALNativeAuthSignUpStartResponseError { .init( error: error, + subError: subError, errorDescription: nil, errorCodes: nil, errorURI: nil, diff --git a/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift index 209a22c4ff..1adfb53c08 100644 --- a/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift @@ -120,7 +120,7 @@ class MSALNativeAuthTokenIntegrationTests: MSALNativeAuthIntegrationBaseTests { try await perform_testFail( endpoint: .signInToken, response: .invalidPassword, - expectedError: Error(error: .invalidGrant, errorDescription: nil, errorCodes: [MSALNativeAuthESTSApiErrorCodes.invalidCredentials.rawValue], errorURI: nil, innerErrors: nil, continuationToken: nil) + expectedError: createError(.invalidGrant, subError: .passwordInvalid) ) } @@ -128,7 +128,7 @@ class MSALNativeAuthTokenIntegrationTests: MSALNativeAuthIntegrationBaseTests { try await perform_testFail( endpoint: .signInToken, response: .invalidOOBValue, - expectedError: Error(error: .invalidGrant, errorDescription: nil, errorCodes: [MSALNativeAuthESTSApiErrorCodes.invalidOTP.rawValue], errorURI: nil, innerErrors: nil, continuationToken: nil) + expectedError: createError(.invalidGrant, subError: .invalidOOBValue) ) } @@ -173,7 +173,7 @@ class MSALNativeAuthTokenIntegrationTests: MSALNativeAuthIntegrationBaseTests { XCTAssertEqual(result.error.rawValue, expectedError.error.rawValue) } - private func createError(_ code: MSALNativeAuthTokenOauth2ErrorCode) -> Error { - .init(error: code, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil) + private func createError(_ code: MSALNativeAuthTokenOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, errorCodes: [MSALNativeAuthESTSApiErrorCodes]? = nil) -> Error { + .init(error: code, subError: subError, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil) } } diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift index 716889d2e7..502b7827fa 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift @@ -477,6 +477,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() let error : MSALNativeAuthResetPasswordContinueValidatedResponse = .error( MSALNativeAuthResetPasswordContinueResponseError(error: .invalidRequest, + subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, @@ -567,7 +568,8 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() let error : MSALNativeAuthResetPasswordSubmitValidatedResponse = .passwordError(error: - MSALNativeAuthResetPasswordSubmitResponseError(error: .passwordTooWeak, + MSALNativeAuthResetPasswordSubmitResponseError(error: .invalidGrant, + subError: .passwordTooWeak, errorDescription: "Password too weak", errorCodes: nil, errorURI: nil, @@ -595,6 +597,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() let error : MSALNativeAuthResetPasswordSubmitValidatedResponse = .error( MSALNativeAuthResetPasswordSubmitResponseError(error: .invalidRequest, + subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, @@ -687,7 +690,8 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() let error : MSALNativeAuthResetPasswordPollCompletionValidatedResponse = .passwordError(error: - MSALNativeAuthResetPasswordPollCompletionResponseError(error: .passwordBanned, + MSALNativeAuthResetPasswordPollCompletionResponseError(error: .invalidGrant, + subError: .passwordBanned, errorDescription: "Password banned", errorCodes: nil, errorURI: nil, @@ -719,6 +723,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() let error : MSALNativeAuthResetPasswordPollCompletionValidatedResponse = .error( MSALNativeAuthResetPasswordPollCompletionResponseError(error: .expiredToken, + subError: nil, errorDescription: "Expired Token", errorCodes: nil, errorURI: nil, diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift index b7d39458d8..eef16ebe58 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift @@ -93,10 +93,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) } - func test_whenSignUpStartPassword_returnsVerificationRequired_it_returnsChallenge() async { + func test_whenSignUpStartPassword_returnsSuccess_it_callsChallenge() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -187,7 +187,8 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams let error : MSALNativeAuthSignUpStartValidatedResponse = .error( - MSALNativeAuthSignUpStartResponseError(error: .passwordTooLong, + MSALNativeAuthSignUpStartResponseError(error: .invalidGrant, + subError: .passwordTooLong, errorDescription: nil, errorCodes: nil, errorURI: nil, @@ -219,6 +220,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams let invalidUsername : MSALNativeAuthSignUpStartValidatedResponse = .invalidUsername( MSALNativeAuthSignUpStartResponseError(error: .invalidRequest, + subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, @@ -250,6 +252,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams let invalidClientId : MSALNativeAuthSignUpStartValidatedResponse = .invalidClientId( MSALNativeAuthSignUpStartResponseError(error: .invalidRequest, + subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, @@ -303,7 +306,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartPassword_challenge_cantCreateRequest_it_returns_unexpectedError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() @@ -327,7 +330,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartPassword_challenge_succeeds_it_continuesTheFlow() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "continuationToken 2")) @@ -353,7 +356,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartPassword_challenge_returns_passwordRequired_it_returnsCorrectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("")) @@ -378,7 +381,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartPassword_challenge_returns_redirect_it_returnsCorrectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.redirect) @@ -403,7 +406,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartPassword_challenge_returns_error_it_returnsCorrectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() let error : MSALNativeAuthSignUpChallengeValidatedResponse = .error( @@ -435,7 +438,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenValidatorInSignUpStartPassword_challenge_returns_unexpectedError_it_returnsGeneralError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -480,10 +483,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) } - func test_whenSignUpStartCode_returnsVerificationRequired_it_returnsChallenge() async { + func test_whenSignUpStartCode_returnsSuccess_it_returnsChallenge() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -573,6 +576,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams let error : MSALNativeAuthSignUpStartValidatedResponse = .error( MSALNativeAuthSignUpStartResponseError(error: .userAlreadyExists, + subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, @@ -604,6 +608,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams let invalidUsername : MSALNativeAuthSignUpStartValidatedResponse = .invalidUsername( MSALNativeAuthSignUpStartResponseError(error: .invalidRequest, + subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, @@ -635,6 +640,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams let invalidClientId : MSALNativeAuthSignUpStartValidatedResponse = .invalidClientId( MSALNativeAuthSignUpStartResponseError(error: .invalidRequest, + subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, @@ -688,7 +694,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartCode_challenge_cantCreateRequest_it_returns_unexpectedError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(nil, throwError: true) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() @@ -712,7 +718,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartCode_challenge_succeeds_it_continuesTheFlow() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken 1", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken 1")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 1") validatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "continuationToken 2")) @@ -738,7 +744,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartCode_challenge_succeedsPassword_it_returnsCorrectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("")) @@ -763,7 +769,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartCode_challenge_returns_redirect_it_returnsCorrectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.redirect) @@ -788,7 +794,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpStartCode_challenge_returns_error_it_returnsCorrectError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() let error : MSALNativeAuthSignUpChallengeValidatedResponse = .error( @@ -820,7 +826,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenValidatorInSignUpStartCode_challenge_it_returns_unexpectedError_returnsGeneralError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""])) + validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) @@ -1023,7 +1029,8 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitCode_returns_invalidUserInput_it_returnsInvalidCode() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) let error : MSALNativeAuthSignUpContinueValidatedResponse = .invalidUserInput( - MSALNativeAuthSignUpContinueResponseError(error: .invalidOOBValue, + MSALNativeAuthSignUpContinueResponseError(error: .invalidGrant, + subError: .invalidOOBValue, errorDescription: nil, errorCodes: nil, errorURI: nil, @@ -1100,7 +1107,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitCode_returns_attributeValidationFailed_returnsCorrectError() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() - validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(continuationToken: "continuationToken 2", invalidAttributes: ["name"])) + validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(invalidAttributes: ["name"])) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) @@ -1123,6 +1130,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() let error : MSALNativeAuthSignUpContinueValidatedResponse = .error( MSALNativeAuthSignUpContinueResponseError(error: .invalidRequest, + subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, @@ -1427,7 +1435,8 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) let error : MSALNativeAuthSignUpContinueValidatedResponse = .invalidUserInput( - MSALNativeAuthSignUpContinueResponseError(error: .passwordTooWeak, + MSALNativeAuthSignUpContinueResponseError(error: .invalidGrant, + subError: .passwordTooWeak, errorDescription: "Password too weak", errorCodes: nil, errorURI: nil, @@ -1503,6 +1512,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) let error : MSALNativeAuthSignUpContinueValidatedResponse = .error( MSALNativeAuthSignUpContinueResponseError(error: .invalidRequest, + subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, @@ -1571,7 +1581,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitPassword_returns_attributeValidationFailed_it_returnsCorrectError() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) - validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(continuationToken: "continuationToken 2", invalidAttributes: ["key"])) + validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(invalidAttributes: ["key"])) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) @@ -1643,7 +1653,8 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { attributes: ["key": "value"] ) let error : MSALNativeAuthSignUpContinueValidatedResponse = .invalidUserInput( - MSALNativeAuthSignUpContinueResponseError(error: .attributeValidationFailed, + MSALNativeAuthSignUpContinueResponseError(error: .invalidGrant, + subError: .attributeValidationFailed, errorDescription: nil, errorCodes: nil, errorURI: nil, @@ -1676,6 +1687,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { ) let error : MSALNativeAuthSignUpContinueValidatedResponse = .error( MSALNativeAuthSignUpContinueResponseError(error: .invalidRequest, + subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, @@ -1773,7 +1785,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { oobCode: nil, attributes: ["key": "value"] ) - validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(continuationToken: "continuationToken 2", invalidAttributes: ["attribute"])) + validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(invalidAttributes: ["attribute"])) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) @@ -1784,7 +1796,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { await fulfillment(of: [exp], timeout: 1) XCTAssertTrue(helper.onSignUpInvalidAttributesCalled) - XCTAssertEqual(helper.newState?.continuationToken, "continuationToken 2") + XCTAssertEqual(helper.newState?.continuationToken, "continuationToken") XCTAssertEqual(helper.invalidAttributes, ["attribute"]) checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitAttributes, isSuccessful: false) diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift index 735ab2f31a..632c299185 100644 --- a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift @@ -214,7 +214,7 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { wait(for: [expectation], timeout: 1) } - func test_shouldCompleteWithAPIErrorUsingCorrectResponseSerializer_whenStatusCode400AndVerificationRequired() throws { + func test_shouldCompleteWithAPIErrorUsingCorrectResponseSerializer_whenStatusCode400AndAttributesRequired() throws { let expectation = expectation(description: "Handle Error Retry Success") let httpResponse = HTTPURLResponse( @@ -227,8 +227,8 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { let httpRequest = MSALNativeAuthHTTPRequestMock.prepareMockRequest() var dictionary = [String: Any]() - dictionary["error"] = "verification_required" - dictionary["error_description"] = "AADSTS55102: Verification required." + dictionary["error"] = "attributes_required" + dictionary["error_description"] = "AADSTS55102: Attributes Required." dictionary["error_uri"] = HttpModuleMockConfigurator.baseUrl.absoluteString dictionary["continuation_token"] = "abcdef" @@ -249,8 +249,8 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { expectation.fulfill() return } - XCTAssertEqual(error.error, MSALNativeAuthSignUpStartOauth2ErrorCode.verificationRequired) - XCTAssertEqual(error.errorDescription, "AADSTS55102: Verification required.") + XCTAssertEqual(error.error, MSALNativeAuthSignUpStartOauth2ErrorCode.attributesRequired) + XCTAssertEqual(error.errorDescription, "AADSTS55102: Attributes Required.") XCTAssertEqual(error.errorURI, HttpModuleMockConfigurator.baseUrl.absoluteString) XCTAssertEqual(error.continuationToken, "abcdef") expectation.fulfill() diff --git a/MSAL/test/unit/native_auth/network/errors/MSALNativeAuthSubErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/MSALNativeAuthSubErrorCodeTests.swift new file mode 100644 index 0000000000..81e0ce2c3e --- /dev/null +++ b/MSAL/test/unit/native_auth/network/errors/MSALNativeAuthSubErrorCodeTests.swift @@ -0,0 +1,66 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import XCTest +@testable import MSAL + +final class MSALNativeAuthSubErrorCodeTests: XCTestCase { + private typealias sut = MSALNativeAuthSubErrorCode + + func test_allCases() { + XCTAssertEqual(sut.allCases.count, 8) + } + + func test_passwordTooWeak() { + XCTAssertEqual(sut.passwordTooWeak.rawValue, "password_too_weak") + } + + func test_passwordTooShort() { + XCTAssertEqual(sut.passwordTooShort.rawValue, "password_too_short") + } + + func test_passwordTooLong() { + XCTAssertEqual(sut.passwordTooLong.rawValue, "password_too_long") + } + + func test_passwordRecentlyUsed() { + XCTAssertEqual(sut.passwordRecentlyUsed.rawValue, "password_recently_used") + } + + func test_passwordBanned() { + XCTAssertEqual(sut.passwordBanned.rawValue, "password_banned") + } + + func test_passwordInvalid() { + XCTAssertEqual(sut.passwordInvalid.rawValue, "password_is_invalid") + } + + func test_attributeValidationFailed() { + XCTAssertEqual(sut.attributeValidationFailed.rawValue, "attribute_validation_failed") + } + + func test_invalidOOBValue() { + XCTAssertEqual(sut.invalidOOBValue.rawValue, "invalid_oob_value") + } +} diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift index 84a4c2080f..e03f6639bb 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift @@ -30,7 +30,7 @@ final class MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests: XCTestCase private typealias sut = MSALNativeAuthResetPasswordContinueOauth2ErrorCode func test_allCases() { - XCTAssertEqual(sut.allCases.count, 6) + XCTAssertEqual(sut.allCases.count, 5) } func test_invalidRequest() { @@ -52,8 +52,4 @@ final class MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests: XCTestCase func test_verificationRequired() { XCTAssertEqual(sut.verificationRequired.rawValue, "verification_required") } - - func test_invalidOOBValue() { - XCTAssertEqual(sut.invalidOOBValue.rawValue, "invalid_oob_value") - } } diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift index b19dee8fb9..a2a855459b 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift @@ -33,42 +33,42 @@ final class MSALNativeAuthResetPasswordContinueResponseErrorTests: XCTestCase { // MARK: - to toVerifyCodePublicError tests func test_toResetPasswordStartPublicError_invalidRequest() { - sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidRequest, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidRequest, subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, .generalError) XCTAssertNotNil(error.errorDescription) } func test_toResetPasswordStartPublicError_invalidClient() { - sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidClient, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidClient, subError: nil, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, .generalError) XCTAssertEqual(error.errorDescription, testDescription) } func test_toResetPasswordStartPublicError_invalidGrant() { - sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidGrant, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidGrant, subError: nil, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, .generalError) XCTAssertEqual(error.errorDescription, testDescription) } func test_toResetPasswordStartPublicError_expiredToken() { - sut = MSALNativeAuthResetPasswordContinueResponseError(error: .expiredToken, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .expiredToken, subError: nil, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, .generalError) XCTAssertEqual(error.errorDescription, testDescription) } func test_toResetPasswordStartPublicError_unsupportedChallengeType() { - sut = MSALNativeAuthResetPasswordContinueResponseError(error: .verificationRequired, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .verificationRequired, subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, .generalError) XCTAssertNotNil(error.errorDescription) } func test_toResetPasswordStartPublicError_invalidOOBValue() { - sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidOOBValue, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidGrant, subError: .invalidOOBValue, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, .invalidCode) XCTAssertNotNil(error.errorDescription) diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift index 08f96846c9..34fbc5c305 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift @@ -30,7 +30,11 @@ final class MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests: XCTes private typealias sut = MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode func test_allCases() { - XCTAssertEqual(sut.allCases.count, 9) + XCTAssertEqual(sut.allCases.count, 5) + } + + func test_invalidGrant() { + XCTAssertEqual(sut.invalidGrant.rawValue, "invalid_grant") } func test_invalidRequest() { @@ -45,26 +49,6 @@ final class MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests: XCTes XCTAssertEqual(sut.expiredToken.rawValue, "expired_token") } - func test_passwordTooWeak() { - XCTAssertEqual(sut.passwordTooWeak.rawValue, "password_too_weak") - } - - func test_passwordTooShort() { - XCTAssertEqual(sut.passwordTooShort.rawValue, "password_too_short") - } - - func test_passwordTooLong() { - XCTAssertEqual(sut.passwordTooLong.rawValue, "password_too_long") - } - - func test_passwordRecentlyUsed() { - XCTAssertEqual(sut.passwordRecentlyUsed.rawValue, "password_recently_used") - } - - func test_passwordBanned() { - XCTAssertEqual(sut.passwordBanned.rawValue, "password_banned") - } - func test_userNotFound() { XCTAssertEqual(sut.userNotFound.rawValue, "user_not_found") } diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift index 530d22ff92..ee34968f0b 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift @@ -45,23 +45,23 @@ final class MSALNativeAuthResetPasswordPollCompletionResponseErrorTests: XCTestC } func test_toPasswordRequiredPublicError_passwordTooWeak() { - testPasswordRequiredError(code: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword) + testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword) } func test_toPasswordRequiredPublicError_passwordTooShort() { - testPasswordRequiredError(code: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword) + testPasswordRequiredError(code: .invalidGrant,subError: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword) } func test_toPasswordRequiredPublicError_passwordTooLong() { - testPasswordRequiredError(code: .passwordTooLong, description: "General error", expectedErrorType: .invalidPassword) + testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooLong, description: "General error", expectedErrorType: .invalidPassword) } func test_toPasswordRequiredPublicError_passwordRecentlyUsed() { - testPasswordRequiredError(code: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword) + testPasswordRequiredError(code: .invalidGrant, subError: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword) } func test_toPasswordRequiredPublicError_passwordBanned() { - testPasswordRequiredError(code: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword) + testPasswordRequiredError(code: .invalidGrant, subError: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword) } func test_toPasswordRequiredPublicError_userNotFound() { @@ -70,8 +70,8 @@ final class MSALNativeAuthResetPasswordPollCompletionResponseErrorTests: XCTestC // MARK: private methods - private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) { - sut = MSALNativeAuthResetPasswordPollCompletionResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) + private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) { + sut = MSALNativeAuthResetPasswordPollCompletionResponseError(error: code, subError: subError, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) let error = sut.toPasswordRequiredPublicError() XCTAssertEqual(error.type, expectedErrorType) XCTAssertEqual(error.errorDescription, description) diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift index f259c2e515..f0476682fb 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift @@ -30,7 +30,7 @@ final class MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests: XCTestCase { private typealias sut = MSALNativeAuthResetPasswordSubmitOauth2ErrorCode func test_allCases() { - XCTAssertEqual(sut.allCases.count, 8) + XCTAssertEqual(sut.allCases.count, 4) } func test_invalidRequest() { @@ -44,24 +44,8 @@ final class MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests: XCTestCase { func test_expiredToken() { XCTAssertEqual(sut.expiredToken.rawValue, "expired_token") } - - func test_passwordTooWeak() { - XCTAssertEqual(sut.passwordTooWeak.rawValue, "password_too_weak") - } - - func test_passwordTooShort() { - XCTAssertEqual(sut.passwordTooShort.rawValue, "password_too_short") - } - - func test_passwordTooLong() { - XCTAssertEqual(sut.passwordTooLong.rawValue, "password_too_long") - } - - func test_passwordRecentlyUsed() { - XCTAssertEqual(sut.passwordRecentlyUsed.rawValue, "password_recently_used") - } - - func test_passwordBanned() { - XCTAssertEqual(sut.passwordBanned.rawValue, "password_banned") + + func test_invalidGrant() { + XCTAssertEqual(sut.invalidGrant.rawValue, "invalid_grant") } } diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift index 90f71a71b9..13a1438efc 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift @@ -45,29 +45,29 @@ final class MSALNativeAuthResetPasswordSubmitResponseErrorTests: XCTestCase { } func test_toPasswordRequiredPublicError_passwordTooWeak() { - testPasswordRequiredError(code: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword) + testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword) } func test_toPasswordRequiredPublicError_passwordTooShort() { - testPasswordRequiredError(code: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword) + testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword) } func test_toPasswordRequiredPublicError_passwordTooLong() { - testPasswordRequiredError(code: .passwordTooLong, description: "General error", expectedErrorType: .invalidPassword) + testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooLong, description: "General error", expectedErrorType: .invalidPassword) } func test_toPasswordRequiredPublicError_passwordRecentlyUsed() { - testPasswordRequiredError(code: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword) + testPasswordRequiredError(code: .invalidGrant, subError: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword) } func test_toPasswordRequiredPublicError_passwordBanned() { - testPasswordRequiredError(code: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword) + testPasswordRequiredError(code: .invalidGrant, subError: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword) } // MARK: private methods - private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) { - sut = MSALNativeAuthResetPasswordSubmitResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) + private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) { + sut = MSALNativeAuthResetPasswordSubmitResponseError(error: code, subError: subError, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) let error = sut.toPasswordRequiredPublicError() XCTAssertEqual(error.type, expectedErrorType) XCTAssertEqual(error.errorDescription, description) diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift index 90ee233b4a..d2e22c2bb4 100644 --- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift @@ -30,7 +30,7 @@ final class MSALNativeAuthSignUpContinueOauth2ErrorCodeTests: XCTestCase { private typealias sut = MSALNativeAuthSignUpContinueOauth2ErrorCode func test_allCases() { - XCTAssertEqual(sut.allCases.count, 15) + XCTAssertEqual(sut.allCases.count, 8) } func test_invalidRequest() { @@ -49,26 +49,6 @@ final class MSALNativeAuthSignUpContinueOauth2ErrorCodeTests: XCTestCase { XCTAssertEqual(sut.expiredToken.rawValue, "expired_token") } - func test_passwordTooWeak() { - XCTAssertEqual(sut.passwordTooWeak.rawValue, "password_too_weak") - } - - func test_passwordTooShort() { - XCTAssertEqual(sut.passwordTooShort.rawValue, "password_too_short") - } - - func test_passwordTooLong() { - XCTAssertEqual(sut.passwordTooLong.rawValue, "password_too_long") - } - - func test_passwordRecentlyUsed() { - XCTAssertEqual(sut.passwordRecentlyUsed.rawValue, "password_recently_used") - } - - func test_passwordBanned() { - XCTAssertEqual(sut.passwordBanned.rawValue, "password_banned") - } - func test_userAlreadyExists() { XCTAssertEqual(sut.userAlreadyExists.rawValue, "user_already_exists") } @@ -81,15 +61,7 @@ final class MSALNativeAuthSignUpContinueOauth2ErrorCodeTests: XCTestCase { XCTAssertEqual(sut.verificationRequired.rawValue, "verification_required") } - func test_attributeValidationFailed() { - XCTAssertEqual(sut.attributeValidationFailed.rawValue, "attribute_validation_failed") - } - func test_credentialRequired() { XCTAssertEqual(sut.credentialRequired.rawValue, "credential_required") } - - func test_invalidOOBValue() { - XCTAssertEqual(sut.invalidOOBValue.rawValue, "invalid_oob_value") - } } diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift index 663e2e4628..6891d2062f 100644 --- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift @@ -49,23 +49,23 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase { } func test_toVerifyCodePublicError_passwordTooWeak() { - testSignUpContinueErrorToVerifyCode(code: .passwordTooWeak, description: testDescription, expectedErrorType: .generalError) + testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordTooWeak, description: testDescription, expectedErrorType: .generalError) } func test_toVerifyCodePublicError_passwordTooShort() { - testSignUpContinueErrorToVerifyCode(code: .passwordTooShort, description: testDescription, expectedErrorType: .generalError) + testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordTooShort, description: testDescription, expectedErrorType: .generalError) } func test_toVerifyCodePublicError_passwordTooLong() { - testSignUpContinueErrorToVerifyCode(code: .passwordTooLong, description: testDescription, expectedErrorType: .generalError) + testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordTooLong, description: testDescription, expectedErrorType: .generalError) } func test_toVerifyCodePublicError_passwordRecentlyUsed() { - testSignUpContinueErrorToVerifyCode(code: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .generalError) + testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .generalError) } func test_toVerifyCodePublicError_passwordBanned() { - testSignUpContinueErrorToVerifyCode(code: .passwordBanned, description: testDescription, expectedErrorType: .generalError) + testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordBanned, description: testDescription, expectedErrorType: .generalError) } func test_toVerifyCodePublicError_userAlreadyExists() { @@ -81,7 +81,7 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase { } func test_toVerifyCodePublicError_attributeValidationFailed() { - testSignUpContinueErrorToVerifyCode(code: .attributeValidationFailed, description: testDescription, expectedErrorType: .generalError) + testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .attributeValidationFailed, description: testDescription, expectedErrorType: .generalError) } func test_toVerifyCodePublicError_credentialRequired() { @@ -89,7 +89,7 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase { } func test_toVerifyCodePublicError_invalidOOBValue() { - testSignUpContinueErrorToVerifyCode(code: .invalidOOBValue, description: testDescription, expectedErrorType: .invalidCode) + testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .invalidOOBValue, description: testDescription, expectedErrorType: .invalidCode) } // MARK: - toPasswordRequiredPublicError tests @@ -111,23 +111,23 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase { } func test_toPasswordRequiredPublicError_passwordTooWeak() { - testSignUpContinueErrorToPasswordRequired(code: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword) + testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword) } func test_toPasswordRequiredPublicError_passwordTooShort() { - testSignUpContinueErrorToPasswordRequired(code: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword) + testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword) } func test_toPasswordRequiredPublicError_passwordTooLong() { - testSignUpContinueErrorToPasswordRequired(code: .passwordTooLong, description: testDescription, expectedErrorType: .invalidPassword) + testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordTooLong, description: testDescription, expectedErrorType: .invalidPassword) } func test_toPasswordRequiredPublicError_passwordRecentlyUsed() { - testSignUpContinueErrorToPasswordRequired(code: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword) + testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword) } func test_toPasswordRequiredPublicError_passwordBanned() { - testSignUpContinueErrorToPasswordRequired(code: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword) + testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword) } func test_toPasswordRequiredPublicError_userAlreadyExists() { @@ -143,7 +143,7 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase { } func test_toPasswordRequiredPublicError_attributeValidationFailed() { - testSignUpContinueErrorToPasswordRequired(code: .attributeValidationFailed, description: testDescription, expectedErrorType: .generalError) + testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .attributeValidationFailed, description: testDescription, expectedErrorType: .generalError) } func test_toPasswordRequiredPublicError_credentialRequired() { @@ -151,7 +151,7 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase { } func test_toPasswordRequiredPublicError_invalidOOBValue() { - testSignUpContinueErrorToPasswordRequired(code: .invalidOOBValue, description: testDescription, expectedErrorType: .generalError) + testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .invalidOOBValue, description: testDescription, expectedErrorType: .generalError) } // MARK: - toAttributesRequiredPublicError tests @@ -173,23 +173,23 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase { } func test_toAttributesRequiredPublicError_passwordTooWeak() { - testSignUpContinueErrorToAttributesRequired(code: .passwordTooWeak, description: testDescription) + testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordTooWeak, description: testDescription) } func test_toAttributesRequiredPublicError_passwordTooShort() { - testSignUpContinueErrorToAttributesRequired(code: .passwordTooShort, description: testDescription) + testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordTooShort, description: testDescription) } func test_toAttributesRequiredPublicError_passwordTooLong() { - testSignUpContinueErrorToAttributesRequired(code: .passwordTooLong, description: testDescription) + testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordTooLong, description: testDescription) } func test_toAttributesRequiredPublicError_passwordRecentlyUsed() { - testSignUpContinueErrorToAttributesRequired(code: .passwordRecentlyUsed, description: testDescription) + testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordRecentlyUsed, description: testDescription) } func test_toAttributesRequiredPublicError_passwordBanned() { - testSignUpContinueErrorToAttributesRequired(code: .passwordBanned, description: testDescription) + testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordBanned, description: testDescription) } func test_toAttributesRequiredPublicError_userAlreadyExists() { @@ -205,7 +205,7 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase { } func test_toAttributesRequiredPublicError_attributeValidationFailed() { - testSignUpContinueErrorToAttributesRequired(code: .attributeValidationFailed, description: testDescription) + testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .attributeValidationFailed, description: testDescription) } func test_toAttributesRequiredPublicError_credentialRequired() { @@ -213,27 +213,27 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase { } func test_toAttributesRequiredPublicError_invalidOOBValue() { - testSignUpContinueErrorToAttributesRequired(code: .invalidOOBValue, description: testDescription) + testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .invalidOOBValue, description: testDescription) } // MARK: private methods - private func testSignUpContinueErrorToVerifyCode(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, description: String?, expectedErrorType: VerifyCodeError.ErrorType) { - sut = MSALNativeAuthSignUpContinueResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) + private func testSignUpContinueErrorToVerifyCode(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, description: String?, expectedErrorType: VerifyCodeError.ErrorType) { + sut = MSALNativeAuthSignUpContinueResponseError(error: code, subError: subError, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, expectedErrorType) XCTAssertEqual(error.errorDescription, description) } - private func testSignUpContinueErrorToPasswordRequired(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) { - sut = MSALNativeAuthSignUpContinueResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) + private func testSignUpContinueErrorToPasswordRequired(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) { + sut = MSALNativeAuthSignUpContinueResponseError(error: code, subError: subError, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) let error = sut.toPasswordRequiredPublicError() XCTAssertEqual(error.type, expectedErrorType) XCTAssertEqual(error.errorDescription, description) } - private func testSignUpContinueErrorToAttributesRequired(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, description: String?) { - sut = MSALNativeAuthSignUpContinueResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) + private func testSignUpContinueErrorToAttributesRequired(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, description: String?) { + sut = MSALNativeAuthSignUpContinueResponseError(error: code, subError: subError, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil) let error = sut.toAttributesRequiredPublicError() XCTAssertEqual(error.errorDescription, description) } diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift index 941f799bb6..01829d6761 100644 --- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift @@ -30,7 +30,11 @@ final class MSALNativeAuthSignUpStartOauth2ErrorCodeTests: XCTestCase { private typealias sut = MSALNativeAuthSignUpStartOauth2ErrorCode func test_allCases() { - XCTAssertEqual(sut.allCases.count, 13) + XCTAssertEqual(sut.allCases.count, 7) + } + + func test_invalidGrant() { + XCTAssertEqual(sut.invalidGrant.rawValue, "invalid_grant") } func test_invalidRequest() { @@ -45,26 +49,6 @@ final class MSALNativeAuthSignUpStartOauth2ErrorCodeTests: XCTestCase { XCTAssertEqual(sut.unsupportedChallengeType.rawValue, "unsupported_challenge_type") } - func test_passwordTooWeak() { - XCTAssertEqual(sut.passwordTooWeak.rawValue, "password_too_weak") - } - - func test_passwordTooShort() { - XCTAssertEqual(sut.passwordTooShort.rawValue, "password_too_short") - } - - func test_passwordTooLong() { - XCTAssertEqual(sut.passwordTooLong.rawValue, "password_too_long") - } - - func test_passwordRecentlyUsed() { - XCTAssertEqual(sut.passwordRecentlyUsed.rawValue, "password_recently_used") - } - - func test_passwordBanned() { - XCTAssertEqual(sut.passwordBanned.rawValue, "password_banned") - } - func test_userAlreadyExists() { XCTAssertEqual(sut.userAlreadyExists.rawValue, "user_already_exists") } @@ -72,16 +56,8 @@ final class MSALNativeAuthSignUpStartOauth2ErrorCodeTests: XCTestCase { func test_attributesRequired() { XCTAssertEqual(sut.attributesRequired.rawValue, "attributes_required") } - - func test_verificationRequired() { - XCTAssertEqual(sut.verificationRequired.rawValue, "verification_required") - } func test_unsupportedAuthMethod() { XCTAssertEqual(sut.unsupportedAuthMethod.rawValue, "unsupported_auth_method") } - - func test_attributeValidationFailed() { - XCTAssertEqual(sut.attributeValidationFailed.rawValue, "attribute_validation_failed") - } } diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift index 3f5ec7d6e3..811cb04ad7 100644 --- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift @@ -45,23 +45,23 @@ final class MSALNativeAuthSignUpStartResponseErrorTests: XCTestCase { } func test_toSignUpStartPublicError_passwordTooWeak() { - testSignUpStartErrorToSignUpStart(code: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword) + testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword) } func test_toSignUpStartPublicError_passwordTooShort() { - testSignUpStartErrorToSignUpStart(code: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword) + testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword) } func test_toSignUpStartPublicError_passwordTooLong() { - testSignUpStartErrorToSignUpStart(code: .passwordTooLong, description: testDescription, expectedErrorType: .invalidPassword) + testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordTooLong, description: testDescription, expectedErrorType: .invalidPassword) } func test_toSignUpStartPublicError_passwordRecentlyUsed() { - testSignUpStartErrorToSignUpStart(code: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword) + testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword) } func test_toSignUpStartPublicError_passwordBanned() { - testSignUpStartErrorToSignUpStart(code: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword) + testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword) } func test_toSignUpStartPublicError_userAlreadyExists() { @@ -72,22 +72,18 @@ final class MSALNativeAuthSignUpStartResponseErrorTests: XCTestCase { testSignUpStartErrorToSignUpStart(code: .attributesRequired, description: testDescription, expectedErrorType: .generalError) } - func test_toSignUpStartPublicError_verificationRequired() { - testSignUpStartErrorToSignUpStart(code: .verificationRequired, description: testDescription, expectedErrorType: .generalError) - } - func test_toSignUpStartPublicError_unsupportedAuthMethod() { testSignUpStartErrorToSignUpStart(code: .unsupportedAuthMethod, description: testDescription, expectedErrorType: .generalError) } func test_toSignUpStartPublicError_attributeValidationFailed() { - testSignUpStartErrorToSignUpStart(code: .attributeValidationFailed, description: testDescription, expectedErrorType: .generalError) + testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .attributeValidationFailed, description: testDescription, expectedErrorType: .generalError) } // MARK: private methods - private func testSignUpStartErrorToSignUpStart(code: MSALNativeAuthSignUpStartOauth2ErrorCode, description: String?, expectedErrorType: SignUpStartError.ErrorType) { - sut = MSALNativeAuthSignUpStartResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, unverifiedAttributes: nil, invalidAttributes: nil) + private func testSignUpStartErrorToSignUpStart(code: MSALNativeAuthSignUpStartOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, description: String?, expectedErrorType: SignUpStartError.ErrorType) { + sut = MSALNativeAuthSignUpStartResponseError(error: code, subError: subError, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, unverifiedAttributes: nil, invalidAttributes: nil) let error = sut.toSignUpStartPublicError() XCTAssertEqual(error.type, expectedErrorType) XCTAssertEqual(error.errorDescription, description) diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift index 5e3d92b524..be125739a7 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift @@ -254,7 +254,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } func test_whenResetPasswordContinueErrorResponseIs_invalidOOBValue_itReturnsExpectedError() { - let result = buildContinueErrorResponse(expectedError: .invalidOOBValue) + let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .invalidOOBValue) XCTAssertEqual(result, .invalidOOB) } @@ -325,56 +325,56 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } func test_whenResetPasswordSubmitErrorResponseIs_passwordTooWeak_itReturnsExpectedError() { - let result = buildSubmitErrorResponse(expectedError: .passwordTooWeak) + let result = buildSubmitErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordTooWeak) guard case .passwordError(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordTooWeak = error.error {} else { + if case .passwordTooWeak = error.subError {} else { XCTFail("Unexpected error: \(error.error)") } } func test_whenResetPasswordSubmitErrorResponseIs_passwordTooShort_itReturnsExpectedError() { - let result = buildSubmitErrorResponse(expectedError: .passwordTooShort) + let result = buildSubmitErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordTooShort) guard case .passwordError(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordTooShort = error.error {} else { + if case .passwordTooShort = error.subError {} else { XCTFail("Unexpected error: \(error.error)") } } func test_whenResetPasswordSubmitErrorResponseIs_passwordTooLong_itReturnsExpectedError() { - let result = buildSubmitErrorResponse(expectedError: .passwordTooLong) + let result = buildSubmitErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordTooLong) guard case .passwordError(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordTooLong = error.error {} else { + if case .passwordTooLong = error.subError {} else { XCTFail("Unexpected error: \(error.error)") } } func test_whenResetPasswordSubmitErrorResponseIs_passwordRecentlyUsed_itReturnsExpectedError() { - let result = buildSubmitErrorResponse(expectedError: .passwordRecentlyUsed) + let result = buildSubmitErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordRecentlyUsed) guard case .passwordError(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordRecentlyUsed = error.error {} else { + if case .passwordRecentlyUsed = error.subError {} else { XCTFail("Unexpected error: \(error.error)") } } func test_whenResetPasswordSubmitErrorResponseIs_passwordBanned_itReturnsExpectedError() { - let result = buildSubmitErrorResponse(expectedError: .passwordBanned) + let result = buildSubmitErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordBanned) guard case .passwordError(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordBanned = error.error {} else { + if case .passwordBanned = error.subError {} else { XCTFail("Unexpected error: \(error.error)") } } @@ -435,56 +435,56 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } func test_whenResetPasswordPollCompletionErrorResponseIsPasswordTooWeak_itReturnsExpectedError() { - let result = buildPollCompletionErrorResponse(expectedError: .passwordTooWeak) + let result = buildPollCompletionErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordTooWeak) guard case .passwordError(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordTooWeak = error.error {} else { + if case .passwordTooWeak = error.subError {} else { XCTFail("Unexpected error: \(error.error)") } } func test_whenResetPasswordPollCompletionErrorResponseIsPasswordTooShort_itReturnsExpectedError() { - let result = buildPollCompletionErrorResponse(expectedError: .passwordTooShort) + let result = buildPollCompletionErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordTooShort) guard case .passwordError(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordTooShort = error.error {} else { + if case .passwordTooShort = error.subError {} else { XCTFail("Unexpected error: \(error.error)") } } func test_whenResetPasswordPollCompletionErrorResponseIsPasswordTooLong_itReturnsExpectedError() { - let result = buildPollCompletionErrorResponse(expectedError: .passwordTooLong) + let result = buildPollCompletionErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordTooLong) guard case .passwordError(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordTooLong = error.error {} else { + if case .passwordTooLong = error.subError {} else { XCTFail("Unexpected error: \(error.error)") } } func test_whenResetPasswordPollCompletionErrorResponseIsPasswordRecentlyUsed_itReturnsExpectedError() { - let result = buildPollCompletionErrorResponse(expectedError: .passwordRecentlyUsed) + let result = buildPollCompletionErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordRecentlyUsed) guard case .passwordError(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordRecentlyUsed = error.error {} else { + if case .passwordRecentlyUsed = error.subError {} else { XCTFail("Unexpected error: \(error.error)") } } func test_whenResetPasswordPollCompletionErrorResponseIsPasswordBanned_itReturnsExpectedError() { - let result = buildPollCompletionErrorResponse(expectedError: .passwordBanned) + let result = buildPollCompletionErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordBanned) guard case .passwordError(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordBanned = error.error {} else { + if case .passwordBanned = error.subError {} else { XCTFail("Unexpected error: \(error.error)") } } @@ -533,11 +533,13 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { private func buildContinueErrorResponse( expectedError: MSALNativeAuthResetPasswordContinueOauth2ErrorCode, + expectedSubError: MSALNativeAuthSubErrorCode? = nil, expectedContinuationToken: String? = nil ) -> MSALNativeAuthResetPasswordContinueValidatedResponse { let response: Result = .failure( createResetPasswordContinueError( error: expectedError, + subError: expectedSubError, continuationToken: expectedContinuationToken ) ) @@ -546,11 +548,13 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } private func buildSubmitErrorResponse( - expectedError: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode + expectedError: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode, + expectedSubError: MSALNativeAuthSubErrorCode? = nil ) -> MSALNativeAuthResetPasswordSubmitValidatedResponse { let response: Result = .failure( createResetPasswordSubmitError( - error: expectedError + error: expectedError, + subError: expectedSubError ) ) @@ -558,11 +562,13 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } private func buildPollCompletionErrorResponse( - expectedError: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode + expectedError: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode, + expectedSubError: MSALNativeAuthSubErrorCode? = nil ) -> MSALNativeAuthResetPasswordPollCompletionValidatedResponse { let response: Result = .failure( createResetPasswordPollCompletionError( - error: expectedError + error: expectedError, + subError: expectedSubError ) ) @@ -607,6 +613,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { private func createResetPasswordContinueError( error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode, + subError: MSALNativeAuthSubErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, errorURI: String? = nil, @@ -616,6 +623,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { ) -> MSALNativeAuthResetPasswordContinueResponseError { .init( error: error, + subError: subError, errorDescription: errorDescription, errorCodes: errorCodes, errorURI: errorURI, @@ -627,6 +635,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { private func createResetPasswordSubmitError( error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode, + subError: MSALNativeAuthSubErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, errorURI: String? = nil, @@ -635,6 +644,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { ) -> MSALNativeAuthResetPasswordSubmitResponseError { .init( error: error, + subError: subError, errorDescription: errorDescription, errorCodes: errorCodes, errorURI: errorURI, @@ -645,6 +655,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { private func createResetPasswordPollCompletionError( error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode, + subError: MSALNativeAuthSubErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, errorURI: String? = nil, @@ -653,6 +664,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { ) -> MSALNativeAuthResetPasswordPollCompletionResponseError { .init( error: error, + subError: subError, errorDescription: errorDescription, errorCodes: errorCodes, errorURI: errorURI, diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift index 79a4963a5a..d2f5ca8ea8 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift @@ -65,51 +65,22 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { XCTAssertEqual(result, .unexpectedError) } - func test_whenSignUpStart_verificationRequiredErrorWithSignUpTokenAndUnverifiedAttributes_it_returns_verificationRequired() { - let error = createSignUpStartError( - error: .verificationRequired, - continuationToken: "continuation-token", - unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes(name: "username")] - ) - let response: Result = .failure(error) + func test_whenSignUpStart_succeedsWithContinuationToken_it_returns_success() { + let response: Result = .success(.init(continuationToken: "continuation-token", challengeType: nil)) let result = sut.validate(response, with: context) - guard case .verificationRequired(let continuationToken, let unverifiedAttributes) = result else { + guard case let .success(continuationToken) = result else { return XCTFail("Unexpected response") } XCTAssertEqual(continuationToken, "continuation-token") - XCTAssertEqual(unverifiedAttributes.first, "username") - } - - func test_whenSignUpStart_verificationRequiredErrorWithSignUpToken_but_unverifiedAttributesIsEmpty_it_returns_unexpectedError() { - let error = createSignUpStartError( - error: .verificationRequired, - continuationToken: "continuation-token", - unverifiedAttributes: [] - ) - let response: Result = .failure(error) - - let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) - } - - func test_whenSignUpStart_verificationRequiredErrorWithSignUpToken_but_unverifiedAttributesIsNil_it_returns_unexpectedError() { - let error = createSignUpStartError( - error: .verificationRequired, - continuationToken: "continuation-token", - unverifiedAttributes: nil - ) - let response: Result = .failure(error) - - let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) } - func test_whenSignUpStart_attributeValidationFailedWithSignUpTokenAndInvalidAttributes_it_returns_attributeValidationFailed() { + func test_whenSignUpStart_attributeValidationFailed_it_returns_attributeValidationFailed() { let error = createSignUpStartError( - error: .attributeValidationFailed, + error: .invalidGrant, + subError: .attributeValidationFailed, invalidAttributes: [MSALNativeAuthErrorBasicAttributes(name: "city")] ) let response: Result = .failure(error) @@ -123,9 +94,10 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { XCTAssertEqual(invalidAttributes.first, "city") } - func test_whenSignUpStart_attributeValidationFailedWithSignUpToken_but_invalidAttributesIsEmpty_it_returns_attributeValidationFailed() { + func test_whenSignUpStart_attributeValidationFailed_but_invalidAttributesIsEmpty_it_returns_attributeValidationFailed() { let error = createSignUpStartError( - error: .attributeValidationFailed, + error: .invalidGrant, + subError: .attributeValidationFailed, invalidAttributes: [] ) let response: Result = .failure(error) @@ -134,9 +106,10 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { XCTAssertEqual(result, .unexpectedError) } - func test_whenSignUpStart_attributeValidationFailedWithSignUpToken_but_invalidAttributesIsNil_it_returns_attributeValidationFailed() { + func test_whenSignUpStart_attributeValidationFailed_but_invalidAttributesIsNil_it_returns_attributeValidationFailed() { let error = createSignUpStartError( - error: .verificationRequired, + error: .invalidGrant, + subError: .attributeValidationFailed, invalidAttributes: nil ) let response: Result = .failure(error) @@ -145,14 +118,6 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { XCTAssertEqual(result, .unexpectedError) } - func test_whenSignUpStart_expectedVerificationRequiredErrorWithoutSignUpToken_it_returns_unexpectedError() { - let error = createSignUpStartError(error: .verificationRequired, continuationToken: nil) - let response: Result = .failure(error) - - let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) - } - func test_whenSignUpStartErrorResponseIsExpected_it_returns_error() { let error = createSignUpStartError(error: .userAlreadyExists) let response: Result = .failure(error) @@ -411,143 +376,118 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpContinueErrorResponseIs_invalidOOBValue_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .invalidOOBValue, expectedContinuationToken: "continuation-token") + let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .invalidOOBValue, expectedContinuationToken: "continuation-token") guard case .invalidUserInput(let error) = result else { return XCTFail("Unexpected response") } - if case .invalidOOBValue = error.error {} else { + if case .invalidGrant = error.error {} else { XCTFail("Unexpected error: \(error.error)") } + if case .invalidOOBValue = error.subError {} else { + XCTFail("Unexpected suberror: \(String(describing: error.subError))") + } } func test_whenSignUpContinueErrorResponseIs_passwordTooWeak_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .passwordTooWeak, expectedContinuationToken: "continuation-token") + let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordTooWeak, expectedContinuationToken: "continuation-token") guard case .invalidUserInput(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordTooWeak = error.error {} else { + if case .invalidGrant = error.error {} else { XCTFail("Unexpected error: \(error.error)") } + if case .passwordTooWeak = error.subError {} else { + XCTFail("Unexpected suberror: \(String(describing: error.subError))") + } } func test_whenSignUpContinueErrorResponseIs_passwordTooShort_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .passwordTooShort, expectedContinuationToken: "continuation-token") + let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordTooShort, expectedContinuationToken: "continuation-token") guard case .invalidUserInput(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordTooShort = error.error {} else { + if case .invalidGrant = error.error {} else { XCTFail("Unexpected error: \(error.error)") } + if case .passwordTooShort = error.subError {} else { + XCTFail("Unexpected suberror: \(String(describing: error.subError))") + } } func test_whenSignUpContinueErrorResponseIs_passwordTooLong_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .passwordTooLong, expectedContinuationToken: "continuation-token") + let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordTooLong, expectedContinuationToken: "continuation-token") guard case .invalidUserInput(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordTooLong = error.error {} else { + if case .invalidGrant = error.error {} else { XCTFail("Unexpected error: \(error.error)") } + if case .passwordTooLong = error.subError {} else { + XCTFail("Unexpected suberror: \(String(describing: error.subError))") + } } func test_whenSignUpContinueErrorResponseIs_passwordRecentlyUsed_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .passwordRecentlyUsed, expectedContinuationToken: "continuation-token") + let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordRecentlyUsed, expectedContinuationToken: "continuation-token") guard case .invalidUserInput(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordRecentlyUsed = error.error {} else { + if case .invalidGrant = error.error {} else { XCTFail("Unexpected error: \(error.error)") } + if case .passwordRecentlyUsed = error.subError {} else { + XCTFail("Unexpected suberror: \(String(describing: error.subError))") + } } func test_whenSignUpContinueErrorResponseIs_passwordBanned_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .passwordBanned, expectedContinuationToken: "continuation-token") + let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .passwordBanned, expectedContinuationToken: "continuation-token") guard case .invalidUserInput(let error) = result else { return XCTFail("Unexpected response") } - if case .passwordBanned = error.error {} else { + if case .invalidGrant = error.error {} else { XCTFail("Unexpected error: \(error.error)") } + if case .passwordBanned = error.subError {} else { + XCTFail("Unexpected suberror: \(String(describing: error.subError))") + } } func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .attributeValidationFailed, expectedContinuationToken: "continuation-token", invalidAttributes: [MSALNativeAuthErrorBasicAttributes(name: "email")]) + let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .attributeValidationFailed, invalidAttributes: [MSALNativeAuthErrorBasicAttributes(name: "email")]) - guard case .attributeValidationFailed(let continuationToken, let invalidAttributes) = result else { + guard case .attributeValidationFailed(let invalidAttributes) = result else { return XCTFail("Unexpected response") } - XCTAssertEqual(continuationToken, "continuation-token") XCTAssertEqual(invalidAttributes.first, "email") } - func test_whenSignUpContinueErrorResponseIs_invalidRequestWithInvalidOTPErrorCode_it_returns_expectedError() { - let continuationToken = "continuation-token" - var errorCodes = [MSALNativeAuthESTSApiErrorCodes.invalidOTP.rawValue, Int.max] - var result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedContinuationToken: continuationToken, errorCodes: errorCodes) - checkInvalidOOBValue() - errorCodes = [MSALNativeAuthESTSApiErrorCodes.incorrectOTP.rawValue] - result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedContinuationToken: continuationToken, errorCodes: errorCodes) - checkInvalidOOBValue() - errorCodes = [MSALNativeAuthESTSApiErrorCodes.OTPNoCacheEntryForUser.rawValue] - result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedContinuationToken: continuationToken, errorCodes: errorCodes) - checkInvalidOOBValue() - func checkInvalidOOBValue() { - guard case .invalidUserInput(let error) = result else { - return XCTFail("Unexpected response") - } - if case .invalidOOBValue = error.error {} else { - XCTFail("Unexpected error: \(error.error)") - } - XCTAssertNil(error.errorDescription) - XCTAssertNil(error.errorURI) - XCTAssertNil(error.innerErrors) - XCTAssertEqual(error.continuationToken, continuationToken) - XCTAssertNil(error.requiredAttributes) - XCTAssertNil(error.unverifiedAttributes) - XCTAssertNil(error.invalidAttributes) - XCTAssertEqual(error.errorCodes, errorCodes) + func test_whenSignUpContinueErrorResponseIs_invalidRequest_it_returns_generalError() { + let result = buildContinueErrorResponse(expectedError: .invalidRequest) + + guard case .error(let error) = result else { + return XCTFail("Unexpected response") } - } - - func test_whenSignUpContinueErrorResponseIs_invalidRequestWithGenericErrorCode_it_returns_expectedError() { - var result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedContinuationToken: "continuation-token", errorCodes: [MSALNativeAuthESTSApiErrorCodes.strongAuthRequired.rawValue]) - checkValidatedErrorResult() - result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedContinuationToken: "continuation-token", errorCodes: [Int.max]) - checkValidatedErrorResult() - result = buildContinueErrorResponse(expectedError: .invalidRequest, expectedContinuationToken: "continuation-token", errorCodes: [MSALNativeAuthESTSApiErrorCodes.userNotHaveAPassword.rawValue]) - checkValidatedErrorResult() - func checkValidatedErrorResult() { - guard case .error(let error) = result else { - return XCTFail("Unexpected response") - } - if case .invalidRequest = error.error {} else { - XCTFail("Unexpected error: \(error.error)") - } + if case .invalidRequest = error.error {} else { + XCTFail("Unexpected error: \(error.error)") } } - - - func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_but_continuationTokenIsNil_it_returns_unexpectedError() { - let result = buildContinueErrorResponse(expectedError: .attributeValidationFailed, expectedContinuationToken: nil, invalidAttributes: [MSALNativeAuthErrorBasicAttributes(name: "email")]) - - XCTAssertEqual(result, .unexpectedError) - } func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_but_invalidAttributesIsNil_it_returns_unexpectedError() { - let result = buildContinueErrorResponse(expectedError: .attributeValidationFailed, invalidAttributes: nil) + let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .attributeValidationFailed, invalidAttributes: nil) XCTAssertEqual(result, .unexpectedError) } func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_but_invalidAttributesIsEmpty_it_returns_unexpectedError() { - let result = buildContinueErrorResponse(expectedError: .attributeValidationFailed, invalidAttributes: []) + let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .attributeValidationFailed, invalidAttributes: []) XCTAssertEqual(result, .unexpectedError) } @@ -660,6 +600,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { private func buildContinueErrorResponse( expectedError: MSALNativeAuthSignUpContinueOauth2ErrorCode, + expectedSubError: MSALNativeAuthSubErrorCode? = nil, expectedContinuationToken: String? = nil, requiredAttributes: [MSALNativeAuthRequiredAttributesInternal]? = nil, invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil, @@ -668,6 +609,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { let response: Result = .failure( createSignUpContinueError( error: expectedError, + subError: expectedSubError, errorCodes: errorCodes, continuationToken: expectedContinuationToken, requiredAttributes: requiredAttributes, @@ -680,6 +622,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { private func createSignUpStartError( error: MSALNativeAuthSignUpStartOauth2ErrorCode, + subError: MSALNativeAuthSubErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, errorURI: String? = nil, @@ -690,6 +633,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { ) -> MSALNativeAuthSignUpStartResponseError { .init( error: error, + subError: subError, errorDescription: errorDescription, errorCodes: errorCodes, errorURI: errorURI, @@ -718,6 +662,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { private func createSignUpContinueError( error: MSALNativeAuthSignUpContinueOauth2ErrorCode, + subError: MSALNativeAuthSubErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, errorURI: String? = nil, @@ -729,6 +674,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { ) -> MSALNativeAuthSignUpContinueResponseError { .init( error: error, + subError: subError, errorDescription: errorDescription, errorCodes: errorCodes, errorURI: errorURI, diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift index cc335bf46e..34d48ec1af 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift @@ -88,7 +88,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { let errorCodes: [Int] = [unknownErrorCode1, unknownErrorCode2] - let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, errorDescription: nil, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil) + let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, subError: nil, errorDescription: nil, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil) let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) @@ -103,8 +103,8 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { } func test_invalidClient_isProperlyHandled() { - let error = MSALNativeAuthTokenResponseError(error: .invalidClient, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil) - + let error = MSALNativeAuthTokenResponseError(error: .invalidClient, subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil) + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) @@ -118,8 +118,8 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { } func test_unauthorizedClient_isProperlyHandled() { - let error = MSALNativeAuthTokenResponseError(error: .unauthorizedClient, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil) - + let error = MSALNativeAuthTokenResponseError(error: .unauthorizedClient, subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil) + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) @@ -142,18 +142,6 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { guard case .userNotFound(message: description) = checkErrorCodes() else { return XCTFail("Unexpected Error") } - errorCodes = [MSALNativeAuthESTSApiErrorCodes.invalidOTP.rawValue, unknownErrorCode1, unknownErrorCode2] - guard case .invalidOOBCode(message: description) = checkErrorCodes() else { - return XCTFail("Unexpected Error") - } - errorCodes = [MSALNativeAuthESTSApiErrorCodes.incorrectOTP.rawValue, unknownErrorCode1, unknownErrorCode2] - guard case .invalidOOBCode(message: description) = checkErrorCodes() else { - return XCTFail("Unexpected Error") - } - errorCodes = [MSALNativeAuthESTSApiErrorCodes.OTPNoCacheEntryForUser.rawValue, unknownErrorCode1, unknownErrorCode2] - guard case .invalidOOBCode(message: description) = checkErrorCodes() else { - return XCTFail("Unexpected Error") - } errorCodes = [MSALNativeAuthESTSApiErrorCodes.strongAuthRequired.rawValue, unknownErrorCode1, unknownErrorCode2] guard case .strongAuthRequired(message: description) = checkErrorCodes() else { return XCTFail("Unexpected Error") @@ -171,8 +159,8 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { return XCTFail("Unexpected Error") } func checkErrorCodes() -> MSALNativeAuthTokenValidatedErrorType? { - let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil) - + let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, subError: nil, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil) + let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) guard case .error(let innerError) = result else { @@ -191,8 +179,8 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { let errorCodes: [Int] = [unknownErrorCode1, knownErrorCode, unknownErrorCode2] - let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, errorDescription: nil, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil) - + let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, subError: nil, errorDescription: nil, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil) + let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) guard case .error(let innerError) = result else { @@ -204,31 +192,6 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { } } - func test_invalidRequesTokenResponse_withOTPErrorCodes_isTranslatedToInvalidCode() { - let unknownErrorCode1 = Int.max - var errorCodes: [Int] = [MSALNativeAuthESTSApiErrorCodes.invalidOTP.rawValue, unknownErrorCode1] - checkErrorCodes() - errorCodes = [MSALNativeAuthESTSApiErrorCodes.incorrectOTP.rawValue, unknownErrorCode1] - checkErrorCodes() - errorCodes = [MSALNativeAuthESTSApiErrorCodes.OTPNoCacheEntryForUser.rawValue, unknownErrorCode1] - checkErrorCodes() - func checkErrorCodes() { - let description = "description" - let error = MSALNativeAuthTokenResponseError(error: .invalidRequest, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil) - - let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) - let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) - - guard case .error(let innerError) = result else { - return XCTFail("Unexpected response") - } - - guard case .invalidOOBCode(message: description) = innerError else { - return XCTFail("Unexpected Error") - } - } - } - func test_invalidRequesTokenResponse_withGenericErrorCode_isTranslatedToGeneralError() { let description = "description" let unknownErrorCode1 = Int.max @@ -239,8 +202,8 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { errorCodes = [MSALNativeAuthESTSApiErrorCodes.userNotFound.rawValue] checkErrorCodes() func checkErrorCodes() { - let error = MSALNativeAuthTokenResponseError(error: .invalidRequest, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil) - + let error = MSALNativeAuthTokenResponseError(error: .invalidRequest, subError: nil, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil) + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift index 6c6f53539c..e37ee516ff 100644 --- a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift +++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift @@ -549,7 +549,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { signUpRequestProviderMock.expectedContinueRequestParameters = expectedSignUpContinueParams(token: "continuationToken 2") let signUpResponseValidatorMock = MSALNativeAuthSignUpResponseValidatorMock() - signUpResponseValidatorMock.mockValidateSignUpStartFunc((.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""]))) + signUpResponseValidatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) signUpResponseValidatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "continuationToken 2")) signUpResponseValidatorMock.mockValidateSignUpContinueFunc(.success("continuationToken")) @@ -650,7 +650,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { signUpRequestProviderMock.expectedContinueRequestParameters = expectedSignUpContinueParams(token: "continuationToken 2") let signUpResponseValidatorMock = MSALNativeAuthSignUpResponseValidatorMock() - signUpResponseValidatorMock.mockValidateSignUpStartFunc((.verificationRequired(continuationToken: "continuationToken", unverifiedAttributes: [""]))) + signUpResponseValidatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) signUpResponseValidatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "continuationToken 2")) signUpResponseValidatorMock.mockValidateSignUpContinueFunc(.success("continuationToken")) From 359eb681b150bf112acadc7d6848911217071696 Mon Sep 17 00:00:00 2001 From: Chase Hawthorne Date: Thu, 11 Jan 2024 14:34:28 -0500 Subject: [PATCH 29/84] Updated common core submodule --- MSAL/IdentityCore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index c93de42e8a..5c7460538f 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit c93de42e8a43c7c64373cfa64a33f0d38ae9e619 +Subproject commit 5c7460538f9fdc663ef6ce74f7d784e1b01b009c From 3bce0a3bed1e149abbe071fe5be7e933442821c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodh=C3=A1n=20Hickey?= <110929942+rodhan-ms@users.noreply.github.com> Date: Mon, 15 Jan 2024 11:38:04 +0000 Subject: [PATCH 30/84] Reuse MSAL initialised cache for Native Auth flows (#1958) * Reuse MSAL initialised cache for Native Auth flows * Added test for cacheAccessor to public client application test (and related changes) * Reuse existing MSALNativeAuthCacheAccessorMock in tests --- MSAL/MSAL.xcodeproj/project.pbxproj | 4 ++ .../cache/MSALNativeAuthCacheAccessor.swift | 14 ++++--- .../cache/MSALNativeAuthCacheInterface.swift | 2 + .../MSALNativeAuthCredentialsController.swift | 6 +-- .../MSALNativeAuthCacheAccessorFactory.swift | 41 +++++++++++++++++++ .../MSALNativeAuthControllerFactory.swift | 24 +++++------ .../MSALNativeAuthResultFactory.swift | 8 ++-- ...SALNativeAuthResetPasswordController.swift | 4 +- .../MSALNativeAuthSignInController.swift | 6 +-- .../MSALNativeAuthSignUpController.swift | 4 +- ...AuthPublicClientApplication+Internal.swift | 6 +-- ...SALNativeAuthPublicClientApplication.swift | 11 ++++- ...NativeAuthUserAccountResult+Internal.swift | 5 ++- .../MSALNativeAuthUserAccountResult.swift | 6 ++- .../MSALNativeAuthCacheAccessorTest.swift | 10 ++++- .../MSALNativeAuthResultFactoryTests.swift | 2 +- .../mock/MSALNativeAuthCacheMocks.swift | 17 ++++++++ .../mock/MSALNativeAuthFactoriesMocks.swift | 28 +++++++++---- ...ativeAuthPublicClientApplicationTest.swift | 12 ++++++ 19 files changed, 162 insertions(+), 48 deletions(-) create mode 100644 MSAL/src/native_auth/controllers/factories/MSALNativeAuthCacheAccessorFactory.swift diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index 293f5f833a..bf20150611 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -415,6 +415,7 @@ 9B6EECEF2A3146ED008ABA50 /* MSALNativeAuthResetPasswordResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B6EECEE2A3146ED008ABA50 /* MSALNativeAuthResetPasswordResponseValidatorTests.swift */; }; 9B839A102A4D7CF600BCC6F6 /* MSAL.docc in Sources */ = {isa = PBXBuildFile; fileRef = 9B839A0F2A4D7CF600BCC6F6 /* MSAL.docc */; }; 9B839A112A4D7CF600BCC6F6 /* MSAL.docc in Sources */ = {isa = PBXBuildFile; fileRef = 9B839A0F2A4D7CF600BCC6F6 /* MSAL.docc */; }; + 9B9D05E82B4FFBEC00024E6E /* MSALNativeAuthCacheAccessorFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B9D05E72B4FFBEC00024E6E /* MSALNativeAuthCacheAccessorFactory.swift */; }; 9BB5180B2A2A2B5B00D6276A /* MSALNativeAuthResetPasswordControllerSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BB518032A2A2B5B00D6276A /* MSALNativeAuthResetPasswordControllerSpy.swift */; }; 9BD2763D2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD2763C2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift */; }; 9BD2765A2A0E7E6F00FBD033 /* ResetPasswordTestValidatorHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD276582A0E7E6700FBD033 /* ResetPasswordTestValidatorHelpers.swift */; }; @@ -1662,6 +1663,7 @@ 9B61C91B2A27E57C00CE9E3A /* MSALNativeAuthResetPasswordResponseValidatorMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordResponseValidatorMock.swift; sourceTree = ""; }; 9B6EECEE2A3146ED008ABA50 /* MSALNativeAuthResetPasswordResponseValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordResponseValidatorTests.swift; sourceTree = ""; }; 9B839A0F2A4D7CF600BCC6F6 /* MSAL.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = MSAL.docc; sourceTree = ""; }; + 9B9D05E72B4FFBEC00024E6E /* MSALNativeAuthCacheAccessorFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCacheAccessorFactory.swift; sourceTree = ""; }; 9BB518032A2A2B5B00D6276A /* MSALNativeAuthResetPasswordControllerSpy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordControllerSpy.swift; sourceTree = ""; }; 9BD2763C2A0D3DBD00FBD033 /* MSALNativeAuthResetPasswordController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordController.swift; sourceTree = ""; }; 9BD276562A0E7DEC00FBD033 /* ResetPasswordCodeSentStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordCodeSentStateTests.swift; sourceTree = ""; }; @@ -3717,6 +3719,7 @@ DEE34F41D170B71C00BC302A /* factories */ = { isa = PBXGroup; children = ( + 9B9D05E72B4FFBEC00024E6E /* MSALNativeAuthCacheAccessorFactory.swift */, 28D5B05C2A028D2B0066E32B /* MSALNativeAuthControllerFactory.swift */, DEE34F43D170B71C00BC302A /* MSALNativeAuthResultFactory.swift */, ); @@ -5643,6 +5646,7 @@ 23A68A7C20F538B90071E435 /* MSALB2CAuthority.m in Sources */, DEE34F48D170B71C00BC302A /* MSALNativeAuthResultFactory.swift in Sources */, 6077D4A922498D87001798A2 /* MSALTenantProfile.m in Sources */, + 9B9D05E82B4FFBEC00024E6E /* MSALNativeAuthCacheAccessorFactory.swift in Sources */, A0274CD824B54A4E00BD198D /* MSALDevicePopManagerUtil.m in Sources */, DE9245122A38736600C0389F /* CredentialsDelegates.swift in Sources */, B223B0C022ADFACB00FB8713 /* MSALLegacySharedAccount.m in Sources */, diff --git a/MSAL/src/native_auth/cache/MSALNativeAuthCacheAccessor.swift b/MSAL/src/native_auth/cache/MSALNativeAuthCacheAccessor.swift index 500f65f1cd..e134e941a1 100644 --- a/MSAL/src/native_auth/cache/MSALNativeAuthCacheAccessor.swift +++ b/MSAL/src/native_auth/cache/MSALNativeAuthCacheAccessor.swift @@ -25,17 +25,19 @@ import Foundation @_implementationOnly import MSAL_Private -class MSALNativeAuthCacheAccessor: MSALNativeAuthCacheInterface { +final class MSALNativeAuthCacheAccessor: MSALNativeAuthCacheInterface { + private let tokenCacheAccessor: MSIDDefaultTokenCacheAccessor - private let tokenCacheAccessor: MSIDDefaultTokenCacheAccessor = { - let dataSource = MSIDKeychainTokenCache() - return MSIDDefaultTokenCacheAccessor(dataSource: dataSource, otherCacheAccessors: []) - }() + private let accountMetadataCache: MSIDAccountMetadataCacheAccessor - private let accountMetadataCache: MSIDAccountMetadataCacheAccessor = MSIDAccountMetadataCacheAccessor(dataSource: MSIDKeychainTokenCache()) private let externalAccountProvider: MSALExternalAccountHandler = MSALExternalAccountHandler() private let validator = MSIDTokenResponseValidator() + init(tokenCache: MSIDDefaultTokenCacheAccessor, accountMetadataCache: MSIDAccountMetadataCacheAccessor) { + self.tokenCacheAccessor = tokenCache + self.accountMetadataCache = accountMetadataCache + } + func getTokens( account: MSALAccount, configuration: MSIDConfiguration, diff --git a/MSAL/src/native_auth/cache/MSALNativeAuthCacheInterface.swift b/MSAL/src/native_auth/cache/MSALNativeAuthCacheInterface.swift index d467ee8abf..7b66d97346 100644 --- a/MSAL/src/native_auth/cache/MSALNativeAuthCacheInterface.swift +++ b/MSAL/src/native_auth/cache/MSALNativeAuthCacheInterface.swift @@ -26,6 +26,8 @@ import Foundation @_implementationOnly import MSAL_Private protocol MSALNativeAuthCacheInterface { + init(tokenCache: MSIDDefaultTokenCacheAccessor, accountMetadataCache: MSIDAccountMetadataCacheAccessor) + func getTokens( account: MSALAccount, configuration: MSIDConfiguration, diff --git a/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift index 378364730a..f977783346 100644 --- a/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift +++ b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift @@ -50,13 +50,13 @@ final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController, ) } - convenience init(config: MSALNativeAuthConfiguration) { - let factory = MSALNativeAuthResultFactory(config: config) + convenience init(config: MSALNativeAuthConfiguration, cacheAccessor: MSALNativeAuthCacheInterface) { + let factory = MSALNativeAuthResultFactory(config: config, cacheAccessor: cacheAccessor) self.init( clientId: config.clientId, requestProvider: MSALNativeAuthTokenRequestProvider( requestConfigurator: MSALNativeAuthRequestConfigurator(config: config)), - cacheAccessor: MSALNativeAuthCacheAccessor(), + cacheAccessor: cacheAccessor, factory: factory, responseValidator: MSALNativeAuthTokenResponseValidator(factory: factory, msidValidator: MSIDTokenResponseValidator()) diff --git a/MSAL/src/native_auth/controllers/factories/MSALNativeAuthCacheAccessorFactory.swift b/MSAL/src/native_auth/controllers/factories/MSALNativeAuthCacheAccessorFactory.swift new file mode 100644 index 0000000000..116877e003 --- /dev/null +++ b/MSAL/src/native_auth/controllers/factories/MSALNativeAuthCacheAccessorFactory.swift @@ -0,0 +1,41 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthCacheAccessorBuildable { + func makeCacheAccessor( + tokenCache: MSIDDefaultTokenCacheAccessor, + accountMetadataCache: MSIDAccountMetadataCacheAccessor + ) -> MSALNativeAuthCacheAccessor +} + +final class MSALNativeAuthCacheAccessorFactory: MSALNativeAuthCacheAccessorBuildable { + func makeCacheAccessor( + tokenCache: MSIDDefaultTokenCacheAccessor, + accountMetadataCache: MSIDAccountMetadataCacheAccessor + ) -> MSALNativeAuthCacheAccessor { + return MSALNativeAuthCacheAccessor(tokenCache: tokenCache, accountMetadataCache: accountMetadataCache) + } +} diff --git a/MSAL/src/native_auth/controllers/factories/MSALNativeAuthControllerFactory.swift b/MSAL/src/native_auth/controllers/factories/MSALNativeAuthControllerFactory.swift index 6d36efd41e..997286e8d4 100644 --- a/MSAL/src/native_auth/controllers/factories/MSALNativeAuthControllerFactory.swift +++ b/MSAL/src/native_auth/controllers/factories/MSALNativeAuthControllerFactory.swift @@ -23,10 +23,10 @@ // THE SOFTWARE. protocol MSALNativeAuthControllerBuildable { - func makeSignUpController() -> MSALNativeAuthSignUpControlling - func makeSignInController() -> MSALNativeAuthSignInControlling - func makeResetPasswordController() -> MSALNativeAuthResetPasswordControlling - func makeCredentialsController() -> MSALNativeAuthCredentialsControlling + func makeSignUpController(cacheAccessor: MSALNativeAuthCacheInterface) -> MSALNativeAuthSignUpControlling + func makeSignInController(cacheAccessor: MSALNativeAuthCacheInterface) -> MSALNativeAuthSignInControlling + func makeResetPasswordController(cacheAccessor: MSALNativeAuthCacheInterface) -> MSALNativeAuthResetPasswordControlling + func makeCredentialsController(cacheAccessor: MSALNativeAuthCacheInterface) -> MSALNativeAuthCredentialsControlling } final class MSALNativeAuthControllerFactory: MSALNativeAuthControllerBuildable { @@ -36,19 +36,19 @@ final class MSALNativeAuthControllerFactory: MSALNativeAuthControllerBuildable { self.config = config } - func makeSignUpController() -> MSALNativeAuthSignUpControlling { - return MSALNativeAuthSignUpController(config: config) + func makeSignUpController(cacheAccessor: MSALNativeAuthCacheInterface) -> MSALNativeAuthSignUpControlling { + return MSALNativeAuthSignUpController(config: config, cacheAccessor: cacheAccessor) } - func makeSignInController() -> MSALNativeAuthSignInControlling { - return MSALNativeAuthSignInController(config: config) + func makeSignInController(cacheAccessor: MSALNativeAuthCacheInterface) -> MSALNativeAuthSignInControlling { + return MSALNativeAuthSignInController(config: config, cacheAccessor: cacheAccessor) } - func makeResetPasswordController() -> MSALNativeAuthResetPasswordControlling { - return MSALNativeAuthResetPasswordController(config: config) + func makeResetPasswordController(cacheAccessor: MSALNativeAuthCacheInterface) -> MSALNativeAuthResetPasswordControlling { + return MSALNativeAuthResetPasswordController(config: config, cacheAccessor: cacheAccessor) } - func makeCredentialsController() -> MSALNativeAuthCredentialsControlling { - return MSALNativeAuthCredentialsController(config: config) + func makeCredentialsController(cacheAccessor: MSALNativeAuthCacheInterface) -> MSALNativeAuthCredentialsControlling { + return MSALNativeAuthCredentialsController(config: config, cacheAccessor: cacheAccessor) } } diff --git a/MSAL/src/native_auth/controllers/factories/MSALNativeAuthResultFactory.swift b/MSAL/src/native_auth/controllers/factories/MSALNativeAuthResultFactory.swift index 7fd3a0c2df..6f9a9a5df9 100644 --- a/MSAL/src/native_auth/controllers/factories/MSALNativeAuthResultFactory.swift +++ b/MSAL/src/native_auth/controllers/factories/MSALNativeAuthResultFactory.swift @@ -38,9 +38,11 @@ protocol MSALNativeAuthResultBuildable { final class MSALNativeAuthResultFactory: MSALNativeAuthResultBuildable { let config: MSALNativeAuthConfiguration + let cacheAccessor: MSALNativeAuthCacheInterface - init(config: MSALNativeAuthConfiguration) { + init(config: MSALNativeAuthConfiguration, cacheAccessor: MSALNativeAuthCacheInterface) { self.config = config + self.cacheAccessor = cacheAccessor } func makeUserAccountResult(tokenResult: MSIDTokenResult, context: MSIDRequestContext) -> MSALNativeAuthUserAccountResult? { @@ -79,11 +81,11 @@ final class MSALNativeAuthResultFactory: MSALNativeAuthResultBuildable { let authTokens = MSALNativeAuthTokens(accessToken: tokenResult.accessToken, refreshToken: refreshToken, rawIdToken: tokenResult.rawIdToken) - return .init(account: account, authTokens: authTokens, configuration: config, cacheAccessor: MSALNativeAuthCacheAccessor()) + return .init(account: account, authTokens: authTokens, configuration: config, cacheAccessor: cacheAccessor) } func makeUserAccountResult(account: MSALAccount, authTokens: MSALNativeAuthTokens) -> MSALNativeAuthUserAccountResult? { - return .init(account: account, authTokens: authTokens, configuration: config, cacheAccessor: MSALNativeAuthCacheAccessor()) + return .init(account: account, authTokens: authTokens, configuration: config, cacheAccessor: cacheAccessor) } func makeMSIDConfiguration(scopes: [String]) -> MSIDConfiguration { diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift index e290ce5338..9502588ac9 100644 --- a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift @@ -46,7 +46,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, super.init(clientId: config.clientId) } - convenience init(config: MSALNativeAuthConfiguration) { + convenience init(config: MSALNativeAuthConfiguration, cacheAccessor: MSALNativeAuthCacheInterface) { self.init( config: config, requestProvider: MSALNativeAuthResetPasswordRequestProvider( @@ -54,7 +54,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, telemetryProvider: MSALNativeAuthTelemetryProvider() ), responseValidator: MSALNativeAuthResetPasswordResponseValidator(), - signInController: MSALNativeAuthSignInController(config: config) + signInController: MSALNativeAuthSignInController(config: config, cacheAccessor: cacheAccessor) ) } diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift index 2a6f82f3ad..6bff8e2664 100644 --- a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift @@ -55,15 +55,15 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN ) } - convenience init(config: MSALNativeAuthConfiguration) { - let factory = MSALNativeAuthResultFactory(config: config) + convenience init(config: MSALNativeAuthConfiguration, cacheAccessor: MSALNativeAuthCacheInterface) { + let factory = MSALNativeAuthResultFactory(config: config, cacheAccessor: cacheAccessor) self.init( clientId: config.clientId, signInRequestProvider: MSALNativeAuthSignInRequestProvider( requestConfigurator: MSALNativeAuthRequestConfigurator(config: config)), tokenRequestProvider: MSALNativeAuthTokenRequestProvider( requestConfigurator: MSALNativeAuthRequestConfigurator(config: config)), - cacheAccessor: MSALNativeAuthCacheAccessor(), + cacheAccessor: cacheAccessor, factory: factory, signInResponseValidator: MSALNativeAuthSignInResponseValidator(), tokenResponseValidator: MSALNativeAuthTokenResponseValidator( diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift index 7475e39850..108606d5f1 100644 --- a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift @@ -48,7 +48,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa super.init(clientId: config.clientId) } - convenience init(config: MSALNativeAuthConfiguration) { + convenience init(config: MSALNativeAuthConfiguration, cacheAccessor: MSALNativeAuthCacheInterface) { self.init( config: config, requestProvider: MSALNativeAuthSignUpRequestProvider( @@ -56,7 +56,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa telemetryProvider: MSALNativeAuthTelemetryProvider() ), responseValidator: MSALNativeAuthSignUpResponseValidator(), - signInController: MSALNativeAuthSignInController(config: config) + signInController: MSALNativeAuthSignInController(config: config, cacheAccessor: cacheAccessor) ) } diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift index a2c0fac2a9..c559948d10 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift @@ -40,7 +40,7 @@ extension MSALNativeAuthPublicClientApplication { return .init(.error(SignUpStartError(type: .invalidPassword))) } - let controller = controllerFactory.makeSignUpController() + let controller = controllerFactory.makeSignUpController(cacheAccessor: cacheAccessor) let context = MSALNativeAuthRequestContext(correlationId: correlationId) let parameters = MSALNativeAuthSignUpStartRequestProviderParameters( @@ -66,7 +66,7 @@ extension MSALNativeAuthPublicClientApplication { return .init(.error(SignInStartError(type: .invalidCredentials))) } - let controller = controllerFactory.makeSignInController() + let controller = controllerFactory.makeSignInController(cacheAccessor: cacheAccessor) let params = MSALNativeAuthSignInParameters( username: username, @@ -85,7 +85,7 @@ extension MSALNativeAuthPublicClientApplication { return .init(.error(ResetPasswordStartError(type: .invalidUsername))) } - let controller = controllerFactory.makeResetPasswordController() + let controller = controllerFactory.makeResetPasswordController(cacheAccessor: cacheAccessor) let context = MSALNativeAuthRequestContext(correlationId: correlationId) return await controller.resetPassword( diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift index 8a76ee6ce5..e67e31979d 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift @@ -31,6 +31,11 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic let inputValidator: MSALNativeAuthInputValidating private let internalChallengeTypes: [MSALNativeAuthInternalChallengeType] + private var cacheAccessorFactory: MSALNativeAuthCacheAccessorBuildable + lazy var cacheAccessor: MSALNativeAuthCacheAccessor = { + return cacheAccessorFactory.makeCacheAccessor(tokenCache: tokenCache, accountMetadataCache: accountMetadataCache) + }() + /// Initialize a MSALNativePublicClientApplication with a given configuration and challenge types /// - Parameters: /// - config: Configuration for PublicClientApplication @@ -54,6 +59,7 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic nativeConfiguration.sliceConfig = config.sliceConfig self.controllerFactory = MSALNativeAuthControllerFactory(config: nativeConfiguration) + self.cacheAccessorFactory = MSALNativeAuthCacheAccessorFactory() self.inputValidator = MSALNativeAuthInputValidator() try super.init(configuration: config) @@ -82,6 +88,7 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic ) self.controllerFactory = MSALNativeAuthControllerFactory(config: nativeConfiguration) + self.cacheAccessorFactory = MSALNativeAuthCacheAccessorFactory() self.inputValidator = MSALNativeAuthInputValidator() let configuration = MSALPublicClientApplicationConfig( @@ -101,10 +108,12 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic init( controllerFactory: MSALNativeAuthControllerBuildable, + cacheAccessorFactory: MSALNativeAuthCacheAccessorBuildable, inputValidator: MSALNativeAuthInputValidating, internalChallengeTypes: [MSALNativeAuthInternalChallengeType] ) { self.controllerFactory = controllerFactory + self.cacheAccessorFactory = cacheAccessorFactory self.inputValidator = inputValidator self.internalChallengeTypes = internalChallengeTypes @@ -226,7 +235,7 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic /// - Parameter correlationId: Optional. UUID to correlate this request with the server for debugging. /// - Returns: An object representing the account information if present in the local cache. public func getNativeAuthUserAccount(correlationId: UUID? = nil) -> MSALNativeAuthUserAccountResult? { - let controller = controllerFactory.makeCredentialsController() + let controller = controllerFactory.makeCredentialsController(cacheAccessor: cacheAccessor) let context = MSALNativeAuthRequestContext(correlationId: correlationId) return controller.retrieveUserAccountResult(context: context) diff --git a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift index 4dfff8685e..9581381bb4 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift @@ -28,14 +28,15 @@ extension MSALNativeAuthUserAccountResult { func getAccessTokenInternal( forceRefresh: Bool, - correlationId: UUID? + correlationId: UUID?, + cacheAccessor: MSALNativeAuthCacheInterface ) async -> MSALNativeAuthCredentialsControlling.RefreshTokenCredentialControllerResponse { let context = MSALNativeAuthRequestContext(correlationId: correlationId) if let accessToken = self.authTokens.accessToken { if forceRefresh || accessToken.isExpired() { let controllerFactory = MSALNativeAuthControllerFactory(config: configuration) - let credentialsController = controllerFactory.makeCredentialsController() + let credentialsController = controllerFactory.makeCredentialsController(cacheAccessor: cacheAccessor) return await credentialsController.refreshToken(context: context, authTokens: authTokens) } else { return .init(.success(accessToken.accessToken)) diff --git a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift index 63e5bc4cea..69b906a64e 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift @@ -87,7 +87,11 @@ import Foundation /// - delegate: Delegate that receives callbacks for the Get Access Token flow. @objc public func getAccessToken(forceRefresh: Bool = false, correlationId: UUID? = nil, delegate: CredentialsDelegate) { Task { - let controllerResponse = await getAccessTokenInternal(forceRefresh: forceRefresh, correlationId: correlationId) + let controllerResponse = await getAccessTokenInternal( + forceRefresh: forceRefresh, + correlationId: correlationId, + cacheAccessor: cacheAccessor + ) let delegateDispatcher = CredentialsDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate) switch controllerResponse.result { diff --git a/MSAL/test/unit/native_auth/cache/MSALNativeAuthCacheAccessorTest.swift b/MSAL/test/unit/native_auth/cache/MSALNativeAuthCacheAccessorTest.swift index c0b2e83d5a..ad14e9d6ca 100644 --- a/MSAL/test/unit/native_auth/cache/MSALNativeAuthCacheAccessorTest.swift +++ b/MSAL/test/unit/native_auth/cache/MSALNativeAuthCacheAccessorTest.swift @@ -27,7 +27,15 @@ import XCTest @_implementationOnly import MSAL_Private final class MSALNativeAuthCacheAccessorTest: XCTestCase { - private let cacheAccessor = MSALNativeAuthCacheAccessor() + private let tokenCache: MSIDDefaultTokenCacheAccessor = { + let dataSource = MSIDKeychainTokenCache() + return MSIDDefaultTokenCacheAccessor(dataSource: dataSource, otherCacheAccessors: []) + }() + + private let accountMetadataCache: MSIDAccountMetadataCacheAccessor = MSIDAccountMetadataCacheAccessor(dataSource: MSIDKeychainTokenCache()) + + private lazy var cacheAccessor = MSALNativeAuthCacheAccessor(tokenCache: tokenCache, accountMetadataCache: accountMetadataCache) + private lazy var parameters = getParameters() private lazy var contextStub = ContextStub() diff --git a/MSAL/test/unit/native_auth/controllers/factories/MSALNativeAuthResultFactoryTests.swift b/MSAL/test/unit/native_auth/controllers/factories/MSALNativeAuthResultFactoryTests.swift index 8e82aa8798..2138c7221c 100644 --- a/MSAL/test/unit/native_auth/controllers/factories/MSALNativeAuthResultFactoryTests.swift +++ b/MSAL/test/unit/native_auth/controllers/factories/MSALNativeAuthResultFactoryTests.swift @@ -42,7 +42,7 @@ final class MSALNativeAuthResultFactoryTests: XCTestCase { ] override func setUpWithError() throws { - sut = .init(config: MSALNativeAuthConfigStubs.configuration) + sut = .init(config: MSALNativeAuthConfigStubs.configuration, cacheAccessor: MSALNativeAuthCacheAccessorMock()) } func test_makeMsidConfiguration() { diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthCacheMocks.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthCacheMocks.swift index b94b20b853..b0983f6802 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthCacheMocks.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthCacheMocks.swift @@ -27,6 +27,23 @@ import XCTest @_implementationOnly import MSAL_Private class MSALNativeAuthCacheAccessorMock: MSALNativeAuthCacheInterface { + var tokenCache: MSIDDefaultTokenCacheAccessor + var accountMetadataCache: MSIDAccountMetadataCacheAccessor + + required init(tokenCache: MSIDDefaultTokenCacheAccessor, accountMetadataCache: MSIDAccountMetadataCacheAccessor) { + self.tokenCache = tokenCache + self.accountMetadataCache = accountMetadataCache + } + + convenience init() { + let dataSource = MSIDKeychainTokenCache() + let tokenCache = MSIDDefaultTokenCacheAccessor(dataSource: dataSource, otherCacheAccessors: []) + + let accountMetadataCache = MSIDAccountMetadataCacheAccessor(dataSource: MSIDKeychainTokenCache()) + + self.init(tokenCache: tokenCache!, accountMetadataCache: accountMetadataCache!) + } + enum E: Error { case notImplemented case noAccount diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthFactoriesMocks.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthFactoriesMocks.swift index 4c7e36d511..a1acb93231 100644 --- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthFactoriesMocks.swift +++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthFactoriesMocks.swift @@ -75,19 +75,19 @@ class MSALNativeAuthControllerFactoryMock: MSALNativeAuthControllerBuildable { var resetPasswordController = MSALNativeAuthResetPasswordControllerMock() var credentialsController = MSALNativeAuthCredentialsControllerMock() - func makeSignUpController() -> MSAL.MSALNativeAuthSignUpControlling { + func makeSignUpController(cacheAccessor: MSAL.MSALNativeAuthCacheInterface) -> MSAL.MSALNativeAuthSignUpControlling { return signUpController } - func makeSignInController() -> MSAL.MSALNativeAuthSignInControlling { + func makeSignInController(cacheAccessor: MSAL.MSALNativeAuthCacheInterface) -> MSAL.MSALNativeAuthSignInControlling { return signInController } - func makeResetPasswordController() -> MSAL.MSALNativeAuthResetPasswordControlling { + func makeResetPasswordController(cacheAccessor: MSAL.MSALNativeAuthCacheInterface) -> MSAL.MSALNativeAuthResetPasswordControlling { return resetPasswordController } - func makeCredentialsController() -> MSAL.MSALNativeAuthCredentialsControlling { + func makeCredentialsController(cacheAccessor: MSAL.MSALNativeAuthCacheInterface) -> MSAL.MSALNativeAuthCredentialsControlling { return credentialsController } } @@ -109,19 +109,31 @@ class MSALNativeAuthControllerProtocolFactoryMock: MSALNativeAuthControllerBuild self.credentialsController = credentialsController } - func makeSignUpController() -> MSAL.MSALNativeAuthSignUpControlling { + func makeSignUpController(cacheAccessor: MSAL.MSALNativeAuthCacheInterface) -> MSAL.MSALNativeAuthSignUpControlling { return signUpController } - func makeSignInController() -> MSAL.MSALNativeAuthSignInControlling { + func makeSignInController(cacheAccessor: MSAL.MSALNativeAuthCacheInterface) -> MSAL.MSALNativeAuthSignInControlling { return signInController } - func makeResetPasswordController() -> MSAL.MSALNativeAuthResetPasswordControlling { + func makeResetPasswordController(cacheAccessor: MSAL.MSALNativeAuthCacheInterface) -> MSAL.MSALNativeAuthResetPasswordControlling { return resetPasswordController } - func makeCredentialsController() -> MSAL.MSALNativeAuthCredentialsControlling { + func makeCredentialsController(cacheAccessor: MSAL.MSALNativeAuthCacheInterface) -> MSAL.MSALNativeAuthCredentialsControlling { return credentialsController } } + +class MSALNativeAuthCacheAccessorFactoryMock: MSALNativeAuthCacheAccessorBuildable { + var tokenCache: MSIDDefaultTokenCacheAccessor? + var accountMetadataCache: MSIDAccountMetadataCacheAccessor? + + func makeCacheAccessor(tokenCache: MSIDDefaultTokenCacheAccessor, accountMetadataCache: MSIDAccountMetadataCacheAccessor) -> MSAL.MSALNativeAuthCacheAccessor { + self.tokenCache = tokenCache + self.accountMetadataCache = accountMetadataCache + + return MSALNativeAuthCacheAccessor(tokenCache: tokenCache, accountMetadataCache: accountMetadataCache) + } +} diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift index e37ee516ff..6c57b12a4a 100644 --- a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift +++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift @@ -32,6 +32,7 @@ import XCTest final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock() + private let cacheAccessorFactoryMock = MSALNativeAuthCacheAccessorFactoryMock() private var sut: MSALNativeAuthPublicClientApplication! private var correlationId: UUID = UUID() @@ -47,6 +48,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { sut = MSALNativeAuthPublicClientApplication( controllerFactory: controllerFactoryMock, + cacheAccessorFactory: cacheAccessorFactoryMock, inputValidator: MSALNativeAuthInputValidator(), internalChallengeTypes: [] ) @@ -67,6 +69,11 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { XCTAssertNoThrow(try MSALNativeAuthPublicClientApplication(clientId: "genericClient", tenantSubdomain: "genericTenenat", challengeTypes: [.OOB])) } + func testInit_nativeAuthCacheAccessor_itShouldUseConfigFromSuperclass() { + XCTAssertEqual(sut.tokenCache, cacheAccessorFactoryMock.tokenCache) + XCTAssertEqual(sut.accountMetadataCache, cacheAccessorFactoryMock.accountMetadataCache) + } + // MARK: - Delegates // Sign Up with password @@ -603,6 +610,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { sut = MSALNativeAuthPublicClientApplication( controllerFactory: controllerFactory, + cacheAccessorFactory: cacheAccessorFactoryMock, inputValidator: MSALNativeAuthInputValidator(), internalChallengeTypes: [] ) @@ -704,6 +712,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { sut = MSALNativeAuthPublicClientApplication( controllerFactory: controllerFactory, + cacheAccessorFactory: cacheAccessorFactoryMock, inputValidator: MSALNativeAuthInputValidator(), internalChallengeTypes: [] ) @@ -795,6 +804,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { sut = MSALNativeAuthPublicClientApplication( controllerFactory: controllerFactory, + cacheAccessorFactory: cacheAccessorFactoryMock, inputValidator: MSALNativeAuthInputValidator(), internalChallengeTypes: [] ) @@ -884,6 +894,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { sut = MSALNativeAuthPublicClientApplication( controllerFactory: controllerFactory, + cacheAccessorFactory: cacheAccessorFactoryMock, inputValidator: MSALNativeAuthInputValidator(), internalChallengeTypes: [] ) @@ -984,6 +995,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase { sut = MSALNativeAuthPublicClientApplication( controllerFactory: controllerFactory, + cacheAccessorFactory: cacheAccessorFactoryMock, inputValidator: MSALNativeAuthInputValidator(), internalChallengeTypes: [] ) From bdea46b33b90e47562bfc0dd9f1cce5511a28c81 Mon Sep 17 00:00:00 2001 From: Silviu Petrescu <111577419+spetrescu84@users.noreply.github.com> Date: Tue, 16 Jan 2024 12:53:25 +0000 Subject: [PATCH 31/84] Add documentation needed for NativeAuth (#1968) * - Added documentation for all public classes, methods, enums and properties - Renamed MSALNativeAuthRequiredAttributes to MSALNativeAuthRequiredAttribute as it's a singular object rather than multiple ones * PR comments * PR comments * PR comments * Changed MSALNativeAuthErrorBasicAttributes to MSALNativeAuthErrorBasicAttribute * Reverted changes to MSALNativeAuthErrorBasicAttributes and MSALNativeAuthRequiredAttributes * Reverted more things * Revert project.pbxproj * Reverted MSALNativeAuthRequiredAttributesOptions to MSALNativeAuthRequiredAttributeOptions * Reverted MSALNativeAuthRequiredAttributesOptions * PR comments --- .../public/MSALNativeAuthChallengeTypes.h | 6 ++++++ .../public/MSALNativeAuthChannelType.swift | 5 +++++ ...SALNativeAuthPublicClientApplication.swift | 20 +++++++++++++++++++ .../MSALNativeAuthRequiredAttributes.swift | 5 +++++ .../delegate/CredentialsDelegates.swift | 1 + .../delegate/ResetPasswordDelegates.swift | 4 ++++ .../SignInAfterResetPasswordDelegate.swift | 1 + .../delegate/SignInAfterSignUpDelegate.swift | 1 + .../delegate/SignInDelegates.swift | 4 ++++ .../delegate/SignUpDelegates.swift | 5 +++++ .../error/AttributesRequiredError.swift | 1 + .../error/MSALNativeAuthError.swift | 1 + .../error/PasswordRequiredError.swift | 1 + .../state_machine/error/ResendCodeError.swift | 1 + .../error/ResetPasswordStartError.swift | 1 + .../error/RetrieveAccessTokenError.swift | 1 + .../error/SignInAfterResetPasswordError.swift | 1 + .../error/SignInAfterSignUpError.swift | 1 + .../error/SignInStartError.swift | 1 + .../error/SignUpStartError.swift | 1 + .../state_machine/error/VerifyCodeError.swift | 1 + .../state/MSALNativeAuthBaseState.swift | 1 + .../state/ResetPasswordStates.swift | 1 + .../SignInAfterPreviousFlowBaseState.swift | 1 + .../state_machine/state/SignInStates.swift | 1 + .../state_machine/state/SignUpStates.swift | 1 + 26 files changed, 68 insertions(+) diff --git a/MSAL/src/native_auth/public/MSALNativeAuthChallengeTypes.h b/MSAL/src/native_auth/public/MSALNativeAuthChallengeTypes.h index b1860d0e21..d711648d22 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthChallengeTypes.h +++ b/MSAL/src/native_auth/public/MSALNativeAuthChallengeTypes.h @@ -25,13 +25,19 @@ #ifndef MSALNativeAuthChallengeTypes_h #define MSALNativeAuthChallengeTypes_h +#import + /// The set of capabilities that an application wishes to support for Native Auth operations. /// /// Valid options are: /// * OOB: The application can support asking a user to supply a verification code that is sent by email. /// * Password: The application can support asking a user to supply a password + typedef NS_OPTIONS(NSInteger, MSALNativeAuthChallengeTypes) { + /// Specifies if the Challenge Type is OOB MSALNativeAuthChallengeTypeOOB = 1 << 0, + + /// Specifies if the Challenge Type is Password MSALNativeAuthChallengeTypePassword = 1 << 1 }; diff --git a/MSAL/src/native_auth/public/MSALNativeAuthChannelType.swift b/MSAL/src/native_auth/public/MSALNativeAuthChannelType.swift index 2af38fe411..0a6531eb19 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthChannelType.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthChannelType.swift @@ -24,8 +24,13 @@ import Foundation +/// The possible Channel Types via which a code was sent @objc public enum MSALNativeAuthChannelType: Int { + + /// Specifies if the channel type is Email case email + + /// Specifies if the channel type is Phone case phone } diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift index e67e31979d..beb17cacb0 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift @@ -24,6 +24,26 @@ import Foundation +/// Main interface to interact with the Native Auth methods +/// +/// To create an instance of the MSALNativeAuthPublicClientApplication use the clientId, tenantSubdomain, challengeTypes and redirectUri (optional) +/// to the initialiser method. +/// +/// For example: + +///
+///     do {
+///         nativeAuth = try MSALNativeAuthPublicClientApplication(
+///             clientId: "Enter_the_Application_Id_Here",
+///             tenantSubdomain: "Enter_the_Tenant_Subdomain_Here",
+///             challengeTypes: [.OOB]
+///        )
+///        print("Initialised Native Auth successfully.")
+///     } catch {
+///         print("Unable to initialize MSAL \(error)")
+///     }
+/// 
+ @objcMembers public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplication { diff --git a/MSAL/src/native_auth/public/state_machine/MSALNativeAuthRequiredAttributes.swift b/MSAL/src/native_auth/public/state_machine/MSALNativeAuthRequiredAttributes.swift index 33258fb5a1..c40e4274a3 100644 --- a/MSAL/src/native_auth/public/state_machine/MSALNativeAuthRequiredAttributes.swift +++ b/MSAL/src/native_auth/public/state_machine/MSALNativeAuthRequiredAttributes.swift @@ -24,11 +24,16 @@ import Foundation +/// Class that defines the structure of a Required Attribute @objc public class MSALNativeAuthRequiredAttributes: NSObject { + /// The name of the Required Attribute public let name: String + /// The type of the Required Attribute public let type: String + /// Specifies if the attribute is required or not public let required: Bool + /// Regex to specify the format of the Attribute public let regex: String? init(name: String, type: String, required: Bool, regex: String? = nil) { diff --git a/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift index 53d85cee98..1d20fc6013 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift @@ -24,6 +24,7 @@ import Foundation +/// Protocol that defines the methods of a Credentials delegate @objc public protocol CredentialsDelegate { /// Notifies the delegate that the operation resulted in an error. diff --git a/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift index a0edddb6ab..2b39469cf3 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/ResetPasswordDelegates.swift @@ -24,6 +24,7 @@ import Foundation +/// Protocol that defines the methods of a ResetPasswordStart delegate @objc public protocol ResetPasswordStartDelegate { /// Notifies the delegate that the operation resulted in an error. @@ -45,6 +46,7 @@ public protocol ResetPasswordStartDelegate { ) } +/// Protocol that defines the methods of a ResetPasswordVerifyCode delegate @objc public protocol ResetPasswordVerifyCodeDelegate { /// Notifies the delegate that the operation resulted in an error. @@ -59,6 +61,7 @@ public protocol ResetPasswordVerifyCodeDelegate { @MainActor @objc optional func onPasswordRequired(newState: ResetPasswordRequiredState) } +/// Protocol that defines the methods of a ResetPasswordResendCode delegate @objc public protocol ResetPasswordResendCodeDelegate { /// Notifies the delegate that the operation resulted in an error. @@ -82,6 +85,7 @@ public protocol ResetPasswordResendCodeDelegate { ) } +/// Protocol that defines the methods of a ResetPasswordRequired delegate @objc public protocol ResetPasswordRequiredDelegate { /// Notifies the delegate that the operation resulted in an error. diff --git a/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterResetPasswordDelegate.swift b/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterResetPasswordDelegate.swift index 8c24f02e03..c0929de6ba 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterResetPasswordDelegate.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterResetPasswordDelegate.swift @@ -24,6 +24,7 @@ import Foundation +/// Protocol that defines the methods of a SignInAfterResetPassword delegate @objc public protocol SignInAfterResetPasswordDelegate { /// Notifies the delegate that the operation resulted in an error. diff --git a/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterSignUpDelegate.swift b/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterSignUpDelegate.swift index 9e6e8443fa..03bedc6e41 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterSignUpDelegate.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/SignInAfterSignUpDelegate.swift @@ -24,6 +24,7 @@ import Foundation +/// Protocol that defines the methods of a SignInAfterSignUp delegate @objc public protocol SignInAfterSignUpDelegate { /// Notifies the delegate that the operation resulted in an error. diff --git a/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift index fb39c1a020..80d385d51a 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/SignInDelegates.swift @@ -24,6 +24,7 @@ import Foundation +/// Protocol that defines the methods of a SignInStart delegate @objc public protocol SignInStartDelegate { /// Notifies the delegate that the operation resulted in an error. @@ -53,6 +54,7 @@ public protocol SignInStartDelegate { @MainActor @objc optional func onSignInCompleted(result: MSALNativeAuthUserAccountResult) } +/// Protocol that defines the methods of a SignInPasswordRequired delegate @objc public protocol SignInPasswordRequiredDelegate { /// Notifies the delegate that the operation resulted in an error. @@ -67,6 +69,7 @@ public protocol SignInPasswordRequiredDelegate { @MainActor @objc optional func onSignInCompleted(result: MSALNativeAuthUserAccountResult) } +/// Protocol that defines the methods of a SignInResendCode delegate @objc public protocol SignInResendCodeDelegate { /// Notifies the delegate that the operation resulted in an error. @@ -88,6 +91,7 @@ public protocol SignInResendCodeDelegate { codeLength: Int) } +/// Protocol that defines the methods of a SignInVerifyCode delegate @objc public protocol SignInVerifyCodeDelegate { /// Notifies the delegate that the operation resulted in an error. diff --git a/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift index 0660521035..b2abbc2745 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift @@ -24,6 +24,7 @@ import Foundation +/// Protocol that defines the methods of a SignUpStart delegate @objc public protocol SignUpStartDelegate { /// Notifies the delegate that the operation resulted in an error. @@ -48,6 +49,7 @@ public protocol SignUpStartDelegate { @MainActor @objc optional func onSignUpAttributesInvalid(attributeNames: [String]) } +/// Protocol that defines the methods of a SignUpVerifyCode delegate @objc public protocol SignUpVerifyCodeDelegate { /// Notifies the delegate that the operation resulted in an error. @@ -74,6 +76,7 @@ public protocol SignUpVerifyCodeDelegate { @MainActor @objc optional func onSignUpCompleted(newState: SignInAfterSignUpState) } +/// Protocol that defines the methods of a SignUpResendCode delegate @objc public protocol SignUpResendCodeDelegate { /// Notifies the delegate that the operation resulted in an error. @@ -97,6 +100,7 @@ public protocol SignUpResendCodeDelegate { ) } +/// Protocol that defines the methods of a SignUpPasswordRequired delegate @objc public protocol SignUpPasswordRequiredDelegate { /// Notifies the delegate that the operation resulted in an error. @@ -118,6 +122,7 @@ public protocol SignUpPasswordRequiredDelegate { @MainActor @objc optional func onSignUpCompleted(newState: SignInAfterSignUpState) } +/// Protocol that defines the methods of a SignUpAttributesRequired delegate @objc public protocol SignUpAttributesRequiredDelegate { /// Notifies the delegate that the operation resulted in an error. diff --git a/MSAL/src/native_auth/public/state_machine/error/AttributesRequiredError.swift b/MSAL/src/native_auth/public/state_machine/error/AttributesRequiredError.swift index 3bdc18f050..61fe69d4a1 100644 --- a/MSAL/src/native_auth/public/state_machine/error/AttributesRequiredError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/AttributesRequiredError.swift @@ -24,6 +24,7 @@ import Foundation +/// Class that defines the structure and type of an Attributes Required error @objc public class AttributesRequiredError: MSALNativeAuthError { /// Describes why an error occurred and provides more information about the error. diff --git a/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift b/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift index a46e217d7e..17106d5d00 100644 --- a/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift @@ -24,6 +24,7 @@ import Foundation +/// Class that defines the basic structure of a Native Auth error @objcMembers public class MSALNativeAuthError: NSObject, LocalizedError { /// Describes why an error occurred and provides more information about the error. diff --git a/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift b/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift index 99385d81b7..23b27a455d 100644 --- a/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift @@ -24,6 +24,7 @@ import Foundation +/// Class that defines the structure and type of a PasswordRequired error @objcMembers public class PasswordRequiredError: MSALNativeAuthError { enum ErrorType: CaseIterable { diff --git a/MSAL/src/native_auth/public/state_machine/error/ResendCodeError.swift b/MSAL/src/native_auth/public/state_machine/error/ResendCodeError.swift index ffb964e173..7962cb3d33 100644 --- a/MSAL/src/native_auth/public/state_machine/error/ResendCodeError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/ResendCodeError.swift @@ -24,6 +24,7 @@ import Foundation +/// Class that defines the structure and type of a ResendCode error @objc public class ResendCodeError: MSALNativeAuthError { /// Describes why an error occurred and provides more information about the error. diff --git a/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift b/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift index 851bda969d..ca01c1f5d8 100644 --- a/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift @@ -24,6 +24,7 @@ import Foundation +/// Class that defines the structure and type of a ResetPasswordStart error @objcMembers public class ResetPasswordStartError: MSALNativeAuthError { enum ErrorType: CaseIterable { diff --git a/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift b/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift index b21de75962..c82619fc70 100644 --- a/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift @@ -24,6 +24,7 @@ import Foundation +/// Class that defines the structure and type of a RetrieveAccessToken error @objcMembers public class RetrieveAccessTokenError: MSALNativeAuthError { enum ErrorType: CaseIterable { diff --git a/MSAL/src/native_auth/public/state_machine/error/SignInAfterResetPasswordError.swift b/MSAL/src/native_auth/public/state_machine/error/SignInAfterResetPasswordError.swift index be75c1bfa3..af46bce94a 100644 --- a/MSAL/src/native_auth/public/state_machine/error/SignInAfterResetPasswordError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/SignInAfterResetPasswordError.swift @@ -24,6 +24,7 @@ import Foundation +/// Class that defines the structure and type of a SignInAfterResetPassword error @objc public class SignInAfterResetPasswordError: MSALNativeAuthError { /// Describes why an error occurred and provides more information about the error. diff --git a/MSAL/src/native_auth/public/state_machine/error/SignInAfterSignUpError.swift b/MSAL/src/native_auth/public/state_machine/error/SignInAfterSignUpError.swift index 6955f658d7..8a55561371 100644 --- a/MSAL/src/native_auth/public/state_machine/error/SignInAfterSignUpError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/SignInAfterSignUpError.swift @@ -24,6 +24,7 @@ import Foundation +/// Class that defines the structure and type of a SignInAfterSignUp error @objc public class SignInAfterSignUpError: MSALNativeAuthError { /// Describes why an error occurred and provides more information about the error. diff --git a/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift index e5db743a8e..2b34a011ee 100644 --- a/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift @@ -24,6 +24,7 @@ import Foundation +/// Class that defines the structure and type of a SignInStart error @objcMembers public class SignInStartError: MSALNativeAuthError { enum ErrorType: CaseIterable { diff --git a/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift index cc61ed102f..b3c22f0d81 100644 --- a/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift @@ -24,6 +24,7 @@ import Foundation +/// Class that defines the structure and type of a SignUpStart error @objcMembers public class SignUpStartError: MSALNativeAuthError { enum ErrorType: CaseIterable { diff --git a/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift b/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift index ef7b98ce1d..8b74b65e03 100644 --- a/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift @@ -24,6 +24,7 @@ import Foundation +/// Class that defines the structure and type of a VerifyCode error @objcMembers public class VerifyCodeError: MSALNativeAuthError { enum ErrorType: CaseIterable { diff --git a/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift b/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift index 1dc39b1258..8a71603408 100644 --- a/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift +++ b/MSAL/src/native_auth/public/state_machine/state/MSALNativeAuthBaseState.swift @@ -24,6 +24,7 @@ import Foundation +/// Base class for Native Auth states @objc public class MSALNativeAuthBaseState: NSObject { let continuationToken: String diff --git a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift index 3a243d7870..20210da777 100644 --- a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift +++ b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift @@ -24,6 +24,7 @@ import Foundation +/// Base class for the ResetPassword state @objcMembers public class ResetPasswordBaseState: MSALNativeAuthBaseState { let controller: MSALNativeAuthResetPasswordControlling diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState.swift index 87816a2b4f..28bbdb62bc 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterPreviousFlowBaseState.swift @@ -24,6 +24,7 @@ import Foundation +/// Base class for the SignInAfterPreviousFlow state @objcMembers public class SignInAfterPreviousFlowBaseState: NSObject { let controller: MSALNativeAuthSignInControlling let username: String diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift b/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift index 6c83b3c484..1a85a23da9 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift @@ -24,6 +24,7 @@ import Foundation +/// Base class for the SignIn state @objcMembers public class SignInBaseState: MSALNativeAuthBaseState { let controller: MSALNativeAuthSignInControlling let inputValidator: MSALNativeAuthInputValidating diff --git a/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift b/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift index 4cd97e330a..9ef55e0ac4 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift @@ -24,6 +24,7 @@ import Foundation +/// Base class for the SignUp state @objcMembers public class SignUpBaseState: MSALNativeAuthBaseState { let controller: MSALNativeAuthSignUpControlling From 65e4f53af1119b8615e0b68126556433261d62d7 Mon Sep 17 00:00:00 2001 From: Silviu Petrescu <111577419+spetrescu84@users.noreply.github.com> Date: Tue, 16 Jan 2024 17:03:43 +0000 Subject: [PATCH 32/84] Renamed MSALNativeAuthErrorBasicAttributes to MSALNativeAuthErrorBasicAttribute (#1971) Renamed MSALNativeAuthRequiredAttributes to MSALNativeAuthRequiredAttribute Renamed MSALNativeAuthRequiredAttributesInternal to MSALNativeAuthRequiredAttributeInternal --- MSAL/MSAL.xcodeproj/project.pbxproj | 24 +++++++++---------- .../controllers/responses/SignUpResults.swift | 6 ++--- ...> MSALNativeAuthErrorBasicAttribute.swift} | 2 +- ...NativeAuthRequiredAttributeInternal.swift} | 6 ++--- ...ativeAuthSignUpContinueResponseError.swift | 6 ++--- ...ALNativeAuthSignUpStartResponseError.swift | 4 ++-- ...SALNativeAuthSignUpResponseValidator.swift | 4 ++-- ...ALNativeAuthSignUpValidatedResponses.swift | 2 +- ... => MSALNativeAuthRequiredAttribute.swift} | 2 +- .../delegate/SignUpDelegates.swift | 6 ++--- .../SignUpDelegateDispatchers.swift | 6 ++--- .../sign_up/SignUpDelegateSpies.swift | 6 ++--- .../mock/SignUpDelegateSpies.swift | 12 +++++----- .../mock/SignUpTestsValidatorHelpers.swift | 2 +- ...tiveAuthErrorRequiredAttributesTests.swift | 4 ++-- ...tiveAuthSignUpResponseValidatorTests.swift | 24 +++++++++---------- ...butesRequiredDelegateDispatcherTests.swift | 4 ++-- ...swordRequiredDelegateDispatcherTests.swift | 4 ++-- ...nUpVerifyCodeDelegateDispatcherTests.swift | 4 ++-- .../SignUpAttributesRequiredStateTests.swift | 4 ++-- 20 files changed, 66 insertions(+), 66 deletions(-) rename MSAL/src/native_auth/network/errors/sign_up/{MSALNativeAuthErrorBasicAttributes.swift => MSALNativeAuthErrorBasicAttribute.swift} (95%) rename MSAL/src/native_auth/network/errors/sign_up/{MSALNativeAuthRequiredAttributesInternal.swift => MSALNativeAuthRequiredAttributeInternal.swift} (86%) rename MSAL/src/native_auth/public/state_machine/{MSALNativeAuthRequiredAttributes.swift => MSALNativeAuthRequiredAttribute.swift} (96%) diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index bf20150611..499291d646 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -313,10 +313,10 @@ 886F516729CCA58900F09471 /* MSALCIAMAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 886F516329CCA58900F09471 /* MSALCIAMAuthority.m */; }; 88A25EE729E7347400066311 /* MSALCIAMAuthorityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25ED229E7185B00066311 /* MSALCIAMAuthorityTests.m */; }; 8D2733142AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D2733132AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift */; }; - 8D35C8E72A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D35C8E62A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift */; }; + 8D35C8E72A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D35C8E62A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttribute.swift */; }; 8D35C8F12A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D35C8F02A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift */; }; 8D61F9A12A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D61F9A02A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift */; }; - 8DDF473F2A98FE1C00126A47 /* MSALNativeAuthRequiredAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DDF473E2A98FE1C00126A47 /* MSALNativeAuthRequiredAttributes.swift */; }; + 8DDF473F2A98FE1C00126A47 /* MSALNativeAuthRequiredAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DDF473E2A98FE1C00126A47 /* MSALNativeAuthRequiredAttribute.swift */; }; 94E876CE1E492D6000FB96ED /* MSALAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 94E876CB1E492D6000FB96ED /* MSALAuthority.m */; }; 960751BB2183E82C00F2BF2F /* MSALAccountIdTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 960751BA2183E82C00F2BF2F /* MSALAccountIdTests.m */; }; 960751BC2183E82C00F2BF2F /* MSALAccountIdTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 960751BA2183E82C00F2BF2F /* MSALAccountIdTests.m */; }; @@ -1005,7 +1005,7 @@ DEE34F89D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F88D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionStatus.swift */; }; DEE34F8CD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F8AD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift */; }; DEE34F8DD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F8BD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponseError.swift */; }; - DEE34F96D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F95D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift */; }; + DEE34F96D170B71C00BC302A /* MSALNativeAuthRequiredAttributeInternal.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F95D170B71C00BC302A /* MSALNativeAuthRequiredAttributeInternal.swift */; }; DEE34FA1D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34FA0D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift */; }; DEF1DD322AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF1DD312AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift */; }; DEF1DD3C2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF1DD3B2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift */; }; @@ -1592,10 +1592,10 @@ 886F516329CCA58900F09471 /* MSALCIAMAuthority.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALCIAMAuthority.m; sourceTree = ""; }; 88A25ED229E7185B00066311 /* MSALCIAMAuthorityTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALCIAMAuthorityTests.m; sourceTree = ""; }; 8D2733132AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCustomErrorSerializer.swift; sourceTree = ""; }; - 8D35C8E62A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthErrorBasicAttributes.swift; sourceTree = ""; }; + 8D35C8E62A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthErrorBasicAttribute.swift; sourceTree = ""; }; 8D35C8F02A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequiredAttributeOptions.swift; sourceTree = ""; }; 8D61F9A02A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequestableTests.swift; sourceTree = ""; }; - 8DDF473E2A98FE1C00126A47 /* MSALNativeAuthRequiredAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequiredAttributes.swift; sourceTree = ""; }; + 8DDF473E2A98FE1C00126A47 /* MSALNativeAuthRequiredAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequiredAttribute.swift; sourceTree = ""; }; 94E876B01E4556B400FB96ED /* MSAL.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSAL.pch; sourceTree = ""; }; 94E876CA1E492D6000FB96ED /* MSALAuthority.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSALAuthority.h; sourceTree = ""; }; 94E876CB1E492D6000FB96ED /* MSALAuthority.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALAuthority.m; sourceTree = ""; }; @@ -2015,7 +2015,7 @@ DEE34F88D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordPollCompletionStatus.swift; sourceTree = ""; }; DEE34F8AD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift; sourceTree = ""; }; DEE34F8BD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordPollCompletionResponseError.swift; sourceTree = ""; }; - DEE34F95D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequiredAttributesInternal.swift; sourceTree = ""; }; + DEE34F95D170B71C00BC302A /* MSALNativeAuthRequiredAttributeInternal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequiredAttributeInternal.swift; sourceTree = ""; }; DEE34FA0D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordRequestProvider.swift; sourceTree = ""; }; DEF1DD312AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthESTSApiErrorDescriptions.swift; sourceTree = ""; }; DEF1DD3B2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthESTSApiErrorDescriptionsTests.swift; sourceTree = ""; }; @@ -2501,7 +2501,7 @@ isa = PBXGroup; children = ( E2CE91372B0D077C0009AEDD /* delegate_dispatcher */, - 8DDF473E2A98FE1C00126A47 /* MSALNativeAuthRequiredAttributes.swift */, + 8DDF473E2A98FE1C00126A47 /* MSALNativeAuthRequiredAttribute.swift */, 28DCD09629D7171600C4601E /* error */, 28DCD09529D7170F00C4601E /* state */, 28DCD09029D7165700C4601E /* delegate */, @@ -4042,8 +4042,8 @@ E2C61FD829DECE8900F15203 /* sign_up */ = { isa = PBXGroup; children = ( - DEE34F95D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift */, - 8D35C8E62A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift */, + DEE34F95D170B71C00BC302A /* MSALNativeAuthRequiredAttributeInternal.swift */, + 8D35C8E62A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttribute.swift */, 8D35C8F02A97BD2300BEC29A /* MSALNativeAuthRequiredAttributeOptions.swift */, E2C61FE029DECEDB00F15203 /* MSALNativeAuthSignUpStartOauth2ErrorCode.swift */, E2C61FE329DED15800F15203 /* MSALNativeAuthSignUpStartResponseError.swift */, @@ -5583,7 +5583,7 @@ DE1D8AA829E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift in Sources */, DEF1DD322AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift in Sources */, DE0D65BF29D30BAE005798B1 /* MSALNativeAuthResponseError.swift in Sources */, - 8DDF473F2A98FE1C00126A47 /* MSALNativeAuthRequiredAttributes.swift in Sources */, + 8DDF473F2A98FE1C00126A47 /* MSALNativeAuthRequiredAttribute.swift in Sources */, 285F36082A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift in Sources */, DEE34F8CD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift in Sources */, 232D68CC223DB00500594BBD /* MSALTokenParameters.m in Sources */, @@ -5716,7 +5716,7 @@ E2C872C3294CDEE800C4F580 /* MSALNativeAuthRequestable.swift in Sources */, 1E72193B24773D1B00AB9B67 /* MSALHttpMethod.m in Sources */, E243F69D29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift in Sources */, - DEE34F96D170B71C00BC302A /* MSALNativeAuthRequiredAttributesInternal.swift in Sources */, + DEE34F96D170B71C00BC302A /* MSALNativeAuthRequiredAttributeInternal.swift in Sources */, 289E15592948E601006104D9 /* MSALNativeAuthCacheInterface.swift in Sources */, 289E156D2948EB8A006104D9 /* MSALNativeAuthCacheAccessor.swift in Sources */, E2C61FE729DED73700F15203 /* MSALNativeAuthSignUpChallengeResponseError.swift in Sources */, @@ -5759,7 +5759,7 @@ E22427DB2B0594670006C55E /* CredentialsDelegateDispatcher.swift in Sources */, B26756C622921C42000F01D7 /* MSALAADOauth2Provider.m in Sources */, DEE34F12D170B71C00BC302A /* MSALNativeAuthResetPasswordStartRequestParameters.swift in Sources */, - 8D35C8E72A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttributes.swift in Sources */, + 8D35C8E72A97BD0000BEC29A /* MSALNativeAuthErrorBasicAttribute.swift in Sources */, 28DCD09229D7166F00C4601E /* SignUpDelegates.swift in Sources */, DE0D656F29BF72F7005798B1 /* MSALNativeAuthSignInInitiateRequestParameters.swift in Sources */, E2F626AA2A780F8200C4A303 /* SignInStates+Internal.swift in Sources */, diff --git a/MSAL/src/native_auth/controllers/responses/SignUpResults.swift b/MSAL/src/native_auth/controllers/responses/SignUpResults.swift index afc2c36247..00285f3640 100644 --- a/MSAL/src/native_auth/controllers/responses/SignUpResults.swift +++ b/MSAL/src/native_auth/controllers/responses/SignUpResults.swift @@ -33,7 +33,7 @@ enum SignUpStartResult { enum SignUpVerifyCodeResult { case completed(SignInAfterSignUpState) case passwordRequired(SignUpPasswordRequiredState) - case attributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) + case attributesRequired(attributes: [MSALNativeAuthRequiredAttribute], newState: SignUpAttributesRequiredState) case error(error: VerifyCodeError, newState: SignUpCodeRequiredState?) } @@ -41,13 +41,13 @@ typealias SignUpResendCodeResult = CodeRequiredGenericResult MSALNativeAuthRequiredAttributes { - MSALNativeAuthRequiredAttributes(name: name, type: type, required: required, regex: options?.regex) + func toRequiredAttributePublic() -> MSALNativeAuthRequiredAttribute { + MSALNativeAuthRequiredAttribute(name: name, type: type, required: required, regex: options?.regex) } } diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift index 57cbd610aa..c80f7e9e89 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift @@ -32,9 +32,9 @@ struct MSALNativeAuthSignUpContinueResponseError: MSALNativeAuthResponseError { let errorURI: String? let innerErrors: [MSALNativeAuthInnerError]? let continuationToken: String? - let requiredAttributes: [MSALNativeAuthRequiredAttributesInternal]? - let unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes]? - let invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? + let requiredAttributes: [MSALNativeAuthRequiredAttributeInternal]? + let unverifiedAttributes: [MSALNativeAuthErrorBasicAttribute]? + let invalidAttributes: [MSALNativeAuthErrorBasicAttribute]? enum CodingKeys: String, CodingKey { case error diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift index 4d7cbf15cb..bd89d0b064 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift @@ -33,8 +33,8 @@ struct MSALNativeAuthSignUpStartResponseError: MSALNativeAuthResponseError { let errorURI: String? let innerErrors: [MSALNativeAuthInnerError]? let continuationToken: String? - let unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes]? - let invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? + let unverifiedAttributes: [MSALNativeAuthErrorBasicAttribute]? + let invalidAttributes: [MSALNativeAuthErrorBasicAttribute]? enum CodingKeys: String, CodingKey { case error diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift index 0379cc971f..7d43519753 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift @@ -191,7 +191,7 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV !requiredAttributes.isEmpty { return .attributesRequired( continuationToken: continuationToken, - requiredAttributes: requiredAttributes.map { $0.toRequiredAttributesPublic() } + requiredAttributes: requiredAttributes.map { $0.toRequiredAttributePublic() } ) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/continue for attributes_required error") @@ -249,7 +249,7 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV return knownErrorCode == .invalidRequestParameter && errorDescription.contains(knownErrorDescription) } - private func extractAttributeNames(from attributes: [MSALNativeAuthErrorBasicAttributes]) -> [String] { + private func extractAttributeNames(from attributes: [MSALNativeAuthErrorBasicAttribute]) -> [String] { return attributes.map { $0.name } } } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift index 37c819a7cb..b9844b4d25 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift @@ -46,7 +46,7 @@ enum MSALNativeAuthSignUpContinueValidatedResponse: Equatable { /// error that represents invalidOOB or invalidPassword, depending on which State the input comes from. case invalidUserInput(_ error: MSALNativeAuthSignUpContinueResponseError) case credentialRequired(continuationToken: String) - case attributesRequired(continuationToken: String, requiredAttributes: [MSALNativeAuthRequiredAttributes]) + case attributesRequired(continuationToken: String, requiredAttributes: [MSALNativeAuthRequiredAttribute]) case attributeValidationFailed(invalidAttributes: [String]) case error(MSALNativeAuthSignUpContinueResponseError) case unexpectedError diff --git a/MSAL/src/native_auth/public/state_machine/MSALNativeAuthRequiredAttributes.swift b/MSAL/src/native_auth/public/state_machine/MSALNativeAuthRequiredAttribute.swift similarity index 96% rename from MSAL/src/native_auth/public/state_machine/MSALNativeAuthRequiredAttributes.swift rename to MSAL/src/native_auth/public/state_machine/MSALNativeAuthRequiredAttribute.swift index c40e4274a3..af79ac9d12 100644 --- a/MSAL/src/native_auth/public/state_machine/MSALNativeAuthRequiredAttributes.swift +++ b/MSAL/src/native_auth/public/state_machine/MSALNativeAuthRequiredAttribute.swift @@ -26,7 +26,7 @@ import Foundation /// Class that defines the structure of a Required Attribute @objc -public class MSALNativeAuthRequiredAttributes: NSObject { +public class MSALNativeAuthRequiredAttribute: NSObject { /// The name of the Required Attribute public let name: String /// The type of the Required Attribute diff --git a/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift index b2abbc2745..849732af8f 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate/SignUpDelegates.swift @@ -63,7 +63,7 @@ public protocol SignUpVerifyCodeDelegate { /// - Parameters: /// - attributes: List of required attributes. /// - newState: An object representing the new state of the flow with follow on methods. - @MainActor @objc optional func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) + @MainActor @objc optional func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttribute], newState: SignUpAttributesRequiredState) /// Notifies the delegate that a password is required from the user to continue. /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpVerifyCodeError(error:newState:)`` will be called. @@ -114,7 +114,7 @@ public protocol SignUpPasswordRequiredDelegate { /// - Parameters: /// - attributes: List of required attributes. /// - newState: An object representing the new state of the flow with follow on methods. - @MainActor @objc optional func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) + @MainActor @objc optional func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttribute], newState: SignUpAttributesRequiredState) /// Notifies the delegate that the sign up operation completed successfully. /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpPasswordRequiredError(error:newState:)`` will be called. @@ -134,7 +134,7 @@ public protocol SignUpAttributesRequiredDelegate { /// - Parameters: /// - attributes: List of required attributes. /// - newState: An object representing the new state of the flow with follow on methods. - @MainActor @objc optional func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) + @MainActor @objc optional func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttribute], newState: SignUpAttributesRequiredState) /// Notifies the delegate that invalid attributes were sent. /// - Note: If a flow requires this optional method and it is not implemented, then ``onSignUpAttributesRequiredError(error:)`` will be called. diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift index d39149da8c..47e70b59d2 100644 --- a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift +++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift @@ -56,7 +56,7 @@ final class SignUpStartDelegateDispatcher: DelegateDispatcher { - func dispatchSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) async { + func dispatchSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttribute], newState: SignUpAttributesRequiredState) async { if let onSignUpAttributesRequired = delegate.onSignUpAttributesRequired { telemetryUpdate?(.success(())) await onSignUpAttributesRequired(attributes, newState) @@ -111,7 +111,7 @@ final class SignUpResendCodeDelegateDispatcher: DelegateDispatcher { - func dispatchSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) async { + func dispatchSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttribute], newState: SignUpAttributesRequiredState) async { if let onSignUpAttributesRequired = delegate.onSignUpAttributesRequired { telemetryUpdate?(.success(())) await onSignUpAttributesRequired(attributes, newState) @@ -136,7 +136,7 @@ final class SignUpPasswordRequiredDelegateDispatcher: DelegateDispatcher { - func dispatchSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) async { + func dispatchSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttribute], newState: SignUpAttributesRequiredState) async { if let onSignUpAttributesRequired = delegate.onSignUpAttributesRequired { telemetryUpdate?(.success(())) await onSignUpAttributesRequired(attributes, newState) diff --git a/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift b/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift index 8a212e8781..22961d01b7 100644 --- a/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift +++ b/MSAL/test/integration/native_auth/end_to_end/sign_up/SignUpDelegateSpies.swift @@ -112,7 +112,7 @@ class SignUpVerifyCodeDelegateSpy: SignUpVerifyCodeDelegate { expectation.fulfill() } - func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) { + func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttribute], newState: SignUpAttributesRequiredState) { onSignUpAttributesRequiredCalled = true attributesRequiredNewState = newState @@ -186,7 +186,7 @@ class SignUpPasswordRequiredDelegateSpy: SignUpPasswordRequiredDelegate { expectation.fulfill() } - func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: SignUpAttributesRequiredState) { + func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttribute], newState: SignUpAttributesRequiredState) { onSignUpAttributesRequiredCalled = true attributesRequiredState = newState @@ -227,7 +227,7 @@ class SignUpAttributesRequiredDelegateSpy: SignUpAttributesRequiredDelegate { expectation.fulfill() } - func onSignUpAttributesRequired(attributes: [MSAL.MSALNativeAuthRequiredAttributes], newState: MSAL.SignUpAttributesRequiredState) { + func onSignUpAttributesRequired(attributes: [MSAL.MSALNativeAuthRequiredAttribute], newState: MSAL.SignUpAttributesRequiredState) { onSignUpAttributesRequiredErrorCalled = true attributesRequiredState = newState expectation.fulfill() diff --git a/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift b/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift index 5317727312..6573bc4bc2 100644 --- a/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift +++ b/MSAL/test/unit/native_auth/mock/SignUpDelegateSpies.swift @@ -175,7 +175,7 @@ class SignUpVerifyCodeDelegateSpy: SignUpVerifyCodeDelegate { private(set) var newAttributesRequiredState: SignUpAttributesRequiredState? private(set) var newPasswordRequiredState: SignUpPasswordRequiredState? private(set) var newSignInAfterSignUpState: SignInAfterSignUpState? - private(set) var newAttributesRequired: [MSALNativeAuthRequiredAttributes]? + private(set) var newAttributesRequired: [MSALNativeAuthRequiredAttribute]? init(expectation: XCTestExpectation? = nil) { self.expectation = expectation @@ -190,7 +190,7 @@ class SignUpVerifyCodeDelegateSpy: SignUpVerifyCodeDelegate { expectation?.fulfill() } - func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttributes], newState: MSAL.SignUpAttributesRequiredState) { + func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttribute], newState: MSAL.SignUpAttributesRequiredState) { onSignUpAttributesRequiredCalled = true newAttributesRequired = attributes newAttributesRequiredState = newState @@ -225,7 +225,7 @@ class SignUpPasswordRequiredDelegateSpy: SignUpPasswordRequiredDelegate { private(set) var newPasswordRequiredState: SignUpPasswordRequiredState? private(set) var newAttributesRequiredState: SignUpAttributesRequiredState? private(set) var signInAfterSignUpState: SignInAfterSignUpState? - private(set) var newAttributesRequired: [MSALNativeAuthRequiredAttributes]? + private(set) var newAttributesRequired: [MSALNativeAuthRequiredAttribute]? init(expectation: XCTestExpectation? = nil) { self.expectation = expectation @@ -240,7 +240,7 @@ class SignUpPasswordRequiredDelegateSpy: SignUpPasswordRequiredDelegate { expectation?.fulfill() } - func onSignUpAttributesRequired(attributes: [MSAL.MSALNativeAuthRequiredAttributes], newState: MSAL.SignUpAttributesRequiredState) { + func onSignUpAttributesRequired(attributes: [MSAL.MSALNativeAuthRequiredAttribute], newState: MSAL.SignUpAttributesRequiredState) { onSignUpAttributesRequiredCalled = true newAttributesRequiredState = newState newAttributesRequired = attributes @@ -265,7 +265,7 @@ class SignUpAttributesRequiredDelegateSpy: SignUpAttributesRequiredDelegate { private(set) var onSignUpCompletedCalled = false private(set) var error: AttributesRequiredError? private(set) var newState: SignUpAttributesRequiredState? - private(set) var attributes: [MSAL.MSALNativeAuthRequiredAttributes]? + private(set) var attributes: [MSAL.MSALNativeAuthRequiredAttribute]? private(set) var invalidAttributes: [String]? private(set) var newSignInAfterSignUpState: SignInAfterSignUpState? @@ -289,7 +289,7 @@ class SignUpAttributesRequiredDelegateSpy: SignUpAttributesRequiredDelegate { expectation?.fulfill() } - func onSignUpAttributesRequired(attributes: [MSAL.MSALNativeAuthRequiredAttributes], newState: MSAL.SignUpAttributesRequiredState) { + func onSignUpAttributesRequired(attributes: [MSAL.MSALNativeAuthRequiredAttribute], newState: MSAL.SignUpAttributesRequiredState) { self.attributes = attributes self.newState = newState onSignUpAttributesRequiredCalled = true diff --git a/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift b/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift index b61323877f..e5b1aefbb4 100644 --- a/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift +++ b/MSAL/test/unit/native_auth/mock/SignUpTestsValidatorHelpers.swift @@ -214,7 +214,7 @@ class SignUpAttributesRequiredTestsValidatorHelper { private(set) var error: AttributesRequiredError? private(set) var newState: SignUpAttributesRequiredState? private(set) var signInAfterSignUpState: SignInAfterSignUpState? - private(set) var attributes: [MSALNativeAuthRequiredAttributes]? + private(set) var attributes: [MSALNativeAuthRequiredAttribute]? private(set) var invalidAttributes: [String]? init(expectation: XCTestExpectation? = nil) { diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthErrorRequiredAttributesTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthErrorRequiredAttributesTests.swift index 41b9c01f48..6b33f6460b 100644 --- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthErrorRequiredAttributesTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthErrorRequiredAttributesTests.swift @@ -28,12 +28,12 @@ import XCTest final class MSALNativeAuthErrorRequiredAttributesTests: XCTestCase { func test_toString_requiredTrue() { - let sut = MSALNativeAuthRequiredAttributesInternal(name: "aName", type: "", required: true) + let sut = MSALNativeAuthRequiredAttributeInternal(name: "aName", type: "", required: true) XCTAssertEqual(sut.description, "aName") } func test_toString_requiredFalse() { - let sut = MSALNativeAuthRequiredAttributesInternal(name: "aName", type: "", required: false) + let sut = MSALNativeAuthRequiredAttributeInternal(name: "aName", type: "", required: false) XCTAssertEqual(sut.description, "aName") } } diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift index d2f5ca8ea8..7aa03c604d 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift @@ -81,7 +81,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { let error = createSignUpStartError( error: .invalidGrant, subError: .attributeValidationFailed, - invalidAttributes: [MSALNativeAuthErrorBasicAttributes(name: "city")] + invalidAttributes: [MSALNativeAuthErrorBasicAttribute(name: "city")] ) let response: Result = .failure(error) @@ -132,7 +132,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpStartErrorResponseIs_invalidRequestWithInvalidUsernameErrorDescription_it_returns_expectedError() { - let attributes = [MSALNativeAuthErrorBasicAttributes(name: "attribute")] + let attributes = [MSALNativeAuthErrorBasicAttribute(name: "attribute")] let errorCodes = [MSALNativeAuthESTSApiErrorCodes.invalidRequestParameter.rawValue, Int.max] let apiError = createSignUpStartError( @@ -155,7 +155,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpStartErrorResponseIs_invalidRequestWithInvalidClientIdErrorDescription_it_returns_expectedError() { - let attributes = [MSALNativeAuthErrorBasicAttributes(name: "attribute")] + let attributes = [MSALNativeAuthErrorBasicAttribute(name: "attribute")] let errorCodes = [MSALNativeAuthESTSApiErrorCodes.invalidRequestParameter.rawValue, Int.max] let apiError = createSignUpStartError( @@ -178,7 +178,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpStartErrorResponseIs_invalidRequestWithGenericErrorCode_it_returns_expectedError() { - let attributes = [MSALNativeAuthErrorBasicAttributes(name: "attribute")] + let attributes = [MSALNativeAuthErrorBasicAttribute(name: "attribute")] let errorCodes = [Int.max] let apiError = createSignUpStartError( @@ -460,7 +460,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_it_returns_expectedError() { - let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .attributeValidationFailed, invalidAttributes: [MSALNativeAuthErrorBasicAttributes(name: "email")]) + let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .attributeValidationFailed, invalidAttributes: [MSALNativeAuthErrorBasicAttribute(name: "email")]) guard case .attributeValidationFailed(let invalidAttributes) = result else { return XCTFail("Unexpected response") @@ -602,8 +602,8 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { expectedError: MSALNativeAuthSignUpContinueOauth2ErrorCode, expectedSubError: MSALNativeAuthSubErrorCode? = nil, expectedContinuationToken: String? = nil, - requiredAttributes: [MSALNativeAuthRequiredAttributesInternal]? = nil, - invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil, + requiredAttributes: [MSALNativeAuthRequiredAttributeInternal]? = nil, + invalidAttributes: [MSALNativeAuthErrorBasicAttribute]? = nil, errorCodes: [Int]? = nil ) -> MSALNativeAuthSignUpContinueValidatedResponse { let response: Result = .failure( @@ -628,8 +628,8 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { errorURI: String? = nil, innerErrors: [MSALNativeAuthInnerError]? = nil, continuationToken: String? = nil, - unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil, - invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil + unverifiedAttributes: [MSALNativeAuthErrorBasicAttribute]? = nil, + invalidAttributes: [MSALNativeAuthErrorBasicAttribute]? = nil ) -> MSALNativeAuthSignUpStartResponseError { .init( error: error, @@ -668,9 +668,9 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { errorURI: String? = nil, innerErrors: [MSALNativeAuthInnerError]? = nil, continuationToken: String? = nil, - requiredAttributes: [MSALNativeAuthRequiredAttributesInternal]? = nil, - unverifiedAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil, - invalidAttributes: [MSALNativeAuthErrorBasicAttributes]? = nil + requiredAttributes: [MSALNativeAuthRequiredAttributeInternal]? = nil, + unverifiedAttributes: [MSALNativeAuthErrorBasicAttribute]? = nil, + invalidAttributes: [MSALNativeAuthErrorBasicAttribute]? = nil ) -> MSALNativeAuthSignUpContinueResponseError { .init( error: error, diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift index c82b2eea67..e9827bf514 100644 --- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift @@ -49,7 +49,7 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + let expectedAttributes: [MSALNativeAuthRequiredAttribute] = [ .init(name: "attribute1", type: "", required: true), .init(name: "attribute2", type: "", required: true), ] @@ -77,7 +77,7 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + let expectedAttributes: [MSALNativeAuthRequiredAttribute] = [ .init(name: "attribute1", type: "", required: true), .init(name: "attribute2", type: "", required: true), ] diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift index 33b7315b23..c6978e31f3 100644 --- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift @@ -49,7 +49,7 @@ final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + let expectedAttributes: [MSALNativeAuthRequiredAttribute] = [ .init(name: "attribute1", type: "", required: true), .init(name: "attribute2", type: "", required: true), ] @@ -77,7 +77,7 @@ final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + let expectedAttributes: [MSALNativeAuthRequiredAttribute] = [ .init(name: "attribute1", type: "", required: true), .init(name: "attribute2", type: "", required: true), ] diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift index 12c5d24144..e42cc2a23b 100644 --- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift +++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift @@ -49,7 +49,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + let expectedAttributes: [MSALNativeAuthRequiredAttribute] = [ .init(name: "attribute1", type: "", required: true), .init(name: "attribute2", type: "", required: true), ] @@ -77,7 +77,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase { self.telemetryExp.fulfill() }) - let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + let expectedAttributes: [MSALNativeAuthRequiredAttribute] = [ .init(name: "attribute1", type: "", required: true), .init(name: "attribute2", type: "", required: true), ] diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift index dc63bb1f1c..7b26d52cf5 100644 --- a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift +++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift @@ -97,7 +97,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "telemetry expectation") let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", continuationToken: "continuationToken", correlationId: correlationId) - let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + let expectedAttributes: [MSALNativeAuthRequiredAttribute] = [ .init(name: "anAttribute", type: "aType", required: true) ] @@ -119,7 +119,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase { let exp = expectation(description: "sign-up states") let exp2 = expectation(description: "telemetry expectation") let expectedState = SignUpAttributesRequiredState(controller: MSALNativeAuthSignUpControllerMock(), username: "", continuationToken: "continuationToken", correlationId: correlationId) - let expectedAttributes: [MSALNativeAuthRequiredAttributes] = [ + let expectedAttributes: [MSALNativeAuthRequiredAttribute] = [ .init(name: "anAttribute", type: "aType", required: true) ] From b34229dcba06131c17d59976d06b63f939c4a6d2 Mon Sep 17 00:00:00 2001 From: mipetriu Date: Tue, 16 Jan 2024 15:28:36 -0800 Subject: [PATCH 33/84] Removed reference to MSIDInteractiveParam for preferredAuthMethod and put pc=18 directly into extraAuthorizeQP --- MSAL/IdentityCore | 2 +- MSAL/src/MSALPublicClientApplication.m | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 620960a9d0..45fdb31097 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 620960a9d0be56feffc795296e0d1d7b23d73474 +Subproject commit 45fdb3109757d6cec3fea20f787dc94882b184cf diff --git a/MSAL/src/MSALPublicClientApplication.m b/MSAL/src/MSALPublicClientApplication.m index 8459f7ce3d..e3d9b5399f 100644 --- a/MSAL/src/MSALPublicClientApplication.m +++ b/MSAL/src/MSALPublicClientApplication.m @@ -1183,6 +1183,13 @@ - (void)acquireTokenWithParameters:(MSALInteractiveTokenParameters *)parameters // Extra parameters to be added to the /authorize endpoint. msidParams.extraAuthorizeURLQueryParameters = self.internalConfig.extraQueryParameters.extraAuthorizeURLQueryParameters; + if (parameters.preferredAuthMethod == MSALPreferredAuthMethodQRPIN) + { + NSMutableDictionary *extraAuthorizeURLQueryParameters = [msidParams.extraAuthorizeURLQueryParameters mutableCopy];; + [extraAuthorizeURLQueryParameters setObject:MSID_PREFERRED_AUTH_METHOD_QR_PIN forKey:MSID_PREFERRED_AUTH_METHOD_KEY]; + msidParams.extraAuthorizeURLQueryParameters = extraAuthorizeURLQueryParameters; + } + // Extra parameters to be added to the /token endpoint. msidParams.extraTokenRequestParameters = self.internalConfig.extraQueryParameters.extraTokenURLParameters; @@ -1206,11 +1213,6 @@ - (void)acquireTokenWithParameters:(MSALInteractiveTokenParameters *)parameters msidParams.currentRequestTelemetry.apiId = [msidParams.telemetryApiId integerValue]; msidParams.currentRequestTelemetry.tokenCacheRefreshType = TokenCacheRefreshTypeNoCacheLookupInvolved; - if (parameters.preferredAuthMethod == MSALPreferredAuthMethodQRPIN) - { - msidParams.preferredAuthMethod = MSIDPreferredAuthMethodQRPIN; - } - MSIDAccountMetadataState signInState = [self accountStateForParameters:msidParams error:nil]; if (signInState == MSIDAccountMetadataStateSignedOut && msidParams.promptType != MSIDPromptTypeConsent) From c8d45084c96075c80005e48242816fc5103f2c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodh=C3=A1n=20Hickey?= <110929942+rodhan-ms@users.noreply.github.com> Date: Wed, 17 Jan 2024 10:41:15 +0000 Subject: [PATCH 34/84] Print warning on console if URL scheme is not configured (#1970) * Updated public initializers of MSALNativeAuthPublicClientApplication to output a message when redirectUri is not set * Use MSALLogger instead of print to display warning about redirectUri not set --- .../network/errors/MSALNativeAuthErrorMessage.swift | 1 + .../public/MSALNativeAuthPublicClientApplication.swift | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift index fa9fefe3e7..5b35132912 100644 --- a/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift @@ -43,6 +43,7 @@ enum MSALNativeAuthErrorMessage { static let invalidCode = "Invalid code" static let refreshTokenExpired = "Refresh token is expired" static let tokenNotFound = "Token not found" + static let redirectUriNotSetWarning = "WARNING ⚠️: redirectUri not set during MSAL Native Auth initialization. Production apps must correctly configure a redirect URI and call acquireToken in response to all browserRequired errors. See https://learn.microsoft.com/entra/identity-platform/redirect-uris-ios" } // swiftlint:enable line_length diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift index beb17cacb0..6f0e4e5507 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift @@ -82,6 +82,10 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic self.cacheAccessorFactory = MSALNativeAuthCacheAccessorFactory() self.inputValidator = MSALNativeAuthInputValidator() + if config.redirectUri == nil { + MSALLogger.log(level: .warning, context: nil, format: MSALNativeAuthErrorMessage.redirectUriNotSetWarning) + } + try super.init(configuration: config) } @@ -117,6 +121,10 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic authority: ciamAuthority ) + if redirectUri == nil { + MSALLogger.log(level: .warning, context: nil, format: MSALNativeAuthErrorMessage.redirectUriNotSetWarning) + } + // we need to bypass redirect URI validation because we don't need a redirect URI for Native Auth scenarios configuration.bypassRedirectURIValidation = redirectUri == nil let defaultRedirectUri = String(format: "msauth.%@://auth", Bundle.main.bundleIdentifier ?? "") From f46564d4e9531b83074c32f83a18f0cb1f7182b0 Mon Sep 17 00:00:00 2001 From: mipetriu Date: Wed, 17 Jan 2024 15:25:22 -0800 Subject: [PATCH 35/84] add a comment to a public method --- MSAL/src/public/MSALInteractiveTokenParameters.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MSAL/src/public/MSALInteractiveTokenParameters.h b/MSAL/src/public/MSALInteractiveTokenParameters.h index 01f8013453..455dff2681 100644 --- a/MSAL/src/public/MSALInteractiveTokenParameters.h +++ b/MSAL/src/public/MSALInteractiveTokenParameters.h @@ -95,6 +95,10 @@ Modal presentation style for displaying authentication web content. */ @property (nonatomic, nullable) WKWebView *customWebview DEPRECATED_MSG_ATTRIBUTE("Create MSALWebviewParameters and provide it to -initWithScopes:webviewParameters: instead"); +/** + The pre-defined preferred auth method for the interactive request. + By default, it will be set to MSALPreferredAuthMethod.MSALPreferredAuthMethodNone. + */ @property (nonatomic) MSALPreferredAuthMethod preferredAuthMethod; #pragma mark - Constructing MSALInteractiveTokenParameters From 647990c2f283838da72179146e4f031bec7c6632 Mon Sep 17 00:00:00 2001 From: Silviu Petrescu <111577419+spetrescu84@users.noreply.github.com> Date: Fri, 19 Jan 2024 14:06:36 +0000 Subject: [PATCH 36/84] Rename invalid client to unauthorized client (#1972) * Renamed invalidClient to unauthorizedClient * Added back the skipping of the test * Renamed all internal invalidClient references to unauthorizedClient except for the /token endpoint * Added unauthorizedClient to responses from MockAPI * Skipping unauthorizedClient as the response is not yet implemented --- .../MSALNativeAuthSignUpController.swift | 2 +- ...esetPasswordChallengeOauth2ErrorCode.swift | 2 +- ...hResetPasswordChallengeResponseError.swift | 4 ++-- ...ResetPasswordContinueOauth2ErrorCode.swift | 2 +- ...thResetPasswordContinueResponseError.swift | 2 +- ...asswordPollCompletionOauth2ErrorCode.swift | 2 +- ...tPasswordPollCompletionResponseError.swift | 2 +- ...uthResetPasswordStartOauth2ErrorCode.swift | 2 +- ...thResetPasswordSubmitOauth2ErrorCode.swift | 2 +- ...AuthResetPasswordSubmitResponseError.swift | 2 +- ...veAuthResetPasswordResponseValidator.swift | 10 ++++---- ...eAuthResetPasswordValidatedResponses.swift | 4 ++-- ...SALNativeAuthSignInResponseValidator.swift | 4 ++-- ...AuthSignInChallengeValidatedResponse.swift | 4 ++-- ...eAuthSignInInitiateValidatedResponse.swift | 6 ++--- ...SALNativeAuthSignUpResponseValidator.swift | 2 +- ...ALNativeAuthSignUpValidatedResponses.swift | 2 +- ...MSALNativeAuthTokenResponseValidator.swift | 2 +- ...MSALNativeAuthTokenValidatedResponse.swift | 8 +++---- .../native_auth/common/Model.swift | 1 + ...setPasswordChallengeIntegrationTests.swift | 8 ++++--- ...esetPasswordContinueIntegrationTests.swift | 8 ++++--- ...sswordPollCompletionIntegrationTests.swift | 8 ++++--- ...thResetPasswordStartIntegrationTests.swift | 8 ++++--- ...hResetPasswordSubmitIntegrationTests.swift | 8 ++++--- ...eAuthSignInChallengeIntegrationTests.swift | 2 +- ...veAuthSignInInitiateIntegrationTests.swift | 2 +- ...eAuthSignUpChallengeIntegrationTests.swift | 2 +- ...veAuthSignUpContinueIntegrationTests.swift | 2 +- ...ativeAuthSignUpStartIntegrationTests.swift | 2 +- ...NativeAuthCredentialsControllerTests.swift | 2 +- .../MSALNativeAuthSignInControllerTests.swift | 12 +++++----- .../MSALNativeAuthSignUpControllerTests.swift | 12 +++++----- ...asswordChallengeOauth2ErrorCodeTests.swift | 4 ++-- ...tPasswordChallengeResponseErrorTests.swift | 8 +++---- ...PasswordContinueOauth2ErrorCodeTests.swift | 4 ++-- ...etPasswordContinueResponseErrorTests.swift | 4 ++-- ...rdPollCompletionOauth2ErrorCodeTests.swift | 4 ++-- ...wordPollCompletionResponseErrorTests.swift | 4 ++-- ...setPasswordStartOauth2ErrorCodeTests.swift | 4 ++-- ...etPasswordSubmitOauth2ErrorCodeTests.swift | 4 ++-- ...esetPasswordSubmitResponseErrorTests.swift | 4 ++-- ...hResetPasswordResponseValidatorTests.swift | 24 +++++++++---------- ...PasswordStartValidatedErrorTypeTests.swift | 4 ++-- ...ignInInitiateValidatedErrorTypeTests.swift | 8 +++---- ...tiveAuthSignUpResponseValidatorTests.swift | 4 ++-- ...ativeAuthTokenResponseValidatorTests.swift | 4 ++-- ...tiveAuthTokenValidatedErrorTypeTests.swift | 4 ++-- 48 files changed, 120 insertions(+), 109 deletions(-) diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift index 108606d5f1..0c1263e9d5 100644 --- a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift @@ -201,7 +201,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa context: context, format: "InvalidUsername in signup/start request \(error.errorDescription ?? "No error description")") return .init(.error(error)) - case .invalidClientId(let apiError): + case .unauthorizedClient(let apiError): let error = SignUpStartError(type: .generalError, message: apiError.errorDescription) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift index 8fd2cc2043..ec8de747f0 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift @@ -26,7 +26,7 @@ import Foundation enum MSALNativeAuthResetPasswordChallengeOauth2ErrorCode: String, Decodable, CaseIterable { case invalidRequest = "invalid_request" - case invalidClient = "invalid_client" + case unauthorizedClient = "unauthorized_client" case expiredToken = "expired_token" case unsupportedChallengeType = "unsupported_challenge_type" } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift index 25ec42d489..7013e1440b 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift @@ -48,7 +48,7 @@ extension MSALNativeAuthResetPasswordChallengeResponseError { func toResetPasswordStartPublicError() -> ResetPasswordStartError { switch error { case .invalidRequest, - .invalidClient, + .unauthorizedClient, .unsupportedChallengeType, .expiredToken: return .init(type: .generalError, message: errorDescription) @@ -57,7 +57,7 @@ extension MSALNativeAuthResetPasswordChallengeResponseError { func toResendCodePublicError() -> ResendCodeError { switch error { - case .invalidClient, + case .unauthorizedClient, .unsupportedChallengeType, .expiredToken, .invalidRequest: diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift index 59b7d23abf..94635283ba 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift @@ -26,7 +26,7 @@ import Foundation enum MSALNativeAuthResetPasswordContinueOauth2ErrorCode: String, Decodable, CaseIterable { case invalidRequest = "invalid_request" - case invalidClient = "invalid_client" + case unauthorizedClient = "unauthorized_client" case invalidGrant = "invalid_grant" case expiredToken = "expired_token" case verificationRequired = "verification_required" diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift index 123b244863..094444ac58 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift @@ -54,7 +54,7 @@ extension MSALNativeAuthResetPasswordContinueResponseError { case .invalidGrant: return subError == .invalidOOBValue ? .init(type: .invalidCode, message: errorDescription) : .init(type: .generalError, message: errorDescription) - case .invalidClient, + case .unauthorizedClient, .expiredToken, .invalidRequest, .verificationRequired: diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift index effb36081e..8007bdc8c0 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift @@ -27,7 +27,7 @@ import Foundation enum MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode: String, Decodable, CaseIterable { case invalidGrant = "invalid_grant" case invalidRequest = "invalid_request" - case invalidClient = "invalid_client" + case unauthorizedClient = "unauthorized_client" case expiredToken = "expired_token" case userNotFound = "user_not_found" } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift index 3a674ab01a..ec2d09aaf9 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift @@ -55,7 +55,7 @@ extension MSALNativeAuthResetPasswordPollCompletionResponseError { } else { return .init(type: .generalError, message: errorDescription) } - case .invalidClient, + case .unauthorizedClient, .expiredToken, .invalidRequest, .userNotFound: diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift index c136e4a571..4a413ec5fe 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift @@ -26,7 +26,7 @@ import Foundation enum MSALNativeAuthResetPasswordStartOauth2ErrorCode: String, Decodable, CaseIterable { case invalidRequest = "invalid_request" - case invalidClient = "invalid_client" + case unauthorizedClient = "unauthorized_client" case userNotFound = "user_not_found" case unsupportedChallengeType = "unsupported_challenge_type" } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift index 0037eda721..702bdce34c 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift @@ -26,7 +26,7 @@ import Foundation enum MSALNativeAuthResetPasswordSubmitOauth2ErrorCode: String, Decodable, CaseIterable { case invalidRequest = "invalid_request" - case invalidClient = "invalid_client" + case unauthorizedClient = "unauthorized_client" case expiredToken = "expired_token" case invalidGrant = "invalid_grant" } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift index 15452206d5..380bc7c7c1 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift @@ -55,7 +55,7 @@ extension MSALNativeAuthResetPasswordSubmitResponseError { } else { return .init(type: .generalError, message: errorDescription) } - case .invalidClient, + case .unauthorizedClient, .expiredToken, .invalidRequest: return .init(type: .generalError, message: errorDescription) diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift index 44ef1db68d..5a8588a85a 100644 --- a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift @@ -83,8 +83,8 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas } else { return .error(.invalidRequest(message: apiError.errorDescription)) } - case .invalidClient: - return .error(.invalidClient(message: apiError.errorDescription)) + case .unauthorizedClient: + return .error(.unauthorizedClient(message: apiError.errorDescription)) case .userNotFound: return .error(.userNotFound(message: apiError.errorDescription)) case .unsupportedChallengeType: @@ -173,7 +173,7 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas switch apiError.error { case .invalidGrant: return apiError.subError == .invalidOOBValue ? .invalidOOB : .error(apiError) - case .invalidClient, + case .unauthorizedClient, .expiredToken, .invalidRequest: return .error(apiError) @@ -220,7 +220,7 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas return .error(apiError) } case .invalidRequest, - .invalidClient, + .unauthorizedClient, .expiredToken: return .error(apiError) } @@ -265,7 +265,7 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas } case .userNotFound, .invalidRequest, - .invalidClient, + .unauthorizedClient, .expiredToken: return .error(apiError) } diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift index 5d0074ec64..4c03a89974 100644 --- a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift +++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift @@ -31,7 +31,7 @@ enum MSALNativeAuthResetPasswordStartValidatedResponse { enum MSALNativeAuthResetPasswordStartValidatedErrorType: Error { case invalidRequest(message: String?) - case invalidClient(message: String?) + case unauthorizedClient(message: String?) case userNotFound(message: String?) case unsupportedChallengeType(message: String?) case userDoesNotHavePassword @@ -42,7 +42,7 @@ enum MSALNativeAuthResetPasswordStartValidatedErrorType: Error { return .init(type: .userNotFound, message: message) case .unsupportedChallengeType(let message), .invalidRequest(let message), - .invalidClient(let message): + .unauthorizedClient(let message): return .init(type: .generalError, message: message) case .userDoesNotHavePassword: return .init(type: .userDoesNotHavePassword, message: MSALNativeAuthErrorMessage.userDoesNotHavePassword) diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift index 3aa93dbdc7..8bf625a13c 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift @@ -133,7 +133,7 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV case .invalidRequest: return .error(.invalidRequest(message: error.errorDescription)) case .unauthorizedClient: - return .error(.invalidClient(message: error.errorDescription)) + return .error(.unauthorizedClient(message: error.errorDescription)) case .invalidGrant: return .error(.invalidToken(message: error.errorDescription)) case .expiredToken: @@ -150,7 +150,7 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV case .invalidRequest: return .error(.invalidRequest(message: error.errorDescription)) case .unauthorizedClient: - return .error(.invalidClient(message: error.errorDescription)) + return .error(.unauthorizedClient(message: error.errorDescription)) case .unsupportedChallengeType: return .error(.unsupportedChallengeType(message: error.errorDescription)) case .userNotFound: diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift index a0f446cb14..c3b0817b59 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift @@ -34,7 +34,7 @@ enum MSALNativeAuthSignInChallengeValidatedErrorType: Error { case redirect case expiredToken(message: String?) case invalidToken(message: String?) - case invalidClient(message: String?) + case unauthorizedClient(message: String?) case invalidRequest(message: String?) case invalidServerResponse case userNotFound(message: String?) @@ -50,7 +50,7 @@ enum MSALNativeAuthSignInChallengeValidatedErrorType: Error { .invalidToken(let message), .invalidRequest(let message): return .init(type: .generalError, message: message) - case .invalidClient(let message): + case .unauthorizedClient(let message): return .init(type: .generalError, message: message) case .userNotFound(let message): return .init(type: .userNotFound, message: message) diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift index 45d6cb274e..d76c6ec3eb 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift @@ -31,7 +31,7 @@ enum MSALNativeAuthSignInInitiateValidatedResponse { enum MSALNativeAuthSignInInitiateValidatedErrorType: Error { case redirect - case invalidClient(message: String?) + case unauthorizedClient(message: String?) case invalidRequest(message: String?) case invalidServerResponse case userNotFound(message: String?) @@ -45,7 +45,7 @@ enum MSALNativeAuthSignInInitiateValidatedErrorType: Error { return .init(type: .userNotFound, message: message) case .invalidServerResponse: return .init(type: .generalError) - case .invalidClient(let message), + case .unauthorizedClient(let message), .unsupportedChallengeType(let message), .invalidRequest(let message): return .init(type: .generalError, message: message) @@ -60,7 +60,7 @@ enum MSALNativeAuthSignInInitiateValidatedErrorType: Error { return .init(type: .userNotFound, message: message) case .invalidServerResponse: return .init(type: .generalError) - case .invalidClient(let message), + case .unauthorizedClient(let message), .unsupportedChallengeType(let message), .invalidRequest(let message): return .init(type: .generalError, message: message) diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift index 7d43519753..46272fc685 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift @@ -91,7 +91,7 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV case .invalidRequest where isSignUpStartInvalidRequestParameter( apiError, knownErrorDescription: MSALNativeAuthESTSApiErrorDescriptions.clientIdParameterIsEmptyOrNotValid.rawValue): - return .invalidClientId(apiError) + return .unauthorizedClient(apiError) default: return .error(apiError) } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift index b9844b4d25..b3261cff96 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift @@ -29,7 +29,7 @@ enum MSALNativeAuthSignUpStartValidatedResponse: Equatable { case error(MSALNativeAuthSignUpStartResponseError) // TODO: Special errors handled separately. Remove after refactor validated error handling case invalidUsername(MSALNativeAuthSignUpStartResponseError) - case invalidClientId(MSALNativeAuthSignUpStartResponseError) + case unauthorizedClient(MSALNativeAuthSignUpStartResponseError) case unexpectedError } diff --git a/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift index a856880c81..eece78e64e 100644 --- a/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift @@ -97,7 +97,7 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal return handleInvalidRequestErrorCodes(responseError.errorCodes, errorDescription: responseError.errorDescription, context: context) case .invalidClient, .unauthorizedClient: - return .error(.invalidClient(message: responseError.errorDescription)) + return .error(.unauthorizedClient(message: responseError.errorDescription)) case .invalidGrant: if responseError.subError == .invalidOOBValue { return .error(.invalidOOBCode(message: responseError.errorDescription)) diff --git a/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift index e95dae8d7d..d9a234ea8b 100644 --- a/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift @@ -33,7 +33,7 @@ enum MSALNativeAuthTokenValidatedErrorType: Error { case generalError case expiredToken(message: String?) case expiredRefreshToken(message: String?) - case invalidClient(message: String?) + case unauthorizedClient(message: String?) case invalidRequest(message: String?) case invalidServerResponse case userNotFound(message: String?) @@ -52,7 +52,7 @@ enum MSALNativeAuthTokenValidatedErrorType: Error { .slowDown(let message), .invalidRequest(let message), .invalidOOBCode(let message), - .invalidClient(let message), + .unauthorizedClient(let message), .unsupportedChallengeType(let message), .invalidScope(let message): return SignInStartError(type: .generalError, message: message) @@ -78,7 +78,7 @@ enum MSALNativeAuthTokenValidatedErrorType: Error { .authorizationPending(let message), .slowDown(let message), .invalidRequest(let message), - .invalidClient(let message), + .unauthorizedClient(let message), .unsupportedChallengeType(let message), .invalidScope(let message): return RetrieveAccessTokenError(type: .generalError, message: message) @@ -108,7 +108,7 @@ enum MSALNativeAuthTokenValidatedErrorType: Error { .authorizationPending(let message), .slowDown(let message), .invalidRequest(let message), - .invalidClient(let message), + .unauthorizedClient(let message), .unsupportedChallengeType(let message), .invalidScope(let message), .expiredRefreshToken(let message), diff --git a/MSAL/test/integration/native_auth/common/Model.swift b/MSAL/test/integration/native_auth/common/Model.swift index 870d7b5dc6..81621c8395 100644 --- a/MSAL/test/integration/native_auth/common/Model.swift +++ b/MSAL/test/integration/native_auth/common/Model.swift @@ -49,6 +49,7 @@ enum MockAPIResponse: String { case invalidRequest = "InvalidRequest" case invalidToken = "InvalidToken" case invalidClient = "InvalidClient" + case unauthorizedClient = "UnauthorizedClient" case invalidGrant = "InvalidGrant" case invalidScope = "InvalidScope" case expiredToken = "ExpiredToken" diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift index 31f7b2f5d9..c9b7e5e547 100644 --- a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordChallengeIntegrationTests.swift @@ -74,11 +74,13 @@ final class MSALNativeAuthResetPasswordChallengeIntegrationTests: MSALNativeAuth XCTAssertNil(response?.codeLength) } - func test_resetPasswordChallenge_invalidClient() async throws { + func test_resetPasswordChallenge_unauthorizedClient() async throws { + throw XCTSkip() + try await perform_testFail( endpoint: .resetPasswordChallenge, - response: .invalidClient, - expectedError: createError(.invalidClient) + response: .unauthorizedClient, + expectedError: createError(.unauthorizedClient) ) } diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift index b59ca975ff..1f39062e95 100644 --- a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordContinueIntegrationTests.swift @@ -61,11 +61,13 @@ final class MSALNativeAuthResetPasswordContinueIntegrationTests: MSALNativeAuthI XCTAssertNotNil(response?.expiresIn) } - func test_resetPasswordContinue_invalidClient() async throws { + func test_resetPasswordContinue_unauthorizedClient() async throws { + throw XCTSkip() + try await perform_testFail( endpoint: .resetPasswordContinue, - response: .invalidClient, - expectedError: createResetPasswordContinueError(error: .invalidClient) + response: .unauthorizedClient, + expectedError: createResetPasswordContinueError(error: .unauthorizedClient) ) } diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift index dc00bcfb82..67c1a172b8 100644 --- a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift @@ -103,11 +103,13 @@ final class MSALNativeAuthResetPasswordPollCompletionIntegrationTests: MSALNativ XCTAssertNil(response?.expiresIn) } - func test_resetPasswordPollCompletion_invalidClient() async throws { + func test_resetPasswordPollCompletion_unauthorizedClient() async throws { + throw XCTSkip() + try await perform_testFail( endpoint: .resetPasswordPollCompletion, - response: .invalidClient, - expectedError: createResetPasswordPollCompletionError(error: .invalidClient) + response: .unauthorizedClient, + expectedError: createResetPasswordPollCompletionError(error: .unauthorizedClient) ) } diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordStartIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordStartIntegrationTests.swift index 22a066a145..8515b5fd0c 100644 --- a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordStartIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordStartIntegrationTests.swift @@ -69,11 +69,13 @@ final class MSALNativeAuthResetPasswordStartIntegrationTests: MSALNativeAuthInte XCTAssertEqual(response?.challengeType, .redirect) } - func test_resetPasswordStart_invalidClient() async throws { + func test_resetPasswordStart_unauthorizedClient() async throws { + throw XCTSkip() + try await perform_testFail( endpoint: .resetPasswordStart, - response: .invalidClient, - expectedError: createResetPasswordStartError(error: .invalidClient) + response: .unauthorizedClient, + expectedError: createResetPasswordStartError(error: .unauthorizedClient) ) } diff --git a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordSubmitIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordSubmitIntegrationTests.swift index b33419728b..e57f57ebee 100644 --- a/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordSubmitIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/reset_password/MSALNativeAuthResetPasswordSubmitIntegrationTests.swift @@ -60,11 +60,13 @@ final class MSALNativeAuthResetPasswordSubmitIntegrationTests: MSALNativeAuthInt XCTAssertNotNil(response?.pollInterval) } - func test_resetPasswordSubmit_invalidClient() async throws { + func test_resetPasswordSubmit_unauthorizedClient() async throws { + throw XCTSkip() + try await perform_testFail( endpoint: .resetPasswordSubmit, - response: .invalidClient, - expectedError: createError(.invalidClient) + response: .unauthorizedClient, + expectedError: createError(.unauthorizedClient) ) } diff --git a/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInChallengeIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInChallengeIntegrationTests.swift index ad0d1a50c8..071b1c4c65 100644 --- a/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInChallengeIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInChallengeIntegrationTests.swift @@ -80,7 +80,7 @@ class MSALNativeAuthSignInChallengeIntegrationTests: MSALNativeAuthIntegrationBa try await perform_testFail( endpoint: .signInChallenge, - response: .invalidClient, + response: .unauthorizedClient, expectedError: Error(error: .unauthorizedClient, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) ) } diff --git a/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift index 679b9bb1f0..bdfcac292d 100644 --- a/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/sign_in/MSALNativeAuthSignInInitiateIntegrationTests.swift @@ -69,7 +69,7 @@ class MSALNativeAuthSignInInitiateIntegrationTests: MSALNativeAuthIntegrationBas try await perform_testFail( endpoint: .signInInitiate, - response: .invalidClient, + response: .unauthorizedClient, expectedError: Error(error: .unauthorizedClient, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) ) } diff --git a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift index 6278a999dc..fbec1cd4e1 100644 --- a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpChallengeIntegrationTests.swift @@ -77,7 +77,7 @@ final class MSALNativeAuthSignUpChallengeIntegrationTests: MSALNativeAuthIntegra try await perform_testFail( endpoint: .signUpChallenge, - response: .invalidClient, + response: .unauthorizedClient, expectedError: createError(.unauthorizedClient) ) } diff --git a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift index 9ba5e81ad2..c15207861a 100644 --- a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift @@ -89,7 +89,7 @@ final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrat try await perform_testFail( endpoint: .signUpContinue, - response: .invalidClient, + response: .unauthorizedClient, expectedError: createError(.unauthorizedClient) ) } diff --git a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift index 8090acf4f1..912c5415df 100644 --- a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift +++ b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpStartIntegrationTests.swift @@ -68,7 +68,7 @@ final class MSALNativeAuthSignUpStartIntegrationTests: MSALNativeAuthIntegration try await perform_testFail( endpoint: .signUpStart, - response: .invalidClient, + response: .unauthorizedClient, expectedError: createError(.unauthorizedClient) ) } diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift index 314695362f..75bba41b3b 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift @@ -163,7 +163,7 @@ final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase { await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .slowDown(message: nil)) await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .invalidRequest(message: nil)) await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: MSALNativeAuthErrorMessage.invalidServerResponse), validatorError: .invalidServerResponse) - await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Invalid Client ID"), validatorError: .invalidClient(message: "Invalid Client ID")) + await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Invalid Client ID"), validatorError: .unauthorizedClient(message: "Invalid Client ID")) await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Unsupported challenge type"), validatorError: .unsupportedChallengeType(message: "Unsupported challenge type")) await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Invalid scope"), validatorError: .invalidScope(message: "Invalid scope")) await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .refreshTokenExpired), validatorError: .expiredRefreshToken(message: nil)) diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift index 060ca42f0b..8dd8bff809 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift @@ -263,7 +263,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .slowDown(message: nil)) await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidRequest(message: nil)) await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Invalid server response"), validatorError: .invalidServerResponse) - await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Invalid Client ID"), validatorError: .invalidClient(message: "Invalid Client ID")) + await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Invalid Client ID"), validatorError: .unauthorizedClient(message: "Invalid Client ID")) await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Unsupported challenge type"), validatorError: .unsupportedChallengeType(message: "Unsupported challenge type")) await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Invalid scope"), validatorError: .invalidScope(message: "Invalid scope")) await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .userNotFound), validatorError: .userNotFound(message: nil)) @@ -469,7 +469,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { func test_whenSignInWithCodeStartAndInitiateReturnError_properErrorShouldBeReturned() async { await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .browserRequired), validatorError: .redirect) - await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError, message: nil), validatorError: .invalidClient(message: nil)) + await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError, message: nil), validatorError: .unauthorizedClient(message: nil)) await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .userNotFound), validatorError: .userNotFound(message: nil)) await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .unsupportedChallengeType(message: nil)) await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidRequest(message: nil)) @@ -502,7 +502,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidToken(message: nil)) await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidRequest(message: nil)) await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidServerResponse) - await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: nil), validatorError: .invalidClient(message: nil)) + await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: nil), validatorError: .unauthorizedClient(message: nil)) await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .userNotFound), validatorError: .userNotFound(message: nil)) await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: nil), validatorError: .unsupportedChallengeType(message: nil)) } @@ -632,7 +632,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { func test_whenSignInWithCodeSubmitPasswordTokenAPIReturnError_correctErrorShouldBeReturned() async { await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .generalError) await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .expiredToken(message: nil)) - await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidClient(message: nil)) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .unauthorizedClient(message: nil)) await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidRequest(message: nil)) await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidServerResponse) await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .userNotFound(message: nil)) @@ -665,7 +665,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { func test_signInWithCodeSubmitCodeReturnError_correctResultShouldReturned() { checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .generalError) checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .expiredToken(message: nil)) - checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidClient(message: nil)) + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .unauthorizedClient(message: nil)) checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidRequest(message: nil)) checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidServerResponse) checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .userNotFound(message: nil)) @@ -826,7 +826,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: expectation, expectedError: SignInAfterSignUpError(message: "Invalid Client ID")) - tokenResponseValidatorMock.tokenValidatedResponse = .error(.invalidClient(message: "Invalid Client ID")) + tokenResponseValidatorMock.tokenValidatedResponse = .error(.unauthorizedClient(message: "Invalid Client ID")) let state = SignInAfterSignUpState(controller: sut, username: "", continuationToken: continuationToken, correlationId: defaultUUID) state.signIn(delegate: mockDelegate) diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift index eef16ebe58..03fdb5947d 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift @@ -247,10 +247,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) } - func test_whenSignUpStartPassword_returns_invalidClientId_it_returnsGeneralError() async { + func test_whenSignUpStartPassword_returns_unauthorizedClient_it_returnsGeneralError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - let invalidClientId : MSALNativeAuthSignUpStartValidatedResponse = .invalidClientId( + let unauthorizedClient : MSALNativeAuthSignUpStartValidatedResponse = .unauthorizedClient( MSALNativeAuthSignUpStartResponseError(error: .invalidRequest, subError: nil, errorDescription: nil, @@ -260,7 +260,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { continuationToken: nil, unverifiedAttributes: nil, invalidAttributes: nil)) - validatorMock.mockValidateSignUpStartFunc(invalidClientId) + validatorMock.mockValidateSignUpStartFunc(unauthorizedClient) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) @@ -635,10 +635,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) } - func test_whenSignUpStartCode_returns_invalidClientId_it_returnsGeneralError() async { + func test_whenSignUpStartCode_returns_unauthorizedClient_it_returnsGeneralError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - let invalidClientId : MSALNativeAuthSignUpStartValidatedResponse = .invalidClientId( + let unauthorizedClient : MSALNativeAuthSignUpStartValidatedResponse = .unauthorizedClient( MSALNativeAuthSignUpStartResponseError(error: .invalidRequest, subError: nil, errorDescription: nil, @@ -648,7 +648,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { continuationToken: nil, unverifiedAttributes: nil, invalidAttributes: nil)) - validatorMock.mockValidateSignUpStartFunc(invalidClientId) + validatorMock.mockValidateSignUpStartFunc(unauthorizedClient) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift index 6e185a4e71..5cd00827ba 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift @@ -37,8 +37,8 @@ final class MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests: XCTestCase XCTAssertEqual(sut.invalidRequest.rawValue, "invalid_request") } - func test_invalidClient() { - XCTAssertEqual(sut.invalidClient.rawValue, "invalid_client") + func test_unauthorizedClient() { + XCTAssertEqual(sut.unauthorizedClient.rawValue, "unauthorized_client") } func test_expiredToken() { diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift index 8f06f3adb1..02a9922f40 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift @@ -32,8 +32,8 @@ final class MSALNativeAuthResetPasswordChallengeResponseErrorTests: XCTestCase { // MARK: - to ResetPasswordStartError tests - func test_toResetPasswordStartPublicError_invalidClient() { - sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .invalidClient, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) + func test_toResetPasswordStartPublicError_unauthorizedClient() { + sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .unauthorizedClient, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) let error = sut.toResetPasswordStartPublicError() XCTAssertEqual(error.type, .generalError) XCTAssertEqual(error.errorDescription, testDescription) @@ -62,8 +62,8 @@ final class MSALNativeAuthResetPasswordChallengeResponseErrorTests: XCTestCase { // MARK: - to ResendCodePublicError tests - func test_toResendCodePublicError_invalidClient() { - sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .invalidClient, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) + func test_toResendCodePublicError_unauthorizedClient() { + sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .unauthorizedClient, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil) let error = sut.toResendCodePublicError() XCTAssertEqual(error.errorDescription, testDescription) } diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift index e03f6639bb..6de5119040 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift @@ -37,8 +37,8 @@ final class MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests: XCTestCase XCTAssertEqual(sut.invalidRequest.rawValue, "invalid_request") } - func test_invalidClient() { - XCTAssertEqual(sut.invalidClient.rawValue, "invalid_client") + func test_unauthorizedClient() { + XCTAssertEqual(sut.unauthorizedClient.rawValue, "unauthorized_client") } func test_invalidGrant() { diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift index a2a855459b..7359144745 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift @@ -39,8 +39,8 @@ final class MSALNativeAuthResetPasswordContinueResponseErrorTests: XCTestCase { XCTAssertNotNil(error.errorDescription) } - func test_toResetPasswordStartPublicError_invalidClient() { - sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidClient, subError: nil, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) + func test_toResetPasswordStartPublicError_unauthorizedClient() { + sut = MSALNativeAuthResetPasswordContinueResponseError(error: .unauthorizedClient, subError: nil, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil) let error = sut.toVerifyCodePublicError() XCTAssertEqual(error.type, .generalError) XCTAssertEqual(error.errorDescription, testDescription) diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift index 34fbc5c305..5efaa3ec29 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift @@ -41,8 +41,8 @@ final class MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests: XCTes XCTAssertEqual(sut.invalidRequest.rawValue, "invalid_request") } - func test_invalidClient() { - XCTAssertEqual(sut.invalidClient.rawValue, "invalid_client") + func test_unauthorizedClient() { + XCTAssertEqual(sut.unauthorizedClient.rawValue, "unauthorized_client") } func test_expiredToken() { diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift index ee34968f0b..4e9044f5d2 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift @@ -36,8 +36,8 @@ final class MSALNativeAuthResetPasswordPollCompletionResponseErrorTests: XCTestC testPasswordRequiredError(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError) } - func test_toPasswordRequiredPublicError_invalidClient() { - testPasswordRequiredError(code: .invalidClient, description: "General error", expectedErrorType: .generalError) + func test_toPasswordRequiredPublicError_unauthorizedClient() { + testPasswordRequiredError(code: .unauthorizedClient, description: "General error", expectedErrorType: .generalError) } func test_toPasswordRequiredPublicError_expiredToken() { diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift index 9c6eab4e60..4b938e476b 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift @@ -37,8 +37,8 @@ final class MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests: XCTestCase { XCTAssertEqual(sut.invalidRequest.rawValue, "invalid_request") } - func test_invalidClient() { - XCTAssertEqual(sut.invalidClient.rawValue, "invalid_client") + func test_unauthorizedClient() { + XCTAssertEqual(sut.unauthorizedClient.rawValue, "unauthorized_client") } func test_userNotFound() { diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift index f0476682fb..28add44966 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift @@ -37,8 +37,8 @@ final class MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests: XCTestCase { XCTAssertEqual(sut.invalidRequest.rawValue, "invalid_request") } - func test_invalidClient() { - XCTAssertEqual(sut.invalidClient.rawValue, "invalid_client") + func test_unauthorizedClient() { + XCTAssertEqual(sut.unauthorizedClient.rawValue, "unauthorized_client") } func test_expiredToken() { diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift index 13a1438efc..2c21c5e709 100644 --- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift +++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift @@ -36,8 +36,8 @@ final class MSALNativeAuthResetPasswordSubmitResponseErrorTests: XCTestCase { testPasswordRequiredError(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError) } - func test_toPasswordRequiredPublicError_invalidClient() { - testPasswordRequiredError(code: .invalidClient, description: "General error", expectedErrorType: .generalError) + func test_toPasswordRequiredPublicError_unauthorizedClient() { + testPasswordRequiredError(code: .unauthorizedClient, description: "General error", expectedErrorType: .generalError) } func test_toPasswordRequiredPublicError_expiredToken() { diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift index be125739a7..e718ccbad6 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift @@ -95,12 +95,12 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } } - func test_whenResetPasswordStartErrorResponseInvalidClient_itReturnsRelatedError() { - let error = createResetPasswordStartError(error: .invalidClient) + func test_whenResetPasswordStartErrorResponseUnauthorizedClient_itReturnsRelatedError() { + let error = createResetPasswordStartError(error: .unauthorizedClient) let response: Result = .failure(error) let result = sut.validate(response, with: context) - if case .error(.invalidClient) = result {} else { + if case .error(.unauthorizedClient) = result {} else { XCTFail("Unexpected result: \(result)") } } @@ -265,13 +265,13 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { XCTAssertEqual(result, .unexpectedError) } - func test_whenResetPasswordContinueErrorResponseIs_invalidClient_itReturnsExpectedError() { - let result = buildContinueErrorResponse(expectedError: .invalidClient) + func test_whenResetPasswordContinueErrorResponseIs_unauthorizedClient_itReturnsExpectedError() { + let result = buildContinueErrorResponse(expectedError: .unauthorizedClient) guard case .error(let error) = result else { return XCTFail("Unexpected response") } - if case .invalidClient = error.error {} else { + if case .unauthorizedClient = error.error {} else { XCTFail("Unexpected error: \(error.error)") } } @@ -390,13 +390,13 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } } - func test_whenResetPasswordSubmitErrorResponseIs_invalidClient_itReturnsExpectedError() { - let result = buildSubmitErrorResponse(expectedError: .invalidClient) + func test_whenResetPasswordSubmitErrorResponseIs_unauthorizedClient_itReturnsExpectedError() { + let result = buildSubmitErrorResponse(expectedError: .unauthorizedClient) guard case .error(let error) = result else { return XCTFail("Unexpected response") } - if case .invalidClient = error.error {} else { + if case .unauthorizedClient = error.error {} else { XCTFail("Unexpected error: \(error.error)") } } @@ -500,13 +500,13 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } } - func test_whenResetPasswordPollCompletionErrorResponseIsInvalidClient_itReturnsExpectedError() { - let result = buildPollCompletionErrorResponse(expectedError: .invalidClient) + func test_whenResetPasswordPollCompletionErrorResponseIsUnauthorizedClient_itReturnsExpectedError() { + let result = buildPollCompletionErrorResponse(expectedError: .unauthorizedClient) guard case .error(let error) = result else { return XCTFail("Unexpected response") } - if case .invalidClient = error.error {} else { + if case .unauthorizedClient = error.error {} else { XCTFail("Unexpected error: \(error.error)") } } diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift index 328806c000..d76e16adcf 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift @@ -32,8 +32,8 @@ final class MSALNativeAuthResetPasswordStartValidatedErrorTypeTests: XCTestCase // MARK: - to ResetPasswordStartError tests - func test_toResetPasswordStartPublicError_invalidClient() { - let error = sut.invalidClient(message: testDescription).toResetPasswordStartPublicError() + func test_toResetPasswordStartPublicError_unauthorizedClient() { + let error = sut.unauthorizedClient(message: testDescription).toResetPasswordStartPublicError() XCTAssertEqual(error.type, .generalError) XCTAssertEqual(error.errorDescription, testDescription) } diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift index 5e41ee28fd..fd76b95963 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift @@ -39,8 +39,8 @@ final class MSALNativeAuthSignInInitiateValidatedErrorTypeTests: XCTestCase { XCTAssertEqual(error.errorDescription, MSALNativeAuthErrorMessage.browserRequired) } - func test_convertToSignInStartError_invalidClient() { - let error = sut.invalidClient(message: testDescription).convertToSignInStartError() + func test_convertToSignInStartError_unauthorizedClient() { + let error = sut.unauthorizedClient(message: testDescription).convertToSignInStartError() XCTAssertEqual(error.type, .generalError) XCTAssertEqual(error.errorDescription, testDescription) } @@ -77,8 +77,8 @@ final class MSALNativeAuthSignInInitiateValidatedErrorTypeTests: XCTestCase { XCTAssertEqual(error.errorDescription, MSALNativeAuthErrorMessage.browserRequired) } - func test_convertToSignInPasswordStartError_invalidClient() { - let error = sut.invalidClient(message: testDescription).convertToSignInPasswordStartError() + func test_convertToSignInPasswordStartError_unauthorizedClient() { + let error = sut.unauthorizedClient(message: testDescription).convertToSignInPasswordStartError() XCTAssertEqual(error.type, .generalError) XCTAssertEqual(error.errorDescription, testDescription) } diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift index 7aa03c604d..bbafe6ab64 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift @@ -154,7 +154,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { XCTAssertEqual(error as MSALNativeAuthSignUpStartResponseError, apiError) } - func test_whenSignUpStartErrorResponseIs_invalidRequestWithInvalidClientIdErrorDescription_it_returns_expectedError() { + func test_whenSignUpStartErrorResponseIs_invalidRequestWithUnauthorizedClientErrorDescription_it_returns_expectedError() { let attributes = [MSALNativeAuthErrorBasicAttribute(name: "attribute")] let errorCodes = [MSALNativeAuthESTSApiErrorCodes.invalidRequestParameter.rawValue, Int.max] @@ -170,7 +170,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { let response: Result = .failure(apiError) let result = sut.validate(response, with: context) - guard case .invalidClientId(let error) = result else { + guard case .unauthorizedClient(let error) = result else { return XCTFail("Unexpected response") } diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift index 34d48ec1af..7c984a3a81 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift @@ -112,7 +112,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { return XCTFail("Unexpected response") } - if case .invalidClient(message: nil) = innerError {} else { + if case .unauthorizedClient(message: nil) = innerError {} else { XCTFail("Unexpected Error") } } @@ -127,7 +127,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { return XCTFail("Unexpected response") } - if case .invalidClient(message: nil) = innerError {} else { + if case .unauthorizedClient(message: nil) = innerError {} else { XCTFail("Unexpected Error") } } diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift index 00bec14919..6d8f997c49 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift @@ -51,8 +51,8 @@ final class MSALNativeAuthTokenValidatedErrorTypeTests: XCTestCase { XCTAssertEqual(error.errorDescription, testDescription) } - func test_convertToSignInPasswordStartError_invalidClient() { - let error = sut.invalidClient(message: testDescription).convertToSignInPasswordStartError() + func test_convertToSignInPasswordStartError_unauthorizedClient() { + let error = sut.unauthorizedClient(message: testDescription).convertToSignInPasswordStartError() XCTAssertEqual(error.type, .generalError) XCTAssertEqual(error.errorDescription, testDescription) } From cc4b6ead0db863637036aba0e7efc4290e8820e9 Mon Sep 17 00:00:00 2001 From: Olga Dalton Date: Fri, 19 Jan 2024 15:15:12 -0800 Subject: [PATCH 37/84] Support dual headed acount hint in broker --- MSAL/IdentityCore | 2 +- MSAL/test/unit/MSALPublicClientApplicationTests.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index d012ccd1b3..50dd65f817 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit d012ccd1b37df91ebb6dc11084677cbb3f6eed2c +Subproject commit 50dd65f817950a9b5c25306eaa9e20e5c0ba6b7d diff --git a/MSAL/test/unit/MSALPublicClientApplicationTests.m b/MSAL/test/unit/MSALPublicClientApplicationTests.m index 731107a187..835d9e4c6a 100644 --- a/MSAL/test/unit/MSALPublicClientApplicationTests.m +++ b/MSAL/test/unit/MSALPublicClientApplicationTests.m @@ -3272,7 +3272,7 @@ - (void)testRemoveAccount_whenAccountExists_andIsFociClient_shouldRemoveAccount_ XCTAssertEqual([application allAccounts:nil].count, 0); // 5. Make sure account and FOCI tokens are still in cache - MSIDAccount *cachedAccount = [self.tokenCacheAccessor getAccountForIdentifier:account.accountIdentifier authority:authority realmHint:nil context:nil error:nil]; + MSIDAccount *cachedAccount = [self.tokenCacheAccessor getAccountForIdentifier:account.accountIdentifier authority:authority realmHint:nil dualHeadedAccountHint:nil accountSelectionLog:nil context:nil error:nil]; XCTAssertNotNil(cachedAccount); MSIDRefreshToken *fociToken = [self.tokenCacheAccessor getRefreshTokenWithAccount:account.accountIdentifier familyId:@"1" configuration:configuration context:nil error:nil]; From 84217a1c1cdc4a44470d9a6b5938b1c36c7fd2fd Mon Sep 17 00:00:00 2001 From: Olga Dalton Date: Sun, 21 Jan 2024 16:07:21 -0800 Subject: [PATCH 38/84] Updated variable name --- MSAL/IdentityCore | 2 +- MSAL/test/unit/MSALPublicClientApplicationTests.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 7d184c4364..7441b5e351 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 7d184c4364e25fd496730e416f89b4af6a153788 +Subproject commit 7441b5e351da79b3047f9af96b411f81b18c8446 diff --git a/MSAL/test/unit/MSALPublicClientApplicationTests.m b/MSAL/test/unit/MSALPublicClientApplicationTests.m index 9ad5f132ed..2ab56e61e6 100644 --- a/MSAL/test/unit/MSALPublicClientApplicationTests.m +++ b/MSAL/test/unit/MSALPublicClientApplicationTests.m @@ -3273,7 +3273,7 @@ - (void)testRemoveAccount_whenAccountExists_andIsFociClient_shouldRemoveAccount_ XCTAssertEqual([application allAccounts:nil].count, 0); // 5. Make sure account and FOCI tokens are still in cache - MSIDAccount *cachedAccount = [self.tokenCacheAccessor getAccountForIdentifier:account.accountIdentifier authority:authority realmHint:nil dualHeadedAccountHint:nil accountSelectionLog:nil context:nil error:nil]; + MSIDAccount *cachedAccount = [self.tokenCacheAccessor getAccountForIdentifier:account.accountIdentifier authority:authority realmHint:nil dualHeadedAccountTenantIDHint:nil accountSelectionLog:nil context:nil error:nil]; XCTAssertNotNil(cachedAccount); MSIDRefreshToken *fociToken = [self.tokenCacheAccessor getRefreshTokenWithAccount:account.accountIdentifier familyId:@"1" configuration:configuration context:nil error:nil]; From 4b1dadf1d52fd5c4057d9ec4d40ee75010ed34b6 Mon Sep 17 00:00:00 2001 From: Olga Dalton Date: Sun, 21 Jan 2024 16:34:55 -0800 Subject: [PATCH 39/84] Fixed indent --- MSAL/IdentityCore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 7441b5e351..c378b86b12 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 7441b5e351da79b3047f9af96b411f81b18c8446 +Subproject commit c378b86b1275fd0c65fabb1272a16073a13b4898 From fc93af5e5245431b267c6a4367c03d864d88a9ae Mon Sep 17 00:00:00 2001 From: Silviu Petrescu <111577419+spetrescu84@users.noreply.github.com> Date: Tue, 23 Jan 2024 09:06:33 +0000 Subject: [PATCH 40/84] When SDK receives an unexpected Error type, the error description is returned to the developer (#1974) * -Allowed decoding of errors even if the type is cannot be decoded -Made the API message to be sent back all the way to the developer Fixed failing unit tests PR Comments PR comments changed invalidServerResponse to unexpectedError * Add errorDescription check to SignInDelegateSpy for passwordError * PR comments * PR comments --------- Co-authored-by: Diego Jerez --- ...SALNativeAuthResetPasswordController.swift | 40 ++++--- .../MSALNativeAuthSignUpController.swift | 60 ++++++++--- .../errors/MSALNativeAuthErrorMessage.swift | 3 +- .../errors/MSALNativeAuthInnerError.swift | 2 +- .../errors/MSALNativeAuthResponseError.swift | 2 +- ...hResetPasswordChallengeResponseError.swift | 8 +- ...thResetPasswordContinueResponseError.swift | 7 +- ...tPasswordPollCompletionResponseError.swift | 6 +- ...eAuthResetPasswordStartResponseError.swift | 2 +- ...AuthResetPasswordSubmitResponseError.swift | 5 +- ...tiveAuthSignInChallengeResponseError.swift | 2 +- ...ativeAuthSignInInitiateResponseError.swift | 2 +- ...tiveAuthSignUpChallengeResponseError.swift | 11 +- ...ativeAuthSignUpContinueResponseError.swift | 8 +- ...ALNativeAuthSignUpStartResponseError.swift | 5 +- .../MSALNativeAuthTokenResponseError.swift | 2 +- ...veAuthResetPasswordResponseValidator.swift | 40 ++++--- ...eAuthResetPasswordValidatedResponses.swift | 18 ++-- ...SALNativeAuthSignInResponseValidator.swift | 28 ++--- ...AuthSignInChallengeValidatedResponse.swift | 13 +-- ...eAuthSignInInitiateValidatedResponse.swift | 12 +-- ...SALNativeAuthSignUpResponseValidator.swift | 38 ++++--- ...ALNativeAuthSignUpValidatedResponses.swift | 6 +- ...MSALNativeAuthTokenResponseValidator.swift | 7 +- ...MSALNativeAuthTokenValidatedResponse.swift | 14 +-- ...NativeAuthCredentialsControllerTests.swift | 2 +- ...tiveAuthResetPasswordControllerTests.swift | 25 +++-- .../MSALNativeAuthSignInControllerTests.swift | 28 ++--- .../MSALNativeAuthSignUpControllerTests.swift | 31 +++--- .../mock/SignInDelegatesSpies.swift | 1 + .../mock/SignInTestsValidatorHelpers.swift | 3 +- ...ALNativeAuthRequestErrorHandlerTests.swift | 59 +++++++++-- ...hResetPasswordResponseValidatorTests.swift | 100 +++++++++++------- ...ignInInitiateValidatedErrorTypeTests.swift | 8 +- ...ativeAuthSignInResponseValidatorTest.swift | 20 ++-- ...tiveAuthSignUpResponseValidatorTests.swift | 86 ++++++++------- ...ativeAuthTokenResponseValidatorTests.swift | 2 +- ...tiveAuthTokenValidatedErrorTypeTests.swift | 4 +- 38 files changed, 436 insertions(+), 274 deletions(-) diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift index 9502588ac9..31a255b7fc 100644 --- a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift @@ -125,7 +125,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, request = try requestProvider.start(parameters: parameters) } catch { MSALLogger.log(level: .error, context: parameters.context, format: "Error creating resetpassword/start request: \(error)") - return .unexpectedError + return .unexpectedError(message: nil) } MSALLogger.log(level: .info, context: parameters.context, format: "Performing resetpassword/start request") @@ -159,8 +159,8 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context, format: "Error in resetpassword/start request \(error.errorDescription ?? "No error description")") return .init(.error(error)) - case .unexpectedError: - let error = ResetPasswordStartError(type: .generalError) + case .unexpectedError(let message): + let error = ResetPasswordStartError(type: .generalError, message: message) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, @@ -181,7 +181,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, request = try requestProvider.challenge(token: continuationToken, context: context) } catch { MSALLogger.log(level: .error, context: context, format: "Error creating Challenge Request: \(error)") - return .unexpectedError + return .unexpectedError(message: nil) } MSALLogger.log(level: .info, context: context, format: "Performing resetpassword/challenge request") @@ -227,8 +227,8 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context, format: "Redirect error in resetpassword/challenge request \(error.errorDescription ?? "No error description")") return .init(.error(error)) - case .unexpectedError: - let error = ResetPasswordStartError(type: .generalError) + case .unexpectedError(let message): + let error = ResetPasswordStartError(type: .generalError, message: message) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, @@ -266,14 +266,20 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context, format: "Error in resetpassword/challenge request (resend code) \(error.errorDescription ?? "No error description")") return .init(.error(error: error, newState: nil)) - case .redirect, - .unexpectedError: + case .redirect: let error = ResendCodeError() stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in resetpassword/challenge request (resend code) \(error.errorDescription ?? "No error description")") return .init(.error(error: error, newState: nil)) + case .unexpectedError(let message): + let error = ResendCodeError(message: message) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Error in resetpassword/challenge request (resend code) \(error.errorDescription ?? "No error description")") + return .init(.error(error: error, newState: nil)) } } @@ -288,7 +294,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, request = try requestProvider.continue(parameters: parameters) } catch { MSALLogger.log(level: .error, context: parameters.context, format: "Error creating Continue Request: \(error)") - return .unexpectedError + return .unexpectedError(message: nil) } MSALLogger.log(level: .info, context: parameters.context, format: "Performing resetpassword/continue request") @@ -324,8 +330,8 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context, format: "Error in resetpassword/continue request \(error.errorDescription ?? "No error description")") return .init(.error(error: error, newState: nil)) - case .unexpectedError: - let error = VerifyCodeError(type: .generalError) + case .unexpectedError(let message): + let error = VerifyCodeError(type: .generalError, message: message) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, @@ -362,7 +368,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, request = try requestProvider.submit(parameters: parameters) } catch { MSALLogger.log(level: .error, context: parameters.context, format: "Error creating Submit Request: \(error)") - return .unexpectedError + return .unexpectedError(message: nil) } MSALLogger.log(level: .info, context: parameters.context, format: "Performing resetpassword/submit request") @@ -413,8 +419,8 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, format: "Error calling resetpassword/submit \(error.errorDescription ?? "No error description")") return .init(.error(error: error, newState: nil)) - case .unexpectedError: - let error = PasswordRequiredError(type: .generalError) + case .unexpectedError(let message): + let error = PasswordRequiredError(type: .generalError, message: message) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, @@ -469,7 +475,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, request = try requestProvider.pollCompletion(parameters: parameters) } catch { MSALLogger.log(level: .error, context: parameters.context, format: "Error creating Poll Completion Request: \(error)") - return .unexpectedError + return .unexpectedError(message: nil) } MSALLogger.log(level: .info, context: parameters.context, format: "Performing resetpassword/poll_completion request") @@ -547,8 +553,8 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, format: "Error calling resetpassword/poll_completion \(error.errorDescription ?? "No error description")") return .init(.error(error: error, newState: nil)) - case .unexpectedError: - let error = PasswordRequiredError(type: .generalError) + case .unexpectedError(let message): + let error = PasswordRequiredError(type: .generalError, message: message) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift index 0c1263e9d5..45f7409985 100644 --- a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift @@ -147,7 +147,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa request = try requestProvider.start(parameters: parameters) } catch { MSALLogger.log(level: .error, context: parameters.context, format: "Error while creating Start Request: \(error)") - return .unexpectedError + return .unexpectedError(message: nil) } MSALLogger.log(level: .info, context: parameters.context, format: "Performing signup/start request") @@ -208,8 +208,8 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa context: context, format: "Invalid Client Id in signup/start request \(error.errorDescription ?? "No error description")") return .init(.error(error)) - case .unexpectedError: - let error = SignUpStartError(type: .generalError) + case .unexpectedError(let message): + let error = SignUpStartError(type: .generalError, message: message) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, @@ -230,7 +230,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa request = try requestProvider.challenge(token: continuationToken, context: context) } catch { MSALLogger.log(level: .error, context: context, format: "Error while creating Challenge Request: \(error)") - return .unexpectedError + return .unexpectedError(message: nil) } MSALLogger.log(level: .info, context: context, format: "Performing signup/challenge request") @@ -275,14 +275,20 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa context: context, format: "Redirect error in signup/challenge request \(error.errorDescription ?? "No error description")") return .init(.error(error)) - case .unexpectedError, - .passwordRequired: + case .passwordRequired: let error = SignUpStartError(type: .generalError) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/challenge request \(error.errorDescription ?? "No error description")") return .init(.error(error)) + case .unexpectedError(let message): + let error = SignUpStartError(type: .generalError, message: message) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/challenge request \(error.errorDescription ?? "No error description")") + return .init(.error(error)) } } @@ -323,7 +329,6 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa ) return .init(.error(error: error, newState: newState)) case .redirect, - .unexpectedError, .passwordRequired: let error = ResendCodeError() stopTelemetryEvent(event, context: context, error: error) @@ -331,6 +336,13 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa context: context, format: "Unexpected error in signup/challenge resendCode request \(error.errorDescription ?? "No error description")") return .init(.error(error: error, newState: nil)) + case .unexpectedError(let message): + let error = ResendCodeError(message: message) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/challenge resendCode request \(error.errorDescription ?? "No error description")") + return .init(.error(error: error, newState: nil)) } } @@ -361,14 +373,20 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa format: "Redirect error in signup/challenge request \(error.errorDescription ?? "No error description")") return .init(.error(error: error, newState: nil)) case .error, - .codeRequired, - .unexpectedError: + .codeRequired: let error = VerifyCodeError(type: .generalError) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/challenge request \(error.errorDescription ?? "No error description")") return .init(.error(error: error, newState: nil)) + case .unexpectedError(let message): + let error = VerifyCodeError(type: .generalError, message: message) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/challenge request \(error.errorDescription ?? "No error description")") + return .init(.error(error: error, newState: nil)) } } @@ -383,7 +401,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa request = try requestProvider.continue(parameters: parameters) } catch { MSALLogger.log(level: .error, context: parameters.context, format: "Error while creating Continue Request: \(error)") - return .unexpectedError + return .unexpectedError(message: nil) } MSALLogger.log(level: .info, context: parameters.context, format: "Performing signup/continue request") @@ -392,6 +410,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa return responseValidator.validate(result, with: parameters.context) } + // swiftlint:disable:next function_body_length private func handleSubmitCodeResult( _ result: MSALNativeAuthSignUpContinueValidatedResponse, username: String, @@ -440,17 +459,24 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa context: context, format: "Error in signup/continue request \(error.errorDescription ?? "No error description")") return .init(.error(error: error, newState: nil)) - case .attributeValidationFailed, - .unexpectedError: + case .attributeValidationFailed: let error = VerifyCodeError(type: .generalError) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/continue request \(error.errorDescription ?? "No error description")") return .init(.error(error: error, newState: nil)) + case .unexpectedError(let message): + let error = VerifyCodeError(type: .generalError, message: message) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/continue request \(error.errorDescription ?? "No error description")") + return .init(.error(error: error, newState: nil)) } } + // swiftlint:disable:next function_body_length private func handleSubmitPasswordResult( _ result: MSALNativeAuthSignUpContinueValidatedResponse, username: String, @@ -498,14 +524,20 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa format: "Unexpected error in signup/continue submitPassword request \(error.errorDescription ?? "No error description")") return .init(.error(error: error, newState: nil)) case .attributeValidationFailed, - .credentialRequired, - .unexpectedError: + .credentialRequired: let error = PasswordRequiredError(type: .generalError) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/continue submitPassword request \(error.errorDescription ?? "No error description")") return .init(.error(error: error, newState: nil)) + case .unexpectedError(let message): + let error = PasswordRequiredError(type: .generalError, message: message) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/continue submitPassword request \(error.errorDescription ?? "No error description")") + return .init(.error(error: error, newState: nil)) } } diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift index 5b35132912..a814deb147 100644 --- a/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift @@ -29,7 +29,6 @@ enum MSALNativeAuthErrorMessage { static let unsupportedMFA = "MFA currently not supported. Use the browser instead" static let browserRequired = "Browser required. Use acquireTokenInteractively instead" static let userDoesNotHavePassword = "User does not have password associated with account" - static let invalidServerResponse = "Invalid server response" static let userNotFound = "User does not exist" static let attributeValidationFailedSignUpStart = "Check the invalid attributes and start the sign-up process again. Invalid attributes: %@" static let attributeValidationFailed = "Invalid attributes: %@" @@ -44,6 +43,8 @@ enum MSALNativeAuthErrorMessage { static let refreshTokenExpired = "Refresh token is expired" static let tokenNotFound = "Token not found" static let redirectUriNotSetWarning = "WARNING ⚠️: redirectUri not set during MSAL Native Auth initialization. Production apps must correctly configure a redirect URI and call acquireToken in response to all browserRequired errors. See https://learn.microsoft.com/entra/identity-platform/redirect-uris-ios" + static let unexpectedResponseBody = "Unexpected response body received" + static let unexpectedChallengeType = "Unexpected challenge type" } // swiftlint:enable line_length diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthInnerError.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthInnerError.swift index 16c0cb2f99..da21dcf456 100644 --- a/MSAL/src/native_auth/network/errors/MSALNativeAuthInnerError.swift +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthInnerError.swift @@ -25,7 +25,7 @@ import Foundation struct MSALNativeAuthInnerError: Decodable, Equatable { - let error: String + let error: String? let errorDescription: String? enum CodingKeys: String, CodingKey { case error diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift index 6f2a400213..50def369db 100644 --- a/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift @@ -27,7 +27,7 @@ import Foundation protocol MSALNativeAuthResponseError: Error, Decodable, Equatable { associatedtype ErrorCode: RawRepresentable where ErrorCode.RawValue == String - var error: ErrorCode { get } + var error: ErrorCode? { get } var errorDescription: String? { get } var errorCodes: [Int]? { get } var errorURI: String? { get } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift index 7013e1440b..791c85caff 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift @@ -26,7 +26,7 @@ import Foundation struct MSALNativeAuthResetPasswordChallengeResponseError: MSALNativeAuthResponseError { - let error: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode + let error: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode? let errorDescription: String? let errorCodes: [Int]? let errorURI: String? @@ -50,7 +50,8 @@ extension MSALNativeAuthResetPasswordChallengeResponseError { case .invalidRequest, .unauthorizedClient, .unsupportedChallengeType, - .expiredToken: + .expiredToken, + .none: return .init(type: .generalError, message: errorDescription) } } @@ -60,7 +61,8 @@ extension MSALNativeAuthResetPasswordChallengeResponseError { case .unauthorizedClient, .unsupportedChallengeType, .expiredToken, - .invalidRequest: + .invalidRequest, + .none: return .init(message: errorDescription) } } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift index 094444ac58..c43b51d8b7 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift @@ -26,7 +26,7 @@ import Foundation struct MSALNativeAuthResetPasswordContinueResponseError: MSALNativeAuthResponseError { - let error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode + let error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode? let subError: MSALNativeAuthSubErrorCode? let errorDescription: String? let errorCodes: [Int]? @@ -53,11 +53,12 @@ extension MSALNativeAuthResetPasswordContinueResponseError { switch error { case .invalidGrant: return subError == .invalidOOBValue ? .init(type: .invalidCode, message: errorDescription) - : .init(type: .generalError, message: errorDescription) + : .init(type: .generalError, message: errorDescription) case .unauthorizedClient, .expiredToken, .invalidRequest, - .verificationRequired: + .verificationRequired, + .none: return .init(type: .generalError, message: errorDescription) } } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift index ec2d09aaf9..d1b11aeca6 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift @@ -26,7 +26,7 @@ import Foundation struct MSALNativeAuthResetPasswordPollCompletionResponseError: MSALNativeAuthResponseError { - let error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode + let error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode? let subError: MSALNativeAuthSubErrorCode? let errorDescription: String? let errorCodes: [Int]? @@ -58,8 +58,10 @@ extension MSALNativeAuthResetPasswordPollCompletionResponseError { case .unauthorizedClient, .expiredToken, .invalidRequest, - .userNotFound: + .userNotFound, + .none: return .init(type: .generalError, message: errorDescription) + } } } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift index d9aa86dc1f..3271f6c1d0 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift @@ -26,7 +26,7 @@ import Foundation struct MSALNativeAuthResetPasswordStartResponseError: MSALNativeAuthResponseError { - let error: MSALNativeAuthResetPasswordStartOauth2ErrorCode + let error: MSALNativeAuthResetPasswordStartOauth2ErrorCode? let errorDescription: String? let errorCodes: [Int]? let errorURI: String? diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift index 380bc7c7c1..0dfa431c7d 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift @@ -26,7 +26,7 @@ import Foundation struct MSALNativeAuthResetPasswordSubmitResponseError: MSALNativeAuthResponseError { - let error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode + let error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode? let subError: MSALNativeAuthSubErrorCode? let errorDescription: String? let errorCodes: [Int]? @@ -57,7 +57,8 @@ extension MSALNativeAuthResetPasswordSubmitResponseError { } case .unauthorizedClient, .expiredToken, - .invalidRequest: + .invalidRequest, + .none: return .init(type: .generalError, message: errorDescription) } } diff --git a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift index 308b5d8153..2d2288d2f6 100644 --- a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift @@ -26,7 +26,7 @@ import Foundation struct MSALNativeAuthSignInChallengeResponseError: MSALNativeAuthResponseError { - let error: MSALNativeAuthSignInChallengeOauth2ErrorCode + let error: MSALNativeAuthSignInChallengeOauth2ErrorCode? let errorDescription: String? let errorCodes: [Int]? let errorURI: String? diff --git a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift index 0b77edf5a9..f06215c97d 100644 --- a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift @@ -26,7 +26,7 @@ import Foundation struct MSALNativeAuthSignInInitiateResponseError: MSALNativeAuthResponseError { - let error: MSALNativeAuthSignInInitiateOauth2ErrorCode + let error: MSALNativeAuthSignInInitiateOauth2ErrorCode? let errorDescription: String? let errorCodes: [Int]? let errorURI: String? diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift index de7aadff9a..be141648e5 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift @@ -25,7 +25,7 @@ import Foundation struct MSALNativeAuthSignUpChallengeResponseError: MSALNativeAuthResponseError { - let error: MSALNativeAuthSignUpChallengeOauth2ErrorCode + let error: MSALNativeAuthSignUpChallengeOauth2ErrorCode? let errorDescription: String? let errorCodes: [Int]? let errorURI: String? @@ -47,7 +47,8 @@ extension MSALNativeAuthSignUpChallengeResponseError { case .unauthorizedClient, .unsupportedChallengeType, .expiredToken, - .invalidRequest: + .invalidRequest, + .none: return .init(type: .generalError, message: errorDescription) } } @@ -57,7 +58,8 @@ extension MSALNativeAuthSignUpChallengeResponseError { case .unauthorizedClient, .unsupportedChallengeType, .expiredToken, - .invalidRequest: + .invalidRequest, + .none: return .init(message: errorDescription) } } @@ -67,7 +69,8 @@ extension MSALNativeAuthSignUpChallengeResponseError { case .unauthorizedClient, .unsupportedChallengeType, .expiredToken, - .invalidRequest: + .invalidRequest, + .none: return .init(type: .generalError, message: errorDescription) } } diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift index c80f7e9e89..fbddbe5212 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift @@ -25,7 +25,7 @@ import Foundation struct MSALNativeAuthSignUpContinueResponseError: MSALNativeAuthResponseError { - let error: MSALNativeAuthSignUpContinueOauth2ErrorCode + let error: MSALNativeAuthSignUpContinueOauth2ErrorCode? let subError: MSALNativeAuthSubErrorCode? let errorDescription: String? let errorCodes: [Int]? @@ -63,7 +63,8 @@ extension MSALNativeAuthSignUpContinueResponseError { .userAlreadyExists, .attributesRequired, .verificationRequired, - .credentialRequired: + .credentialRequired, + .none: return .init(type: .generalError, message: errorDescription) } } @@ -82,7 +83,8 @@ extension MSALNativeAuthSignUpContinueResponseError { .userAlreadyExists, .attributesRequired, .verificationRequired, - .credentialRequired: + .credentialRequired, + .none: return .init(type: .generalError, message: errorDescription) } } diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift index bd89d0b064..fe8d0d9ab5 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift @@ -26,7 +26,7 @@ import Foundation struct MSALNativeAuthSignUpStartResponseError: MSALNativeAuthResponseError { - let error: MSALNativeAuthSignUpStartOauth2ErrorCode + let error: MSALNativeAuthSignUpStartOauth2ErrorCode? let subError: MSALNativeAuthSubErrorCode? let errorDescription: String? let errorCodes: [Int]? @@ -65,7 +65,8 @@ extension MSALNativeAuthSignUpStartResponseError { .unauthorizedClient, .unsupportedChallengeType, .unsupportedAuthMethod, - .invalidRequest: + .invalidRequest, + .none: return .init(type: .generalError, message: errorDescription) } } diff --git a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift index 1b88e7cb77..c56cd04ae9 100644 --- a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift +++ b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift @@ -26,7 +26,7 @@ import Foundation struct MSALNativeAuthTokenResponseError: MSALNativeAuthResponseError { - let error: MSALNativeAuthTokenOauth2ErrorCode + let error: MSALNativeAuthTokenOauth2ErrorCode? let subError: MSALNativeAuthSubErrorCode? let errorDescription: String? let errorCodes: [Int]? diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift index 5a8588a85a..36ae21c2b2 100644 --- a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift @@ -62,7 +62,7 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas context: context, format: "resetpassword/start returned success with unexpected response body") - return .unexpectedError + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } } @@ -71,9 +71,9 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas guard let apiError = error as? MSALNativeAuthResetPasswordStartResponseError else { MSALLogger.log(level: .error, context: context, - format: "Error type not expected") + format: "resetpassword/start: Unable to decode error response: \(error)") - return .unexpectedError + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } switch apiError.error { @@ -89,6 +89,8 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas return .error(.userNotFound(message: apiError.errorDescription)) case .unsupportedChallengeType: return .error(.unsupportedChallengeType(message: apiError.errorDescription)) + case .none: + return .error(.unexpectedError(message: apiError.errorDescription)) } } @@ -126,21 +128,23 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas ) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields from backend") - return .unexpectedError + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } case .password, .otp: MSALLogger.log(level: .error, context: context, format: "ChallengeType not expected") - return .unexpectedError + return .unexpectedError(message: nil) } } private func handleChallengeError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordChallengeValidatedResponse { guard let apiError = error as? MSALNativeAuthResetPasswordChallengeResponseError else { - MSALLogger.log(level: .info, context: context, format: "Error type not expected") - return .unexpectedError + MSALLogger.log(level: .info, context: context, format: "resetpassword/challenge: Unable to decode error response: \(error)") + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + } + if apiError.error == .none { + return .unexpectedError(message: apiError.errorDescription) } - return .error(apiError) } @@ -166,8 +170,8 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas private func handleContinueError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordContinueValidatedResponse { guard let apiError = error as? MSALNativeAuthResetPasswordContinueResponseError else { - MSALLogger.log(level: .error, context: context, format: "resetpassword/continue returned unexpected error type") - return .unexpectedError + MSALLogger.log(level: .error, context: context, format: "resetpassword/continue: Unable to decode error response: \(error)") + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } switch apiError.error { @@ -179,7 +183,9 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas return .error(apiError) case .verificationRequired: MSALLogger.log(level: .error, context: context, format: "verificationRequired is not supported yet") - return .unexpectedError + return .unexpectedError(message: nil) + case .none: + return .unexpectedError(message: apiError.errorDescription) } } @@ -208,8 +214,8 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas private func handleSubmitError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordSubmitValidatedResponse { guard let apiError = error as? MSALNativeAuthResetPasswordSubmitResponseError else { - MSALLogger.log(level: .error, context: context, format: "resetpassword/submit returned unexpected error type") - return .unexpectedError + MSALLogger.log(level: .error, context: context, format: "resetpassword/submit: Unable to decode error response: \(error)") + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } switch apiError.error { @@ -223,6 +229,8 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas .unauthorizedClient, .expiredToken: return .error(apiError) + case .none: + return .unexpectedError(message: apiError.errorDescription) } } @@ -252,8 +260,8 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas with context: MSIDRequestContext ) -> MSALNativeAuthResetPasswordPollCompletionValidatedResponse { guard let apiError = error as? MSALNativeAuthResetPasswordPollCompletionResponseError else { - MSALLogger.log(level: .error, context: context, format: "Poll Completion returned unexpected error type") - return .unexpectedError + MSALLogger.log(level: .error, context: context, format: "resetpassword/poll_completion: Unable to decode error response: \(error)") + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } switch apiError.error { @@ -268,6 +276,8 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas .unauthorizedClient, .expiredToken: return .error(apiError) + case .none: + return .unexpectedError(message: apiError.errorDescription) } } } diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift index 4c03a89974..f1a36731bc 100644 --- a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift +++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift @@ -22,19 +22,20 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -enum MSALNativeAuthResetPasswordStartValidatedResponse { +enum MSALNativeAuthResetPasswordStartValidatedResponse: Equatable { case success(continuationToken: String) case redirect case error(MSALNativeAuthResetPasswordStartValidatedErrorType) - case unexpectedError + case unexpectedError(message: String?) } -enum MSALNativeAuthResetPasswordStartValidatedErrorType: Error { +enum MSALNativeAuthResetPasswordStartValidatedErrorType: Equatable, Error { case invalidRequest(message: String?) case unauthorizedClient(message: String?) case userNotFound(message: String?) case unsupportedChallengeType(message: String?) case userDoesNotHavePassword + case unexpectedError(message: String?) func toResetPasswordStartPublicError() -> ResetPasswordStartError { switch self { @@ -46,6 +47,8 @@ enum MSALNativeAuthResetPasswordStartValidatedErrorType: Error { return .init(type: .generalError, message: message) case .userDoesNotHavePassword: return .init(type: .userDoesNotHavePassword, message: MSALNativeAuthErrorMessage.userDoesNotHavePassword) + case .unexpectedError(message: let message): + return .init(type: .generalError, message: message) } } } @@ -54,27 +57,26 @@ enum MSALNativeAuthResetPasswordChallengeValidatedResponse: Equatable { case success(_ sentTo: String, _ channelTargetType: MSALNativeAuthChannelType, _ codeLength: Int, _ resetPasswordChallengeToken: String) case redirect case error(MSALNativeAuthResetPasswordChallengeResponseError) - case unexpectedError + case unexpectedError(message: String?) } enum MSALNativeAuthResetPasswordContinueValidatedResponse: Equatable { case success(continuationToken: String) case invalidOOB case error(MSALNativeAuthResetPasswordContinueResponseError) - case unexpectedError + case unexpectedError(message: String?) } enum MSALNativeAuthResetPasswordSubmitValidatedResponse: Equatable { case success(continuationToken: String, pollInterval: Int) case passwordError(error: MSALNativeAuthResetPasswordSubmitResponseError) case error(MSALNativeAuthResetPasswordSubmitResponseError) - case unexpectedError + case unexpectedError(message: String?) } enum MSALNativeAuthResetPasswordPollCompletionValidatedResponse: Equatable { - // TODO: Update to continuation_token case success(status: MSALNativeAuthResetPasswordPollCompletionStatus, continuationToken: String?) case passwordError(error: MSALNativeAuthResetPasswordPollCompletionResponseError) case error(MSALNativeAuthResetPasswordPollCompletionResponseError) - case unexpectedError + case unexpectedError(message: String?) } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift index 8bf625a13c..0756ba70da 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift @@ -51,8 +51,8 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV MSALLogger.log( level: .error, context: context, - format: "SignIn Challenge: Error type not expected, error: \(signInChallengeResponseError)") - return .error(.invalidServerResponse) + format: "signin/challenge: Unable to decode error response: \(signInChallengeResponseError)") + return .error(.unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } return handleFailedSignInChallengeResult(context, error: signInChallengeResponseError) } @@ -70,15 +70,15 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV if let continuationToken = initiateResponse.continuationToken { return .success(continuationToken: continuationToken) } - MSALLogger.log(level: .error, context: context, format: "SignIn Initiate: challengeType and continuation token empty") - return .error(.invalidServerResponse) + MSALLogger.log(level: .error, context: context, format: "signin/initiate: challengeType and continuation token empty") + return .error(.unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody)) case .failure(let responseError): guard let initiateResponseError = responseError as? MSALNativeAuthSignInInitiateResponseError else { MSALLogger.log( level: .error, context: context, - format: "SignIn Initiate: Error type not expected, error: \(responseError)") - return .error(.invalidServerResponse) + format: "signin/initiate: Unable to decode error response: \(responseError)") + return .error(.unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } return handleFailedSignInInitiateResult(context, error: initiateResponseError) } @@ -94,8 +94,8 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV MSALLogger.log( level: .error, context: context, - format: "SignIn Challenge: Received unexpected challenge type: \(response.challengeType)") - return .error(.invalidServerResponse) + format: "signin/challenge: Received unexpected challenge type: \(response.challengeType)") + return .error(.unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedChallengeType)) case .oob: guard let continuationToken = response.continuationToken, let targetLabel = response.challengeTargetLabel, @@ -104,8 +104,8 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV MSALLogger.log( level: .error, context: context, - format: "SignIn Challenge: Invalid response with challenge type oob, response: \(response)") - return .error(.invalidServerResponse) + format: "signin/challenge: Invalid response with challenge type oob, response: \(response)") + return .error(.unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } return .codeRequired( continuationToken: continuationToken, @@ -117,8 +117,8 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV MSALLogger.log( level: .error, context: context, - format: "SignIn Challenge: Expected continuation token not nil with credential type password") - return .error(.invalidServerResponse) + format: "signin/challenge: Expected continuation token not nil with credential type password") + return .error(.unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } return .passwordRequired(continuationToken: continuationToken) case .redirect: @@ -140,6 +140,8 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV return .error(.expiredToken(message: error.errorDescription)) case .unsupportedChallengeType: return .error(.unsupportedChallengeType(message: error.errorDescription)) + case .none: + return .error(.unexpectedError(message: error.errorDescription)) } } @@ -155,6 +157,8 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV return .error(.unsupportedChallengeType(message: error.errorDescription)) case .userNotFound: return .error(.userNotFound(message: error.errorDescription)) + case .none: + return .error(.unexpectedError(message: error.errorDescription)) } } } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift index c3b0817b59..255f559ae7 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift @@ -36,7 +36,7 @@ enum MSALNativeAuthSignInChallengeValidatedErrorType: Error { case invalidToken(message: String?) case unauthorizedClient(message: String?) case invalidRequest(message: String?) - case invalidServerResponse + case unexpectedError(message: String?) case userNotFound(message: String?) case unsupportedChallengeType(message: String?) @@ -44,18 +44,15 @@ enum MSALNativeAuthSignInChallengeValidatedErrorType: Error { switch self { case .redirect: return .init(type: .browserRequired) - case .invalidServerResponse: - return .init(type: .generalError) case .expiredToken(let message), .invalidToken(let message), - .invalidRequest(let message): - return .init(type: .generalError, message: message) - case .unauthorizedClient(let message): + .invalidRequest(let message), + .unauthorizedClient(let message), + .unsupportedChallengeType(let message), + .unexpectedError(let message): return .init(type: .generalError, message: message) case .userNotFound(let message): return .init(type: .userNotFound, message: message) - case .unsupportedChallengeType(let message): - return .init(type: .generalError, message: message) } } } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift index d76c6ec3eb..b8c5364026 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift @@ -33,7 +33,7 @@ enum MSALNativeAuthSignInInitiateValidatedErrorType: Error { case redirect case unauthorizedClient(message: String?) case invalidRequest(message: String?) - case invalidServerResponse + case unexpectedError(message: String?) case userNotFound(message: String?) case unsupportedChallengeType(message: String?) @@ -43,11 +43,10 @@ enum MSALNativeAuthSignInInitiateValidatedErrorType: Error { return .init(type: .browserRequired) case .userNotFound(let message): return .init(type: .userNotFound, message: message) - case .invalidServerResponse: - return .init(type: .generalError) case .unauthorizedClient(let message), .unsupportedChallengeType(let message), - .invalidRequest(let message): + .invalidRequest(let message), + .unexpectedError(message: let message): return .init(type: .generalError, message: message) } } @@ -58,11 +57,10 @@ enum MSALNativeAuthSignInInitiateValidatedErrorType: Error { return .init(type: .browserRequired) case .userNotFound(let message): return .init(type: .userNotFound, message: message) - case .invalidServerResponse: - return .init(type: .generalError) case .unauthorizedClient(let message), .unsupportedChallengeType(let message), - .invalidRequest(let message): + .invalidRequest(let message), + .unexpectedError(message: let message): return .init(type: .generalError, message: message) } } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift index 46272fc685..d16cc84afc 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift @@ -62,14 +62,14 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV return .success(continuationToken: continuationToken) } else { MSALLogger.log(level: .error, context: context, format: "signup/start returned success with unexpected response body") - return .unexpectedError + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } } private func handleStartFailed(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthSignUpStartValidatedResponse { guard let apiError = error as? MSALNativeAuthSignUpStartResponseError else { - MSALLogger.log(level: .error, context: context, format: "Error type not expected") - return .unexpectedError + MSALLogger.log(level: .error, context: context, format: "signup/start: Unable to decode error response: \(error)") + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } switch apiError.error { @@ -82,7 +82,7 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV context: context, format: "Missing expected fields in signup/start for attribute_validation_failed error" ) - return .unexpectedError + return .unexpectedError(message: apiError.errorDescription) } case .invalidRequest where isSignUpStartInvalidRequestParameter( apiError, @@ -92,6 +92,8 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV apiError, knownErrorDescription: MSALNativeAuthESTSApiErrorDescriptions.clientIdParameterIsEmptyOrNotValid.rawValue): return .unauthorizedClient(apiError) + case .none: + return .unexpectedError(message: apiError.errorDescription) default: return .error(apiError) } @@ -117,7 +119,7 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV ) -> MSALNativeAuthSignUpChallengeValidatedResponse { guard let challengeTypeIssued = response.challengeType else { MSALLogger.log(level: .error, context: context, format: "Missing ChallengeType from backend in signup/challenge response") - return .unexpectedError + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } switch challengeTypeIssued { @@ -131,25 +133,28 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV return .codeRequired(sentTo, channelType, codeLength, continuationToken) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/challenge with challenge_type = oob") - return .unexpectedError + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } case .password: if let continuationToken = response.continuationToken { return .passwordRequired(continuationToken) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/challenge with challenge_type = password") - return .unexpectedError + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } case .otp: MSALLogger.log(level: .error, context: context, format: "ChallengeType OTP not expected for signup/challenge") - return .unexpectedError + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } } private func handleChallengeError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthSignUpChallengeValidatedResponse { guard let apiError = error as? MSALNativeAuthSignUpChallengeResponseError else { - MSALLogger.log(level: .error, context: context, format: "Error type not expected") - return .unexpectedError + MSALLogger.log(level: .error, context: context, format: "signup/challenge: Unable to decode error response: \(error)") + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + } + if apiError.error == .none { + return .unexpectedError(message: apiError.errorDescription) } return .error(apiError) @@ -172,7 +177,8 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV private func handleContinueError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthSignUpContinueValidatedResponse { guard let apiError = error as? MSALNativeAuthSignUpContinueResponseError else { - return .unexpectedError + MSALLogger.log(level: .error, context: context, format: "signup/continue: Unable to decode error response: \(error)") + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } switch apiError.error { @@ -183,7 +189,7 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV return .credentialRequired(continuationToken: continuationToken) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/continue for credential_required error") - return .unexpectedError + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } case .attributesRequired: if let continuationToken = apiError.continuationToken, @@ -195,17 +201,19 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV ) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/continue for attributes_required error") - return .unexpectedError + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } // TODO: .verificationRequired is not supported by the API team yet. We treat it as an unexpectedError case .verificationRequired: MSALLogger.log(level: .error, context: context, format: "verificationRequired is not supported yet") - return .unexpectedError + return .unexpectedError(message: nil) case .unauthorizedClient, .expiredToken, .userAlreadyExists, .invalidRequest: return .error(apiError) + case .none: + return .unexpectedError(message: apiError.errorDescription) } } @@ -235,7 +243,7 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV context: context, format: "Missing expected fields in signup/continue for attribute_validation_failed error" ) - return .unexpectedError + return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) } } } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift index b3261cff96..754d450aea 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift @@ -30,7 +30,7 @@ enum MSALNativeAuthSignUpStartValidatedResponse: Equatable { // TODO: Special errors handled separately. Remove after refactor validated error handling case invalidUsername(MSALNativeAuthSignUpStartResponseError) case unauthorizedClient(MSALNativeAuthSignUpStartResponseError) - case unexpectedError + case unexpectedError(message: String?) } enum MSALNativeAuthSignUpChallengeValidatedResponse: Equatable { @@ -38,7 +38,7 @@ enum MSALNativeAuthSignUpChallengeValidatedResponse: Equatable { case passwordRequired(_ signUpChallengeToken: String) case redirect case error(MSALNativeAuthSignUpChallengeResponseError) - case unexpectedError + case unexpectedError(message: String?) } enum MSALNativeAuthSignUpContinueValidatedResponse: Equatable { @@ -49,5 +49,5 @@ enum MSALNativeAuthSignUpContinueValidatedResponse: Equatable { case attributesRequired(continuationToken: String, requiredAttributes: [MSALNativeAuthRequiredAttribute]) case attributeValidationFailed(invalidAttributes: [String]) case error(MSALNativeAuthSignUpContinueResponseError) - case unexpectedError + case unexpectedError(message: String?) } diff --git a/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift index eece78e64e..6bb3b78376 100644 --- a/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift @@ -64,8 +64,8 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal MSALLogger.log( level: .error, context: context, - format: "Token: Error type not expected, error: \(tokenResponseError)") - return .error(.invalidServerResponse) + format: "Token: Unable to decode error response: \(tokenResponseError)") + return .error(.unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } return handleFailedTokenResult(context, tokenResponseError) } @@ -89,6 +89,7 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal return validAccount } + // swiftlint:disable:next cyclomatic_complexity private func handleFailedTokenResult( _ context: MSALNativeAuthRequestContext, _ responseError: MSALNativeAuthTokenResponseError) -> MSALNativeAuthTokenValidatedResponse { @@ -118,6 +119,8 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal return .error(.slowDown(message: responseError.errorDescription)) case .userNotFound: return .error(.userNotFound(message: responseError.errorDescription)) + case .none: + return .error(.unexpectedError(message: responseError.errorDescription)) } } diff --git a/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift index d9a234ea8b..93db145804 100644 --- a/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift @@ -35,7 +35,7 @@ enum MSALNativeAuthTokenValidatedErrorType: Error { case expiredRefreshToken(message: String?) case unauthorizedClient(message: String?) case invalidRequest(message: String?) - case invalidServerResponse + case unexpectedError(message: String?) case userNotFound(message: String?) case invalidPassword(message: String?) case invalidOOBCode(message: String?) @@ -58,8 +58,6 @@ enum MSALNativeAuthTokenValidatedErrorType: Error { return SignInStartError(type: .generalError, message: message) case .generalError: return SignInStartError(type: .generalError) - case .invalidServerResponse: - return SignInStartError(type: .generalError, message: MSALNativeAuthErrorMessage.invalidServerResponse) case .userNotFound(let message): return SignInStartError(type: .userNotFound, message: message) case .invalidPassword(let message): @@ -69,6 +67,8 @@ enum MSALNativeAuthTokenValidatedErrorType: Error { case .expiredRefreshToken(let message): MSALLogger.log(level: .error, context: nil, format: "Error not treated - \(self))") return SignInStartError(type: .generalError, message: message) + case .unexpectedError(message: let message): + return SignInStartError(type: .generalError, message: message) } } @@ -84,8 +84,6 @@ enum MSALNativeAuthTokenValidatedErrorType: Error { return RetrieveAccessTokenError(type: .generalError, message: message) case .generalError: return RetrieveAccessTokenError(type: .generalError) - case .invalidServerResponse: - return RetrieveAccessTokenError(type: .generalError, message: MSALNativeAuthErrorMessage.invalidServerResponse) case .expiredRefreshToken: return RetrieveAccessTokenError(type: .refreshTokenExpired) case .strongAuthRequired(let message): @@ -95,6 +93,8 @@ enum MSALNativeAuthTokenValidatedErrorType: Error { .invalidOOBCode(let message): MSALLogger.log(level: .error, context: nil, format: "Error not treated - \(self))") return RetrieveAccessTokenError(type: .generalError, message: message) + case .unexpectedError(message: let message): + return RetrieveAccessTokenError(type: .generalError, message: message) } } @@ -117,8 +117,8 @@ enum MSALNativeAuthTokenValidatedErrorType: Error { return VerifyCodeError(type: .generalError, message: message) case .generalError: return VerifyCodeError(type: .generalError) - case .invalidServerResponse: - return VerifyCodeError(type: .generalError, message: MSALNativeAuthErrorMessage.invalidServerResponse) + case .unexpectedError(message: let message): + return VerifyCodeError(type: .generalError, message: message) } } diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift index 75bba41b3b..75f5db4063 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift @@ -162,8 +162,8 @@ final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase { await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .authorizationPending(message: nil)) await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .slowDown(message: nil)) await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .invalidRequest(message: nil)) - await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: MSALNativeAuthErrorMessage.invalidServerResponse), validatorError: .invalidServerResponse) await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Invalid Client ID"), validatorError: .unauthorizedClient(message: "Invalid Client ID")) + await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Unexpected response body received"), validatorError: .unexpectedError(message: "Unexpected response body received")) await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Unsupported challenge type"), validatorError: .unsupportedChallengeType(message: "Unsupported challenge type")) await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Invalid scope"), validatorError: .invalidScope(message: "Invalid scope")) await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .refreshTokenExpired), validatorError: .expiredRefreshToken(message: nil)) diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift index 502b7827fa..aff6b0ef7d 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift @@ -85,7 +85,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { validatorMock.mockValidateResetPasswordStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() - validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError) + validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError(message: nil)) _ = prepareResetPasswordStartValidatorHelper() _ = await sut.resetPassword(parameters: resetPasswordStartParams) @@ -140,7 +140,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenValidatorInResetPasswordStart_returns_unexpectedError_it_returnsGeneralError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams - validatorMock.mockValidateResetPasswordStartFunc(.unexpectedError) + validatorMock.mockValidateResetPasswordStartFunc(.unexpectedError(message: "Error description")) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordStartValidatorHelper(exp) @@ -155,6 +155,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { XCTAssertNil(helper.channelTargetType) XCTAssertNil(helper.codeLength) XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Error description") checkTelemetryEventResult(id: .telemetryApiIdResetPasswordStart, isSuccessful: false) } @@ -275,7 +276,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { validatorMock.mockValidateResetPasswordStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() - validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError) + validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError(message: "Error description")) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordStartValidatorHelper(exp) @@ -290,6 +291,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { XCTAssertNil(helper.channelTargetType) XCTAssertNil(helper.codeLength) XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Error description") checkTelemetryEventResult(id: .telemetryApiIdResetPasswordStart, isSuccessful: false) } @@ -392,7 +394,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenResetPasswordResendCode_returns_unexpectedError_it_returnsCorrectError() async { requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() - validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError) + validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError(message: "Error description")) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordResendCodeValidatorHelper(exp) @@ -406,6 +408,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { XCTAssertNil(helper.sentTo) XCTAssertNil(helper.channelTargetType) XCTAssertNil(helper.codeLength) + XCTAssertEqual(helper.error?.errorDescription, "Error description") checkTelemetryEventResult(id: .telemetryApiIdResetPasswordResendCode, isSuccessful: false) } @@ -504,7 +507,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenResetPasswordSubmitCode_returns_unexpectedError_it_returnsCorrectError() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() - validatorMock.mockValidateResetPasswordContinueFunc(.unexpectedError) + validatorMock.mockValidateResetPasswordContinueFunc(.unexpectedError(message: "Error description")) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp) @@ -517,6 +520,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { XCTAssertNil(helper.newCodeRequiredState?.continuationToken) XCTAssertNil(helper.newPasswordRequiredState) XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Error description") checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmitCode, isSuccessful: false) } @@ -622,7 +626,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { func test_whenResetPasswordSubmitPassword_returns_unexpectedError_it_returnsCorrectError() async { requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams() - validatorMock.mockValidateResetPasswordSubmitFunc(.unexpectedError) + validatorMock.mockValidateResetPasswordSubmitFunc(.unexpectedError(message: "Error description")) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) @@ -634,6 +638,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) XCTAssertNil(helper.newPasswordRequiredState) XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Error description") checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) } @@ -646,7 +651,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { validatorMock.mockValidateResetPasswordSubmitFunc(.success(continuationToken: "continuationToken", pollInterval: 0)) requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() - validatorMock.mockValidateResetPasswordPollCompletionFunc(.unexpectedError) + validatorMock.mockValidateResetPasswordPollCompletionFunc(.unexpectedError(message: "Error description")) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) @@ -657,6 +662,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { await fulfillment(of: [exp]) XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Error description") checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) } @@ -667,7 +673,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { validatorMock.mockValidateResetPasswordSubmitFunc(.success(continuationToken: "continuationToken", pollInterval: 0)) requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters() - validatorMock.mockValidateResetPasswordPollCompletionFunc(.unexpectedError) + validatorMock.mockValidateResetPasswordPollCompletionFunc(.unexpectedError(message: "Error description")) let exp = expectation(description: "ResetPasswordController expectation") let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp) @@ -678,7 +684,8 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase { await fulfillment(of: [exp]) XCTAssertTrue(helper.onResetPasswordRequiredErrorCalled) XCTAssertEqual(helper.error?.type, .generalError) - + XCTAssertEqual(helper.error?.errorDescription, "Error description") + checkTelemetryEventResult(id: .telemetryApiIdResetPasswordSubmit, isSuccessful: false) } diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift index 8dd8bff809..897573fda5 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift @@ -207,9 +207,8 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { tokenRequestProviderMock.expectedUsername = expectedUsername tokenRequestProviderMock.expectedContext = expectedContext - let userAccountResult = MSALNativeAuthUserAccountResultStub.result - - let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedUserAccountResult: userAccountResult) + let delegateError = SignInStartError(type: .generalError) + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: delegateError) tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) tokenResponseValidatorMock.expectedTokenResponse = tokenResponse @@ -242,9 +241,8 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { tokenRequestProviderMock.expectedUsername = expectedUsername tokenRequestProviderMock.expectedContext = expectedContext - let userAccountResult = MSALNativeAuthUserAccountResultStub.result - - let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedUserAccountResult: userAccountResult) + let delegateError = SignInStartError(type: .generalError) + let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: delegateError) tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse) tokenResponseValidatorMock.expectedTokenResponse = tokenResponse @@ -262,12 +260,13 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .authorizationPending(message: nil)) await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .slowDown(message: nil)) await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidRequest(message: nil)) - await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Invalid server response"), validatorError: .invalidServerResponse) await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Invalid Client ID"), validatorError: .unauthorizedClient(message: "Invalid Client ID")) + await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Unexpected response body received"), validatorError: .unexpectedError(message: "Unexpected response body received")) await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Unsupported challenge type"), validatorError: .unsupportedChallengeType(message: "Unsupported challenge type")) await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Invalid scope"), validatorError: .invalidScope(message: "Invalid scope")) await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .userNotFound), validatorError: .userNotFound(message: nil)) await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .invalidCredentials), validatorError: .invalidPassword(message: nil)) + await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Error message"), validatorError: .unexpectedError(message: "Error message")) } func test_whenCredentialsAreRequired_browserRequiredErrorIsReturned() async { @@ -473,7 +472,8 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .userNotFound), validatorError: .userNotFound(message: nil)) await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .unsupportedChallengeType(message: nil)) await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidRequest(message: nil)) - await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidServerResponse) + await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError, message: "Unexpected response body received"), validatorError: .unexpectedError(message: "Unexpected response body received")) + await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError, message: "Error message"), validatorError: .unexpectedError(message: "Error message")) } func test_whenSignInWithCodeChallengeRequestCreationFail_errorShouldBeReturned() async { @@ -501,10 +501,11 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .expiredToken(message: nil)) await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidToken(message: nil)) await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidRequest(message: nil)) - await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidServerResponse) await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: nil), validatorError: .unauthorizedClient(message: nil)) + await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: "Unexpected response body received"), validatorError: .unexpectedError(message: "Unexpected response body received")) await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .userNotFound), validatorError: .userNotFound(message: nil)) await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: nil), validatorError: .unsupportedChallengeType(message: nil)) + await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: "Error message"), validatorError: .unexpectedError(message: "Error message")) } func test_whenSignInWithCodePasswordIsRequired_newStateIsPropagatedToUser() async { @@ -634,15 +635,16 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .expiredToken(message: nil)) await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .unauthorizedClient(message: nil)) await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidRequest(message: nil)) - await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidServerResponse) - await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .userNotFound(message: nil)) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, message: "Unexpected response body received"), validatorError: .unexpectedError(message: "Unexpected response body received")) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, message: "User not found"), validatorError: .userNotFound(message: "User not found")) await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidOOBCode(message: nil)) await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .unsupportedChallengeType(message: nil)) await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .browserRequired), validatorError: .strongAuthRequired(message: nil)) await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidScope(message: nil)) await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .authorizationPending(message: nil)) await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .slowDown(message: nil)) - await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .invalidPassword), validatorError: .invalidPassword(message: nil)) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .invalidPassword), validatorError: .invalidPassword(message: "Invalid password")) + await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, message: "Error message"), validatorError: .unexpectedError(message: "Error message")) } func test_signInWithCodeSubmitCodeTokenRequestFailCreation_errorShouldBeReturned() { @@ -667,7 +669,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase { checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .expiredToken(message: nil)) checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .unauthorizedClient(message: nil)) checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidRequest(message: nil)) - checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidServerResponse) + checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .unexpectedError(message: "Unexpected response body received")) checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .userNotFound(message: nil)) checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .invalidCode, validatorError: .invalidOOBCode(message: nil)) checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .unsupportedChallengeType(message: nil)) diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift index 03fdb5947d..a5de9ac5f5 100644 --- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift +++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift @@ -99,7 +99,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() - validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) + validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(message: nil)) let helper = prepareSignUpPasswordStartValidatorHelper() @@ -282,7 +282,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenValidatorInSignUpStartPassword_returns_unexpectedError_it_returnsGeneralError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams - validatorMock.mockValidateSignUpStartFunc(.unexpectedError) + validatorMock.mockValidateSignUpStartFunc(.unexpectedError(message: "Error message")) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) @@ -297,6 +297,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { XCTAssertNil(helper.channelTargetType) XCTAssertNil(helper.codeLength) XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Error message") checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) } @@ -441,7 +442,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() - validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) + validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(message: "Error message")) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpPasswordStartValidatorHelper(exp) @@ -456,6 +457,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { XCTAssertNil(helper.channelTargetType) XCTAssertNil(helper.codeLength) XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Error message") checkTelemetryEventResult(id: .telemetryApiIdSignUpPasswordStart, isSuccessful: false) } @@ -489,7 +491,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() - validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) + validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(message: nil)) let helper = prepareSignUpCodeStartValidatorHelper() @@ -670,7 +672,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenValidatorInSignUpStartCode_returns_unexpectedError_it_returnsGeneralError() async { requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams - validatorMock.mockValidateSignUpStartFunc(.unexpectedError) + validatorMock.mockValidateSignUpStartFunc(.unexpectedError(message: "Error Message")) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) @@ -685,6 +687,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { XCTAssertNil(helper.channelTargetType) XCTAssertNil(helper.codeLength) XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Error Message") checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) } @@ -829,7 +832,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() - validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) + validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(message: "Error message")) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpCodeStartValidatorHelper(exp) @@ -844,6 +847,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { XCTAssertNil(helper.channelTargetType) XCTAssertNil(helper.codeLength) XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Error message") checkTelemetryEventResult(id: .telemetryApiIdSignUpCodeStart, isSuccessful: false) } @@ -965,7 +969,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpResendCode_returns_unexpectedError_it_returnsCorrectError() async { requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams() - validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) + validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(message: "Error message")) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpResendCodeValidatorHelper(exp) @@ -979,6 +983,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { XCTAssertNil(helper.sentTo) XCTAssertNil(helper.codeLength) XCTAssertNotNil(helper.error) + XCTAssertEqual(helper.error?.errorDescription, "Error message") checkTelemetryEventResult(id: .telemetryApiIdSignUpResendCode, isSuccessful: false) } @@ -1160,7 +1165,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitCode_returns_unexpectedError_it_returnsCorrectError() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams() - validatorMock.mockValidateSignUpContinueFunc(.unexpectedError) + validatorMock.mockValidateSignUpContinueFunc(.unexpectedError(message: "Error description")) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitCodeValidatorHelper(exp) @@ -1174,6 +1179,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { XCTAssertNil(helper.newCodeRequiredState?.continuationToken) XCTAssertNil(helper.newPasswordRequiredState) XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Error description") checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitCode, isSuccessful: false) } @@ -1186,7 +1192,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2") - validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) + validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(message: nil)) XCTAssertFalse(requestProviderMock.challengeCalled) @@ -1370,7 +1376,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2")) requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2") - validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError) + validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(message: nil)) XCTAssertFalse(requestProviderMock.challengeCalled) @@ -1561,7 +1567,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { func test_whenSignUpSubmitPassword_returns_unexpectedError_it_returnsCorrectError() async { requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest()) requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil) - validatorMock.mockValidateSignUpContinueFunc(.unexpectedError) + validatorMock.mockValidateSignUpContinueFunc(.unexpectedError(message: "Error description")) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitPasswordValidatorHelper(exp) @@ -1574,6 +1580,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { XCTAssertNil(helper.newAttributesRequiredState) XCTAssertNil(helper.newPasswordRequiredState) XCTAssertEqual(helper.error?.type, .generalError) + XCTAssertEqual(helper.error?.errorDescription, "Error description") checkTelemetryEventResult(id: .telemetryApiIdSignUpSubmitPassword, isSuccessful: false) } @@ -1763,7 +1770,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase { oobCode: nil, attributes: ["key": "value"] ) - validatorMock.mockValidateSignUpContinueFunc(.unexpectedError) + validatorMock.mockValidateSignUpContinueFunc(.unexpectedError(message: nil)) let exp = expectation(description: "SignUpController expectation") let helper = prepareSignUpSubmitAttributesValidatorHelper(exp) diff --git a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift index f71824533e..c48a4c8863 100644 --- a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift +++ b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift @@ -91,6 +91,7 @@ class SignInPasswordRequiredDelegateSpy: SignInPasswordRequiredDelegate { func onSignInPasswordRequiredError(error: MSAL.PasswordRequiredError, newState: MSAL.SignInPasswordRequiredState?) { XCTAssertTrue(Thread.isMainThread) XCTAssertEqual(error.type, expectedError?.type) + XCTAssertEqual(error.errorDescription, expectedError?.errorDescription) newPasswordRequiredState = newState expectation.fulfill() } diff --git a/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift b/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift index cb7027e163..bcb8034439 100644 --- a/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift +++ b/MSAL/test/unit/native_auth/mock/SignInTestsValidatorHelpers.swift @@ -32,8 +32,7 @@ class SignInPasswordStartTestsValidatorHelper: SignInPasswordStartDelegateSpy { expectation.fulfill() return XCTFail("input should be .error") } - - self.expectedError = error + Task { await self.onSignInStartError(error: error) } } diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift index 632c299185..6221acc7a9 100644 --- a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift @@ -258,7 +258,50 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { wait(for: [expectation], timeout: 1) } - func test_shouldFailWithDecodeError_whenStatusCode400AndJSONMissing() throws { + func test_shouldDecodeErrorWithCorrectResponseSerializer_whenStatusCode400AndInvalidCode() throws { + let expectation = expectation(description: "Handle Error Retry Success") + + let httpResponse = HTTPURLResponse( + url: HttpModuleMockConfigurator.baseUrl, + statusCode: 400, + httpVersion: nil, + headerFields: nil + ) + + let httpRequest = MSALNativeAuthHTTPRequestMock.prepareMockRequest() + + var dictionary = [String: Any]() + dictionary["error_code"] = "invalid code" + dictionary["error_description"] = "API Description" + dictionary["error_uri"] = HttpModuleMockConfigurator.baseUrl.absoluteString + dictionary["continuation_token"] = "abcdef" + + let data = try JSONSerialization.data(withJSONObject: dictionary) + + let errorHandler = MSALNativeAuthResponseErrorHandler() + errorHandler.handleError( + error, + httpResponse: httpResponse, + data: data, + httpRequest: httpRequest, + responseSerializer: MSIDHttpResponseSerializer(), // Some transient response serializer + externalSSOContext: nil, + context: context + ) { result, error in + guard let error = error as? MSALNativeAuthSignUpStartResponseError else { + XCTFail("Error type not expected, actual error type: \(type(of: error))") + expectation.fulfill() + return + } + XCTAssertEqual(error.error, .none) + XCTAssertEqual(error.errorDescription, "API Description") + XCTAssertEqual(error.errorURI, HttpModuleMockConfigurator.baseUrl.absoluteString) + expectation.fulfill() + } + wait(for: [expectation], timeout: 1) + } + + func test_shouldNotFailWithDecodeError_whenStatusCode400AndJSONMissing() throws { let expectation = expectation(description: "Handle Error Retry Success") let httpResponse = HTTPURLResponse( @@ -282,18 +325,18 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { externalSSOContext: nil, context: context ) { result, error in - guard let error = error as? DecodingError else { - XCTFail("Error type not expected, actual error type: \(type(of: error))") + guard let error = error as? MSALNativeAuthSignInInitiateResponseError else { + XCTFail("Error is expected to be returned, even with empty data") expectation.fulfill() return } - XCTAssertEqual(error.localizedDescription,"The data couldn’t be read because it is missing.") + XCTAssertEqual(error.error,.none) expectation.fulfill() } wait(for: [expectation], timeout: 1) } - func test_shouldFailWithDecodeError_whenStatusCode400AndJSONInvalid() throws { + func test_shouldNotFailWithDecodeError_whenStatusCode400AndJSONInvalid() throws { let expectation = expectation(description: "Handle Error Retry Success") let httpResponse = HTTPURLResponse( @@ -318,12 +361,12 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase { externalSSOContext: nil, context: context ) { result, error in - guard let error = error as? DecodingError else { - XCTFail("Error type not expected, actual error type: \(type(of: error))") + guard let error = error as? MSALNativeAuthSignInInitiateResponseError else { + XCTFail("Error is expected to be returned, even with empty data") expectation.fulfill() return } - XCTAssertEqual(error.localizedDescription,"The data couldn’t be read because it is missing.") + XCTAssertEqual(error.error,.none) expectation.fulfill() } wait(for: [expectation], timeout: 1) diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift index e718ccbad6..3198d1a52d 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift @@ -77,12 +77,14 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } func test_whenResetPasswordStartErrorResponseIsNotExpected_itReturnsUnexpectedError() { - let response: Result = .failure(NSError()) + let error = createResetPasswordStartError( + error: nil, + errorDescription: "API error message" + ) + let response: Result = .failure(error) let result = sut.validate(response, with: context) - if case .unexpectedError = result {} else { - XCTFail("Unexpected result: \(result)") - } + XCTAssertEqual(result, .error(.unexpectedError(message: "API error message"))) } func test_whenResetPasswordStartErrorResponseUserNotFound_itReturnsRelatedError() { @@ -194,7 +196,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { ) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received")) } func test_whenResetPasswordChallengeSuccessResponseHasInvalidChallengeChannel_itReturnsUnexpectedError() { @@ -208,14 +210,18 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { ) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: nil)) } func test_whenResetPasswordChallengeErrorResponseIsNotExpected_itReturnsUnexpectedError() { - let response: Result = .failure(NSError()) + let error = createResetPasswordChallengeError( + error: nil, + errorDescription: "API error message" + ) + let response: Result = .failure(error) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "API error message")) } func test_whenResetPasswordChallengeErrorResponseIsExpected_itReturnsError() { @@ -228,7 +234,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .expiredToken = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -247,10 +253,14 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } func test_whenResetPasswordContinueErrorResponseIsNotExpected_itReturnsUnexpectedError() { - let response: Result = .failure(NSError()) + let error = createResetPasswordContinueError( + error: nil, + errorDescription: "API error message" + ) + let response: Result = .failure(error) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "API error message")) } func test_whenResetPasswordContinueErrorResponseIs_invalidOOBValue_itReturnsExpectedError() { @@ -262,7 +272,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { func test_whenResetPasswordContinueErrorResponseIs_verificationRequired_itReturnsUnexpectedError() { let result = buildContinueErrorResponse(expectedError: .verificationRequired) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: nil)) } func test_whenResetPasswordContinueErrorResponseIs_unauthorizedClient_itReturnsExpectedError() { @@ -272,7 +282,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .unauthorizedClient = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -283,7 +293,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .invalidGrant = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -294,7 +304,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .expiredToken = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -305,7 +315,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .invalidRequest = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -331,7 +341,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .passwordTooWeak = error.subError {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -342,7 +352,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .passwordTooShort = error.subError {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -353,7 +363,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .passwordTooLong = error.subError {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -364,7 +374,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .passwordRecentlyUsed = error.subError {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -375,7 +385,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .passwordBanned = error.subError {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -386,7 +396,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .invalidRequest = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -397,7 +407,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .unauthorizedClient = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -408,15 +418,19 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .expiredToken = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } func test_whenResetPasswordSubmitErrorResponseIsNotExpected_itReturnsUnexpectedError() { - let response: Result = .failure(NSError()) + let error = createResetPasswordSubmitError( + error: nil, + errorDescription: "API error message" + ) + let response: Result = .failure(error) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "API error message")) } // MARK: - Poll Completion Response @@ -441,7 +455,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .passwordTooWeak = error.subError {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -452,7 +466,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .passwordTooShort = error.subError {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -463,7 +477,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .passwordTooLong = error.subError {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -474,7 +488,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .passwordRecentlyUsed = error.subError {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -485,7 +499,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .passwordBanned = error.subError {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -496,7 +510,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .invalidRequest = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -507,7 +521,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .unauthorizedClient = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -518,15 +532,19 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .expiredToken = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } func test_whenResetPasswordPollCompletionErrorResponseIsNotExpected_itReturnsUnexpectedError() { - let response: Result = .failure(NSError()) + let error = createResetPasswordPollCompletionError( + error: nil, + errorDescription: "API error message" + ) + let response: Result = .failure(error) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "API error message")) } // MARK: - Helper methods @@ -576,7 +594,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } private func createResetPasswordStartError( - error: MSALNativeAuthResetPasswordStartOauth2ErrorCode, + error: MSALNativeAuthResetPasswordStartOauth2ErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, errorURI: String? = nil, @@ -594,7 +612,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } private func createResetPasswordChallengeError( - error: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode, + error: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, errorURI: String? = nil, @@ -612,7 +630,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } private func createResetPasswordContinueError( - error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode, + error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode? = nil, subError: MSALNativeAuthSubErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, @@ -634,7 +652,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } private func createResetPasswordSubmitError( - error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode, + error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode? = nil, subError: MSALNativeAuthSubErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, @@ -654,7 +672,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase { } private func createResetPasswordPollCompletionError( - error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode, + error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode? = nil, subError: MSALNativeAuthSubErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift index fd76b95963..69e85d8ed5 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift @@ -52,9 +52,9 @@ final class MSALNativeAuthSignInInitiateValidatedErrorTypeTests: XCTestCase { } func test_convertToSignInStartError_invalidServerResponse() { - let error = sut.invalidServerResponse.convertToSignInStartError() + let error = sut.unexpectedError(message: "Unexpected response body received").convertToSignInStartError() XCTAssertEqual(error.type, .generalError) - XCTAssertEqual(error.errorDescription, "General error") + XCTAssertEqual(error.errorDescription, "Unexpected response body received") } func test_convertToSignInStartError_userNotFound() { @@ -90,9 +90,9 @@ final class MSALNativeAuthSignInInitiateValidatedErrorTypeTests: XCTestCase { } func test_convertToSignInPasswordStartError_invalidServerResponse() { - let error = sut.invalidServerResponse.convertToSignInPasswordStartError() + let error = sut.unexpectedError(message: "Unexpected response body received").convertToSignInPasswordStartError() XCTAssertEqual(error.type, .generalError) - XCTAssertEqual(error.errorDescription, MSALNativeAuthErrorMessage.generalError) + XCTAssertEqual(error.errorDescription, "Unexpected response body received") } func test_convertToSignInPasswordStartError_userNotFound() { diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift index b23b3ef261..f464d83109 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift @@ -66,7 +66,7 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) let challengeResponse = MSALNativeAuthSignInChallengeResponse(continuationToken: nil, challengeType: .password, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: nil, codeLength: nil, interval: nil) let result = sut.validate(context: context, result: .success(challengeResponse)) - if case .error(.invalidServerResponse) = result {} else { + if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else { XCTFail("Unexpected result: \(result)") } } @@ -92,22 +92,22 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase { let channelType = MSALNativeAuthInternalChannelType.email let missingCredentialToken = MSALNativeAuthSignInChallengeResponse(continuationToken: nil, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: channelType, codeLength: codeLength, interval: nil) var result = sut.validate(context: context, result: .success(missingCredentialToken)) - if case .error(.invalidServerResponse) = result {} else { + if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else { XCTFail("Unexpected result: \(result)") } let missingTargetLabel = MSALNativeAuthSignInChallengeResponse(continuationToken: continuationToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: channelType, codeLength: codeLength, interval: nil) result = sut.validate(context: context, result: .success(missingTargetLabel)) - if case .error(.invalidServerResponse) = result {} else { + if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else { XCTFail("Unexpected result: \(result)") } let missingChannelType = MSALNativeAuthSignInChallengeResponse(continuationToken: continuationToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: nil, codeLength: codeLength, interval: nil) result = sut.validate(context: context, result: .success(missingChannelType)) - if case .error(.invalidServerResponse) = result {} else { + if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else { XCTFail("Unexpected result: \(result)") } let missingCodeLength = MSALNativeAuthSignInChallengeResponse(continuationToken: continuationToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: channelType, codeLength: nil, interval: nil) result = sut.validate(context: context, result: .success(missingCodeLength)) - if case .error(.invalidServerResponse) = result {} else { + if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else { XCTFail("Unexpected result: \(result)") } } @@ -116,7 +116,7 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) let challengeResponse = MSALNativeAuthSignInChallengeResponse(continuationToken: "something", challengeType: .otp, bindingMethod: nil, challengeTargetLabel: "some", challengeChannel: .email, codeLength: 2, interval: nil) let result = sut.validate(context: context, result: .success(challengeResponse)) - if case .error(.invalidServerResponse) = result {} else { + if case .error(.unexpectedError(message: "Unexpected challenge type")) = result {} else { XCTFail("Unexpected result: \(result)") } } @@ -137,7 +137,7 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) let initiateResponse = MSALNativeAuthSignInInitiateResponse(continuationToken: nil, challengeType: nil) let result = sut.validate(context: context, result: .success(initiateResponse)) - if case .error(.invalidServerResponse) = result {} else { + if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else { XCTFail("Unexpected result: \(result)") } } @@ -155,17 +155,17 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) var initiateResponse = MSALNativeAuthSignInInitiateResponse(continuationToken: nil, challengeType: .oob) var result = sut.validate(context: context, result: .success(initiateResponse)) - if case .error(.invalidServerResponse) = result {} else { + if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else { XCTFail("Unexpected result: \(result)") } initiateResponse = MSALNativeAuthSignInInitiateResponse(continuationToken: nil, challengeType: .otp) result = sut.validate(context: context, result: .success(initiateResponse)) - if case .error(.invalidServerResponse) = result {} else { + if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else { XCTFail("Unexpected result: \(result)") } initiateResponse = MSALNativeAuthSignInInitiateResponse(continuationToken: nil, challengeType: .password) result = sut.validate(context: context, result: .success(initiateResponse)) - if case .error(.invalidServerResponse) = result {} else { + if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else { XCTFail("Unexpected result: \(result)") } } diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift index bbafe6ab64..0a62ad952e 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift @@ -55,14 +55,18 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { ) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received")) } func test_whenSignUpStartErrorResponseIsNotExpected_it_returns_unexpectedError() { - let response: Result = .failure(NSError()) + let error = createSignUpStartError( + error: nil, + errorDescription: "API error message" + ) + let response: Result = .failure(error) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "API error message")) } func test_whenSignUpStart_succeedsWithContinuationToken_it_returns_success() { @@ -103,7 +107,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { let response: Result = .failure(error) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: nil)) } func test_whenSignUpStart_attributeValidationFailed_but_invalidAttributesIsNil_it_returns_attributeValidationFailed() { @@ -115,7 +119,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { let response: Result = .failure(error) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: nil)) } func test_whenSignUpStartErrorResponseIsExpected_it_returns_error() { @@ -127,7 +131,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .userAlreadyExists = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -221,7 +225,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { ) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received")) } func test_whenSignUpChallengeSuccessResponseContainsRedirect_it_returns_redirect() { @@ -294,7 +298,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { ) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received")) } func test_whenSignUpChallengeSuccessResponseContainsValidAttributesAndOTP_it_returns_unexpectedError() { @@ -309,7 +313,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { ) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received")) } func test_whenSignUpChallengeSuccessResponseOmitsSomeAttributes_it_returns_unexpectedError() { @@ -324,14 +328,18 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { ) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received")) } func test_whenSignUpChallengeErrorResponseIsNotExpected_it_returns_unexpectedError() { - let response: Result = .failure(NSError()) + let error = createSignUpChallengeError( + error: nil, + errorDescription: "API error message" + ) + let response: Result = .failure(error) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "API error message")) } func test_whenSignUpChallengeErrorResponseIsExpected_it_returns_error() { @@ -344,7 +352,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .expiredToken = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -369,10 +377,14 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } func test_whenSignUpContinueErrorResponseIsNotExpected_it_returns_unexpectedError() { - let response: Result = .failure(NSError()) + let error = createSignUpContinueError( + error: nil, + errorDescription: "API error message" + ) + let response: Result = .failure(error) let result = sut.validate(response, with: context) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "API error message")) } func test_whenSignUpContinueErrorResponseIs_invalidOOBValue_it_returns_expectedError() { @@ -382,7 +394,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .invalidGrant = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } if case .invalidOOBValue = error.subError {} else { XCTFail("Unexpected suberror: \(String(describing: error.subError))") @@ -396,7 +408,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .invalidGrant = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } if case .passwordTooWeak = error.subError {} else { XCTFail("Unexpected suberror: \(String(describing: error.subError))") @@ -410,7 +422,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .invalidGrant = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } if case .passwordTooShort = error.subError {} else { XCTFail("Unexpected suberror: \(String(describing: error.subError))") @@ -424,7 +436,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .invalidGrant = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } if case .passwordTooLong = error.subError {} else { XCTFail("Unexpected suberror: \(String(describing: error.subError))") @@ -438,7 +450,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .invalidGrant = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } if case .passwordRecentlyUsed = error.subError {} else { XCTFail("Unexpected suberror: \(String(describing: error.subError))") @@ -452,7 +464,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .invalidGrant = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } if case .passwordBanned = error.subError {} else { XCTFail("Unexpected suberror: \(String(describing: error.subError))") @@ -476,20 +488,20 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .invalidRequest = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_but_invalidAttributesIsNil_it_returns_unexpectedError() { let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .attributeValidationFailed, invalidAttributes: nil) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received")) } func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_but_invalidAttributesIsEmpty_it_returns_unexpectedError() { let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .attributeValidationFailed, invalidAttributes: []) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received")) } func test_whenSignUpContinueErrorResponseIs_credentialRequired_it_returns_expectedError() { @@ -504,7 +516,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { func test_whenSignUpContinueErrorResponseIs_credentialRequired_but_continuationToken_isNil_it_returns_unexpectedError() { let result = buildContinueErrorResponse(expectedError: .credentialRequired, expectedContinuationToken: nil) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received")) } func test_whenSignUpContinueErrorResponseIs_attributesRequired_it_returns_expectedError() { @@ -523,24 +535,24 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { func test_whenSignUpContinueErrorResponseIs_attributesRequired_but_continuationToken_IsNil_it_returns_expectedError() { let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedContinuationToken: nil, requiredAttributes: [.init(name: "email", type: "", required: true), .init(name: "city", type: "", required: false)]) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received")) } func test_whenSignUpContinueErrorResponseIs_attributesRequired_but_requiredAttributesIsNil_it_returns_expectedError() { let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedContinuationToken: "continuation-token", requiredAttributes: nil) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received")) } func test_whenSignUpContinueErrorResponseIs_attributesRequired_but_requiredAttributes_IsEmpty_it_returns_expectedError() { let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedContinuationToken: "continuation-token", requiredAttributes: []) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received")) } func test_whenSignUpContinueErrorResponseIs_verificationRequired_it_returns_unexpectedError() { let result = buildContinueErrorResponse(expectedError: .attributesRequired) - XCTAssertEqual(result, .unexpectedError) + XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received")) } func test_whenSignUpContinueErrorResponseIs_unauthorizedClient_it_returns_expectedError() { @@ -550,7 +562,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .unauthorizedClient = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -561,7 +573,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .invalidGrant = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -572,7 +584,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .expiredToken = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -583,7 +595,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .invalidRequest = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -594,7 +606,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { return XCTFail("Unexpected response") } if case .userAlreadyExists = error.error {} else { - XCTFail("Unexpected error: \(error.error)") + XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")") } } @@ -621,7 +633,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } private func createSignUpStartError( - error: MSALNativeAuthSignUpStartOauth2ErrorCode, + error: MSALNativeAuthSignUpStartOauth2ErrorCode? = nil, subError: MSALNativeAuthSubErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, @@ -645,7 +657,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } private func createSignUpChallengeError( - error: MSALNativeAuthSignUpChallengeOauth2ErrorCode, + error: MSALNativeAuthSignUpChallengeOauth2ErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, errorURI: String? = nil, @@ -661,7 +673,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase { } private func createSignUpContinueError( - error: MSALNativeAuthSignUpContinueOauth2ErrorCode, + error: MSALNativeAuthSignUpContinueOauth2ErrorCode? = nil, subError: MSALNativeAuthSubErrorCode? = nil, errorDescription: String? = nil, errorCodes: [Int]? = nil, diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift index 7c984a3a81..a012ed41c8 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift @@ -77,7 +77,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { func test_whenInvalidErrorTokenResponse_anErrorIsReturned() { let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(MSALNativeAuthInternalError.headerNotSerialized)) - if case .error(.invalidServerResponse) = result {} else { + if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else { XCTFail("Unexpected result: \(result)") } } diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift index 6d8f997c49..e60fde9b7a 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift @@ -64,9 +64,9 @@ final class MSALNativeAuthTokenValidatedErrorTypeTests: XCTestCase { } func test_convertToSignInPasswordStartError_invalidServerResponse() { - let error = sut.invalidServerResponse.convertToSignInPasswordStartError() + let error = sut.unexpectedError(message: "Unexpected response body received").convertToSignInPasswordStartError() XCTAssertEqual(error.type, .generalError) - XCTAssertEqual(error.errorDescription, MSALNativeAuthErrorMessage.invalidServerResponse) + XCTAssertEqual(error.errorDescription, "Unexpected response body received") } func test_convertToSignInPasswordStartError_userNotFound() { From 0957b9c341af6b30bd90d7f80b5c6a1afc870028 Mon Sep 17 00:00:00 2001 From: Kai Date: Wed, 24 Jan 2024 16:25:46 -0800 Subject: [PATCH 41/84] Update CommonCore submodule to latest (#1983) * Update CommonCore submodule to latest * dummy chang to trigger pipelines --- MSAL/IdentityCore | 2 +- MSAL/src/MSALDeviceInformation.m | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 5c7460538f..3dda64482a 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 5c7460538f9fdc663ef6ce74f7d784e1b01b009c +Subproject commit 3dda64482a452d41272eaa11a16a656098c64602 diff --git a/MSAL/src/MSALDeviceInformation.m b/MSAL/src/MSALDeviceInformation.m index 63fb14de27..371aea200c 100644 --- a/MSAL/src/MSALDeviceInformation.m +++ b/MSAL/src/MSALDeviceInformation.m @@ -87,7 +87,6 @@ - (instancetype)initWithMSIDDeviceInfo:(MSIDDeviceInfo *)deviceInfo #if TARGET_OS_OSX _platformSSOStatus = [self msalPlatformSSOStatusFromMSIDPlatformSSOStatus:deviceInfo.platformSSOStatus]; #endif - _extraDeviceInformation = [NSMutableDictionary new]; [self initExtraDeviceInformation:deviceInfo]; } From 469a4ff37ef853d8b4b95c4b23b380e70a546eef Mon Sep 17 00:00:00 2001 From: mipetriu Date: Thu, 25 Jan 2024 13:51:10 -0800 Subject: [PATCH 42/84] Combined preferredAuthConfiguration and preferredAuthMethod enums based on OneAuth+Android feedback --- MSAL/IdentityCore | 2 +- MSAL/src/MSALDeviceInformation.m | 10 +++++----- MSAL/src/public/MSALDefinitions.h | 19 ++----------------- MSAL/src/public/MSALDeviceInformation.h | 2 +- 4 files changed, 9 insertions(+), 24 deletions(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 6abb6a109d..3e0d4a27b8 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 6abb6a109d0d29a6ee9b367b4f73834163a777d1 +Subproject commit 3e0d4a27b82d0f04c43da5c90005368cb3b56eea diff --git a/MSAL/src/MSALDeviceInformation.m b/MSAL/src/MSALDeviceInformation.m index e7adec0367..f949c7bff3 100644 --- a/MSAL/src/MSALDeviceInformation.m +++ b/MSAL/src/MSALDeviceInformation.m @@ -87,7 +87,7 @@ - (instancetype)initWithMSIDDeviceInfo:(MSIDDeviceInfo *)deviceInfo #if TARGET_OS_OSX _platformSSOStatus = [self msalPlatformSSOStatusFromMSIDPlatformSSOStatus:deviceInfo.platformSSOStatus]; #endif - _preferredAuthConfiguration = [self msalPreferredAuthConfigurationFromMSIDPreferredAuthConfiguration:deviceInfo.preferredAuthConfig]; + _configuredPreferredAuthMethod = [self msalPreferredAuthMethodFromMSIDPreferredAuthMethod:deviceInfo.preferredAuthConfig]; _extraDeviceInformation = [NSMutableDictionary new]; [self initExtraDeviceInformation:deviceInfo]; @@ -136,14 +136,14 @@ - (MSALPlatformSSOStatus)msalPlatformSSOStatusFromMSIDPlatformSSOStatus:(MSIDPla } } -- (MSALPreferredAuthConfiguration)msalPreferredAuthConfigurationFromMSIDPreferredAuthConfiguration:(MSIDPreferredAuthConfiguration)msidPreferredAuthConfig +- (MSALPreferredAuthMethod)msalPreferredAuthMethodFromMSIDPreferredAuthMethod:(MSIDPreferredAuthMethod)msidPreferredAuthConfig { switch (msidPreferredAuthConfig) { - case MSIDPreferredAuthConfigurationQRPIN: - return MSALPreferredAuthConfigurationQRPIN; + case MSIDPreferredAuthMethodQRPIN: + return MSALPreferredAuthMethodQRPIN; default: - return MSALPreferredAuthConfigurationNotConfigured; + return MSALPreferredAuthMethodNone; } } diff --git a/MSAL/src/public/MSALDefinitions.h b/MSAL/src/public/MSALDefinitions.h index 7baf3a5db0..88623b0d2d 100644 --- a/MSAL/src/public/MSALDefinitions.h +++ b/MSAL/src/public/MSALDefinitions.h @@ -179,23 +179,8 @@ typedef NS_ENUM(NSUInteger, MSALPlatformSSOStatus) }; /** - Preferred auth method configuration determined by administrator - */ -typedef NS_ENUM(NSUInteger, MSALPreferredAuthConfiguration) -{ - /* - Administrator hasn't configured QR+PIN as an authentication method for this device. - */ - MSALPreferredAuthConfigurationNotConfigured, - - /* - Administrator has configured QR+PIN as an authentication method for this device. - */ - MSALPreferredAuthConfigurationQRPIN -}; - -/** - Preferred auth method to be passed to the authentication server + Preferred auth method for MSAL requests. Can be configured by admin as part of MSALDeviceInformation and + passed in the interactive params to the server. */ typedef NS_ENUM(NSUInteger, MSALPreferredAuthMethod) { diff --git a/MSAL/src/public/MSALDeviceInformation.h b/MSAL/src/public/MSALDeviceInformation.h index bd90f92160..dac6a89ac4 100644 --- a/MSAL/src/public/MSALDeviceInformation.h +++ b/MSAL/src/public/MSALDeviceInformation.h @@ -72,7 +72,7 @@ NS_ASSUME_NONNULL_BEGIN /** Availability of QR+PIN as an authentication method as configured by the admin */ -@property (nonatomic, readonly) MSALPreferredAuthConfiguration preferredAuthConfiguration; +@property (nonatomic, readonly) MSALPreferredAuthMethod configuredPreferredAuthMethod; /** Specifies whether AAD SSO extension was detected on the device. From 90395cbd1c49cef947d2b8568bc1ff8aa0614b82 Mon Sep 17 00:00:00 2001 From: Olga Dalton Date: Thu, 25 Jan 2024 16:11:54 -0800 Subject: [PATCH 43/84] Added SSO ext property --- MSAL/IdentityCore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index c378b86b12..8cec46a93d 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit c378b86b1275fd0c65fabb1272a16073a13b4898 +Subproject commit 8cec46a93da73fceb6857e0bf0d8895f22c7f383 From 26c06de672956bb9c38a9b617d6a7a44b14ff6a3 Mon Sep 17 00:00:00 2001 From: Olga Dalton Date: Thu, 25 Jan 2024 17:20:38 -0800 Subject: [PATCH 44/84] Renamed dual headed param --- MSAL/IdentityCore | 2 +- MSAL/test/unit/MSALPublicClientApplicationTests.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 8cec46a93d..0961e2d086 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 8cec46a93da73fceb6857e0bf0d8895f22c7f383 +Subproject commit 0961e2d086bbae8927de958acbed6669eae84b28 diff --git a/MSAL/test/unit/MSALPublicClientApplicationTests.m b/MSAL/test/unit/MSALPublicClientApplicationTests.m index 2ab56e61e6..6b8980f8ab 100644 --- a/MSAL/test/unit/MSALPublicClientApplicationTests.m +++ b/MSAL/test/unit/MSALPublicClientApplicationTests.m @@ -3273,7 +3273,7 @@ - (void)testRemoveAccount_whenAccountExists_andIsFociClient_shouldRemoveAccount_ XCTAssertEqual([application allAccounts:nil].count, 0); // 5. Make sure account and FOCI tokens are still in cache - MSIDAccount *cachedAccount = [self.tokenCacheAccessor getAccountForIdentifier:account.accountIdentifier authority:authority realmHint:nil dualHeadedAccountTenantIDHint:nil accountSelectionLog:nil context:nil error:nil]; + MSIDAccount *cachedAccount = [self.tokenCacheAccessor getAccountForIdentifier:account.accountIdentifier authority:authority realmHint:nil accountHomeTenantId:nil accountSelectionLog:nil context:nil error:nil]; XCTAssertNotNil(cachedAccount); MSIDRefreshToken *fociToken = [self.tokenCacheAccessor getRefreshTokenWithAccount:account.accountIdentifier familyId:@"1" configuration:configuration context:nil error:nil]; From 8a6b9c12a2764f6daa4ee591d9bbb09cdbabe5a3 Mon Sep 17 00:00:00 2001 From: Olga Dalton Date: Fri, 26 Jan 2024 15:16:37 -0800 Subject: [PATCH 45/84] Added privacy manifest --- MSAL/MSAL.xcodeproj/project.pbxproj | 4 ++ MSAL/PrivacyInfo.xcprivacy | 105 ++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 MSAL/PrivacyInfo.xcprivacy diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index 499291d646..01e60d1059 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -478,6 +478,7 @@ B2472CA4226FDC46008F22AB /* MSALB2CAuthority_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B2472CA2226FDC46008F22AB /* MSALB2CAuthority_Internal.h */; }; B2472CA5226FDC46008F22AB /* MSALB2CAuthority_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B2472CA2226FDC46008F22AB /* MSALB2CAuthority_Internal.h */; }; B2472CA6226FDC46008F22AB /* MSALB2CAuthority_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B2472CA2226FDC46008F22AB /* MSALB2CAuthority_Internal.h */; }; + B24AC4882B646B4C00832D7A /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = B24AC4872B646B4C00832D7A /* PrivacyInfo.xcprivacy */; }; B253151923DD607600432133 /* MSALDeviceInformation.h in Headers */ = {isa = PBXBuildFile; fileRef = B253151723DD607600432133 /* MSALDeviceInformation.h */; settings = {ATTRIBUTES = (Public, ); }; }; B253151A23DD607600432133 /* MSALDeviceInformation.h in Headers */ = {isa = PBXBuildFile; fileRef = B253151723DD607600432133 /* MSALDeviceInformation.h */; settings = {ATTRIBUTES = (Public, ); }; }; B253151B23DD607600432133 /* MSALDeviceInformation.m in Sources */ = {isa = PBXBuildFile; fileRef = B253151823DD607600432133 /* MSALDeviceInformation.m */; }; @@ -1705,6 +1706,7 @@ B223B0C322AE215D00FB8713 /* MSALLegacySharedAccountFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALLegacySharedAccountFactory.h; sourceTree = ""; }; B223B0C422AE215D00FB8713 /* MSALLegacySharedAccountFactory.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALLegacySharedAccountFactory.m; sourceTree = ""; }; B2472CA2226FDC46008F22AB /* MSALB2CAuthority_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALB2CAuthority_Internal.h; sourceTree = ""; }; + B24AC4872B646B4C00832D7A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; B253151723DD607600432133 /* MSALDeviceInformation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALDeviceInformation.h; sourceTree = ""; }; B253151823DD607600432133 /* MSALDeviceInformation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALDeviceInformation.m; sourceTree = ""; }; B253152823DD66A300432133 /* MSALDeviceInfoProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALDeviceInfoProvider.h; sourceTree = ""; }; @@ -3467,6 +3469,7 @@ D6DFF3991E2579360012891A = { isa = PBXGroup; children = ( + B24AC4872B646B4C00832D7A /* PrivacyInfo.xcprivacy */, DE53C7D4293F9F5A00E5B2BB /* module.modulemap */, 231CE9E01FECBD4600E95D3E /* unit-test-host.entitlements */, 9B235D952A3CC71C00657331 /* NativeAuthEndToEndTestPlan.xctestplan */, @@ -5168,6 +5171,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + B24AC4882B646B4C00832D7A /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MSAL/PrivacyInfo.xcprivacy b/MSAL/PrivacyInfo.xcprivacy new file mode 100644 index 0000000000..101b80857f --- /dev/null +++ b/MSAL/PrivacyInfo.xcprivacy @@ -0,0 +1,105 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPITypeReasons + + 1C8F.1 + CA92.1 + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeName + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeEmailAddress + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherUserContactInfo + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeCustomerSupport + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeUserID + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeDeviceID + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDiagnosticData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + + From 34db3fda85fa6320d0f4f15f64f59b3ac23cc54f Mon Sep 17 00:00:00 2001 From: Danilo Raspa <105228698+nilo-ms@users.noreply.github.com> Date: Wed, 31 Jan 2024 23:04:58 +0000 Subject: [PATCH 46/84] mark MSAL-ObjC-CIAM team as owner of the modulemap file (#1987) --- CODEOWNERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index ad6b3a452c..bde0b19eae 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -5,7 +5,8 @@ # @AzureAD/AppleIdentityTeam and @AzureAD/MSAL-ObjC-CIAM will be the co-owners of the MSAL.project file /MSAL/MSAL.xcodeproj/project.pbxproj @AzureAD/AppleIdentityTeam @AzureAD/MSAL-ObjC-CIAM # @AzureAD/MSAL-ObjC-CIAM owns any files in the */native_auth -# directories and any of its subdirectories. +# directories, subdirectories and the module.modulemap file. +/MSAL/module.modulemap @AzureAD/MSAL-ObjC-CIAM /MSAL/src/native_auth/ @AzureAD/MSAL-ObjC-CIAM /MSAL/test/unit/native_auth/ @AzureAD/MSAL-ObjC-CIAM /MSAL/test/integration/native_auth/ @AzureAD/MSAL-ObjC-CIAM From 1db736b486f72534a1b434edebb0be5cd5d00025 Mon Sep 17 00:00:00 2001 From: Silviu Petrescu <111577419+spetrescu84@users.noreply.github.com> Date: Thu, 1 Feb 2024 09:44:29 +0000 Subject: [PATCH 47/84] Latest version of build_docs.sh (#1973) --- build_docs.sh | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/build_docs.sh b/build_docs.sh index 032755ddef..0dba505886 100755 --- a/build_docs.sh +++ b/build_docs.sh @@ -1,11 +1,24 @@ #!/bin/bash +# To build manually run "sudo sh build_docs.sh" +# As MSAL is a mixed Objective-C and Swift project we need to use SourceKitten to +# first extract the doc comments from the source before building with Jazzy. For more +# details see https://github.com/realm/jazzy?tab=readme-ov-file#mixed-objective-c--swift gem install jazzy echo -e "Copying MSAL public files" mkdir docs.temp mkdir docs.temp/MSAL cp `find MSAL/src/public` docs.temp/MSAL +cp `find MSAL/src/native_auth/public` docs.temp/MSAL cp README.md docs.temp/ -cd docs.temp + echo -e "Generating MSAL documentation" -jazzy --objc --umbrella-header MSAL/MSAL.h --framework-root . --sdk iphonesimulator --author Microsoft\ Corporation --author_url https://aka.ms/azuread --github_url https://github.com/AzureAD/microsoft-authentication-library-for-objc --theme fullwidth +# Generate Swift SourceKitten output +sourcekitten doc -- -workspace MSAL.xcworkspace -scheme "MSAL (iOS Framework)" -configuration Debug RUN_CLANG_STATIC_ANALYZER=NO -sdk iphonesimulator CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -destination 'platform=iOS Simulator' > docs.temp/swiftDoc.json + +# Generate Objective-C SourceKitten output +cd docs.temp +sourcekitten doc --objc $(pwd)/MSAL/MSAL.h -- -x objective-c -isysroot $(xcrun --show-sdk-path --sdk iphonesimulator) \-I $(pwd) -fmodules > objcDoc.json +cd .. +# Feed both outputs to Jazzy as a comma-separated list +jazzy --module MSAL --sourcekitten-sourcefile docs.temp/swiftDoc.json,docs.temp/objcDoc.json --author Microsoft\ Corporation --author_url https://aka.ms/azuread --github_url https://github.com/AzureAD/microsoft-authentication-library-for-objc --theme fullwidth \ No newline at end of file From 2e7c7feed6daa532af39faff1c16235b2be4634f Mon Sep 17 00:00:00 2001 From: Diego Jerez <109726904+diegojerezba@users.noreply.github.com> Date: Tue, 6 Feb 2024 09:19:12 +0000 Subject: [PATCH 48/84] Read correlationId from server on 2xx and 4xx responses. Add correlationId and errorCodes to public errors. (#1981) * Read correlationId from server on 2xx and 4xx responses. Add correlationId and errorCodes to sign-up flow. * Add check for correlationId in every test of the `toPublic...` methods. * Use correlationId instead of MSIDRequestContext. Update tests. PR comments * Add handling of correlationId for 2xx and 4xx responses that can't be deserialized * Return correlationId from the controllers --- MSAL/MSAL.xcodeproj/project.pbxproj | 16 + MSAL/module.modulemap | 1 + .../MSALNativeAuthInternalError.swift | 2 +- .../MSALNativeAuthBaseController.swift | 35 +- ...NativeAuthControllerTelemetryWrapper.swift | 4 +- .../MSALNativeAuthTokenController.swift | 10 +- .../MSALNativeAuthCredentialsController.swift | 18 +- ...SALNativeAuthResetPasswordController.swift | 204 +++++++---- ...ALNativeAuthResetPasswordControlling.swift | 10 +- .../MSALNativeAuthSignInController.swift | 111 ++++-- .../MSALNativeAuthSignUpController.swift | 330 +++++++++++------- .../MSALNativeAuthSignUpControlling.swift | 8 +- .../MSALNativeAuthCustomErrorSerializer.swift | 16 +- .../MSALNativeAuthResponseCorrelatable.swift | 40 +++ .../MSALNativeAuthResponseErrorHandler.swift | 2 +- .../MSALNativeAuthResponseSerializer.swift | 14 +- .../errors/MSALNativeAuthResponseError.swift | 2 +- ...hResetPasswordChallengeResponseError.swift | 39 ++- ...thResetPasswordContinueResponseError.swift | 43 ++- ...tPasswordPollCompletionResponseError.swift | 45 ++- ...eAuthResetPasswordStartResponseError.swift | 20 ++ ...AuthResetPasswordSubmitResponseError.swift | 44 ++- ...tiveAuthSignInChallengeResponseError.swift | 18 + ...ativeAuthSignInInitiateResponseError.swift | 18 + ...tiveAuthSignUpChallengeResponseError.swift | 47 ++- ...ativeAuthSignUpContinueResponseError.swift | 79 ++++- ...ALNativeAuthSignUpStartResponseError.swift | 56 ++- .../MSALNativeAuthTokenResponseError.swift | 22 ++ .../MSALNativeAuthRequestContext.swift | 30 +- .../MSALNativeAuthRequestable.swift | 2 +- ...etPasswordChallengeRequestParameters.swift | 2 +- ...setPasswordContinueRequestParameters.swift | 2 +- ...swordPollCompletionRequestParameters.swift | 2 +- ...hResetPasswordStartRequestParameters.swift | 2 +- ...ResetPasswordSubmitRequestParameters.swift | 2 +- ...AuthSignInChallengeRequestParameters.swift | 2 +- ...eAuthSignInInitiateRequestParameters.swift | 2 +- ...AuthSignUpChallengeRequestParameters.swift | 2 +- ...eAuthSignUpContinueRequestParameters.swift | 2 +- ...tiveAuthSignUpStartRequestParameters.swift | 2 +- ...MSALNativeAuthTokenRequestParameters.swift | 2 +- ...tiveAuthResetPasswordRequestProvider.swift | 4 +- ...LNativeAuthResendCodeRequestResponse.swift | 7 +- ...veAuthResetPasswordChallengeResponse.swift | 3 +- ...iveAuthResetPasswordContinueResponse.swift | 3 +- ...hResetPasswordPollCompletionResponse.swift | 3 +- ...NativeAuthResetPasswordStartResponse.swift | 3 +- ...ativeAuthResetPasswordSubmitResponse.swift | 3 +- ...SALNativeAuthSignInChallengeResponse.swift | 3 +- ...MSALNativeAuthSignInInitiateResponse.swift | 3 +- ...SALNativeAuthSignUpChallengeResponse.swift | 3 +- ...MSALNativeAuthSignUpContinueResponse.swift | 3 +- .../MSALNativeAuthSignUpStartResponse.swift | 3 +- ...veAuthResetPasswordResponseValidator.swift | 65 ++-- ...eAuthResetPasswordValidatedResponses.swift | 71 ++-- ...SALNativeAuthSignInResponseValidator.swift | 63 ++-- ...AuthSignInChallengeValidatedResponse.swift | 81 ++++- ...eAuthSignInInitiateValidatedResponse.swift | 61 ++-- ...SALNativeAuthSignUpResponseValidator.swift | 53 +-- ...ALNativeAuthSignUpValidatedResponses.swift | 20 +- ...MSALNativeAuthTokenResponseValidator.swift | 86 +++-- ...MSALNativeAuthTokenValidatedResponse.swift | 244 +++++++++---- ...hSignUpContinueRequestProviderParams.swift | 4 +- .../MSALNativeAuthSignUpRequestProvider.swift | 4 +- ...AuthPublicClientApplication+Internal.swift | 23 +- ...SALNativeAuthPublicClientApplication.swift | 19 +- ...NativeAuthUserAccountResult+Internal.swift | 5 +- .../MSALNativeAuthUserAccountResult.swift | 6 +- .../CredentialsDelegateDispatcher.swift | 8 +- .../ResetPasswordDelegateDispatchers.swift | 26 +- ...AfterResetPasswordDelegateDispatcher.swift | 4 +- .../SignInAfterSignUpDelegateDispatcher.swift | 4 +- .../SignInDelegateDispatchers.swift | 38 +- .../SignUpDelegateDispatchers.swift | 86 +++-- .../error/MSALNativeAuthError.swift | 14 +- .../error/PasswordRequiredError.swift | 16 +- .../error/ResetPasswordStartError.swift | 4 +- .../error/RetrieveAccessTokenError.swift | 4 +- .../error/SignInStartError.swift | 4 +- .../error/SignUpStartError.swift | 4 +- .../state_machine/error/VerifyCodeError.swift | 4 +- .../state/ResetPasswordStates+Internal.swift | 10 +- .../state/ResetPasswordStates.swift | 7 +- .../state/SignInAfterResetPasswordState.swift | 9 +- .../state/SignInAfterSignUpState.swift | 6 +- .../state/SignInStates+Internal.swift | 7 +- .../state_machine/state/SignInStates.swift | 7 +- .../state/SignUpStates+Internal.swift | 10 +- .../state_machine/state/SignUpStates.swift | 39 ++- .../MSALNativeAuthIntegrationBaseTests.swift | 2 +- ...veAuthSignUpContinueIntegrationTests.swift | 2 +- .../MSALNativeAuthTokenIntegrationTests.swift | 2 +- .../MSALNativeAuthBaseControllerTests.swift | 70 ++++ ...NativeAuthCredentialsControllerTests.swift | 49 ++- ...tiveAuthResetPasswordControllerTests.swift | 43 ++- .../MSALNativeAuthSignInControllerTests.swift | 204 ++++++----- .../MSALNativeAuthSignUpControllerTests.swift | 119 ++++--- .../mock/CredentialsDelegateSpies.swift | 2 + .../mock/MSALNativeAuthNetworkMocks.swift | 30 +- ...ativeAuthResetPasswordControllerMock.swift | 6 +- .../MSALNativeAuthSignUpControllerMock.swift | 8 +- .../MSALNativeAuthSignUpControllerSpy.swift | 20 +- ...LNativeAuthSignUpRequestProviderMock.swift | 2 +- .../mock/SignInDelegatesSpies.swift | 48 ++- ...NativeAuthResetPasswordControllerSpy.swift | 14 +- ...AuthResetPasswordRequestProviderMock.swift | 2 +- ...NativeAuthCustomErrorSerializerTests.swift | 56 +++ ...ALNativeAuthRequestConfiguratorTests.swift | 6 +- .../MSALNativeAuthRequestableTests.swift | 6 +- ...LNativeAuthResponseCorrelatableTests.swift | 55 +++ ...SALNativeAuthResponseSerializerTests.swift | 31 +- ...NativeAuthSignUpRequestProviderTests.swift | 4 +- ...tPasswordChallengeResponseErrorTests.swift | 87 ++++- ...etPasswordContinueResponseErrorTests.swift | 68 +++- ...wordPollCompletionResponseErrorTests.swift | 34 +- ...esetPasswordSubmitResponseErrorTests.swift | 30 +- ...uthSignUpChallengeResponseErrorTests.swift | 64 ++-- ...AuthSignUpContinueResponseErrorTests.swift | 132 ++++--- ...iveAuthSignUpStartResponseErrorTests.swift | 39 ++- .../MSALNativeAuthRequestContextTests.swift | 55 +++ ...hResetPasswordResponseValidatorTests.swift | 22 +- ...PasswordStartValidatedErrorTypeTests.swift | 44 ++- ...ignInInitiateValidatedErrorTypeTests.swift | 89 +++-- ...ativeAuthSignInResponseValidatorTest.swift | 20 +- ...tiveAuthSignUpResponseValidatorTests.swift | 46 +-- ...ativeAuthTokenResponseValidatorTests.swift | 24 +- ...tiveAuthTokenValidatedErrorTypeTests.swift | 104 +++++- ...ativeAuthPublicClientApplicationTest.swift | 66 ++-- ...MSALNativeAuthUserAccountResultTests.swift | 5 +- ...tchAccessTokenRetrieveCompletedTests.swift | 8 +- ...InAfterSignUpDelegateDispatcherTests.swift | 8 +- ...swordRequiredDelegateDispatcherTests.swift | 7 +- ...ordResendCodeDelegateDispatcherTests.swift | 9 +- ...PasswordStartDelegateDispatcherTests.swift | 9 +- ...ordVerifyCodeDelegateDispatcherTests.swift | 7 +- ...ResetPasswordDelegateDispatcherTests.swift | 8 +- ...swordRequiredDelegateDispatcherTests.swift | 8 +- ...PasswordStartDelegateDispatcherTests.swift | 16 +- ...nInResendCodeDelegateDispatcherTests.swift | 9 +- .../SignInStartDelegateDispatcherTests.swift | 16 +- ...nInVerifyCodeDelegateDispatcherTests.swift | 8 +- ...butesRequiredDelegateDispatcherTests.swift | 21 +- ...swordRequiredDelegateDispatcherTests.swift | 14 +- ...PasswordStartDelegateDispatcherTests.swift | 16 +- ...nUpResendCodeDelegateDispatcherTests.swift | 9 +- .../SignUpStartDelegateDispatcherTests.swift | 16 +- ...nUpVerifyCodeDelegateDispatcherTests.swift | 21 +- .../error/AttributesRequiredErrorTests.swift | 13 +- .../error/PasswordRequiredErrorTests.swift | 12 +- .../public/error/ResendCodeErrorTests.swift | 4 +- .../error/ResetPasswordStartErrorTests.swift | 20 +- .../error/RetrieveAccessTokenErrorTests.swift | 16 +- .../SignInAfterResetPasswordErrorTests.swift | 4 +- .../error/SignInAfterSignUpErrorTests.swift | 4 +- .../public/error/SignInStartErrorTests.swift | 20 +- .../public/error/SignUpStartErrorTests.swift | 20 +- .../public/error/VerifyCodeErrorTests.swift | 12 +- .../ResetPasswordCodeSentStateTests.swift | 20 +- .../ResetPasswordRequiredStateTests.swift | 10 +- .../SignInCodeRequiredStateTests.swift | 19 +- .../SignInPasswordRequiredStateTests.swift | 9 +- .../SignUpAttributesRequiredStateTests.swift | 20 +- .../sign_up/SignUpCodeSentStateTests.swift | 30 +- .../SignUpPasswordRequiredStateTests.swift | 15 +- 164 files changed, 3170 insertions(+), 1463 deletions(-) create mode 100644 MSAL/src/native_auth/network/MSALNativeAuthResponseCorrelatable.swift create mode 100644 MSAL/test/unit/native_auth/network/MSALNativeAuthCustomErrorSerializerTests.swift create mode 100644 MSAL/test/unit/native_auth/network/MSALNativeAuthResponseCorrelatableTests.swift create mode 100644 MSAL/test/unit/native_auth/network/parameters/MSALNativeAuthRequestContextTests.swift diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index 499291d646..f15895ceec 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -1059,6 +1059,7 @@ E235613429C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E235613329C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift */; }; E23E955F29D4B9F7001DC59C /* MSALNativeAuthSignUpChallengeIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E23E955E29D4B9F7001DC59C /* MSALNativeAuthSignUpChallengeIntegrationTests.swift */; }; E23E956929D5BD6B001DC59C /* MSALNativeAuthSignUpRequestProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E23E956829D5BD6B001DC59C /* MSALNativeAuthSignUpRequestProviderTests.swift */; }; + E24320752B58428E005290D0 /* MSALNativeAuthResponseCorrelatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24320742B58428E005290D0 /* MSALNativeAuthResponseCorrelatable.swift */; }; E243F69429D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69329D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift */; }; E243F69A29D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69929D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift */; }; E243F69D29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243F69C29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift */; }; @@ -1075,6 +1076,7 @@ E25E6E5A2AA7727D0094461E /* MSALNativeAuthCredentialsControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25E6E592AA7727D0094461E /* MSALNativeAuthCredentialsControllerMock.swift */; }; E25EA4EC2A4C9B75004C8E40 /* MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26E391A2A4C2BE200063C07 /* MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift */; }; E26097C32948FC4D0060DD7C /* MSALNativeAuthLogging.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26097C22948FC4D0060DD7C /* MSALNativeAuthLogging.swift */; }; + E265943A2B60268400723C1A /* MSALNativeAuthResponseCorrelatableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26594392B60268400723C1A /* MSALNativeAuthResponseCorrelatableTests.swift */; }; E26E39242A4C2D7400063C07 /* SignUpDelegateSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26E39232A4C2D7400063C07 /* SignUpDelegateSpies.swift */; }; E272C4EC2A4447520013B805 /* MSALNativeAuthSignUpUsernameEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E272C4EA2A4447520013B805 /* MSALNativeAuthSignUpUsernameEndToEndTests.swift */; }; E27332C02A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E27332BF2A153E6500E1B054 /* MSALNativeAuthErrorMessage.swift */; }; @@ -1121,6 +1123,8 @@ E2D3BC4F2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D3BC4E2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift */; }; E2DC31BC29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DC31BB29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift */; }; E2DC31C829B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DC31C729B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift */; }; + E2DDF1AA2B6A9B2100E9FAB7 /* MSALNativeAuthRequestContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DDF1A92B6A9B2100E9FAB7 /* MSALNativeAuthRequestContextTests.swift */; }; + E2DDF1B32B6A9E1D00E9FAB7 /* MSALNativeAuthCustomErrorSerializerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DDF1B22B6A9E1D00E9FAB7 /* MSALNativeAuthCustomErrorSerializerTests.swift */; }; E2EBD6212A1BB4640049467A /* MSALNativeAuthSignUpRequestProviderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EBD6202A1BB4640049467A /* MSALNativeAuthSignUpRequestProviderMock.swift */; }; E2EBD62A2A1BB7700049467A /* MSALNativeAuthSignUpResponseValidatorMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EBD6292A1BB7700049467A /* MSALNativeAuthSignUpResponseValidatorMock.swift */; }; E2EFACFE2A69915100D6C3DE /* SignInResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EFACFD2A69915100D6C3DE /* SignInResults.swift */; }; @@ -2071,6 +2075,7 @@ E235613329C9D528000E01CA /* MSALNativeAuthInternalChallengeType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthInternalChallengeType.swift; sourceTree = ""; }; E23E955E29D4B9F7001DC59C /* MSALNativeAuthSignUpChallengeIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpChallengeIntegrationTests.swift; sourceTree = ""; }; E23E956829D5BD6B001DC59C /* MSALNativeAuthSignUpRequestProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpRequestProviderTests.swift; sourceTree = ""; }; + E24320742B58428E005290D0 /* MSALNativeAuthResponseCorrelatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResponseCorrelatable.swift; sourceTree = ""; }; E243F69329D1976700DAC60F /* MSALNativeAuthSignUpStartResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpStartResponse.swift; sourceTree = ""; }; E243F69929D1CC6500DAC60F /* MSALNativeAuthSignUpChallengeRequestParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpChallengeRequestParameters.swift; sourceTree = ""; }; E243F69C29D1D9B400DAC60F /* MSALNativeAuthSignUpChallengeResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpChallengeResponse.swift; sourceTree = ""; }; @@ -2086,6 +2091,7 @@ E25E6E592AA7727D0094461E /* MSALNativeAuthCredentialsControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCredentialsControllerMock.swift; sourceTree = ""; }; E26097C22948FC4D0060DD7C /* MSALNativeAuthLogging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthLogging.swift; sourceTree = ""; }; E26097C62948FC720060DD7C /* MSALNativeAuthServerTelemetry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthServerTelemetry.swift; sourceTree = ""; }; + E26594392B60268400723C1A /* MSALNativeAuthResponseCorrelatableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResponseCorrelatableTests.swift; sourceTree = ""; }; E26E391A2A4C2BE200063C07 /* MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpUsernameAndPasswordEndToEndTests.swift; sourceTree = ""; }; E26E39232A4C2D7400063C07 /* SignUpDelegateSpies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpDelegateSpies.swift; sourceTree = ""; }; E272C4EA2A4447520013B805 /* MSALNativeAuthSignUpUsernameEndToEndTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpUsernameEndToEndTests.swift; sourceTree = ""; }; @@ -2134,6 +2140,8 @@ E2D3BC4E2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MSALNativeAuthUserAccountResult+Internal.swift"; sourceTree = ""; }; E2DC31BB29AFA1E700051CE7 /* MSALNativeAuthPublicClientApplication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthPublicClientApplication.swift; sourceTree = ""; }; E2DC31C729B0FDB100051CE7 /* MSALNativeAuthAuthorityProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthAuthorityProvider.swift; sourceTree = ""; }; + E2DDF1A92B6A9B2100E9FAB7 /* MSALNativeAuthRequestContextTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthRequestContextTests.swift; sourceTree = ""; }; + E2DDF1B22B6A9E1D00E9FAB7 /* MSALNativeAuthCustomErrorSerializerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCustomErrorSerializerTests.swift; sourceTree = ""; }; E2EBD6202A1BB4640049467A /* MSALNativeAuthSignUpRequestProviderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpRequestProviderMock.swift; sourceTree = ""; }; E2EBD6292A1BB7700049467A /* MSALNativeAuthSignUpResponseValidatorMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpResponseValidatorMock.swift; sourceTree = ""; }; E2EFACFD2A69915100D6C3DE /* SignInResults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInResults.swift; sourceTree = ""; }; @@ -2409,6 +2417,7 @@ E2C6201F29E0420200F15203 /* sign_in */, DE94C9D629F1898A00C1EC1F /* reset_password */, DE54B5A22A4464D400460B34 /* token */, + E2DDF1A92B6A9B2100E9FAB7 /* MSALNativeAuthRequestContextTests.swift */, ); path = parameters; sourceTree = ""; @@ -2434,6 +2443,8 @@ E23E956829D5BD6B001DC59C /* MSALNativeAuthSignUpRequestProviderTests.swift */, DEDD6F0729E83FD20017989F /* MSALNativeAuthRequestConfiguratorTests.swift */, 8D61F9A02A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift */, + E26594392B60268400723C1A /* MSALNativeAuthResponseCorrelatableTests.swift */, + E2DDF1B22B6A9E1D00E9FAB7 /* MSALNativeAuthCustomErrorSerializerTests.swift */, ); path = network; sourceTree = ""; @@ -4088,6 +4099,7 @@ 8D2733132AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift */, E2ACA49B2953576C00E98964 /* MSALNativeAuthUrlRequestSerializer.swift */, DE1D8AA729E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift */, + E24320742B58428E005290D0 /* MSALNativeAuthResponseCorrelatable.swift */, E2C872C1294CDEAB00C4F580 /* parameters */, DE0FECA92993AD3700B139A8 /* responses */, DEDB29A229DDA992008DA85B /* errors */, @@ -5674,6 +5686,7 @@ 96B5E6F42256D197002232F9 /* MSALExtraQueryParameters.m in Sources */, 886F516429CCA58900F09471 /* MSALCIAMAuthority.m in Sources */, B223B0C622AE215D00FB8713 /* MSALLegacySharedAccountFactory.m in Sources */, + E24320752B58428E005290D0 /* MSALNativeAuthResponseCorrelatable.swift in Sources */, DEE34F72D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeResponseError.swift in Sources */, E2B8532F2A153651007A4776 /* MSALNativeAuthSignUpStartRequestProviderParameters.swift in Sources */, B26756CC22921C5B000F01D7 /* MSALB2COauth2Provider.m in Sources */, @@ -5899,6 +5912,7 @@ B2725ECC22C0466E009B454A /* MSALLegacySharedADALAccountTests.m in Sources */, DE0347A82A41AD08003CB3B6 /* MSALNativeAuthUserAccountResultStub.swift in Sources */, E2CD2EB32A040012009F8FFA /* SignUpTestsValidatorHelpers.swift in Sources */, + E2DDF1AA2B6A9B2100E9FAB7 /* MSALNativeAuthRequestContextTests.swift in Sources */, 23F32F0C1FF4789100B2905E /* MSIDTestURLResponse+MSAL.m in Sources */, D61F5BC31E59193500912CB8 /* MSALFakeViewController.m in Sources */, DE5738B62A8E790100D9120D /* MSALNativeAuthTokenValidatedErrorTypeTests.swift in Sources */, @@ -5906,6 +5920,7 @@ DE94C9E229F19AA200C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParametersTest.swift in Sources */, E2CE91102B0BA3E80009AEDD /* AttributesRequiredErrorTests.swift in Sources */, E2F5BE8E29893A4100C67EC7 /* MSALNativeAuthEndpointTests.swift in Sources */, + E265943A2B60268400723C1A /* MSALNativeAuthResponseCorrelatableTests.swift in Sources */, 287F64F0298186EA00ED90BD /* MSALNativeAuthInputValidatorTest.swift in Sources */, 8D61F9A12A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift in Sources */, E22427E42B0650CD0006C55E /* SignUpPasswordStartDelegateDispatcherTests.swift in Sources */, @@ -5931,6 +5946,7 @@ DE94C9E829F19E6B00C1EC1F /* MSALNativeAuthResetPasswordPollCompletionRequestParametersTest.swift in Sources */, E22427FD2B0671A10006C55E /* ResetPasswordStartDelegateDispatcherTests.swift in Sources */, DE0D659529C1DCC9005798B1 /* MSALNativeAuthSignInInitiateRequestParametersTest.swift in Sources */, + E2DDF1B32B6A9E1D00E9FAB7 /* MSALNativeAuthCustomErrorSerializerTests.swift in Sources */, E2CD2E5129FC087A009F8FFA /* SignUpAttributesRequiredStateTests.swift in Sources */, 28DE3FD02A0921E2003148A4 /* SignInTestsValidatorHelpers.swift in Sources */, B2725ECE22C04679009B454A /* MSALLegacySharedMSAAccountTests.m in Sources */, diff --git a/MSAL/module.modulemap b/MSAL/module.modulemap index 89b8801f0b..c384a02b81 100644 --- a/MSAL/module.modulemap +++ b/MSAL/module.modulemap @@ -90,6 +90,7 @@ module MSAL_Private { header "src/MSALAccountId+Internal.h" header "IdentityCore/IdentityCore/src/requests/sdk/msal/MSIDDefaultTokenResponseValidator.h" header "IdentityCore/IdentityCore/src/network/error_handler/MSIDAADRequestErrorHandler.h" + header "IdentityCore/IdentityCore/src/MSIDOAuth2Constants.h" export * } diff --git a/MSAL/src/native_auth/MSALNativeAuthInternalError.swift b/MSAL/src/native_auth/MSALNativeAuthInternalError.swift index c4405ae444..261d68fd95 100644 --- a/MSAL/src/native_auth/MSALNativeAuthInternalError.swift +++ b/MSAL/src/native_auth/MSALNativeAuthInternalError.swift @@ -31,7 +31,7 @@ enum MSALNativeAuthInternalError: Error, Equatable { case invalidAuthority case invalidUrl case missingResponseSerializer - case responseSerializationError + case responseSerializationError(headerCorrelationId: UUID?) case invalidResponse case invalidRequest case generalError diff --git a/MSAL/src/native_auth/controllers/MSALNativeAuthBaseController.swift b/MSAL/src/native_auth/controllers/MSALNativeAuthBaseController.swift index 4aac3fe1ee..1bfdd8ad20 100644 --- a/MSAL/src/native_auth/controllers/MSALNativeAuthBaseController.swift +++ b/MSAL/src/native_auth/controllers/MSALNativeAuthBaseController.swift @@ -149,12 +149,32 @@ class MSALNativeAuthBaseController { completion(response, error) } - func performRequest(_ request: MSIDHttpRequest, context: MSIDRequestContext) async -> Result { + func performRequest( + _ request: MSIDHttpRequest, + context: MSALNativeAuthRequestContext + ) async -> Result { return await withCheckedContinuation { continuation in - request.send { result, error in + request.send { [weak self] result, error in if let error = error { + // 5xx errors contain the server's returned correlation-id in userInfo. + if let correlationId = self?.extractCorrelationIdFromUserInfo((error as NSError).userInfo) { + context.setServerCorrelationId(UUID(uuidString: correlationId)) + + // 4xx errors are decoded producing an error that conforms to MSALNativeAuthResponseCorrelatable protocol. + } else if let errorWithCorrelationId = error as? MSALNativeAuthResponseCorrelatable { + context.setServerCorrelationId(errorWithCorrelationId.correlationId) + + // If a 4xx error fails to decode, this error is returned from the error deserializer. + } else if case MSALNativeAuthInternalError.responseSerializationError(let correlationId) = error { + context.setServerCorrelationId(correlationId) + } else { + context.setServerCorrelationId(nil) + MSALLogger.log(level: .warning, context: context, format: "Error request - cannot decode error headers. Continuing") + } + continuation.resume(returning: .failure(error)) } else if let response = result as? T { + context.setServerCorrelationId(response.correlationId) continuation.resume(returning: .success(response)) } else { MSALLogger.log(level: .error, context: context, format: "Error request - Both result and error are nil") @@ -163,4 +183,15 @@ class MSALNativeAuthBaseController { } } } + + private func extractCorrelationIdFromUserInfo(_ userInfo: [String: Any]) -> String? { + guard + let headers = userInfo[MSIDHTTPHeadersKey] as? [String: Any], + let correlationId = headers[MSID_OAUTH2_CORRELATION_ID_REQUEST_VALUE] as? String + else { + return nil + } + + return correlationId + } } diff --git a/MSAL/src/native_auth/controllers/MSALNativeAuthControllerTelemetryWrapper.swift b/MSAL/src/native_auth/controllers/MSALNativeAuthControllerTelemetryWrapper.swift index c3578f5363..3381780d46 100644 --- a/MSAL/src/native_auth/controllers/MSALNativeAuthControllerTelemetryWrapper.swift +++ b/MSAL/src/native_auth/controllers/MSALNativeAuthControllerTelemetryWrapper.swift @@ -29,10 +29,12 @@ import Foundation /// (ex: an optional delegate method not implemented by the external developer). struct MSALNativeAuthControllerTelemetryWrapper { let result: R + let correlationId: UUID let telemetryUpdate: ((Result) -> Void)? - init(_ result: R, telemetryUpdate: ((Result) -> Void)? = nil) { + init(_ result: R, correlationId: UUID, telemetryUpdate: ((Result) -> Void)? = nil) { self.result = result + self.correlationId = correlationId self.telemetryUpdate = telemetryUpdate } } diff --git a/MSAL/src/native_auth/controllers/MSALNativeAuthTokenController.swift b/MSAL/src/native_auth/controllers/MSALNativeAuthTokenController.swift index 9c19e1177a..5842ea51c8 100644 --- a/MSAL/src/native_auth/controllers/MSALNativeAuthTokenController.swift +++ b/MSAL/src/native_auth/controllers/MSALNativeAuthTokenController.swift @@ -81,7 +81,7 @@ class MSALNativeAuthTokenController: MSALNativeAuthBaseController { oobCode: String? = nil, grantType: MSALNativeAuthGrantType, includeChallengeType: Bool = true, - context: MSIDRequestContext) -> MSIDHttpRequest? { + context: MSALNativeAuthRequestContext) -> MSIDHttpRequest? { do { let params = MSALNativeAuthTokenRequestParameters( context: context, @@ -103,7 +103,7 @@ class MSALNativeAuthTokenController: MSALNativeAuthBaseController { func createRefreshTokenRequest( scopes: [String], refreshToken: String?, - context: MSIDRequestContext) -> MSIDHttpRequest? { + context: MSALNativeAuthRequestContext) -> MSIDHttpRequest? { guard let refreshToken = refreshToken else { MSALLogger.log(level: .error, context: context, format: "Error creating Refresh Token Request, refresh token is nil!") return nil @@ -128,7 +128,7 @@ class MSALNativeAuthTokenController: MSALNativeAuthBaseController { func cacheTokenResponse( _ tokenResponse: MSIDTokenResponse, - context: MSALNativeAuthRequestContext, + context: MSIDRequestContext, msidConfiguration: MSIDConfiguration ) throws -> MSIDTokenResult { let displayableId = tokenResponse.idTokenObj?.username() @@ -163,7 +163,7 @@ extension MSALNativeAuthTokenController { private func cacheTokenResponseRetrieveTokenResult( _ tokenResponse: MSIDTokenResponse, - context: MSALNativeAuthRequestContext, + context: MSIDRequestContext, msidConfiguration: MSIDConfiguration ) -> MSIDTokenResult? { do { @@ -183,7 +183,7 @@ extension MSALNativeAuthTokenController { return nil } - private func clearAccount(msidConfiguration: MSIDConfiguration, context: MSALNativeAuthRequestContext) throws { + private func clearAccount(msidConfiguration: MSIDConfiguration, context: MSIDRequestContext) throws { do { let accounts = try cacheAccessor.getAllAccounts(configuration: msidConfiguration) if let account = accounts.first { diff --git a/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift index f977783346..b882989d8b 100644 --- a/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift +++ b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift @@ -93,7 +93,10 @@ final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController, context: context ) else { stopTelemetryEvent(telemetryEvent, context: context, error: MSALNativeAuthInternalError.invalidRequest) - return .init(.failure(RetrieveAccessTokenError(type: .generalError))) + return .init( + .failure(RetrieveAccessTokenError(type: .generalError, correlationId: context.correlationId())), + correlationId: context.correlationId() + ) } let config = factory.makeMSIDConfiguration(scopes: scopes) let response = await performAndValidateTokenRequest(request, config: config, context: context) @@ -156,13 +159,13 @@ final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController, config: config ) case .error(let errorType): - let error = errorType.convertToRetrieveAccessTokenError() + let error = errorType.convertToRetrieveAccessTokenError(correlationId: context.correlationId()) MSALLogger.log( level: .error, context: context, format: "Refresh Token completed with error: \(error.errorDescription ?? "No error description")") stopTelemetryEvent(telemetryEvent, context: context, error: error) - return .init(.failure(error)) + return .init(.failure(error), correlationId: context.correlationId()) } } @@ -178,18 +181,21 @@ final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController, level: .verbose, context: context, format: "Refresh Token completed successfully") - return .init(.success(tokenResult.accessToken.accessToken), telemetryUpdate: { [weak self] result in + return .init( + .success(tokenResult.accessToken.accessToken), + correlationId: context.correlationId(), + telemetryUpdate: { [weak self] result in telemetryEvent?.setUserInformation(tokenResult.account) self?.stopTelemetryEvent(telemetryEvent, context: context, delegateDispatcherResult: result) }) } catch { - let error = RetrieveAccessTokenError(type: .generalError) + let error = RetrieveAccessTokenError(type: .generalError, correlationId: context.correlationId()) MSALLogger.log( level: .error, context: context, format: "Token Result was not created properly error - \(error)") stopTelemetryEvent(telemetryEvent, context: context, error: error) - return .init(.failure(error)) + return .init(.failure(error), correlationId: context.correlationId()) } } } diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift index 31a255b7fc..c1afea77f5 100644 --- a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordController.swift @@ -66,7 +66,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, return await handleStartResponse(response, username: parameters.username, event: event, context: parameters.context) } - func resendCode(username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse { + func resendCode(username: String, continuationToken: String, context: MSALNativeAuthRequestContext) async -> ResetPasswordResendCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordResendCode, context: context) let response = await performChallengeRequest(continuationToken: continuationToken, context: context) return await handleResendCodeChallengeResponse(response, username: username, event: event, context: context) @@ -76,7 +76,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, code: String, username: String, continuationToken: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> ResetPasswordSubmitCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordSubmitCode, context: context) @@ -95,7 +95,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, password: String, username: String, continuationToken: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> ResetPasswordSubmitPasswordControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdResetPasswordSubmit, context: context) @@ -125,7 +125,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, request = try requestProvider.start(parameters: parameters) } catch { MSALLogger.log(level: .error, context: parameters.context, format: "Error creating resetpassword/start request: \(error)") - return .unexpectedError(message: nil) + return .unexpectedError(nil) } MSALLogger.log(level: .info, context: parameters.context, format: "Performing resetpassword/start request") @@ -137,7 +137,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, private func handleStartResponse(_ response: MSALNativeAuthResetPasswordStartValidatedResponse, username: String, event: MSIDTelemetryAPIEvent?, - context: MSIDRequestContext) async -> ResetPasswordStartControllerResponse { + context: MSALNativeAuthRequestContext) async -> ResetPasswordStartControllerResponse { MSALLogger.log(level: .verbose, context: context, format: "Finished resetpassword/start request") @@ -146,26 +146,36 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, let challengeResponse = await performChallengeRequest(continuationToken: continuationToken, context: context) return await handleChallengeResponse(challengeResponse, username: username, event: event, context: context) case .redirect: - let error = ResetPasswordStartError(type: .browserRequired, message: MSALNativeAuthErrorMessage.browserRequired) + let error = ResetPasswordStartError( + type: .browserRequired, + message: MSALNativeAuthErrorMessage.browserRequired, + correlationId: context.correlationId() + ) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Redirect error in resetpassword/start request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - case .error(let apiError): - let error = apiError.toResetPasswordStartPublicError() + return .init(.error(error), correlationId: context.correlationId()) + case .error(let validatedError): + let error = validatedError.toResetPasswordStartPublicError(context: context) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in resetpassword/start request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - case .unexpectedError(let message): - let error = ResetPasswordStartError(type: .generalError, message: message) + return .init(.error(error), correlationId: context.correlationId()) + case .unexpectedError(let apiError): + let error = ResetPasswordStartError( + type: .generalError, + message: apiError?.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in resetpassword/start request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) + return .init(.error(error), correlationId: context.correlationId()) } } @@ -173,7 +183,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, private func performChallengeRequest( continuationToken: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> MSALNativeAuthResetPasswordChallengeValidatedResponse { let request: MSIDHttpRequest @@ -181,7 +191,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, request = try requestProvider.challenge(token: continuationToken, context: context) } catch { MSALLogger.log(level: .error, context: context, format: "Error creating Challenge Request: \(error)") - return .unexpectedError(message: nil) + return .unexpectedError(nil) } MSALLogger.log(level: .info, context: context, format: "Performing resetpassword/challenge request") @@ -199,41 +209,52 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, switch response { case .success(let sentTo, let channelTargetType, let codeLength, let challengeToken): MSALLogger.log(level: .info, context: context, format: "Successful resetpassword/challenge request") - - return .init(.codeRequired( - newState: ResetPasswordCodeRequiredState( - controller: self, - username: username, - continuationToken: challengeToken, - correlationId: context.correlationId() - ), + let newState = ResetPasswordCodeRequiredState( + controller: self, + username: username, + continuationToken: challengeToken, + correlationId: context.correlationId() + ) + let result: ResetPasswordStartResult = .codeRequired( + newState: newState, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength - ), telemetryUpdate: { [weak self] result in + ) + return .init(result, correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) case .error(let apiError): - let error = apiError.toResetPasswordStartPublicError() + let error = apiError.toResetPasswordStartPublicError(correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in resetpassword/challenge request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) + return .init(.error(error), correlationId: context.correlationId()) case .redirect: - let error = ResetPasswordStartError(type: .browserRequired, message: MSALNativeAuthErrorMessage.browserRequired) + let error = ResetPasswordStartError( + type: .browserRequired, + message: MSALNativeAuthErrorMessage.browserRequired, + correlationId: context.correlationId() + ) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Redirect error in resetpassword/challenge request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - case .unexpectedError(let message): - let error = ResetPasswordStartError(type: .generalError, message: message) + return .init(.error(error), correlationId: context.correlationId()) + case .unexpectedError(let apiError): + let error = ResetPasswordStartError( + type: .generalError, + message: apiError?.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in resetpassword/challenge request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) + return .init(.error(error), correlationId: context.correlationId()) } } @@ -256,30 +277,35 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, sentTo: sentTo, channelTargetType: channelTargetType, codeLength: codeLength - ), telemetryUpdate: { [weak self] result in + ), correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) case .error(let apiError): - let error = apiError.toResendCodePublicError() + let error = apiError.toResendCodePublicError(correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in resetpassword/challenge request (resend code) \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) case .redirect: - let error = ResendCodeError() + let error = ResendCodeError(correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in resetpassword/challenge request (resend code) \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) - case .unexpectedError(let message): - let error = ResendCodeError(message: message) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) + case .unexpectedError(let apiError): + let error = ResendCodeError( + message: apiError?.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in resetpassword/challenge request (resend code) \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) } } @@ -294,7 +320,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, request = try requestProvider.continue(parameters: parameters) } catch { MSALLogger.log(level: .error, context: parameters.context, format: "Error creating Continue Request: \(error)") - return .unexpectedError(message: nil) + return .unexpectedError(nil) } MSALLogger.log(level: .info, context: parameters.context, format: "Performing resetpassword/continue request") @@ -319,28 +345,39 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, continuationToken: newContinuationToken, correlationId: context.correlationId() ) - return .init(.passwordRequired(newState: newState), - telemetryUpdate: { [weak self] result in + return .init(.passwordRequired(newState: newState), correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) case .error(let apiError): - let error = apiError.toVerifyCodePublicError() + let error = apiError.toVerifyCodePublicError(correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in resetpassword/continue request \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) - case .unexpectedError(let message): - let error = VerifyCodeError(type: .generalError, message: message) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) + case .unexpectedError(let apiError): + let error = VerifyCodeError( + type: .generalError, + message: apiError?.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error calling resetpassword/continue \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) - case .invalidOOB: - let error = VerifyCodeError(type: .invalidCode) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) + case .invalidOOB(let apiError): + let error = VerifyCodeError( + type: .invalidCode, + message: apiError.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, @@ -353,7 +390,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, continuationToken: continuationToken, correlationId: context.correlationId() ) - return .init(.error(error: error, newState: state)) + return .init(.error(error: error, newState: state), correlationId: context.correlationId()) } } @@ -368,7 +405,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, request = try requestProvider.submit(parameters: parameters) } catch { MSALLogger.log(level: .error, context: parameters.context, format: "Error creating Submit Request: \(error)") - return .unexpectedError(message: nil) + return .unexpectedError(nil) } MSALLogger.log(level: .info, context: parameters.context, format: "Performing resetpassword/submit request") @@ -382,7 +419,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, username: String, continuationToken: String, event: MSIDTelemetryAPIEvent?, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> ResetPasswordSubmitPasswordControllerResponse { MSALLogger.log(level: .info, context: context, format: "Finished resetpassword/submit request") @@ -397,7 +434,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, context: context ) case .passwordError(let apiError): - let error = apiError.toPasswordRequiredPublicError() + let error = apiError.toPasswordRequiredPublicError(correlationId: context.correlationId()) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, @@ -409,25 +446,31 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, continuationToken: continuationToken, correlationId: context.correlationId() ) - return .init(.error(error: error, newState: newState)) + return .init(.error(error: error, newState: newState), correlationId: context.correlationId()) case .error(let apiError): - let error = apiError.toPasswordRequiredPublicError() + let error = apiError.toPasswordRequiredPublicError(correlationId: context.correlationId()) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error calling resetpassword/submit \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) - case .unexpectedError(let message): - let error = PasswordRequiredError(type: .generalError, message: message) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) + case .unexpectedError(let apiError): + let error = PasswordRequiredError( + type: .generalError, + message: apiError?.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error calling resetpassword/submit \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) } } @@ -439,7 +482,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, pollInterval: Int, retriesRemaining: Int, event: MSIDTelemetryAPIEvent?, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> ResetPasswordSubmitPasswordControllerResponse { MSALLogger.log(level: .verbose, context: context, format: "Performing poll completion request") @@ -463,7 +506,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, private func performPollCompletionRequest( continuationToken: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> MSALNativeAuthResetPasswordPollCompletionValidatedResponse { let parameters = MSALNativeAuthResetPasswordPollCompletionRequestParameters( context: context, @@ -475,7 +518,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, request = try requestProvider.pollCompletion(parameters: parameters) } catch { MSALLogger.log(level: .error, context: parameters.context, format: "Error creating Poll Completion Request: \(error)") - return .unexpectedError(message: nil) + return .unexpectedError(nil) } MSALLogger.log(level: .info, context: parameters.context, format: "Performing resetpassword/poll_completion request") @@ -495,7 +538,7 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, retriesRemaining: Int, continuationToken: String, event: MSIDTelemetryAPIEvent?, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> ResetPasswordSubmitPasswordControllerResponse { MSALLogger.log(level: .info, context: context, format: "Finished resetpassword/poll_completion") @@ -520,18 +563,21 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, continuationToken: newContinuationToken, correlationId: context.correlationId() ) - return .init(.completed(signInAfterResetPasswordState), telemetryUpdate: { [weak self] result in + return .init( + .completed(signInAfterResetPasswordState), + correlationId: context.correlationId(), + telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) case .failed: - let error = PasswordRequiredError(type: .generalError) + let error = PasswordRequiredError(type: .generalError, correlationId: context.correlationId()) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Password poll completion returned status 'failed'") - return .init(.error(error: error, newState: nil)) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) } case .passwordError(let apiError): - let error = apiError.toPasswordRequiredPublicError() + let error = apiError.toPasswordRequiredPublicError(correlationId: context.correlationId()) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, @@ -543,25 +589,31 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, continuationToken: continuationToken, correlationId: context.correlationId() ) - return .init(.error(error: error, newState: newState)) + return .init(.error(error: error, newState: newState), correlationId: context.correlationId()) case .error(let apiError): - let error = apiError.toPasswordRequiredPublicError() + let error = apiError.toPasswordRequiredPublicError(correlationId: context.correlationId()) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error calling resetpassword/poll_completion \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) - case .unexpectedError(let message): - let error = PasswordRequiredError(type: .generalError, message: message) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) + case .unexpectedError(let apiError): + let error = PasswordRequiredError( + type: .generalError, + message: apiError?.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error calling resetpassword/poll_completion \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) } } // swiftlint:enable function_body_length @@ -572,14 +624,14 @@ final class MSALNativeAuthResetPasswordController: MSALNativeAuthBaseController, retriesRemaining: Int, username: String, event: MSIDTelemetryAPIEvent?, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> ResetPasswordSubmitPasswordControllerResponse { guard retriesRemaining > 0 else { - let error = PasswordRequiredError(type: .generalError) + let error = PasswordRequiredError(type: .generalError, correlationId: context.correlationId()) self.stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Password poll completion did not complete in time") - return .init(.error(error: error, newState: nil)) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) } MSALLogger.log( diff --git a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift index 7e26f4c4f8..6cefb9849a 100644 --- a/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift +++ b/MSAL/src/native_auth/controllers/reset_password/MSALNativeAuthResetPasswordControlling.swift @@ -33,19 +33,23 @@ protocol MSALNativeAuthResetPasswordControlling: AnyObject { func resetPassword(parameters: MSALNativeAuthResetPasswordStartRequestProviderParameters) async -> ResetPasswordStartControllerResponse - func resendCode(username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse + func resendCode( + username: String, + continuationToken: String, + context: MSALNativeAuthRequestContext + ) async -> ResetPasswordResendCodeControllerResponse func submitCode( code: String, username: String, continuationToken: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> ResetPasswordSubmitCodeControllerResponse func submitPassword( password: String, username: String, continuationToken: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> ResetPasswordSubmitPasswordControllerResponse } diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift index 6bff8e2664..c2bc5784b2 100644 --- a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift +++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift @@ -90,7 +90,10 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN case .success(let challengeValidatedResponse): return await handleChallengeResponse(challengeValidatedResponse, params: params, telemetryInfo: telemetryInfo) case .failure(let error): - return .init(.error(error.convertToSignInStartError())) + return .init( + .error(error.convertToSignInStartError(correlationId: params.context.correlationId())), + correlationId: params.context.correlationId() + ) } } @@ -107,9 +110,9 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN ) guard let continuationToken = continuationToken else { MSALLogger.log(level: .error, context: context, format: "SignIn after previous flow not available because continuationToken is nil") - let error = SignInAfterSignUpError(message: MSALNativeAuthErrorMessage.signInNotAvailable) + let error = SignInAfterSignUpError(message: MSALNativeAuthErrorMessage.signInNotAvailable, correlationId: context.correlationId()) stopTelemetryEvent(telemetryInfo, error: error) - return .init(.failure(error)) + return .init(.failure(error), correlationId: context.correlationId()) } let scopes = joinScopes(scopes) guard let request = createTokenRequest( @@ -119,9 +122,9 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN grantType: .continuationToken, context: context ) else { - let error = SignInAfterSignUpError() + let error = SignInAfterSignUpError(correlationId: context.correlationId()) stopTelemetryEvent(telemetryInfo, error: error) - return .init(.failure(error)) + return .init(.failure(error), correlationId: context.correlationId()) } let config = factory.makeMSIDConfiguration(scopes: scopes) let response = await performAndValidateTokenRequest(request, config: config, context: context) @@ -132,12 +135,19 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN scopes: scopes, telemetryInfo: telemetryInfo, onSuccess: { accountResult in - continuation.resume(returning: .init(.success(accountResult), telemetryUpdate: { [weak self] result in + continuation.resume( + returning: .init(.success(accountResult), correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(telemetryInfo.event, context: context, delegateDispatcherResult: result) })) }, onError: { error in - continuation.resume(returning: .init(.failure(SignInAfterSignUpError(message: error.errorDescription)))) + let error = SignInAfterSignUpError( + message: error.errorDescription, + correlationId: error.correlationId, + errorCodes: error.errorCodes, + errorUri: error.errorUri + ) + continuation.resume(returning: .init(.failure(error), correlationId: context.correlationId())) } ) } @@ -164,7 +174,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN MSALLogger.log(level: .error, context: context, format: "SignIn, submit code: unable to create token request") return processSubmitCodeFailure( - errorType: .generalError, + errorType: .generalError(nil), telemetryInfo: telemetryInfo, scopes: scopes, continuationToken: continuationToken, @@ -182,7 +192,11 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN telemetryInfo: telemetryInfo, config: config, onSuccess: { accountResult in - continuation.resume(returning: .init(.completed(accountResult), telemetryUpdate: { [weak self] result in + continuation.resume( + returning: .init( + .completed(accountResult), + correlationId: context.correlationId(), + telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(telemetryInfo.event, context: context, delegateDispatcherResult: result) })) }, @@ -190,7 +204,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN MSALLogger.log(level: .error, context: context, format: "SignIn submit code, token request failed with error \(error)") guard let self = self else { return } continuation.resume(returning: self.processSubmitCodeFailure( - errorType: .generalError, + errorType: .generalError(nil), telemetryInfo: telemetryInfo, scopes: scopes, continuationToken: continuationToken, @@ -231,7 +245,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN context: context) else { MSALLogger.log(level: .error, context: context, format: "SignIn, submit password: unable to create token request") return processSubmitPasswordFailure( - errorType: .generalError, + errorType: .generalError(nil), telemetryInfo: telemetryInfo, username: username, continuationToken: continuationToken, @@ -249,7 +263,11 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN telemetryInfo: telemetryInfo, config: config, onSuccess: { accountResult in - continuation.resume(returning: .init(.completed(accountResult), telemetryUpdate: { [weak self] result in + continuation.resume( + returning: .init( + .completed(accountResult), + correlationId: context.correlationId(), + telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(telemetryInfo.event, context: context, delegateDispatcherResult: result) })) }, @@ -257,7 +275,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN MSALLogger.log(level: .error, context: context, format: "SignIn submit password, token request failed with error \(error)") guard let self = self else { return } continuation.resume(returning: self.processSubmitPasswordFailure( - errorType: .generalError, + errorType: .generalError(nil), telemetryInfo: telemetryInfo, username: username, continuationToken: continuationToken, @@ -287,12 +305,12 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN let result = await performAndValidateChallengeRequest(continuationToken: continuationToken, context: context) switch result { case .passwordRequired: - let error = ResendCodeError() + let error = ResendCodeError(correlationId: context.correlationId()) MSALLogger.log(level: .error, context: context, format: "SignIn ResendCode: received unexpected password required API result") stopTelemetryEvent(event, context: context, error: error) - return .init(.error(error: error, newState: nil)) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) case .error(let challengeError): - let error = ResendCodeError() + let error = challengeError.convertToResendCodeError(correlationId: context.correlationId()) MSALLogger.log(level: .error, context: context, format: "SignIn ResendCode: received challenge error response: \(challengeError)") stopTelemetryEvent(event, context: context, error: error) return .init(.error( @@ -301,8 +319,8 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN scopes: scopes, controller: self, continuationToken: continuationToken, - correlationId: context.correlationId())) - ) + correlationId: context.correlationId()) + ), correlationId: context.correlationId()) case .codeRequired(let newContinuationToken, let sentTo, let channelType, let codeLength): let state = SignInCodeRequiredState( scopes: scopes, @@ -315,7 +333,9 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN newState: state, sentTo: sentTo, channelTargetType: channelType, - codeLength: codeLength), + codeLength: codeLength + ), + correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) @@ -342,7 +362,10 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN continuationToken: continuationToken, correlationId: context.correlationId() ) - return .init(.error(error: errorType.convertToVerifyCodeError(), newState: state)) + return .init( + .error(error: errorType.convertToVerifyCodeError(correlationId: context.correlationId()), newState: state), + correlationId: context.correlationId() + ) } private func processSubmitPasswordFailure( @@ -364,7 +387,10 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN continuationToken: continuationToken, correlationId: telemetryInfo.context.correlationId() ) - return .init(.error(error: errorType.convertToPasswordRequiredError(), newState: state)) + return .init( + .error(error: errorType.convertToPasswordRequiredError(correlationId: telemetryInfo.context.correlationId()), newState: state), + correlationId: telemetryInfo.context.correlationId() + ) } private func performAndValidateSignInInitiate( @@ -372,7 +398,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN telemetryInfo: TelemetryInfo ) async -> MSALNativeAuthSignInInitiateValidatedResponse { guard let request = createInitiateRequest(username: username, context: telemetryInfo.context) else { - let error = MSALNativeAuthSignInInitiateValidatedErrorType.invalidRequest(message: nil) + let error = MSALNativeAuthSignInInitiateValidatedErrorType.invalidRequest(.init()) stopTelemetryEvent(telemetryInfo, error: error) return .error(error) } @@ -420,7 +446,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN onError: onError ) case .error(let errorType): - let error = errorType.convertToSignInPasswordStartError() + let error = errorType.convertToSignInPasswordStartError(correlationId: telemetryInfo.context.correlationId()) MSALLogger.log(level: .error, context: telemetryInfo.context, format: "SignIn completed with errorType: \(error.errorDescription ?? "No error description")") @@ -446,16 +472,16 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN stopTelemetryEvent(telemetryInfo) onSuccess(userAccountResult) } else { - let errorType = MSALNativeAuthTokenValidatedErrorType.generalError + let errorType = MSALNativeAuthTokenValidatedErrorType.generalError(nil) MSALLogger.log(level: .error, context: telemetryInfo.context, format: "SignIn completed with error. Error creating UserAccountResult") stopTelemetryEvent(telemetryInfo, error: errorType) - onError(errorType.convertToSignInPasswordStartError()) + onError(errorType.convertToSignInPasswordStartError(correlationId: telemetryInfo.context.correlationId())) } } catch { - let errorType = MSALNativeAuthTokenValidatedErrorType.generalError + let errorType = MSALNativeAuthTokenValidatedErrorType.generalError(nil) MSALLogger.log(level: .error, context: telemetryInfo.context, format: "SignIn completed with error \(error)") stopTelemetryEvent(telemetryInfo, error: errorType) - onError(errorType.convertToSignInPasswordStartError()) + onError(errorType.convertToSignInPasswordStartError(correlationId: telemetryInfo.context.correlationId())) } } @@ -479,7 +505,10 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN context: telemetryInfo.context ) else { stopTelemetryEvent(telemetryInfo, error: MSALNativeAuthInternalError.invalidRequest) - return .init(.error(SignInStartError(type: .generalError))) + return .init( + .error(SignInStartError(type: .generalError, correlationId: telemetryInfo.context.correlationId())), + correlationId: telemetryInfo.context.correlationId() + ) } let config = factory.makeMSIDConfiguration(scopes: scopes) @@ -491,12 +520,15 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN telemetryInfo: telemetryInfo, onSuccess: { accountResult in continuation.resume(returning: SignInControllerResponse(.completed(accountResult), - telemetryUpdate: { [weak self] result in + correlationId: telemetryInfo.context.correlationId(), + telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, delegateDispatcherResult: result) })) }, onError: { error in - continuation.resume(returning: SignInControllerResponse(.error(error))) + continuation.resume( + returning: SignInControllerResponse(.error(error), correlationId: telemetryInfo.context.correlationId()) + ) } ) } @@ -509,7 +541,10 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN correlationId: params.context.correlationId() ) - return .init(.passwordRequired(newState: state), telemetryUpdate: { [weak self] result in + return .init( + .passwordRequired(newState: state), + correlationId: telemetryInfo.context.correlationId(), + telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, delegateDispatcherResult: result) }) } @@ -527,16 +562,18 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN sentTo: sentTo, channelTargetType: channelType, codeLength: codeLength - ), telemetryUpdate: { [weak self] result in + ), + correlationId: telemetryInfo.context.correlationId(), + telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, delegateDispatcherResult: result) }) case .error(let challengeError): - let error = challengeError.convertToSignInStartError() + let error = challengeError.convertToSignInStartError(correlationId: telemetryInfo.context.correlationId()) MSALLogger.log(level: .error, context: telemetryInfo.context, format: "SignIn, completed with error: \(error.errorDescription ?? "No error description")") stopTelemetryEvent(telemetryInfo, error: error) - return .init(.error(error)) + return .init(.error(error), correlationId: telemetryInfo.context.correlationId()) } } @@ -546,13 +583,13 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN ) async -> MSALNativeAuthSignInChallengeValidatedResponse { guard let challengeRequest = createChallengeRequest(continuationToken: continuationToken, context: context) else { MSALLogger.log(level: .error, context: context, format: "SignIn ResendCode: Cannot create Challenge request object") - return .error(.invalidRequest(message: nil)) + return .error(.invalidRequest(.init())) } let challengeResponse: Result = await performRequest(challengeRequest, context: context) return signInResponseValidator.validate(context: context, result: challengeResponse) } - private func createInitiateRequest(username: String, context: MSIDRequestContext) -> MSIDHttpRequest? { + private func createInitiateRequest(username: String, context: MSALNativeAuthRequestContext) -> MSIDHttpRequest? { let params = MSALNativeAuthSignInInitiateRequestParameters(context: context, username: username) do { return try signInRequestProvider.inititate(parameters: params, context: context) @@ -564,7 +601,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN private func createChallengeRequest( continuationToken: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) -> MSIDHttpRequest? { do { let params = MSALNativeAuthSignInChallengeRequestParameters( diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift index 45f7409985..27fdc9585c 100644 --- a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpController.swift @@ -70,7 +70,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa return await handleSignUpStartResult(result, username: parameters.username, event: event, context: parameters.context) } - func resendCode(username: String, context: MSIDRequestContext, continuationToken: String) async -> SignUpResendCodeControllerResponse { + func resendCode(username: String, context: MSALNativeAuthRequestContext, continuationToken: String) async -> SignUpResendCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpResendCode, context: context) let challengeResult = await performAndValidateChallengeRequest(continuationToken: continuationToken, context: context) return handleResendCodeResult(challengeResult, username: username, event: event, continuationToken: continuationToken, context: context) @@ -80,7 +80,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa _ code: String, username: String, continuationToken: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> SignUpSubmitCodeControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpSubmitCode, context: context) let params = MSALNativeAuthSignUpContinueRequestProviderParams( @@ -98,7 +98,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa _ password: String, username: String, continuationToken: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> SignUpSubmitPasswordControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpSubmitPassword, context: context) @@ -122,7 +122,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa _ attributes: [String: Any], username: String, continuationToken: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> SignUpSubmitAttributesControllerResponse { let event = makeAndStartTelemetryEvent(id: .telemetryApiIdSignUpSubmitAttributes, context: context) let params = MSALNativeAuthSignUpContinueRequestProviderParams( @@ -147,7 +147,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa request = try requestProvider.start(parameters: parameters) } catch { MSALLogger.log(level: .error, context: parameters.context, format: "Error while creating Start Request: \(error)") - return .unexpectedError(message: nil) + return .unexpectedError(nil) } MSALLogger.log(level: .info, context: parameters.context, format: "Performing signup/start request") @@ -161,60 +161,66 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa _ result: MSALNativeAuthSignUpStartValidatedResponse, username: String, event: MSIDTelemetryAPIEvent?, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> SignUpStartControllerResponse { switch result { case .success(let continuationToken): MSALLogger.log(level: .info, context: context, format: "Successful signup/start request") let challengeResult = await performAndValidateChallengeRequest(continuationToken: continuationToken, context: context) return handleSignUpChallengeResult(challengeResult, username: username, event: event, context: context) - case .attributeValidationFailed(let invalidAttributes): + case .attributeValidationFailed(let apiError, let invalidAttributes): MSALLogger.log( level: .error, context: context, format: "attribute_validation_failed received from signup/start request for attributes: \(invalidAttributes)" ) let message = String(format: MSALNativeAuthErrorMessage.attributeValidationFailedSignUpStart, invalidAttributes.description) - let error = SignUpStartError(type: .generalError, message: message) - return .init(.attributesInvalid(invalidAttributes), telemetryUpdate: { [weak self] result in + let error = apiError.toSignUpStartPublicError(correlationId: context.correlationId(), message: message) + return .init(.attributesInvalid(invalidAttributes), correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in // The telemetry event always fails because the attribute validation failed self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result, controllerError: error) }) case .redirect: - let error = SignUpStartError(type: .browserRequired) + let error = SignUpStartError(type: .browserRequired, correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Redirect error in signup/start request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - case .error(let apiError): - let error = apiError.toSignUpStartPublicError() + return .init(.error(error), correlationId: context.correlationId()) + case .error(let apiError), + .unauthorizedClient(let apiError): + let error = apiError.toSignUpStartPublicError(correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in signup/start request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) + return .init(.error(error), correlationId: context.correlationId()) case .invalidUsername(let apiError): - let error = SignUpStartError(type: .invalidUsername, message: apiError.errorDescription) + let error = SignUpStartError( + type: .invalidUsername, + message: apiError.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "InvalidUsername in signup/start request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - case .unauthorizedClient(let apiError): - let error = SignUpStartError(type: .generalError, message: apiError.errorDescription) - stopTelemetryEvent(event, context: context, error: error) - MSALLogger.log(level: .error, - context: context, - format: "Invalid Client Id in signup/start request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - case .unexpectedError(let message): - let error = SignUpStartError(type: .generalError, message: message) + return .init(.error(error), correlationId: context.correlationId()) + case .unexpectedError(let apiError): + let error = SignUpStartError( + type: .generalError, + message: apiError?.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/start request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) + return .init(.error(error), correlationId: context.correlationId()) } } @@ -222,7 +228,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa private func performAndValidateChallengeRequest( continuationToken: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> MSALNativeAuthSignUpChallengeValidatedResponse { let request: MSIDHttpRequest @@ -230,7 +236,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa request = try requestProvider.challenge(token: continuationToken, context: context) } catch { MSALLogger.log(level: .error, context: context, format: "Error while creating Challenge Request: \(error)") - return .unexpectedError(message: nil) + return .unexpectedError(nil) } MSALLogger.log(level: .info, context: context, format: "Performing signup/challenge request") @@ -248,47 +254,55 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa switch result { case .codeRequired(let sentTo, let challengeType, let codeLength, let continuationToken): MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge request") - return SignUpStartControllerResponse( - .codeRequired( - newState: SignUpCodeRequiredState(controller: self, - username: username, - continuationToken: continuationToken, - correlationId: context.correlationId()), - sentTo: sentTo, - channelTargetType: challengeType, - codeLength: codeLength - ), telemetryUpdate: { [weak self] result in + let result: SignUpStartResult = .codeRequired( + newState: SignUpCodeRequiredState( + controller: self, + username: username, + continuationToken: continuationToken, + correlationId: context.correlationId() + ), + sentTo: sentTo, + channelTargetType: challengeType, + codeLength: codeLength + ) + return SignUpStartControllerResponse(result, correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) } ) case .error(let apiError): - let error = apiError.toSignUpStartPublicError() + let error = apiError.toSignUpStartPublicError(correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in signup/challenge request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) + return .init(.error(error), correlationId: context.correlationId()) case .redirect: - let error = SignUpStartError(type: .browserRequired) + let error = SignUpStartError(type: .browserRequired, correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Redirect error in signup/challenge request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) + return .init(.error(error), correlationId: context.correlationId()) case .passwordRequired: - let error = SignUpStartError(type: .generalError) + let error = SignUpStartError(type: .generalError, correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/challenge request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) - case .unexpectedError(let message): - let error = SignUpStartError(type: .generalError, message: message) + return .init(.error(error), correlationId: context.correlationId()) + case .unexpectedError(let apiError): + let error = SignUpStartError( + type: .generalError, + message: apiError?.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/challenge request \(error.errorDescription ?? "No error description")") - return .init(.error(error)) + return .init(.error(error), correlationId: context.correlationId()) } } @@ -302,21 +316,23 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa switch result { case .codeRequired(let sentTo, let challengeType, let codeLength, let newContinuationToken): MSALLogger.log(level: .info, context: context, format: "Successful signup/challenge resendCode request") - return .init(.codeRequired( - newState: SignUpCodeRequiredState( - controller: self, - username: username, - continuationToken: newContinuationToken, - correlationId: context.correlationId() - ), + let newState = SignUpCodeRequiredState( + controller: self, + username: username, + continuationToken: newContinuationToken, + correlationId: context.correlationId() + ) + let result: SignUpResendCodeResult = .codeRequired( + newState: newState, sentTo: sentTo, channelTargetType: challengeType, codeLength: codeLength - ), telemetryUpdate: { [weak self] result in + ) + return .init(result, correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) case .error(let apiError): - let error = apiError.toResendCodePublicError() + let error = apiError.toResendCodePublicError(correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, @@ -327,22 +343,33 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa continuationToken: continuationToken, correlationId: context.correlationId() ) - return .init(.error(error: error, newState: newState)) - case .redirect, - .passwordRequired: - let error = ResendCodeError() + return .init(.error(error: error, newState: newState), correlationId: context.correlationId()) + case .redirect: + let error = ResendCodeError(correlationId: context.correlationId()) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/challenge resendCode request \(error.errorDescription ?? "No error description")") + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) + case .passwordRequired: + let error = ResendCodeError(correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/challenge resendCode request \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) - case .unexpectedError(let message): - let error = ResendCodeError(message: message) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) + case .unexpectedError(let apiError): + let error = ResendCodeError( + message: apiError?.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/challenge resendCode request \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) } } @@ -362,31 +389,48 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa continuationToken: continuationToken, correlationId: context.correlationId()) - return .init(.passwordRequired(state), telemetryUpdate: { [weak self] result in + return .init(.passwordRequired(state), correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) case .redirect: - let error = VerifyCodeError(type: .browserRequired) + let error = VerifyCodeError(type: .browserRequired, correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Redirect error in signup/challenge request \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) - case .error, - .codeRequired: - let error = VerifyCodeError(type: .generalError) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) + case .error(let apiError): + let error = VerifyCodeError( + type: .generalError, + correlationId: context.correlationId(), + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + stopTelemetryEvent(event, context: context, error: error) + MSALLogger.log(level: .error, + context: context, + format: "Unexpected error in signup/challenge request \(error.errorDescription ?? "No error description")") + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) + case .codeRequired: + let error = VerifyCodeError(type: .generalError, correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/challenge request \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) - case .unexpectedError(let message): - let error = VerifyCodeError(type: .generalError, message: message) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) + case .unexpectedError(let apiError): + let error = VerifyCodeError( + type: .generalError, + message: apiError?.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/challenge request \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) } } @@ -401,7 +445,7 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa request = try requestProvider.continue(parameters: parameters) } catch { MSALLogger.log(level: .error, context: parameters.context, format: "Error while creating Continue Request: \(error)") - return .unexpectedError(message: nil) + return .unexpectedError(nil) } MSALLogger.log(level: .info, context: parameters.context, format: "Performing signup/continue request") @@ -416,18 +460,24 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa username: String, continuationToken: String, event: MSIDTelemetryAPIEvent?, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> SignUpSubmitCodeControllerResponse { switch result { case .success(let newContinuationToken): let state = createSignInAfterSignUpStateUsingContinuationToken(newContinuationToken, username: username, event: event, context: context) - return .init(.completed(state), telemetryUpdate: { [weak self] result in + return .init(.completed(state), correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) - case .invalidUserInput: + case .invalidUserInput(let apiError): MSALLogger.log(level: .error, context: context, format: "invalid_user_input error in signup/continue request") - let error = VerifyCodeError(type: .invalidCode) + let error = VerifyCodeError( + type: .invalidCode, + message: apiError.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) stopTelemetryEvent(event, context: context, error: error) let state = SignUpCodeRequiredState( controller: self, @@ -435,13 +485,13 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa continuationToken: continuationToken, correlationId: context.correlationId() ) - return .init(.error(error: error, newState: state)) - case .credentialRequired(let newContinuationToken): + return .init(.error(error: error, newState: state), correlationId: context.correlationId()) + case .credentialRequired(let newContinuationToken, _): MSALLogger.log(level: .verbose, context: context, format: "credential_required received in signup/continue request") let result = await performAndValidateChallengeRequest(continuationToken: newContinuationToken, context: context) return handlePerformChallengeAfterContinueRequest(result, username: username, event: event, context: context) - case .attributesRequired(let newContinuationToken, let attributes): + case .attributesRequired(let newContinuationToken, let attributes, _): MSALLogger.log(level: .verbose, context: context, format: "attributes_required received in signup/continue request: \(attributes)") let state = SignUpAttributesRequiredState(controller: self, @@ -449,30 +499,33 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa continuationToken: newContinuationToken, correlationId: context.correlationId()) - return .init(.attributesRequired(attributes: attributes, newState: state), telemetryUpdate: { [weak self] result in + return .init( + .attributesRequired(attributes: attributes, newState: state), + correlationId: context.correlationId(), + telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) - case .error(let apiError): - let error = apiError.toVerifyCodePublicError() + case .error(let apiError), + .attributeValidationFailed(let apiError, _): + let error = apiError.toVerifyCodePublicError(correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in signup/continue request \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) - case .attributeValidationFailed: - let error = VerifyCodeError(type: .generalError) - stopTelemetryEvent(event, context: context, error: error) - MSALLogger.log(level: .error, - context: context, - format: "Unexpected error in signup/continue request \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) - case .unexpectedError(let message): - let error = VerifyCodeError(type: .generalError, message: message) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) + case .unexpectedError(let apiError): + let error = VerifyCodeError( + type: .generalError, + message: apiError?.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/continue request \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) } } @@ -487,11 +540,11 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa switch result { case .success(let newContinuationToken): let state = createSignInAfterSignUpStateUsingContinuationToken(newContinuationToken, username: username, event: event, context: context) - return .init(.completed(state), telemetryUpdate: { [weak self] result in + return .init(.completed(state), correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) - case .invalidUserInput(let error): - let error = error.toPasswordRequiredPublicError() + case .invalidUserInput(let apiError): + let error = apiError.toPasswordRequiredPublicError(correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log( level: .error, @@ -504,8 +557,8 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa continuationToken: continuationToken, correlationId: context.correlationId()) - return .init(.error(error: error, newState: state)) - case .attributesRequired(let newContinuationToken, let attributes): + return .init(.error(error: error, newState: state), correlationId: context.correlationId()) + case .attributesRequired(let newContinuationToken, let attributes, _): MSALLogger.log(level: .verbose, context: context, format: "attributes_required received in signup/continue request: \(attributes)") let state = SignUpAttributesRequiredState(controller: self, @@ -513,31 +566,34 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa continuationToken: newContinuationToken, correlationId: context.correlationId()) - return .init(.attributesRequired(attributes: attributes, newState: state), telemetryUpdate: { [weak self] result in + return .init( + .attributesRequired(attributes: attributes, newState: state), + correlationId: context.correlationId(), + telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) - case .error(let apiError): - let error = apiError.toPasswordRequiredPublicError() + case .error(let apiError), + .attributeValidationFailed(let apiError, _), + .credentialRequired(_, let apiError): + let error = apiError.toPasswordRequiredPublicError(correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/continue submitPassword request \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) - case .attributeValidationFailed, - .credentialRequired: - let error = PasswordRequiredError(type: .generalError) - stopTelemetryEvent(event, context: context, error: error) - MSALLogger.log(level: .error, - context: context, - format: "Unexpected error in signup/continue submitPassword request \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) - case .unexpectedError(let message): - let error = PasswordRequiredError(type: .generalError, message: message) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) + case .unexpectedError(let apiError): + let error = PasswordRequiredError( + type: .generalError, + message: apiError?.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/continue submitPassword request \(error.errorDescription ?? "No error description")") - return .init(.error(error: error, newState: nil)) + return .init(.error(error: error, newState: nil), correlationId: context.correlationId()) } } @@ -552,11 +608,11 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa switch result { case .success(let newContinuationToken): let state = createSignInAfterSignUpStateUsingContinuationToken(newContinuationToken, username: username, event: event, context: context) - return .init(.completed(state), telemetryUpdate: { [weak self] result in + return .init(.completed(state), correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result) }) - case .attributesRequired(let newContinuationToken, let attributes): - let error = AttributesRequiredError() + case .attributesRequired(let newContinuationToken, let attributes, let apiError): + let error = apiError.toAttributesRequiredPublicError(correlationId: context.correlationId()) MSALLogger.log(level: .error, context: context, format: "attributes_required received in signup/continue submitAttributes request: \(attributes)") @@ -566,43 +622,53 @@ final class MSALNativeAuthSignUpController: MSALNativeAuthBaseController, MSALNa continuationToken: newContinuationToken, correlationId: context.correlationId() ) - return .init(.attributesRequired(attributes: attributes, state: state), telemetryUpdate: { [weak self] result in + return .init( + .attributesRequired(attributes: attributes, state: state), + correlationId: context.correlationId(), + telemetryUpdate: { [weak self] result in // The telemetry event always fails because more attributes are required (we consider this an error after having sent attributes) self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result, controllerError: error) }) - case .attributeValidationFailed(let invalidAttributes): + case .attributeValidationFailed(let apiError, let invalidAttributes): let message = "attribute_validation_failed from signup/continue submitAttributes request. Make sure these attributes are correct: \(invalidAttributes)" // swiftlint:disable:this line_length MSALLogger.log(level: .error, context: context, format: message) let errorMessage = String(format: MSALNativeAuthErrorMessage.attributeValidationFailed, invalidAttributes.description) - let error = AttributesRequiredError(message: errorMessage) - + let error = apiError.toAttributesRequiredPublicError(correlationId: context.correlationId(), message: errorMessage) let state = SignUpAttributesRequiredState( controller: self, username: username, continuationToken: continuationToken, correlationId: context.correlationId() ) - return .init(.attributesInvalid(attributes: invalidAttributes, newState: state), telemetryUpdate: { [weak self] result in + return .init( + .attributesInvalid(attributes: invalidAttributes, newState: state), + correlationId: context.correlationId(), + telemetryUpdate: { [weak self] result in // The telemetry event always fails because the attribute validation failed self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result, controllerError: error) }) - case .error(let apiError): - let error = apiError.toAttributesRequiredPublicError() + case .error(let apiError), + .invalidUserInput(let apiError), + .credentialRequired(_, let apiError): + let error = apiError.toAttributesRequiredPublicError(correlationId: context.correlationId()) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Error in signup/continue submitAttributes request \(error.errorDescription ?? "No error description")") - return .init(.error(error: error)) - case .credentialRequired, - .unexpectedError, - .invalidUserInput: - let error = AttributesRequiredError() + return .init(.error(error: error), correlationId: context.correlationId()) + case .unexpectedError(let apiError): + let error = AttributesRequiredError( + message: apiError?.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) stopTelemetryEvent(event, context: context, error: error) MSALLogger.log(level: .error, context: context, format: "Unexpected error in signup/continue submitAttributes request \(error.errorDescription ?? "No error description")") - return .init(.error(error: error)) + return .init(.error(error: error), correlationId: context.correlationId()) } } diff --git a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift index d0f4dce645..19659596c9 100644 --- a/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift +++ b/MSAL/src/native_auth/controllers/sign_up/MSALNativeAuthSignUpControlling.swift @@ -34,26 +34,26 @@ protocol MSALNativeAuthSignUpControlling: AnyObject { func signUpStart(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) async -> SignUpStartControllerResponse - func resendCode(username: String, context: MSIDRequestContext, continuationToken: String) async -> SignUpResendCodeControllerResponse + func resendCode(username: String, context: MSALNativeAuthRequestContext, continuationToken: String) async -> SignUpResendCodeControllerResponse func submitCode( _ code: String, username: String, continuationToken: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> SignUpSubmitCodeControllerResponse func submitPassword( _ password: String, username: String, continuationToken: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> SignUpSubmitPasswordControllerResponse func submitAttributes( _ attributes: [String: Any], username: String, continuationToken: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) async -> SignUpSubmitAttributesControllerResponse } diff --git a/MSAL/src/native_auth/network/MSALNativeAuthCustomErrorSerializer.swift b/MSAL/src/native_auth/network/MSALNativeAuthCustomErrorSerializer.swift index e15c33a62f..6d4fcf649d 100644 --- a/MSAL/src/native_auth/network/MSALNativeAuthCustomErrorSerializer.swift +++ b/MSAL/src/native_auth/network/MSALNativeAuthCustomErrorSerializer.swift @@ -26,10 +26,18 @@ import Foundation @_implementationOnly import MSAL_Private -final class MSALNativeAuthCustomErrorSerializer: NSObject, MSIDResponseSerialization { +final class MSALNativeAuthCustomErrorSerializer: NSObject, MSIDResponseSerialization { func responseObject(for httpResponse: HTTPURLResponse?, data: Data?, context: MSIDRequestContext?) throws -> Any { - let customError = try JSONDecoder().decode(T.self, from: data ?? Data()) - // the successfuly constructed "customError" needs to be thrown, since the previous "try" command just validates the object (error) decoding - throw customError + do { + var customError = try JSONDecoder().decode(T.self, from: data ?? Data()) + customError.correlationId = T.retrieveCorrelationIdFromHeaders(from: httpResponse) + + // the successfuly constructed "customError" needs to be thrown, + // since the previous "try" command just validates the object (error) decoding + throw customError + } catch is DecodingError { + MSALLogger.log(level: .error, context: context, format: "CustomErrorSerializer failed decoding") + throw MSALNativeAuthInternalError.responseSerializationError(headerCorrelationId: T.retrieveCorrelationIdFromHeaders(from: httpResponse)) + } } } diff --git a/MSAL/src/native_auth/network/MSALNativeAuthResponseCorrelatable.swift b/MSAL/src/native_auth/network/MSALNativeAuthResponseCorrelatable.swift new file mode 100644 index 0000000000..f452319bd7 --- /dev/null +++ b/MSAL/src/native_auth/network/MSALNativeAuthResponseCorrelatable.swift @@ -0,0 +1,40 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthResponseCorrelatable { + var correlationId: UUID? { get set } +} + +extension MSALNativeAuthResponseCorrelatable { + + static func retrieveCorrelationIdFromHeaders(from httpResponse: HTTPURLResponse?) -> UUID? { + guard let headers = httpResponse?.allHeaderFields, let correlationId = headers[MSID_OAUTH2_CORRELATION_ID_REQUEST_VALUE] as? String else { + return nil + } + + return UUID(uuidString: correlationId) + } +} diff --git a/MSAL/src/native_auth/network/MSALNativeAuthResponseErrorHandler.swift b/MSAL/src/native_auth/network/MSALNativeAuthResponseErrorHandler.swift index 7f5574f52b..ce2544c480 100644 --- a/MSAL/src/native_auth/network/MSALNativeAuthResponseErrorHandler.swift +++ b/MSAL/src/native_auth/network/MSALNativeAuthResponseErrorHandler.swift @@ -26,7 +26,7 @@ import Foundation @_implementationOnly import MSAL_Private -final class MSALNativeAuthResponseErrorHandler: NSObject, MSIDHttpRequestErrorHandling { +final class MSALNativeAuthResponseErrorHandler: NSObject, MSIDHttpRequestErrorHandling { // swiftlint:disable:next function_parameter_count func handleError( diff --git a/MSAL/src/native_auth/network/MSALNativeAuthResponseSerializer.swift b/MSAL/src/native_auth/network/MSALNativeAuthResponseSerializer.swift index bd545ed2bb..ae48168d94 100644 --- a/MSAL/src/native_auth/network/MSALNativeAuthResponseSerializer.swift +++ b/MSAL/src/native_auth/network/MSALNativeAuthResponseSerializer.swift @@ -24,16 +24,24 @@ @_implementationOnly import MSAL_Private -final class MSALNativeAuthResponseSerializer: NSObject, MSIDResponseSerialization { +final class MSALNativeAuthResponseSerializer: NSObject, MSIDResponseSerialization { func responseObject(for httpResponse: HTTPURLResponse?, data: Data?, context: MSIDRequestContext?) throws -> Any { guard let data = data else { - throw MSALNativeAuthInternalError.responseSerializationError + MSALLogger.log(level: .error, context: context, format: "ResponseSerializer failed decoding. Empty Data") + throw MSALNativeAuthInternalError.responseSerializationError(headerCorrelationId: T.retrieveCorrelationIdFromHeaders(from: httpResponse)) } let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase - return try decoder.decode(T.self, from: data) + do { + var response = try decoder.decode(T.self, from: data) + response.correlationId = T.retrieveCorrelationIdFromHeaders(from: httpResponse) + return response + } catch { + MSALLogger.log(level: .error, context: context, format: "ResponseSerializer failed decoding \(error)") + throw MSALNativeAuthInternalError.responseSerializationError(headerCorrelationId: T.retrieveCorrelationIdFromHeaders(from: httpResponse)) + } } } diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift index 50def369db..04236b9037 100644 --- a/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift @@ -24,7 +24,7 @@ import Foundation -protocol MSALNativeAuthResponseError: Error, Decodable, Equatable { +protocol MSALNativeAuthResponseError: Error, Decodable, Equatable, MSALNativeAuthResponseCorrelatable { associatedtype ErrorCode: RawRepresentable where ErrorCode.RawValue == String var error: ErrorCode? { get } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift index 791c85caff..4534e6fc13 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift @@ -32,6 +32,7 @@ struct MSALNativeAuthResetPasswordChallengeResponseError: MSALNativeAuthResponse let errorURI: String? let innerErrors: [MSALNativeAuthInnerError]? let target: String? + var correlationId: UUID? enum CodingKeys: String, CodingKey { case error @@ -40,30 +41,60 @@ struct MSALNativeAuthResetPasswordChallengeResponseError: MSALNativeAuthResponse case errorURI = "error_uri" case innerErrors = "inner_errors" case target + case correlationId + } + + init( + error: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode? = nil, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + target: String? = nil, + correlationId: UUID? = nil + ) { + self.error = error + self.errorDescription = errorDescription + self.errorCodes = errorCodes + self.errorURI = errorURI + self.innerErrors = innerErrors + self.target = target + self.correlationId = correlationId } } extension MSALNativeAuthResetPasswordChallengeResponseError { - func toResetPasswordStartPublicError() -> ResetPasswordStartError { + func toResetPasswordStartPublicError(correlationId: UUID) -> ResetPasswordStartError { switch error { case .invalidRequest, .unauthorizedClient, .unsupportedChallengeType, .expiredToken, .none: - return .init(type: .generalError, message: errorDescription) + return .init( + type: .generalError, + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) } } - func toResendCodePublicError() -> ResendCodeError { + func toResendCodePublicError(correlationId: UUID) -> ResendCodeError { switch error { case .unauthorizedClient, .unsupportedChallengeType, .expiredToken, .invalidRequest, .none: - return .init(message: errorDescription) + return .init( + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) } } } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift index c43b51d8b7..663fea097a 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift @@ -34,6 +34,7 @@ struct MSALNativeAuthResetPasswordContinueResponseError: MSALNativeAuthResponseE let innerErrors: [MSALNativeAuthInnerError]? let target: String? let continuationToken: String? + var correlationId: UUID? enum CodingKeys: String, CodingKey { case error @@ -44,22 +45,56 @@ struct MSALNativeAuthResetPasswordContinueResponseError: MSALNativeAuthResponseE case innerErrors = "inner_errors" case target case continuationToken = "continuation_token" + case correlationId + } + + init( + error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode? = nil, + subError: MSALNativeAuthSubErrorCode? = nil, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + target: String? = nil, + continuationToken: String? = nil, + correlationId: UUID? = nil + ) { + self.error = error + self.subError = subError + self.errorDescription = errorDescription + self.errorCodes = errorCodes + self.errorURI = errorURI + self.innerErrors = innerErrors + self.target = target + self.continuationToken = continuationToken + self.correlationId = correlationId } } extension MSALNativeAuthResetPasswordContinueResponseError { - func toVerifyCodePublicError() -> VerifyCodeError { + func toVerifyCodePublicError(correlationId: UUID) -> VerifyCodeError { switch error { case .invalidGrant: - return subError == .invalidOOBValue ? .init(type: .invalidCode, message: errorDescription) - : .init(type: .generalError, message: errorDescription) + return .init( + type: subError == .invalidOOBValue ? .invalidCode : .generalError, + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) case .unauthorizedClient, .expiredToken, .invalidRequest, .verificationRequired, .none: - return .init(type: .generalError, message: errorDescription) + return .init( + type: .generalError, + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) } } } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift index d1b11aeca6..c37a7f4115 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift @@ -33,6 +33,7 @@ struct MSALNativeAuthResetPasswordPollCompletionResponseError: MSALNativeAuthRes let errorURI: String? let innerErrors: [MSALNativeAuthInnerError]? let target: String? + var correlationId: UUID? enum CodingKeys: String, CodingKey { case error @@ -42,26 +43,54 @@ struct MSALNativeAuthResetPasswordPollCompletionResponseError: MSALNativeAuthRes case errorURI = "error_uri" case innerErrors = "inner_errors" case target + case correlationId + } + + init( + error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode? = nil, + subError: MSALNativeAuthSubErrorCode? = nil, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + target: String? = nil, + correlationId: UUID? = nil + ) { + self.error = error + self.subError = subError + self.errorDescription = errorDescription + self.errorCodes = errorCodes + self.errorURI = errorURI + self.innerErrors = innerErrors + self.target = target + self.correlationId = correlationId } } extension MSALNativeAuthResetPasswordPollCompletionResponseError { - func toPasswordRequiredPublicError() -> PasswordRequiredError { + func toPasswordRequiredPublicError(correlationId: UUID) -> PasswordRequiredError { switch error { case .invalidGrant: - if let subError, subError.isAnyPasswordError { - return .init(type: .invalidPassword, message: errorDescription) - } else { - return .init(type: .generalError, message: errorDescription) - } + return .init( + type: subError?.isAnyPasswordError == true ? .invalidPassword : .generalError, + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) case .unauthorizedClient, .expiredToken, .invalidRequest, .userNotFound, .none: - return .init(type: .generalError, message: errorDescription) - + return .init( + type: .generalError, + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) } } } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift index 3271f6c1d0..393acf8a95 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift @@ -32,6 +32,7 @@ struct MSALNativeAuthResetPasswordStartResponseError: MSALNativeAuthResponseErro let errorURI: String? let innerErrors: [MSALNativeAuthInnerError]? let target: String? + var correlationId: UUID? enum CodingKeys: String, CodingKey { case error @@ -40,5 +41,24 @@ struct MSALNativeAuthResetPasswordStartResponseError: MSALNativeAuthResponseErro case errorURI = "error_uri" case innerErrors = "inner_errors" case target + case correlationId + } + + init( + error: MSALNativeAuthResetPasswordStartOauth2ErrorCode? = nil, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + target: String? = nil, + correlationId: UUID? = nil + ) { + self.error = error + self.errorDescription = errorDescription + self.errorCodes = errorCodes + self.errorURI = errorURI + self.innerErrors = innerErrors + self.target = target + self.correlationId = correlationId } } diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift index 0dfa431c7d..3da234e5ee 100644 --- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift +++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift @@ -33,6 +33,7 @@ struct MSALNativeAuthResetPasswordSubmitResponseError: MSALNativeAuthResponseErr let errorURI: String? let innerErrors: [MSALNativeAuthInnerError]? let target: String? + var correlationId: UUID? enum CodingKeys: String, CodingKey { case error @@ -42,24 +43,53 @@ struct MSALNativeAuthResetPasswordSubmitResponseError: MSALNativeAuthResponseErr case errorURI = "error_uri" case innerErrors = "inner_errors" case target + case correlationId + } + + init( + error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode? = nil, + subError: MSALNativeAuthSubErrorCode? = nil, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + target: String? = nil, + correlationId: UUID? = nil + ) { + self.error = error + self.subError = subError + self.errorDescription = errorDescription + self.errorCodes = errorCodes + self.errorURI = errorURI + self.innerErrors = innerErrors + self.target = target + self.correlationId = correlationId } } extension MSALNativeAuthResetPasswordSubmitResponseError { - func toPasswordRequiredPublicError() -> PasswordRequiredError { + func toPasswordRequiredPublicError(correlationId: UUID) -> PasswordRequiredError { switch error { case .invalidGrant: - if let subError, subError.isAnyPasswordError { - return .init(type: .invalidPassword, message: errorDescription) - } else { - return .init(type: .generalError, message: errorDescription) - } + return .init( + type: subError?.isAnyPasswordError == true ? .invalidPassword : .generalError, + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) case .unauthorizedClient, .expiredToken, .invalidRequest, .none: - return .init(type: .generalError, message: errorDescription) + return .init( + type: .generalError, + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) } } } diff --git a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift index 2d2288d2f6..8e86273168 100644 --- a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift @@ -31,6 +31,7 @@ struct MSALNativeAuthSignInChallengeResponseError: MSALNativeAuthResponseError { let errorCodes: [Int]? let errorURI: String? let innerErrors: [MSALNativeAuthInnerError]? + var correlationId: UUID? enum CodingKeys: String, CodingKey { case error @@ -38,5 +39,22 @@ struct MSALNativeAuthSignInChallengeResponseError: MSALNativeAuthResponseError { case errorCodes = "error_codes" case errorURI = "error_uri" case innerErrors = "inner_errors" + case correlationId + } + + init( + error: MSALNativeAuthSignInChallengeOauth2ErrorCode? = nil, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + correlationId: UUID? = nil + ) { + self.error = error + self.errorDescription = errorDescription + self.errorCodes = errorCodes + self.errorURI = errorURI + self.innerErrors = innerErrors + self.correlationId = correlationId } } diff --git a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift index f06215c97d..5440c03494 100644 --- a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift @@ -31,6 +31,7 @@ struct MSALNativeAuthSignInInitiateResponseError: MSALNativeAuthResponseError { let errorCodes: [Int]? let errorURI: String? let innerErrors: [MSALNativeAuthInnerError]? + var correlationId: UUID? enum CodingKeys: String, CodingKey { case error @@ -38,5 +39,22 @@ struct MSALNativeAuthSignInInitiateResponseError: MSALNativeAuthResponseError { case errorCodes = "error_codes" case errorURI = "error_uri" case innerErrors = "inner_errors" + case correlationId + } + + init( + error: MSALNativeAuthSignInInitiateOauth2ErrorCode? = nil, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + correlationId: UUID? = nil + ) { + self.error = error + self.errorDescription = errorDescription + self.errorCodes = errorCodes + self.errorURI = errorURI + self.innerErrors = innerErrors + self.correlationId = correlationId } } diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift index be141648e5..e20c5f4981 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift @@ -30,6 +30,7 @@ struct MSALNativeAuthSignUpChallengeResponseError: MSALNativeAuthResponseError { let errorCodes: [Int]? let errorURI: String? let innerErrors: [MSALNativeAuthInnerError]? + var correlationId: UUID? enum CodingKeys: String, CodingKey { case error @@ -37,41 +38,75 @@ struct MSALNativeAuthSignUpChallengeResponseError: MSALNativeAuthResponseError { case errorCodes = "error_codes" case errorURI = "error_uri" case innerErrors = "inner_errors" + case correlationId + } + + init( + error: MSALNativeAuthSignUpChallengeOauth2ErrorCode? = nil, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + correlationId: UUID? = nil + ) { + self.error = error + self.errorDescription = errorDescription + self.errorCodes = errorCodes + self.errorURI = errorURI + self.innerErrors = innerErrors + self.correlationId = correlationId } } extension MSALNativeAuthSignUpChallengeResponseError { - func toSignUpStartPublicError() -> SignUpStartError { + func toSignUpStartPublicError(correlationId: UUID) -> SignUpStartError { switch error { case .unauthorizedClient, .unsupportedChallengeType, .expiredToken, .invalidRequest, .none: - return .init(type: .generalError, message: errorDescription) + return .init( + type: .generalError, + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) } } - func toResendCodePublicError() -> ResendCodeError { + func toResendCodePublicError(correlationId: UUID) -> ResendCodeError { switch error { case .unauthorizedClient, .unsupportedChallengeType, .expiredToken, .invalidRequest, .none: - return .init(message: errorDescription) + return .init( + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) } } - func toPasswordRequiredPublicError() -> PasswordRequiredError { + func toPasswordRequiredPublicError(correlationId: UUID) -> PasswordRequiredError { switch error { case .unauthorizedClient, .unsupportedChallengeType, .expiredToken, .invalidRequest, .none: - return .init(type: .generalError, message: errorDescription) + return .init( + type: .generalError, + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) } } } diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift index fbddbe5212..837344454e 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift @@ -35,6 +35,7 @@ struct MSALNativeAuthSignUpContinueResponseError: MSALNativeAuthResponseError { let requiredAttributes: [MSALNativeAuthRequiredAttributeInternal]? let unverifiedAttributes: [MSALNativeAuthErrorBasicAttribute]? let invalidAttributes: [MSALNativeAuthErrorBasicAttribute]? + var correlationId: UUID? enum CodingKeys: String, CodingKey { case error @@ -47,16 +48,48 @@ struct MSALNativeAuthSignUpContinueResponseError: MSALNativeAuthResponseError { case requiredAttributes = "required_attributes" case unverifiedAttributes = "unverified_attributes" case invalidAttributes = "invalid_attributes" + case correlationId + } + + init( + error: MSALNativeAuthSignUpContinueOauth2ErrorCode? = nil, + subError: MSALNativeAuthSubErrorCode? = nil, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + continuationToken: String? = nil, + requiredAttributes: [MSALNativeAuthRequiredAttributeInternal]? = nil, + unverifiedAttributes: [MSALNativeAuthErrorBasicAttribute]? = nil, + invalidAttributes: [MSALNativeAuthErrorBasicAttribute]? = nil, + correlationId: UUID? = nil + ) { + self.error = error + self.subError = subError + self.errorDescription = errorDescription + self.errorCodes = errorCodes + self.errorURI = errorURI + self.innerErrors = innerErrors + self.continuationToken = continuationToken + self.requiredAttributes = requiredAttributes + self.unverifiedAttributes = unverifiedAttributes + self.invalidAttributes = invalidAttributes + self.correlationId = correlationId } } extension MSALNativeAuthSignUpContinueResponseError { - func toVerifyCodePublicError() -> VerifyCodeError { + func toVerifyCodePublicError(correlationId: UUID) -> VerifyCodeError { switch error { case .invalidGrant: - return subError == .invalidOOBValue ? .init(type: .invalidCode, message: errorDescription) - : .init(type: .generalError, message: errorDescription) + return .init( + type: subError == .invalidOOBValue ? .invalidCode : .generalError, + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) case .unauthorizedClient, .expiredToken, .invalidRequest, @@ -65,18 +98,27 @@ extension MSALNativeAuthSignUpContinueResponseError { .verificationRequired, .credentialRequired, .none: - return .init(type: .generalError, message: errorDescription) + return .init( + type: .generalError, + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) } } - func toPasswordRequiredPublicError() -> PasswordRequiredError { + func toPasswordRequiredPublicError(correlationId: UUID) -> PasswordRequiredError { switch error { case .invalidGrant: - if let subError, subError.isAnyPasswordError { - return .init(type: .invalidPassword, message: errorDescription) - } else { - return .init(type: .generalError, message: errorDescription) - } + return .init( + type: subError?.isAnyPasswordError == true ? .invalidPassword : .generalError, + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) + case .unauthorizedClient, .expiredToken, .invalidRequest, @@ -85,11 +127,22 @@ extension MSALNativeAuthSignUpContinueResponseError { .verificationRequired, .credentialRequired, .none: - return .init(type: .generalError, message: errorDescription) + return .init( + type: .generalError, + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) } } - func toAttributesRequiredPublicError() -> AttributesRequiredError { - return AttributesRequiredError(message: errorDescription) + func toAttributesRequiredPublicError(correlationId: UUID, message: String? = nil) -> AttributesRequiredError { + return AttributesRequiredError( + message: message ?? errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) } } diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift index fe8d0d9ab5..e39fa3fc11 100644 --- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift +++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift @@ -35,6 +35,7 @@ struct MSALNativeAuthSignUpStartResponseError: MSALNativeAuthResponseError { let continuationToken: String? let unverifiedAttributes: [MSALNativeAuthErrorBasicAttribute]? let invalidAttributes: [MSALNativeAuthErrorBasicAttribute]? + var correlationId: UUID? enum CodingKeys: String, CodingKey { case error @@ -46,28 +47,67 @@ struct MSALNativeAuthSignUpStartResponseError: MSALNativeAuthResponseError { case continuationToken = "continuation_token" case unverifiedAttributes = "unverified_attributes" case invalidAttributes = "invalid_attributes" + case correlationId + } + + init( + error: MSALNativeAuthSignUpStartOauth2ErrorCode? = nil, + subError: MSALNativeAuthSubErrorCode? = nil, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + continuationToken: String? = nil, + unverifiedAttributes: [MSALNativeAuthErrorBasicAttribute]? = nil, + invalidAttributes: [MSALNativeAuthErrorBasicAttribute]? = nil, + correlationId: UUID? = nil + ) { + self.error = error + self.subError = subError + self.errorDescription = errorDescription + self.errorCodes = errorCodes + self.errorURI = errorURI + self.innerErrors = innerErrors + self.continuationToken = continuationToken + self.unverifiedAttributes = unverifiedAttributes + self.invalidAttributes = invalidAttributes + self.correlationId = correlationId } } extension MSALNativeAuthSignUpStartResponseError { - func toSignUpStartPublicError() -> SignUpStartError { + func toSignUpStartPublicError(correlationId: UUID, message: String? = nil) -> SignUpStartError { switch error { case .invalidGrant: - if let subError, subError.isAnyPasswordError { - return .init(type: .invalidPassword, message: errorDescription) - } else { - return .init(type: .generalError, message: errorDescription) - } + return .init( + type: subError?.isAnyPasswordError == true ? .invalidPassword : .generalError, + message: message ?? errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) case .userAlreadyExists: - return .init(type: .userAlreadyExists, message: errorDescription) + return .init( + type: .userAlreadyExists, + message: message ?? errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) case .attributesRequired, .unauthorizedClient, .unsupportedChallengeType, .unsupportedAuthMethod, .invalidRequest, .none: - return .init(type: .generalError, message: errorDescription) + return .init( + type: .generalError, + message: message ?? errorDescription, + correlationId: correlationId, + errorCodes: errorCodes ?? [], + errorUri: errorURI + ) } } } diff --git a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift index c56cd04ae9..4d74b2798b 100644 --- a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift +++ b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift @@ -33,6 +33,7 @@ struct MSALNativeAuthTokenResponseError: MSALNativeAuthResponseError { let errorURI: String? let innerErrors: [MSALNativeAuthInnerError]? let continuationToken: String? + var correlationId: UUID? enum CodingKeys: String, CodingKey { case error @@ -42,5 +43,26 @@ struct MSALNativeAuthTokenResponseError: MSALNativeAuthResponseError { case errorURI = "error_uri" case innerErrors = "inner_errors" case continuationToken = "continuation_token" + case correlationId + } + + init( + error: MSALNativeAuthTokenOauth2ErrorCode? = nil, + subError: MSALNativeAuthSubErrorCode? = nil, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + continuationToken: String? = nil, + correlationId: UUID? = nil + ) { + self.error = error + self.subError = subError + self.errorDescription = errorDescription + self.errorCodes = errorCodes + self.errorURI = errorURI + self.innerErrors = innerErrors + self.continuationToken = continuationToken + self.correlationId = correlationId } } diff --git a/MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestContext.swift b/MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestContext.swift index f9971b2aab..3bd6770fe0 100644 --- a/MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestContext.swift +++ b/MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestContext.swift @@ -24,17 +24,19 @@ @_implementationOnly import MSAL_Private -final class MSALNativeAuthRequestContext: MSIDRequestContext { +class MSALNativeAuthRequestContext: MSIDRequestContext { private let _correlationId: UUID - private let _telemetryRequestId: String = MSIDTelemetry.sharedInstance().generateRequestId() + private let _telemetryRequestId: String + private var _serverCorrelationId: UUID? // TODO: Setting the server correlation id here is wrong. Needs refactoring. - init(correlationId: UUID? = nil) { + init(correlationId: UUID? = nil, telemetryRequestId: String = MSIDTelemetry.sharedInstance().generateRequestId()) { _correlationId = correlationId ?? UUID() + _telemetryRequestId = telemetryRequestId } func correlationId() -> UUID { - _correlationId + _serverCorrelationId ?? _correlationId } func logComponent() -> String { @@ -59,4 +61,24 @@ final class MSALNativeAuthRequestContext: MSIDRequestContext { MSID_APP_VER_KEY: appVersion ] } + + func setServerCorrelationId(_ serverCorrelationId: UUID?) { + guard let serverCorrelationId = serverCorrelationId else { + MSALLogger.log(level: .warning, context: self, format: "correlationId not found in server response") + _serverCorrelationId = serverCorrelationId + return + } + + guard _correlationId != serverCorrelationId else { + return + } + + let log = """ + Inconsistency between the correlationId sent by the SDK and the one received in the response. + Original correlationId: \(_correlationId). Server correlationId \(serverCorrelationId) + """ + MSALLogger.log(level: .warning, context: self, format: log) + + _serverCorrelationId = serverCorrelationId + } } diff --git a/MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestable.swift b/MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestable.swift index 1b03df47e5..b514a86b2b 100644 --- a/MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestable.swift +++ b/MSAL/src/native_auth/network/parameters/MSALNativeAuthRequestable.swift @@ -26,7 +26,7 @@ protocol MSALNativeAuthRequestable { var endpoint: MSALNativeAuthEndpoint { get } - var context: MSIDRequestContext { get } + var context: MSALNativeAuthRequestContext { get } func makeEndpointUrl(config: MSALNativeAuthConfiguration) throws -> URL func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] diff --git a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParameters.swift b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParameters.swift index 5209677c2b..d9d6461427 100644 --- a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordChallengeRequestParameters.swift @@ -26,7 +26,7 @@ struct MSALNativeAuthResetPasswordChallengeRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .resetPasswordChallenge - let context: MSIDRequestContext + let context: MSALNativeAuthRequestContext let continuationToken: String func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { diff --git a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParameters.swift b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParameters.swift index 375a7b70aa..661d9a5c8c 100644 --- a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordContinueRequestParameters.swift @@ -26,7 +26,7 @@ struct MSALNativeAuthResetPasswordContinueRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .resetPasswordContinue - let context: MSIDRequestContext + let context: MSALNativeAuthRequestContext let continuationToken: String let grantType: MSALNativeAuthGrantType let oobCode: String? diff --git a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift index e93629836f..c71eac1e50 100644 --- a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordPollCompletionRequestParameters.swift @@ -26,7 +26,7 @@ struct MSALNativeAuthResetPasswordPollCompletionRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .resetpasswordPollCompletion - let context: MSIDRequestContext + let context: MSALNativeAuthRequestContext let continuationToken: String func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { diff --git a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordStartRequestParameters.swift b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordStartRequestParameters.swift index 85c726f984..6e56e21d23 100644 --- a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordStartRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordStartRequestParameters.swift @@ -26,7 +26,7 @@ struct MSALNativeAuthResetPasswordStartRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .resetPasswordStart - let context: MSIDRequestContext + let context: MSALNativeAuthRequestContext let username: String func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { diff --git a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordSubmitRequestParameters.swift b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordSubmitRequestParameters.swift index 54691135e6..1fed358d3c 100644 --- a/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordSubmitRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/reset_password/MSALNativeAuthResetPasswordSubmitRequestParameters.swift @@ -26,7 +26,7 @@ struct MSALNativeAuthResetPasswordSubmitRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .resetPasswordSubmit - let context: MSIDRequestContext + let context: MSALNativeAuthRequestContext let continuationToken: String let newPassword: String diff --git a/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParameters.swift b/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParameters.swift index 4079d2bc55..7cd236fbf6 100644 --- a/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInChallengeRequestParameters.swift @@ -26,7 +26,7 @@ struct MSALNativeAuthSignInChallengeRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .signInChallenge - let context: MSIDRequestContext + let context: MSALNativeAuthRequestContext let continuationToken: String func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { diff --git a/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInInitiateRequestParameters.swift b/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInInitiateRequestParameters.swift index c0c7b08b6e..9660f8e752 100644 --- a/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInInitiateRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/sign_in/MSALNativeAuthSignInInitiateRequestParameters.swift @@ -26,7 +26,7 @@ struct MSALNativeAuthSignInInitiateRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .signInInitiate - let context: MSIDRequestContext + let context: MSALNativeAuthRequestContext let username: String func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { diff --git a/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParameters.swift b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParameters.swift index ae276d486d..49263992f5 100644 --- a/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpChallengeRequestParameters.swift @@ -27,7 +27,7 @@ struct MSALNativeAuthSignUpChallengeRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .signUpChallenge let continuationToken: String - let context: MSIDRequestContext + let context: MSALNativeAuthRequestContext func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { typealias Key = MSALNativeAuthRequestParametersKey diff --git a/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParameters.swift b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParameters.swift index 62359a996c..5fcc3ff4d4 100644 --- a/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpContinueRequestParameters.swift @@ -31,7 +31,7 @@ struct MSALNativeAuthSignUpContinueRequestParameters: MSALNativeAuthRequestable let password: String? let oobCode: String? let attributes: String? - let context: MSIDRequestContext + let context: MSALNativeAuthRequestContext func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { typealias Key = MSALNativeAuthRequestParametersKey diff --git a/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpStartRequestParameters.swift b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpStartRequestParameters.swift index b3224f7118..3dd6901c0f 100644 --- a/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpStartRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/sign_up/MSALNativeAuthSignUpStartRequestParameters.swift @@ -29,7 +29,7 @@ struct MSALNativeAuthSignUpStartRequestParameters: MSALNativeAuthRequestable { let username: String let password: String? let attributes: String? - let context: MSIDRequestContext + let context: MSALNativeAuthRequestContext func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { typealias Key = MSALNativeAuthRequestParametersKey diff --git a/MSAL/src/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParameters.swift b/MSAL/src/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParameters.swift index 96315a1b89..11e2299dbb 100644 --- a/MSAL/src/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParameters.swift +++ b/MSAL/src/native_auth/network/parameters/token/MSALNativeAuthTokenRequestParameters.swift @@ -26,7 +26,7 @@ struct MSALNativeAuthTokenRequestParameters: MSALNativeAuthRequestable { let endpoint: MSALNativeAuthEndpoint = .token - let context: MSIDRequestContext + let context: MSALNativeAuthRequestContext let username: String? let continuationToken: String? let grantType: MSALNativeAuthGrantType diff --git a/MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordRequestProvider.swift b/MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordRequestProvider.swift index 438d823155..36be42e148 100644 --- a/MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordRequestProvider.swift +++ b/MSAL/src/native_auth/network/reset_password/MSALNativeAuthResetPasswordRequestProvider.swift @@ -31,7 +31,7 @@ protocol MSALNativeAuthResetPasswordRequestProviding { func challenge( token: String, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) throws -> MSIDHttpRequest func `continue`( @@ -83,7 +83,7 @@ final class MSALNativeAuthResetPasswordRequestProvider: MSALNativeAuthResetPassw // MARK: - Reset Password Challenge - func challenge(token: String, context: MSIDRequestContext) throws -> MSIDHttpRequest { + func challenge(token: String, context: MSALNativeAuthRequestContext) throws -> MSIDHttpRequest { let requestParams = MSALNativeAuthResetPasswordChallengeRequestParameters( context: context, continuationToken: token diff --git a/MSAL/src/native_auth/network/responses/MSALNativeAuthResendCodeRequestResponse.swift b/MSAL/src/native_auth/network/responses/MSALNativeAuthResendCodeRequestResponse.swift index ecd7c76a60..df36f9db31 100644 --- a/MSAL/src/native_auth/network/responses/MSALNativeAuthResendCodeRequestResponse.swift +++ b/MSAL/src/native_auth/network/responses/MSALNativeAuthResendCodeRequestResponse.swift @@ -24,12 +24,9 @@ import Foundation -struct MSALNativeAuthResendCodeRequestResponse: Decodable { +struct MSALNativeAuthResendCodeRequestResponse: Decodable, MSALNativeAuthResponseCorrelatable { // MARK: - Variables let continuationToken: String - - enum CodingKeys: String, CodingKey { - case continuationToken - } + var correlationId: UUID? } diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordChallengeResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordChallengeResponse.swift index bfccddd1aa..86fe51e3b2 100644 --- a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordChallengeResponse.swift +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordChallengeResponse.swift @@ -24,7 +24,7 @@ import Foundation -struct MSALNativeAuthResetPasswordChallengeResponse: Decodable { +struct MSALNativeAuthResetPasswordChallengeResponse: Decodable, MSALNativeAuthResponseCorrelatable { // MARK: - Variables let challengeType: MSALNativeAuthInternalChallengeType @@ -33,4 +33,5 @@ struct MSALNativeAuthResetPasswordChallengeResponse: Decodable { let challengeChannel: MSALNativeAuthInternalChannelType? let continuationToken: String? let codeLength: Int? + var correlationId: UUID? } diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordContinueResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordContinueResponse.swift index 10fd7c241f..65ba145203 100644 --- a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordContinueResponse.swift +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordContinueResponse.swift @@ -24,9 +24,10 @@ import Foundation -struct MSALNativeAuthResetPasswordContinueResponse: Decodable { +struct MSALNativeAuthResetPasswordContinueResponse: Decodable, MSALNativeAuthResponseCorrelatable { // MARK: - Variables let continuationToken: String let expiresIn: Int + var correlationId: UUID? } diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionResponse.swift index 4ea53a96a6..7483b79383 100644 --- a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionResponse.swift +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordPollCompletionResponse.swift @@ -24,10 +24,11 @@ import Foundation -struct MSALNativeAuthResetPasswordPollCompletionResponse: Decodable { +struct MSALNativeAuthResetPasswordPollCompletionResponse: Decodable, MSALNativeAuthResponseCorrelatable { // MARK: - Variables let status: MSALNativeAuthResetPasswordPollCompletionStatus let continuationToken: String? let expiresIn: Int? + var correlationId: UUID? } diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift index 38a4122209..c92216624e 100644 --- a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordStartResponse.swift @@ -24,9 +24,10 @@ import Foundation -struct MSALNativeAuthResetPasswordStartResponse: Decodable { +struct MSALNativeAuthResetPasswordStartResponse: Decodable, MSALNativeAuthResponseCorrelatable { // MARK: - Variables let continuationToken: String? let challengeType: MSALNativeAuthInternalChallengeType? + var correlationId: UUID? } diff --git a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordSubmitResponse.swift b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordSubmitResponse.swift index f61c83927b..a15b5a3b75 100644 --- a/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordSubmitResponse.swift +++ b/MSAL/src/native_auth/network/responses/reset_password/MSALNativeAuthResetPasswordSubmitResponse.swift @@ -24,9 +24,10 @@ import Foundation -struct MSALNativeAuthResetPasswordSubmitResponse: Decodable { +struct MSALNativeAuthResetPasswordSubmitResponse: Decodable, MSALNativeAuthResponseCorrelatable { // MARK: - Variables let continuationToken: String let pollInterval: Int + var correlationId: UUID? } diff --git a/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInChallengeResponse.swift b/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInChallengeResponse.swift index 4f969080b1..7dd3891251 100644 --- a/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInChallengeResponse.swift +++ b/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInChallengeResponse.swift @@ -24,7 +24,7 @@ import Foundation -struct MSALNativeAuthSignInChallengeResponse: Decodable { +struct MSALNativeAuthSignInChallengeResponse: Decodable, MSALNativeAuthResponseCorrelatable { // MARK: - Variables let continuationToken: String? @@ -34,4 +34,5 @@ struct MSALNativeAuthSignInChallengeResponse: Decodable { let challengeChannel: MSALNativeAuthInternalChannelType? let codeLength: Int? let interval: Int? + var correlationId: UUID? } diff --git a/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInInitiateResponse.swift b/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInInitiateResponse.swift index 3329b7a562..d9f976c35f 100644 --- a/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInInitiateResponse.swift +++ b/MSAL/src/native_auth/network/responses/sign_in/MSALNativeAuthSignInInitiateResponse.swift @@ -24,9 +24,10 @@ import Foundation -struct MSALNativeAuthSignInInitiateResponse: Decodable { +struct MSALNativeAuthSignInInitiateResponse: Decodable, MSALNativeAuthResponseCorrelatable { // MARK: - Variables let continuationToken: String? let challengeType: MSALNativeAuthInternalChallengeType? + var correlationId: UUID? } diff --git a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpChallengeResponse.swift b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpChallengeResponse.swift index ea8339b5be..3891b6f990 100644 --- a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpChallengeResponse.swift +++ b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpChallengeResponse.swift @@ -24,7 +24,7 @@ import Foundation -struct MSALNativeAuthSignUpChallengeResponse: Decodable { +struct MSALNativeAuthSignUpChallengeResponse: Decodable, MSALNativeAuthResponseCorrelatable { let challengeType: MSALNativeAuthInternalChallengeType? let bindingMethod: String? let interval: Int? @@ -32,4 +32,5 @@ struct MSALNativeAuthSignUpChallengeResponse: Decodable { let challengeChannel: MSALNativeAuthInternalChannelType? let continuationToken: String? let codeLength: Int? + var correlationId: UUID? } diff --git a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpContinueResponse.swift b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpContinueResponse.swift index cba35c6f01..20b7e96a4b 100644 --- a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpContinueResponse.swift +++ b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpContinueResponse.swift @@ -24,7 +24,8 @@ import Foundation -struct MSALNativeAuthSignUpContinueResponse: Decodable { +struct MSALNativeAuthSignUpContinueResponse: Decodable, MSALNativeAuthResponseCorrelatable { let continuationToken: String? let expiresIn: Int? + var correlationId: UUID? } diff --git a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpStartResponse.swift b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpStartResponse.swift index 0846bc4108..f1aa14b9cd 100644 --- a/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpStartResponse.swift +++ b/MSAL/src/native_auth/network/responses/sign_up/MSALNativeAuthSignUpStartResponse.swift @@ -24,7 +24,8 @@ import Foundation -struct MSALNativeAuthSignUpStartResponse: Decodable { +struct MSALNativeAuthSignUpStartResponse: Decodable, MSALNativeAuthResponseCorrelatable { let continuationToken: String? let challengeType: MSALNativeAuthInternalChallengeType? + var correlationId: UUID? } diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift index 36ae21c2b2..09231cdb79 100644 --- a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift @@ -62,7 +62,7 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas context: context, format: "resetpassword/start returned success with unexpected response body") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } } @@ -73,24 +73,29 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas context: context, format: "resetpassword/start: Unable to decode error response: \(error)") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } switch apiError.error { case .invalidRequest: if apiError.errorCodes?.first == MSALNativeAuthESTSApiErrorCodes.userNotHaveAPassword.rawValue { - return .error(.userDoesNotHavePassword) + return .error(.userDoesNotHavePassword(apiError)) } else { - return .error(.invalidRequest(message: apiError.errorDescription)) + return .error(.invalidRequest(apiError)) } case .unauthorizedClient: - return .error(.unauthorizedClient(message: apiError.errorDescription)) + return .error(.unauthorizedClient(apiError)) case .userNotFound: - return .error(.userNotFound(message: apiError.errorDescription)) + return .error(.userNotFound(apiError)) case .unsupportedChallengeType: - return .error(.unsupportedChallengeType(message: apiError.errorDescription)) + return .error(.unsupportedChallengeType(apiError)) case .none: - return .error(.unexpectedError(message: apiError.errorDescription)) + return .error(.unexpectedError(.init( + errorDescription: apiError.errorDescription, + errorCodes: apiError.errorCodes, + errorURI: apiError.errorURI, + correlationId: apiError.correlationId + ))) } } @@ -128,22 +133,22 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas ) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields from backend") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } case .password, .otp: MSALLogger.log(level: .error, context: context, format: "ChallengeType not expected") - return .unexpectedError(message: nil) + return .unexpectedError(.init()) } } private func handleChallengeError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordChallengeValidatedResponse { guard let apiError = error as? MSALNativeAuthResetPasswordChallengeResponseError else { MSALLogger.log(level: .info, context: context, format: "resetpassword/challenge: Unable to decode error response: \(error)") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } if apiError.error == .none { - return .unexpectedError(message: apiError.errorDescription) + return .unexpectedError(.init(errorDescription: apiError.errorDescription)) } return .error(apiError) } @@ -171,21 +176,26 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas private func handleContinueError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordContinueValidatedResponse { guard let apiError = error as? MSALNativeAuthResetPasswordContinueResponseError else { MSALLogger.log(level: .error, context: context, format: "resetpassword/continue: Unable to decode error response: \(error)") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } switch apiError.error { case .invalidGrant: - return apiError.subError == .invalidOOBValue ? .invalidOOB : .error(apiError) + return apiError.subError == .invalidOOBValue ? .invalidOOB(apiError) : .error(apiError) case .unauthorizedClient, .expiredToken, .invalidRequest: return .error(apiError) case .verificationRequired: MSALLogger.log(level: .error, context: context, format: "verificationRequired is not supported yet") - return .unexpectedError(message: nil) + return .unexpectedError(nil) case .none: - return .unexpectedError(message: apiError.errorDescription) + return .unexpectedError(.init( + errorDescription: apiError.errorDescription, + errorCodes: apiError.errorCodes, + errorURI: apiError.errorURI, + correlationId: apiError.correlationId + )) } } @@ -206,16 +216,13 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas private func handleSubmitSuccess( _ response: MSALNativeAuthResetPasswordSubmitResponse ) -> MSALNativeAuthResetPasswordSubmitValidatedResponse { - return .success( - continuationToken: response.continuationToken, - pollInterval: response.pollInterval - ) + return .success(continuationToken: response.continuationToken, pollInterval: response.pollInterval) } private func handleSubmitError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthResetPasswordSubmitValidatedResponse { guard let apiError = error as? MSALNativeAuthResetPasswordSubmitResponseError else { MSALLogger.log(level: .error, context: context, format: "resetpassword/submit: Unable to decode error response: \(error)") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } switch apiError.error { @@ -230,7 +237,12 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas .expiredToken: return .error(apiError) case .none: - return .unexpectedError(message: apiError.errorDescription) + return .unexpectedError(.init( + errorDescription: apiError.errorDescription, + errorCodes: apiError.errorCodes, + errorURI: apiError.errorURI, + correlationId: apiError.correlationId + )) } } @@ -261,7 +273,7 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas ) -> MSALNativeAuthResetPasswordPollCompletionValidatedResponse { guard let apiError = error as? MSALNativeAuthResetPasswordPollCompletionResponseError else { MSALLogger.log(level: .error, context: context, format: "resetpassword/poll_completion: Unable to decode error response: \(error)") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } switch apiError.error { @@ -277,7 +289,12 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas .expiredToken: return .error(apiError) case .none: - return .unexpectedError(message: apiError.errorDescription) + return .unexpectedError(.init( + errorDescription: apiError.errorDescription, + errorCodes: apiError.errorCodes, + errorURI: apiError.errorURI, + correlationId: apiError.correlationId + )) } } } diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift index f1a36731bc..405d787f21 100644 --- a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift +++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordValidatedResponses.swift @@ -22,33 +22,58 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +@_implementationOnly import MSAL_Private + enum MSALNativeAuthResetPasswordStartValidatedResponse: Equatable { case success(continuationToken: String) case redirect case error(MSALNativeAuthResetPasswordStartValidatedErrorType) - case unexpectedError(message: String?) + case unexpectedError(MSALNativeAuthResetPasswordStartResponseError?) } enum MSALNativeAuthResetPasswordStartValidatedErrorType: Equatable, Error { - case invalidRequest(message: String?) - case unauthorizedClient(message: String?) - case userNotFound(message: String?) - case unsupportedChallengeType(message: String?) - case userDoesNotHavePassword - case unexpectedError(message: String?) + case invalidRequest(MSALNativeAuthResetPasswordStartResponseError) + case unauthorizedClient(MSALNativeAuthResetPasswordStartResponseError) + case userNotFound(MSALNativeAuthResetPasswordStartResponseError) + case unsupportedChallengeType(MSALNativeAuthResetPasswordStartResponseError) + case userDoesNotHavePassword(MSALNativeAuthResetPasswordStartResponseError) + case unexpectedError(MSALNativeAuthResetPasswordStartResponseError?) - func toResetPasswordStartPublicError() -> ResetPasswordStartError { + func toResetPasswordStartPublicError(context: MSIDRequestContext) -> ResetPasswordStartError { switch self { - case .userNotFound(let message): - return .init(type: .userNotFound, message: message) - case .unsupportedChallengeType(let message), - .invalidRequest(let message), - .unauthorizedClient(let message): - return .init(type: .generalError, message: message) - case .userDoesNotHavePassword: - return .init(type: .userDoesNotHavePassword, message: MSALNativeAuthErrorMessage.userDoesNotHavePassword) - case .unexpectedError(message: let message): - return .init(type: .generalError, message: message) + case .userNotFound(let apiError): + return .init( + type: .userNotFound, + message: apiError.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + case .unsupportedChallengeType(let apiError), + .invalidRequest(let apiError), + .unauthorizedClient(let apiError): + return .init( + type: .generalError, + message: apiError.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + case .userDoesNotHavePassword(let apiError): + return .init( + type: .userDoesNotHavePassword, + message: apiError.errorDescription, + correlationId: context.correlationId(), + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + case .unexpectedError(let apiError): + return .init( + type: .generalError, + message: apiError?.errorDescription, + correlationId: context.correlationId(), + errorUri: apiError?.errorURI + ) } } } @@ -57,26 +82,26 @@ enum MSALNativeAuthResetPasswordChallengeValidatedResponse: Equatable { case success(_ sentTo: String, _ channelTargetType: MSALNativeAuthChannelType, _ codeLength: Int, _ resetPasswordChallengeToken: String) case redirect case error(MSALNativeAuthResetPasswordChallengeResponseError) - case unexpectedError(message: String?) + case unexpectedError(MSALNativeAuthResetPasswordChallengeResponseError?) } enum MSALNativeAuthResetPasswordContinueValidatedResponse: Equatable { case success(continuationToken: String) - case invalidOOB + case invalidOOB(MSALNativeAuthResetPasswordContinueResponseError) case error(MSALNativeAuthResetPasswordContinueResponseError) - case unexpectedError(message: String?) + case unexpectedError(MSALNativeAuthResetPasswordContinueResponseError?) } enum MSALNativeAuthResetPasswordSubmitValidatedResponse: Equatable { case success(continuationToken: String, pollInterval: Int) case passwordError(error: MSALNativeAuthResetPasswordSubmitResponseError) case error(MSALNativeAuthResetPasswordSubmitResponseError) - case unexpectedError(message: String?) + case unexpectedError(MSALNativeAuthResetPasswordSubmitResponseError?) } enum MSALNativeAuthResetPasswordPollCompletionValidatedResponse: Equatable { case success(status: MSALNativeAuthResetPasswordPollCompletionStatus, continuationToken: String?) case passwordError(error: MSALNativeAuthResetPasswordPollCompletionResponseError) case error(MSALNativeAuthResetPasswordPollCompletionResponseError) - case unexpectedError(message: String?) + case unexpectedError(MSALNativeAuthResetPasswordPollCompletionResponseError?) } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift index 0756ba70da..720eeb5592 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift @@ -26,12 +26,12 @@ protocol MSALNativeAuthSignInResponseValidating { func validate( - context: MSALNativeAuthRequestContext, + context: MSIDRequestContext, result: Result ) -> MSALNativeAuthSignInChallengeValidatedResponse func validate( - context: MSALNativeAuthRequestContext, + context: MSIDRequestContext, result: Result ) -> MSALNativeAuthSignInInitiateValidatedResponse } @@ -39,7 +39,7 @@ protocol MSALNativeAuthSignInResponseValidating { final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseValidating { func validate( - context: MSALNativeAuthRequestContext, + context: MSIDRequestContext, result: Result ) -> MSALNativeAuthSignInChallengeValidatedResponse { switch result { @@ -52,14 +52,14 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV level: .error, context: context, format: "signin/challenge: Unable to decode error response: \(signInChallengeResponseError)") - return .error(.unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody)) + return .error(.unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))) } - return handleFailedSignInChallengeResult(context, error: signInChallengeResponseError) + return handleFailedSignInChallengeResult(error: signInChallengeResponseError) } } func validate( - context: MSALNativeAuthRequestContext, + context: MSIDRequestContext, result: Result ) -> MSALNativeAuthSignInInitiateValidatedResponse { switch result { @@ -71,23 +71,23 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV return .success(continuationToken: continuationToken) } MSALLogger.log(level: .error, context: context, format: "signin/initiate: challengeType and continuation token empty") - return .error(.unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody)) + return .error(.unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))) case .failure(let responseError): guard let initiateResponseError = responseError as? MSALNativeAuthSignInInitiateResponseError else { MSALLogger.log( level: .error, context: context, format: "signin/initiate: Unable to decode error response: \(responseError)") - return .error(.unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody)) + return .error(.unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))) } - return handleFailedSignInInitiateResult(context, error: initiateResponseError) + return handleFailedSignInInitiateResult(error: initiateResponseError) } } // MARK: private methods private func handleSuccessfulSignInChallengeResult( - _ context: MSALNativeAuthRequestContext, + _ context: MSIDRequestContext, response: MSALNativeAuthSignInChallengeResponse) -> MSALNativeAuthSignInChallengeValidatedResponse { switch response.challengeType { case .otp: @@ -95,7 +95,7 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV level: .error, context: context, format: "signin/challenge: Received unexpected challenge type: \(response.challengeType)") - return .error(.unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedChallengeType)) + return .error(.unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedChallengeType))) case .oob: guard let continuationToken = response.continuationToken, let targetLabel = response.challengeTargetLabel, @@ -105,7 +105,7 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV level: .error, context: context, format: "signin/challenge: Invalid response with challenge type oob, response: \(response)") - return .error(.unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody)) + return .error(.unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))) } return .codeRequired( continuationToken: continuationToken, @@ -118,7 +118,7 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV level: .error, context: context, format: "signin/challenge: Expected continuation token not nil with credential type password") - return .error(.unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody)) + return .error(.unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))) } return .passwordRequired(continuationToken: continuationToken) case .redirect: @@ -127,38 +127,45 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV } private func handleFailedSignInChallengeResult( - _ context: MSALNativeAuthRequestContext, error: MSALNativeAuthSignInChallengeResponseError) -> MSALNativeAuthSignInChallengeValidatedResponse { switch error.error { case .invalidRequest: - return .error(.invalidRequest(message: error.errorDescription)) + return .error(.invalidRequest(error)) case .unauthorizedClient: - return .error(.unauthorizedClient(message: error.errorDescription)) + return .error(.unauthorizedClient(error)) case .invalidGrant: - return .error(.invalidToken(message: error.errorDescription)) + return .error(.invalidToken(error)) case .expiredToken: - return .error(.expiredToken(message: error.errorDescription)) + return .error(.expiredToken(error)) case .unsupportedChallengeType: - return .error(.unsupportedChallengeType(message: error.errorDescription)) + return .error(.unsupportedChallengeType(error)) case .none: - return .error(.unexpectedError(message: error.errorDescription)) + return .error(.unexpectedError(.init( + errorDescription: error.errorDescription, + errorCodes: error.errorCodes, + errorURI: error.errorURI, + correlationId: error.correlationId + ))) } } - private func handleFailedSignInInitiateResult( - _ context: MSALNativeAuthRequestContext, - error: MSALNativeAuthSignInInitiateResponseError) -> MSALNativeAuthSignInInitiateValidatedResponse { + private func handleFailedSignInInitiateResult(error: MSALNativeAuthSignInInitiateResponseError) -> MSALNativeAuthSignInInitiateValidatedResponse { switch error.error { case .invalidRequest: - return .error(.invalidRequest(message: error.errorDescription)) + return .error(.invalidRequest(error)) case .unauthorizedClient: - return .error(.unauthorizedClient(message: error.errorDescription)) + return .error(.unauthorizedClient(error)) case .unsupportedChallengeType: - return .error(.unsupportedChallengeType(message: error.errorDescription)) + return .error(.unsupportedChallengeType(error)) case .userNotFound: - return .error(.userNotFound(message: error.errorDescription)) + return .error(.userNotFound(error)) case .none: - return .error(.unexpectedError(message: error.errorDescription)) + return .error(.unexpectedError(.init( + errorDescription: error.errorDescription, + errorCodes: error.errorCodes, + errorURI: error.errorURI, + correlationId: error.correlationId + ))) } } } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift index 255f559ae7..2ee13b32f8 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInChallengeValidatedResponse.swift @@ -32,27 +32,72 @@ enum MSALNativeAuthSignInChallengeValidatedResponse { enum MSALNativeAuthSignInChallengeValidatedErrorType: Error { case redirect - case expiredToken(message: String?) - case invalidToken(message: String?) - case unauthorizedClient(message: String?) - case invalidRequest(message: String?) - case unexpectedError(message: String?) - case userNotFound(message: String?) - case unsupportedChallengeType(message: String?) + case expiredToken(MSALNativeAuthSignInChallengeResponseError) + case invalidToken(MSALNativeAuthSignInChallengeResponseError) + case unauthorizedClient(MSALNativeAuthSignInChallengeResponseError) + case invalidRequest(MSALNativeAuthSignInChallengeResponseError) + case unexpectedError(MSALNativeAuthSignInChallengeResponseError?) + case userNotFound(MSALNativeAuthSignInChallengeResponseError) + case unsupportedChallengeType(MSALNativeAuthSignInChallengeResponseError) - func convertToSignInStartError() -> SignInStartError { + func convertToSignInStartError(correlationId: UUID) -> SignInStartError { switch self { case .redirect: - return .init(type: .browserRequired) - case .expiredToken(let message), - .invalidToken(let message), - .invalidRequest(let message), - .unauthorizedClient(let message), - .unsupportedChallengeType(let message), - .unexpectedError(let message): - return .init(type: .generalError, message: message) - case .userNotFound(let message): - return .init(type: .userNotFound, message: message) + return .init(type: .browserRequired, correlationId: correlationId) + case .unexpectedError(let apiError): + return .init( + type: .generalError, + message: apiError?.errorDescription, + correlationId: correlationId, + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) + case .expiredToken(let apiError), + .invalidToken(let apiError), + .unauthorizedClient(let apiError), + .unsupportedChallengeType(let apiError), + .invalidRequest(let apiError): + return .init( + type: .generalError, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + case .userNotFound(let apiError): + return .init( + type: .userNotFound, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + } + } + + func convertToResendCodeError(correlationId: UUID) -> ResendCodeError { + switch self { + case .redirect: + return .init(correlationId: correlationId) + case .invalidRequest(let apiError), + .expiredToken(let apiError), + .invalidToken(let apiError), + .unauthorizedClient(let apiError), + .userNotFound(let apiError), + .unsupportedChallengeType(let apiError): + return .init( + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + case .unexpectedError(let apiError): + return .init( + message: apiError?.errorDescription, + correlationId: correlationId, + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) } } } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift index b8c5364026..518b88fefe 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_in/validated_response/MSALNativeAuthSignInInitiateValidatedResponse.swift @@ -31,37 +31,42 @@ enum MSALNativeAuthSignInInitiateValidatedResponse { enum MSALNativeAuthSignInInitiateValidatedErrorType: Error { case redirect - case unauthorizedClient(message: String?) - case invalidRequest(message: String?) - case unexpectedError(message: String?) - case userNotFound(message: String?) - case unsupportedChallengeType(message: String?) + case unauthorizedClient(MSALNativeAuthSignInInitiateResponseError) + case invalidRequest(MSALNativeAuthSignInInitiateResponseError) + case unexpectedError(MSALNativeAuthSignInInitiateResponseError?) + case userNotFound(MSALNativeAuthSignInInitiateResponseError) + case unsupportedChallengeType(MSALNativeAuthSignInInitiateResponseError) - func convertToSignInStartError() -> SignInStartError { + func convertToSignInStartError(correlationId: UUID) -> SignInStartError { switch self { case .redirect: - return .init(type: .browserRequired) - case .userNotFound(let message): - return .init(type: .userNotFound, message: message) - case .unauthorizedClient(let message), - .unsupportedChallengeType(let message), - .invalidRequest(let message), - .unexpectedError(message: let message): - return .init(type: .generalError, message: message) - } - } - - func convertToSignInPasswordStartError() -> SignInStartError { - switch self { - case .redirect: - return .init(type: .browserRequired) - case .userNotFound(let message): - return .init(type: .userNotFound, message: message) - case .unauthorizedClient(let message), - .unsupportedChallengeType(let message), - .invalidRequest(let message), - .unexpectedError(message: let message): - return .init(type: .generalError, message: message) + return .init(type: .browserRequired, correlationId: correlationId) + case .userNotFound(let apiError): + return .init( + type: .userNotFound, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + case .unexpectedError(let apiError): + return .init( + type: .generalError, + message: apiError?.errorDescription, + correlationId: correlationId, + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) + case .unauthorizedClient(let apiError), + .unsupportedChallengeType(let apiError), + .invalidRequest(let apiError): + return .init( + type: .generalError, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) } } } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift index d16cc84afc..8f3322616e 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift @@ -62,27 +62,27 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV return .success(continuationToken: continuationToken) } else { MSALLogger.log(level: .error, context: context, format: "signup/start returned success with unexpected response body") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } } private func handleStartFailed(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthSignUpStartValidatedResponse { guard let apiError = error as? MSALNativeAuthSignUpStartResponseError else { MSALLogger.log(level: .error, context: context, format: "signup/start: Unable to decode error response: \(error)") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } switch apiError.error { case .invalidGrant where apiError.subError == .attributeValidationFailed: if let invalidAttributes = apiError.invalidAttributes, !invalidAttributes.isEmpty { - return .attributeValidationFailed(invalidAttributes: extractAttributeNames(from: invalidAttributes)) + return .attributeValidationFailed(error: apiError, invalidAttributes: extractAttributeNames(from: invalidAttributes)) } else { MSALLogger.log( level: .error, context: context, format: "Missing expected fields in signup/start for attribute_validation_failed error" ) - return .unexpectedError(message: apiError.errorDescription) + return .unexpectedError(.init(errorDescription: apiError.errorDescription)) } case .invalidRequest where isSignUpStartInvalidRequestParameter( apiError, @@ -93,7 +93,12 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV knownErrorDescription: MSALNativeAuthESTSApiErrorDescriptions.clientIdParameterIsEmptyOrNotValid.rawValue): return .unauthorizedClient(apiError) case .none: - return .unexpectedError(message: apiError.errorDescription) + return .unexpectedError(.init( + errorDescription: apiError.errorDescription, + errorCodes: apiError.errorCodes, + errorURI: apiError.errorURI, + correlationId: apiError.correlationId + )) default: return .error(apiError) } @@ -119,7 +124,7 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV ) -> MSALNativeAuthSignUpChallengeValidatedResponse { guard let challengeTypeIssued = response.challengeType else { MSALLogger.log(level: .error, context: context, format: "Missing ChallengeType from backend in signup/challenge response") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } switch challengeTypeIssued { @@ -133,28 +138,28 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV return .codeRequired(sentTo, channelType, codeLength, continuationToken) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/challenge with challenge_type = oob") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } case .password: if let continuationToken = response.continuationToken { return .passwordRequired(continuationToken) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/challenge with challenge_type = password") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } case .otp: MSALLogger.log(level: .error, context: context, format: "ChallengeType OTP not expected for signup/challenge") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } } private func handleChallengeError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthSignUpChallengeValidatedResponse { guard let apiError = error as? MSALNativeAuthSignUpChallengeResponseError else { MSALLogger.log(level: .error, context: context, format: "signup/challenge: Unable to decode error response: \(error)") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } if apiError.error == .none { - return .unexpectedError(message: apiError.errorDescription) + return .unexpectedError(.init(errorDescription: apiError.errorDescription)) } return .error(apiError) @@ -169,7 +174,7 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV switch result { case .success(let response): // Even if the `continuationToken` is nil, the signUp flow is considered successfully completed - return .success(response.continuationToken) + return .success(continuationToken: response.continuationToken) case .failure(let error): return handleContinueError(error, with: context) } @@ -178,7 +183,7 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV private func handleContinueError(_ error: Error, with context: MSIDRequestContext) -> MSALNativeAuthSignUpContinueValidatedResponse { guard let apiError = error as? MSALNativeAuthSignUpContinueResponseError else { MSALLogger.log(level: .error, context: context, format: "signup/continue: Unable to decode error response: \(error)") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } switch apiError.error { @@ -186,10 +191,10 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV return handleInvalidGrantError(apiError, with: context) case .credentialRequired: if let continuationToken = apiError.continuationToken { - return .credentialRequired(continuationToken: continuationToken) + return .credentialRequired(continuationToken: continuationToken, error: apiError) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/continue for credential_required error") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } case .attributesRequired: if let continuationToken = apiError.continuationToken, @@ -197,23 +202,29 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV !requiredAttributes.isEmpty { return .attributesRequired( continuationToken: continuationToken, - requiredAttributes: requiredAttributes.map { $0.toRequiredAttributePublic() } + requiredAttributes: requiredAttributes.map { $0.toRequiredAttributePublic() }, + error: apiError ) } else { MSALLogger.log(level: .error, context: context, format: "Missing expected fields in signup/continue for attributes_required error") - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } // TODO: .verificationRequired is not supported by the API team yet. We treat it as an unexpectedError case .verificationRequired: MSALLogger.log(level: .error, context: context, format: "verificationRequired is not supported yet") - return .unexpectedError(message: nil) + return .unexpectedError(nil) case .unauthorizedClient, .expiredToken, .userAlreadyExists, .invalidRequest: return .error(apiError) case .none: - return .unexpectedError(message: apiError.errorDescription) + return .unexpectedError(.init( + errorDescription: apiError.errorDescription, + errorCodes: apiError.errorCodes, + errorURI: apiError.errorURI, + correlationId: apiError.correlationId + )) } } @@ -236,14 +247,14 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV return .invalidUserInput(apiError) case .attributeValidationFailed: if let invalidAttributes = apiError.invalidAttributes, !invalidAttributes.isEmpty { - return .attributeValidationFailed(invalidAttributes: extractAttributeNames(from: invalidAttributes)) + return .attributeValidationFailed(error: apiError, invalidAttributes: extractAttributeNames(from: invalidAttributes)) } else { MSALLogger.log( level: .error, context: context, format: "Missing expected fields in signup/continue for attribute_validation_failed error" ) - return .unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody) + return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody)) } } } diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift index 754d450aea..50129aeaf2 100644 --- a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift +++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpValidatedResponses.swift @@ -24,13 +24,13 @@ enum MSALNativeAuthSignUpStartValidatedResponse: Equatable { case success(continuationToken: String) - case attributeValidationFailed(invalidAttributes: [String]) + case attributeValidationFailed(error: MSALNativeAuthSignUpStartResponseError, invalidAttributes: [String]) case redirect case error(MSALNativeAuthSignUpStartResponseError) // TODO: Special errors handled separately. Remove after refactor validated error handling case invalidUsername(MSALNativeAuthSignUpStartResponseError) case unauthorizedClient(MSALNativeAuthSignUpStartResponseError) - case unexpectedError(message: String?) + case unexpectedError(MSALNativeAuthSignUpStartResponseError?) } enum MSALNativeAuthSignUpChallengeValidatedResponse: Equatable { @@ -38,16 +38,20 @@ enum MSALNativeAuthSignUpChallengeValidatedResponse: Equatable { case passwordRequired(_ signUpChallengeToken: String) case redirect case error(MSALNativeAuthSignUpChallengeResponseError) - case unexpectedError(message: String?) + case unexpectedError(MSALNativeAuthSignUpChallengeResponseError?) } enum MSALNativeAuthSignUpContinueValidatedResponse: Equatable { - case success(_ continuationToken: String?) + case success(continuationToken: String?) /// error that represents invalidOOB or invalidPassword, depending on which State the input comes from. case invalidUserInput(_ error: MSALNativeAuthSignUpContinueResponseError) - case credentialRequired(continuationToken: String) - case attributesRequired(continuationToken: String, requiredAttributes: [MSALNativeAuthRequiredAttribute]) - case attributeValidationFailed(invalidAttributes: [String]) + case credentialRequired(continuationToken: String, error: MSALNativeAuthSignUpContinueResponseError) + case attributesRequired( + continuationToken: String, + requiredAttributes: [MSALNativeAuthRequiredAttribute], + error: MSALNativeAuthSignUpContinueResponseError + ) + case attributeValidationFailed(error: MSALNativeAuthSignUpContinueResponseError, invalidAttributes: [String]) case error(MSALNativeAuthSignUpContinueResponseError) - case unexpectedError(message: String?) + case unexpectedError(MSALNativeAuthSignUpContinueResponseError?) } diff --git a/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift index 6bb3b78376..3693659eee 100644 --- a/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift @@ -26,7 +26,7 @@ protocol MSALNativeAuthTokenResponseValidating { func validate( - context: MSALNativeAuthRequestContext, + context: MSIDRequestContext, msidConfiguration: MSIDConfiguration, result: Result ) -> MSALNativeAuthTokenValidatedResponse @@ -51,7 +51,7 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal } func validate( - context: MSALNativeAuthRequestContext, + context: MSIDRequestContext, msidConfiguration: MSIDConfiguration, result: Result ) -> MSALNativeAuthTokenValidatedResponse { @@ -65,7 +65,7 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal level: .error, context: context, format: "Token: Unable to decode error response: \(tokenResponseError)") - return .error(.unexpectedError(message: MSALNativeAuthErrorMessage.unexpectedResponseBody)) + return .error(.unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))) } return handleFailedTokenResult(context, tokenResponseError) } @@ -91,47 +91,50 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal // swiftlint:disable:next cyclomatic_complexity private func handleFailedTokenResult( - _ context: MSALNativeAuthRequestContext, + _ context: MSIDRequestContext, _ responseError: MSALNativeAuthTokenResponseError) -> MSALNativeAuthTokenValidatedResponse { switch responseError.error { case .invalidRequest: - return handleInvalidRequestErrorCodes(responseError.errorCodes, errorDescription: responseError.errorDescription, context: context) + return handleInvalidRequestErrorCodes(apiError: responseError, context: context) case .invalidClient, .unauthorizedClient: - return .error(.unauthorizedClient(message: responseError.errorDescription)) + return .error(.unauthorizedClient(responseError)) case .invalidGrant: if responseError.subError == .invalidOOBValue { - return .error(.invalidOOBCode(message: responseError.errorDescription)) + return .error(.invalidOOBCode(responseError)) } else { - return handleInvalidGrantErrorCodes(responseError.errorCodes, errorDescription: responseError.errorDescription, context: context) + return handleInvalidGrantErrorCodes(apiError: responseError, context: context) } case .expiredToken: - return .error(.expiredToken(message: responseError.errorDescription)) + return .error(.expiredToken(responseError)) case .expiredRefreshToken: - return .error(.expiredRefreshToken(message: responseError.errorDescription)) + return .error(.expiredRefreshToken(responseError)) case .unsupportedChallengeType: - return .error(.unsupportedChallengeType(message: responseError.errorDescription)) + return .error(.unsupportedChallengeType(responseError)) case .invalidScope: - return .error(.invalidScope(message: responseError.errorDescription)) + return .error(.invalidScope(responseError)) case .authorizationPending: - return .error(.authorizationPending(message: responseError.errorDescription)) + return .error(.authorizationPending(responseError)) case .slowDown: - return .error(.slowDown(message: responseError.errorDescription)) + return .error(.slowDown(responseError)) case .userNotFound: - return .error(.userNotFound(message: responseError.errorDescription)) + return .error(.userNotFound(responseError)) case .none: - return .error(.unexpectedError(message: responseError.errorDescription)) + return .error(.unexpectedError(.init( + errorDescription: responseError.errorDescription, + errorCodes: responseError.errorCodes, + errorURI: responseError.errorURI, + correlationId: responseError.correlationId + ))) } } private func handleInvalidRequestErrorCodes( - _ errorCodes: [Int]?, - errorDescription: String?, - context: MSALNativeAuthRequestContext + apiError: MSALNativeAuthTokenResponseError, + context: MSIDRequestContext ) -> MSALNativeAuthTokenValidatedResponse { return handleInvalidResponseErrorCodes( - errorCodes, - errorDescription: errorDescription, + apiError, context: context, useInvalidRequestAsDefaultResult: true, errorCodesConverterFunction: convertInvalidRequestErrorCodeToErrorType @@ -139,38 +142,31 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal } private func handleInvalidGrantErrorCodes( - _ errorCodes: [Int]?, - errorDescription: String?, - context: MSALNativeAuthRequestContext + apiError: MSALNativeAuthTokenResponseError, + context: MSIDRequestContext ) -> MSALNativeAuthTokenValidatedResponse { - return handleInvalidResponseErrorCodes( - errorCodes, - errorDescription: errorDescription, - context: context, - errorCodesConverterFunction: convertInvalidGrantErrorCodeToErrorType - ) + return handleInvalidResponseErrorCodes(apiError, context: context, errorCodesConverterFunction: convertInvalidGrantErrorCodeToErrorType) } private func handleInvalidResponseErrorCodes( - _ errorCodes: [Int]?, - errorDescription: String?, - context: MSALNativeAuthRequestContext, + _ apiError: MSALNativeAuthTokenResponseError, + context: MSIDRequestContext, useInvalidRequestAsDefaultResult: Bool = false, - errorCodesConverterFunction: (MSALNativeAuthESTSApiErrorCodes, String?) -> MSALNativeAuthTokenValidatedErrorType + errorCodesConverterFunction: (MSALNativeAuthESTSApiErrorCodes, MSALNativeAuthTokenResponseError) -> MSALNativeAuthTokenValidatedErrorType ) -> MSALNativeAuthTokenValidatedResponse { - guard var errorCodes = errorCodes, !errorCodes.isEmpty else { + guard var errorCodes = apiError.errorCodes, !errorCodes.isEmpty else { MSALLogger.log(level: .error, context: context, format: "/token error - Empty error_codes received") - return useInvalidRequestAsDefaultResult ? .error(.invalidRequest(message: errorDescription)) : .error(.generalError) + return useInvalidRequestAsDefaultResult ? .error(.invalidRequest(apiError)) : .error(.generalError(apiError)) } let validatedResponse: MSALNativeAuthTokenValidatedResponse let firstErrorCode = errorCodes.removeFirst() if let knownErrorCode = MSALNativeAuthESTSApiErrorCodes(rawValue: firstErrorCode) { - validatedResponse = .error(errorCodesConverterFunction(knownErrorCode, errorDescription)) + validatedResponse = .error(errorCodesConverterFunction(knownErrorCode, apiError)) } else { MSALLogger.log(level: .error, context: context, format: "/token error - Unknown code received in error_codes: \(firstErrorCode)") - validatedResponse = useInvalidRequestAsDefaultResult ? .error(.invalidRequest(message: errorDescription)) : .error(.generalError) + validatedResponse = useInvalidRequestAsDefaultResult ? .error(.invalidRequest(apiError)) : .error(.generalError(apiError)) } // Log the rest of error_codes @@ -192,24 +188,24 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal private func convertInvalidGrantErrorCodeToErrorType( _ errorCode: MSALNativeAuthESTSApiErrorCodes, - errorDescription: String? + _ apiError: MSALNativeAuthTokenResponseError ) -> MSALNativeAuthTokenValidatedErrorType { switch errorCode { case .userNotFound: - return .userNotFound(message: errorDescription) + return .userNotFound(apiError) case .invalidCredentials: - return .invalidPassword(message: errorDescription) + return .invalidPassword(apiError) case .strongAuthRequired: - return .strongAuthRequired(message: errorDescription) + return .strongAuthRequired(apiError) case .userNotHaveAPassword, .invalidRequestParameter: - return .generalError + return .generalError(apiError) } } private func convertInvalidRequestErrorCodeToErrorType( _ errorCode: MSALNativeAuthESTSApiErrorCodes, - errorDescription: String? + _ apiError: MSALNativeAuthTokenResponseError ) -> MSALNativeAuthTokenValidatedErrorType { switch errorCode { case .userNotFound, @@ -217,7 +213,7 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal .strongAuthRequired, .userNotHaveAPassword, .invalidRequestParameter: - return .invalidRequest(message: errorDescription) + return .invalidRequest(apiError) } } } diff --git a/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift index 93db145804..951c160634 100644 --- a/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift +++ b/MSAL/src/native_auth/network/responses/validator/token/validated_response/MSALNativeAuthTokenValidatedResponse.swift @@ -30,99 +30,189 @@ enum MSALNativeAuthTokenValidatedResponse { } enum MSALNativeAuthTokenValidatedErrorType: Error { - case generalError - case expiredToken(message: String?) - case expiredRefreshToken(message: String?) - case unauthorizedClient(message: String?) - case invalidRequest(message: String?) - case unexpectedError(message: String?) - case userNotFound(message: String?) - case invalidPassword(message: String?) - case invalidOOBCode(message: String?) - case unsupportedChallengeType(message: String?) - case strongAuthRequired(message: String?) - case invalidScope(message: String?) - case authorizationPending(message: String?) - case slowDown(message: String?) + case generalError(MSALNativeAuthTokenResponseError?) + case expiredToken(MSALNativeAuthTokenResponseError) + case expiredRefreshToken(MSALNativeAuthTokenResponseError) + case unauthorizedClient(MSALNativeAuthTokenResponseError) + case invalidRequest(MSALNativeAuthTokenResponseError) + case unexpectedError(MSALNativeAuthTokenResponseError?) + case userNotFound(MSALNativeAuthTokenResponseError) + case invalidPassword(MSALNativeAuthTokenResponseError) + case invalidOOBCode(MSALNativeAuthTokenResponseError) + case unsupportedChallengeType(MSALNativeAuthTokenResponseError) + case strongAuthRequired(MSALNativeAuthTokenResponseError) + case invalidScope(MSALNativeAuthTokenResponseError) + case authorizationPending(MSALNativeAuthTokenResponseError) + case slowDown(MSALNativeAuthTokenResponseError) - func convertToSignInPasswordStartError() -> SignInStartError { + // swiftlint:disable:next function_body_length + func convertToSignInPasswordStartError(correlationId: UUID) -> SignInStartError { switch self { - case .expiredToken(let message), - .authorizationPending(let message), - .slowDown(let message), - .invalidRequest(let message), - .invalidOOBCode(let message), - .unauthorizedClient(let message), - .unsupportedChallengeType(let message), - .invalidScope(let message): - return SignInStartError(type: .generalError, message: message) - case .generalError: - return SignInStartError(type: .generalError) - case .userNotFound(let message): - return SignInStartError(type: .userNotFound, message: message) - case .invalidPassword(let message): - return SignInStartError(type: .invalidCredentials, message: message) - case .strongAuthRequired(let message): - return SignInStartError(type: .browserRequired, message: message) - case .expiredRefreshToken(let message): + case .expiredToken(let apiError), + .authorizationPending(let apiError), + .slowDown(let apiError), + .invalidOOBCode(let apiError), + .unauthorizedClient(let apiError), + .unsupportedChallengeType(let apiError), + .invalidScope(let apiError), + .invalidRequest(let apiError): + return SignInStartError( + type: .generalError, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + case .unexpectedError(let apiError), + .generalError(let apiError): + return SignInStartError( + type: .generalError, + message: apiError?.errorDescription, + correlationId: correlationId, + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) + case .userNotFound(let apiError): + return SignInStartError( + type: .userNotFound, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + case .invalidPassword(let apiError): + return SignInStartError( + type: .invalidCredentials, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + case .strongAuthRequired(let apiError): + return SignInStartError( + type: .browserRequired, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + case .expiredRefreshToken(let apiError): MSALLogger.log(level: .error, context: nil, format: "Error not treated - \(self))") - return SignInStartError(type: .generalError, message: message) - case .unexpectedError(message: let message): - return SignInStartError(type: .generalError, message: message) + return SignInStartError( + type: .generalError, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) } } - func convertToRetrieveAccessTokenError() -> RetrieveAccessTokenError { + func convertToRetrieveAccessTokenError(correlationId: UUID) -> RetrieveAccessTokenError { switch self { - case .expiredToken(let message), - .authorizationPending(let message), - .slowDown(let message), - .invalidRequest(let message), - .unauthorizedClient(let message), - .unsupportedChallengeType(let message), - .invalidScope(let message): - return RetrieveAccessTokenError(type: .generalError, message: message) + case .expiredToken(let apiError), + .authorizationPending(let apiError), + .slowDown(let apiError), + .unauthorizedClient(let apiError), + .unsupportedChallengeType(let apiError), + .invalidScope(let apiError), + .invalidRequest(let apiError): + return RetrieveAccessTokenError( + type: .generalError, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) case .generalError: - return RetrieveAccessTokenError(type: .generalError) - case .expiredRefreshToken: - return RetrieveAccessTokenError(type: .refreshTokenExpired) - case .strongAuthRequired(let message): - return RetrieveAccessTokenError(type: .browserRequired, message: message) - case .userNotFound(let message), - .invalidPassword(let message), - .invalidOOBCode(let message): + return RetrieveAccessTokenError(type: .generalError, correlationId: correlationId) + case .unexpectedError(let apiError): + return RetrieveAccessTokenError( + type: .generalError, + message: apiError?.errorDescription, + correlationId: correlationId, + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) + case .expiredRefreshToken(let apiError): + return RetrieveAccessTokenError( + type: .refreshTokenExpired, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + case .strongAuthRequired(let apiError): + return RetrieveAccessTokenError( + type: .browserRequired, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + case .userNotFound(let apiError), + .invalidPassword(let apiError), + .invalidOOBCode(let apiError): MSALLogger.log(level: .error, context: nil, format: "Error not treated - \(self))") - return RetrieveAccessTokenError(type: .generalError, message: message) - case .unexpectedError(message: let message): - return RetrieveAccessTokenError(type: .generalError, message: message) + return RetrieveAccessTokenError( + type: .generalError, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) } } - func convertToVerifyCodeError() -> VerifyCodeError { + func convertToVerifyCodeError(correlationId: UUID) -> VerifyCodeError { switch self { - case .invalidOOBCode(let message): - return VerifyCodeError(type: .invalidCode, message: message) - case .strongAuthRequired(let message): - return VerifyCodeError(type: .browserRequired, message: message) - case .expiredToken(let message), - .authorizationPending(let message), - .slowDown(let message), - .invalidRequest(let message), - .unauthorizedClient(let message), - .unsupportedChallengeType(let message), - .invalidScope(let message), - .expiredRefreshToken(let message), - .userNotFound(let message), - .invalidPassword(let message): - return VerifyCodeError(type: .generalError, message: message) + case .invalidOOBCode(let apiError): + return VerifyCodeError( + type: .invalidCode, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + case .strongAuthRequired(let apiError): + return VerifyCodeError( + type: .browserRequired, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) + case .expiredToken(let apiError), + .authorizationPending(let apiError), + .slowDown(let apiError), + .unauthorizedClient(let apiError), + .unsupportedChallengeType(let apiError), + .invalidScope(let apiError), + .expiredRefreshToken(let apiError), + .userNotFound(let apiError), + .invalidPassword(let apiError), + .invalidRequest(let apiError): + return VerifyCodeError( + type: .generalError, + message: apiError.errorDescription, + correlationId: correlationId, + errorCodes: apiError.errorCodes ?? [], + errorUri: apiError.errorURI + ) case .generalError: - return VerifyCodeError(type: .generalError) - case .unexpectedError(message: let message): - return VerifyCodeError(type: .generalError, message: message) + return VerifyCodeError(type: .generalError, correlationId: correlationId) + case .unexpectedError(let apiError): + return VerifyCodeError( + type: .generalError, + message: apiError?.errorDescription, + correlationId: correlationId, + errorCodes: apiError?.errorCodes ?? [], + errorUri: apiError?.errorURI + ) } } - func convertToPasswordRequiredError() -> PasswordRequiredError { - return PasswordRequiredError(signInStartError: convertToSignInPasswordStartError()) + func convertToPasswordRequiredError(correlationId: UUID) -> PasswordRequiredError { + return PasswordRequiredError(signInStartError: convertToSignInPasswordStartError(correlationId: correlationId)) } } diff --git a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpContinueRequestProviderParams.swift b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpContinueRequestProviderParams.swift index 46af3ec74c..eadaa42aab 100644 --- a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpContinueRequestProviderParams.swift +++ b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpContinueRequestProviderParams.swift @@ -30,7 +30,7 @@ struct MSALNativeAuthSignUpContinueRequestProviderParams { let password: String? let oobCode: String? let attributes: [String: Any]? - let context: MSIDRequestContext + let context: MSALNativeAuthRequestContext init( grantType: MSALNativeAuthGrantType, @@ -38,7 +38,7 @@ struct MSALNativeAuthSignUpContinueRequestProviderParams { password: String? = nil, oobCode: String? = nil, attributes: [String: Any]? = nil, - context: MSIDRequestContext + context: MSALNativeAuthRequestContext ) { self.grantType = grantType self.continuationToken = continuationToken diff --git a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift index dffb9953f6..9ec7777ed1 100644 --- a/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift +++ b/MSAL/src/native_auth/network/sign_up/MSALNativeAuthSignUpRequestProvider.swift @@ -26,7 +26,7 @@ protocol MSALNativeAuthSignUpRequestProviding { func start(parameters: MSALNativeAuthSignUpStartRequestProviderParameters) throws -> MSIDHttpRequest - func challenge(token: String, context: MSIDRequestContext) throws -> MSIDHttpRequest + func challenge(token: String, context: MSALNativeAuthRequestContext) throws -> MSIDHttpRequest func `continue`(parameters: MSALNativeAuthSignUpContinueRequestProviderParams) throws -> MSIDHttpRequest } @@ -57,7 +57,7 @@ final class MSALNativeAuthSignUpRequestProvider: MSALNativeAuthSignUpRequestProv return request } - func challenge(token: String, context: MSIDRequestContext) throws -> MSIDHttpRequest { + func challenge(token: String, context: MSALNativeAuthRequestContext) throws -> MSIDHttpRequest { let params = MSALNativeAuthSignUpChallengeRequestParameters( continuationToken: token, context: context diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift index c559948d10..e1a250420f 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication+Internal.swift @@ -32,16 +32,18 @@ extension MSALNativeAuthPublicClientApplication { attributes: [String: Any]?, correlationId: UUID? ) async -> MSALNativeAuthSignUpControlling.SignUpStartControllerResponse { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + let correlationId = context.correlationId() + guard inputValidator.isInputValid(username) else { - return .init(.error(SignUpStartError(type: .invalidUsername))) + return .init(.error(SignUpStartError(type: .invalidUsername, correlationId: correlationId)), correlationId: correlationId) } if let password = password, !inputValidator.isInputValid(password) { - return .init(.error(SignUpStartError(type: .invalidPassword))) + return .init(.error(SignUpStartError(type: .invalidPassword, correlationId: correlationId)), correlationId: correlationId) } let controller = controllerFactory.makeSignUpController(cacheAccessor: cacheAccessor) - let context = MSALNativeAuthRequestContext(correlationId: correlationId) let parameters = MSALNativeAuthSignUpStartRequestProviderParameters( username: username, @@ -58,12 +60,15 @@ extension MSALNativeAuthPublicClientApplication { scopes: [String]?, correlationId: UUID? ) async -> MSALNativeAuthSignInControlling.SignInControllerResponse { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + let correlationId = context.correlationId() + guard inputValidator.isInputValid(username) else { - return .init(.error(SignInStartError(type: .invalidUsername))) + return .init(.error(SignInStartError(type: .invalidUsername, correlationId: correlationId)), correlationId: correlationId) } if let password = password, !inputValidator.isInputValid(password) { - return .init(.error(SignInStartError(type: .invalidCredentials))) + return .init(.error(SignInStartError(type: .invalidCredentials, correlationId: correlationId)), correlationId: correlationId) } let controller = controllerFactory.makeSignInController(cacheAccessor: cacheAccessor) @@ -71,7 +76,7 @@ extension MSALNativeAuthPublicClientApplication { let params = MSALNativeAuthSignInParameters( username: username, password: password, - context: MSALNativeAuthRequestContext(correlationId: correlationId), + context: context, scopes: scopes ) return await controller.signIn(params: params) @@ -81,12 +86,14 @@ extension MSALNativeAuthPublicClientApplication { username: String, correlationId: UUID? ) async -> MSALNativeAuthResetPasswordControlling.ResetPasswordStartControllerResponse { + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + let correlationId = context.correlationId() + guard inputValidator.isInputValid(username) else { - return .init(.error(ResetPasswordStartError(type: .invalidUsername))) + return .init(.error(ResetPasswordStartError(type: .invalidUsername, correlationId: correlationId)), correlationId: correlationId) } let controller = controllerFactory.makeResetPasswordController(cacheAccessor: cacheAccessor) - let context = MSALNativeAuthRequestContext(correlationId: correlationId) return await controller.resetPassword( parameters: .init( diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift index 6f0e4e5507..7b9ec9b9f8 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift @@ -30,7 +30,7 @@ import Foundation /// to the initialiser method. /// /// For example: - + ///
 ///     do {
 ///         nativeAuth = try MSALNativeAuthPublicClientApplication(
@@ -171,6 +171,7 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic
                 attributes: attributes,
                 correlationId: correlationId
             )
+
             let delegateDispatcher = SignUpStartDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate)
 
             switch controllerResponse.result {
@@ -179,10 +180,11 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic
                     newState: newState,
                     sentTo: sentTo,
                     channelTargetType: channelTargetType,
-                    codeLength: codeLength
+                    codeLength: codeLength,
+                    correlationId: controllerResponse.correlationId
                 )
             case .attributesInvalid(let attributes):
-                await delegateDispatcher.dispatchSignUpAttributesInvalid(attributeNames: attributes)
+                await delegateDispatcher.dispatchSignUpAttributesInvalid(attributeNames: attributes, correlationId: controllerResponse.correlationId)
             case .error(let error):
                 await delegate.onSignUpStartError(error: error)
             }
@@ -219,12 +221,13 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic
                     newState: newState,
                     sentTo: sentTo,
                     channelTargetType: channelTargetType,
-                    codeLength: codeLength
+                    codeLength: codeLength,
+                    correlationId: controllerResponse.correlationId
                 )
             case .passwordRequired(let newState):
-                await delegateDispatcher.dispatchSignInPasswordRequired(newState: newState)
+                await delegateDispatcher.dispatchSignInPasswordRequired(newState: newState, correlationId: controllerResponse.correlationId)
             case .completed(let result):
-                await delegateDispatcher.dispatchSignInCompleted(result: result)
+                await delegateDispatcher.dispatchSignInCompleted(result: result, correlationId: controllerResponse.correlationId)
             case .error(let error):
                 await delegate.onSignInStartError(error: error)
             }
@@ -243,6 +246,7 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic
     ) {
         Task {
             let controllerResponse = await resetPasswordInternal(username: username, correlationId: correlationId)
+
             let delegateDispatcher = ResetPasswordStartDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate)
 
             switch controllerResponse.result {
@@ -251,7 +255,8 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic
                     newState: newState,
                     sentTo: sentTo,
                     channelTargetType: channelTargetType,
-                    codeLength: codeLength
+                    codeLength: codeLength,
+                    correlationId: controllerResponse.correlationId
                 )
             case .error(let error):
                 await delegate.onResetPasswordStartError(error: error)
diff --git a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift
index 9581381bb4..b2afa7a7bf 100644
--- a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift
+++ b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift
@@ -32,6 +32,7 @@ extension MSALNativeAuthUserAccountResult {
         cacheAccessor: MSALNativeAuthCacheInterface
     ) async -> MSALNativeAuthCredentialsControlling.RefreshTokenCredentialControllerResponse {
         let context = MSALNativeAuthRequestContext(correlationId: correlationId)
+        let correlationId = context.correlationId()
 
         if let accessToken = self.authTokens.accessToken {
             if forceRefresh || accessToken.isExpired() {
@@ -39,11 +40,11 @@ extension MSALNativeAuthUserAccountResult {
                 let credentialsController = controllerFactory.makeCredentialsController(cacheAccessor: cacheAccessor)
                 return await credentialsController.refreshToken(context: context, authTokens: authTokens)
             } else {
-                return .init(.success(accessToken.accessToken))
+                return .init(.success(accessToken.accessToken), correlationId: correlationId)
             }
         } else {
             MSALLogger.log(level: .error, context: context, format: "Retrieve Access Token: Existing token not found")
-            return .init(.failure(RetrieveAccessTokenError(type: .tokenNotFound)))
+            return .init(.failure(RetrieveAccessTokenError(type: .tokenNotFound, correlationId: correlationId)), correlationId: correlationId)
         }
     }
 }
diff --git a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift
index 69b906a64e..90ce3efecb 100644
--- a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift
+++ b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift
@@ -92,11 +92,15 @@ import Foundation
                 correlationId: correlationId,
                 cacheAccessor: cacheAccessor
             )
+
             let delegateDispatcher = CredentialsDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate)
 
             switch controllerResponse.result {
             case .success(let accessToken):
-                await delegateDispatcher.dispatchAccessTokenRetrieveCompleted(accessToken: accessToken)
+                await delegateDispatcher.dispatchAccessTokenRetrieveCompleted(
+                    accessToken: accessToken,
+                    correlationId: controllerResponse.correlationId
+                )
             case .failure(let error):
                 await delegate.onAccessTokenRetrieveError(error: error)
             }
diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/CredentialsDelegateDispatcher.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/CredentialsDelegateDispatcher.swift
index 56723f9611..a587579ea1 100644
--- a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/CredentialsDelegateDispatcher.swift
+++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/CredentialsDelegateDispatcher.swift
@@ -26,12 +26,16 @@ import Foundation
 
 final class CredentialsDelegateDispatcher: DelegateDispatcher {
 
-    func dispatchAccessTokenRetrieveCompleted(accessToken: String) async {
+    func dispatchAccessTokenRetrieveCompleted(accessToken: String, correlationId: UUID) async {
         if let onAccessTokenRetrieveCompleted = delegate.onAccessTokenRetrieveCompleted {
             telemetryUpdate?(.success(()))
             await onAccessTokenRetrieveCompleted(accessToken)
         } else {
-            let error = RetrieveAccessTokenError(type: .generalError, message: requiredErrorMessage(for: "onAccessTokenRetrieveCompleted"))
+            let error = RetrieveAccessTokenError(
+                type: .generalError,
+                message: requiredErrorMessage(for: "onAccessTokenRetrieveCompleted"),
+                correlationId: correlationId
+            )
             telemetryUpdate?(.failure(error))
             await delegate.onAccessTokenRetrieveError(error: error)
         }
diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/ResetPasswordDelegateDispatchers.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/ResetPasswordDelegateDispatchers.swift
index d879c25bd0..95f3615818 100644
--- a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/ResetPasswordDelegateDispatchers.swift
+++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/ResetPasswordDelegateDispatchers.swift
@@ -30,13 +30,18 @@ final class ResetPasswordStartDelegateDispatcher: DelegateDispatcher {
 
-    func dispatchPasswordRequired(newState: ResetPasswordRequiredState) async {
+    func dispatchPasswordRequired(newState: ResetPasswordRequiredState, correlationId: UUID) async {
         if let onPasswordRequired = delegate.onPasswordRequired {
             telemetryUpdate?(.success(()))
             await onPasswordRequired(newState)
         } else {
-            let error = VerifyCodeError(type: .generalError, message: requiredErrorMessage(for: "onPasswordRequired"))
+            let error = VerifyCodeError(type: .generalError, message: requiredErrorMessage(for: "onPasswordRequired"), correlationId: correlationId)
             telemetryUpdate?(.failure(error))
             await delegate.onResetPasswordVerifyCodeError(error: error, newState: nil)
         }
@@ -63,13 +68,14 @@ final class ResetPasswordResendCodeDelegateDispatcher: DelegateDispatcher {
 
-    func dispatchResetPasswordCompleted(newState: SignInAfterResetPasswordState) async {
+    func dispatchResetPasswordCompleted(newState: SignInAfterResetPasswordState, correlationId: UUID) async {
         if let onResetPasswordCompleted = delegate.onResetPasswordCompleted {
             telemetryUpdate?(.success(()))
             await onResetPasswordCompleted(newState)
         } else {
-            let error = PasswordRequiredError(type: .generalError, message: requiredErrorMessage(for: "onResetPasswordCompleted"))
+            let error = PasswordRequiredError(
+                type: .generalError,
+                message: requiredErrorMessage(for: "onResetPasswordCompleted"),
+                correlationId: correlationId
+            )
             telemetryUpdate?(.failure(error))
             await delegate.onResetPasswordRequiredError(error: error, newState: nil)
         }
diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterResetPasswordDelegateDispatcher.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterResetPasswordDelegateDispatcher.swift
index 0aa3c3f2d7..8836e1d6b0 100644
--- a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterResetPasswordDelegateDispatcher.swift
+++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterResetPasswordDelegateDispatcher.swift
@@ -26,12 +26,12 @@ import Foundation
 
 final class SignInAfterResetPasswordDelegateDispatcher: DelegateDispatcher {
 
-    func dispatchSignInCompleted(result: MSALNativeAuthUserAccountResult) async {
+    func dispatchSignInCompleted(result: MSALNativeAuthUserAccountResult, correlationId: UUID) async {
         if let onSignInCompleted = delegate.onSignInCompleted {
             telemetryUpdate?(.success(()))
             await onSignInCompleted(result)
         } else {
-            let error = SignInAfterResetPasswordError(message: requiredErrorMessage(for: "onSignInCompleted"))
+            let error = SignInAfterResetPasswordError(message: requiredErrorMessage(for: "onSignInCompleted"), correlationId: correlationId)
             telemetryUpdate?(.failure(error))
             await delegate.onSignInAfterResetPasswordError(error: error)
         }
diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterSignUpDelegateDispatcher.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterSignUpDelegateDispatcher.swift
index 6f1d88631f..283bf3db22 100644
--- a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterSignUpDelegateDispatcher.swift
+++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterSignUpDelegateDispatcher.swift
@@ -26,12 +26,12 @@ import Foundation
 
 final class SignInAfterSignUpDelegateDispatcher: DelegateDispatcher {
 
-    func dispatchSignInCompleted(result: MSALNativeAuthUserAccountResult) async {
+    func dispatchSignInCompleted(result: MSALNativeAuthUserAccountResult, correlationId: UUID) async {
         if let onSignInCompleted = delegate.onSignInCompleted {
             telemetryUpdate?(.success(()))
             await onSignInCompleted(result)
         } else {
-            let error = SignInAfterSignUpError(message: requiredErrorMessage(for: "onSignInCompleted"))
+            let error = SignInAfterSignUpError(message: requiredErrorMessage(for: "onSignInCompleted"), correlationId: correlationId)
             telemetryUpdate?(.failure(error))
             await delegate.onSignInAfterSignUpError(error: error)
         }
diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInDelegateDispatchers.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInDelegateDispatchers.swift
index a9560488cf..6077935735 100644
--- a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInDelegateDispatchers.swift
+++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInDelegateDispatchers.swift
@@ -30,35 +30,44 @@ final class SignInStartDelegateDispatcher: DelegateDispatcher {
 
-    func dispatchSignInCompleted(result: MSALNativeAuthUserAccountResult) async {
+    func dispatchSignInCompleted(result: MSALNativeAuthUserAccountResult, correlationId: UUID) async {
         if let onSignInCompleted = delegate.onSignInCompleted {
             telemetryUpdate?(.success(()))
             await onSignInCompleted(result)
         } else {
-            let error = PasswordRequiredError(type: .generalError, message: requiredErrorMessage(for: "onSignInCompleted"))
+            let error = PasswordRequiredError(
+                type: .generalError,
+                message: requiredErrorMessage(for: "onSignInCompleted"),
+                correlationId: correlationId
+            )
             telemetryUpdate?(.failure(error))
             await delegate.onSignInPasswordRequiredError(error: error, newState: nil)
         }
@@ -85,13 +98,14 @@ final class SignInResendCodeDelegateDispatcher: DelegateDispatcher {
 
-    func dispatchSignInCompleted(result: MSALNativeAuthUserAccountResult) async {
+    func dispatchSignInCompleted(result: MSALNativeAuthUserAccountResult, correlationId: UUID) async {
         if let onSignInCompleted = delegate.onSignInCompleted {
             telemetryUpdate?(.success(()))
             await onSignInCompleted(result)
         } else {
-            let error = VerifyCodeError(type: .generalError, message: requiredErrorMessage(for: "onSignInCompleted"))
+            let error = VerifyCodeError(type: .generalError, message: requiredErrorMessage(for: "onSignInCompleted"), correlationId: correlationId)
             telemetryUpdate?(.failure(error))
             await delegate.onSignInVerifyCodeError(error: error, newState: nil)
         }
diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift
index 47e70b59d2..53a36b30a2 100644
--- a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift
+++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignUpDelegateDispatchers.swift
@@ -30,24 +30,33 @@ final class SignUpStartDelegateDispatcher: DelegateDispatcher {
 
-    func dispatchSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttribute], newState: SignUpAttributesRequiredState) async {
+    func dispatchSignUpAttributesRequired(
+        attributes: [MSALNativeAuthRequiredAttribute],
+        newState: SignUpAttributesRequiredState,
+        correlationId: UUID
+    ) async {
         if let onSignUpAttributesRequired = delegate.onSignUpAttributesRequired {
             telemetryUpdate?(.success(()))
             await onSignUpAttributesRequired(attributes, newState)
         } else {
-            let error = VerifyCodeError(type: .generalError, message: requiredErrorMessage(for: "onSignUpAttributesRequired"))
+            let error = VerifyCodeError(
+                type: .generalError,
+                message: requiredErrorMessage(for: "onSignUpAttributesRequired"),
+                correlationId: correlationId
+            )
             telemetryUpdate?(.failure(error))
             await delegate.onSignUpVerifyCodeError(error: error, newState: nil)
         }
     }
 
-    func dispatchSignUpPasswordRequired(newState: SignUpPasswordRequiredState) async {
+    func dispatchSignUpPasswordRequired(newState: SignUpPasswordRequiredState, correlationId: UUID) async {
         if let onSignUpPasswordRequired = delegate.onSignUpPasswordRequired {
             telemetryUpdate?(.success(()))
             await onSignUpPasswordRequired(newState)
         } else {
-            let error = VerifyCodeError(type: .generalError, message: requiredErrorMessage(for: "onSignUpPasswordRequired"))
+            let error = VerifyCodeError(
+                type: .generalError,
+                message: requiredErrorMessage(for: "onSignUpPasswordRequired"),
+                correlationId: correlationId
+            )
             telemetryUpdate?(.failure(error))
             await delegate.onSignUpVerifyCodeError(error: error, newState: nil)
         }
     }
 
-    func dispatchSignUpCompleted(newState: SignInAfterSignUpState) async {
+    func dispatchSignUpCompleted(newState: SignInAfterSignUpState, correlationId: UUID) async {
         if let onSignUpCompleted = delegate.onSignUpCompleted {
             telemetryUpdate?(.success(()))
             await onSignUpCompleted(newState)
         } else {
-            let error = VerifyCodeError(type: .generalError, message: requiredErrorMessage(for: "onSignUpCompleted"))
+            let error = VerifyCodeError(
+                type: .generalError,
+                message: requiredErrorMessage(for: "onSignUpCompleted"),
+                correlationId: correlationId
+            )
             telemetryUpdate?(.failure(error))
             await delegate.onSignUpVerifyCodeError(error: error, newState: nil)
         }
@@ -96,13 +121,14 @@ final class SignUpResendCodeDelegateDispatcher: DelegateDispatcher {
 
-    func dispatchSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttribute], newState: SignUpAttributesRequiredState) async {
+    func dispatchSignUpAttributesRequired(
+        attributes: [MSALNativeAuthRequiredAttribute],
+        newState: SignUpAttributesRequiredState,
+        correlationId: UUID
+    ) async {
         if let onSignUpAttributesRequired = delegate.onSignUpAttributesRequired {
             telemetryUpdate?(.success(()))
             await onSignUpAttributesRequired(attributes, newState)
         } else {
-            let error = PasswordRequiredError(type: .generalError, message: requiredErrorMessage(for: "onSignUpAttributesRequired"))
+            let error = PasswordRequiredError(
+                type: .generalError,
+                message: requiredErrorMessage(for: "onSignUpAttributesRequired"),
+                correlationId: correlationId
+            )
             telemetryUpdate?(.failure(error))
             await delegate.onSignUpPasswordRequiredError(error: error, newState: nil)
         }
     }
 
-    func dispatchSignUpCompleted(newState: SignInAfterSignUpState) async {
+    func dispatchSignUpCompleted(newState: SignInAfterSignUpState, correlationId: UUID) async {
         if let onSignUpCompleted = delegate.onSignUpCompleted {
             telemetryUpdate?(.success(()))
             await onSignUpCompleted(newState)
         } else {
-            let error = PasswordRequiredError(type: .generalError, message: requiredErrorMessage(for: "onSignUpCompleted"))
+            let error = PasswordRequiredError(
+                type: .generalError,
+                message: requiredErrorMessage(for: "onSignUpCompleted"),
+                correlationId: correlationId
+            )
             telemetryUpdate?(.failure(error))
             await delegate.onSignUpPasswordRequiredError(error: error, newState: nil)
         }
@@ -136,34 +174,38 @@ final class SignUpPasswordRequiredDelegateDispatcher: DelegateDispatcher {
 
-    func dispatchSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttribute], newState: SignUpAttributesRequiredState) async {
+    func dispatchSignUpAttributesRequired(
+        attributes: [MSALNativeAuthRequiredAttribute],
+        newState: SignUpAttributesRequiredState,
+        correlationId: UUID
+    ) async {
         if let onSignUpAttributesRequired = delegate.onSignUpAttributesRequired {
             telemetryUpdate?(.success(()))
             await onSignUpAttributesRequired(attributes, newState)
         } else {
-            let error = AttributesRequiredError(message: requiredErrorMessage(for: "onSignUpAttributesRequired"))
+            let error = AttributesRequiredError(message: requiredErrorMessage(for: "onSignUpAttributesRequired"), correlationId: correlationId)
             telemetryUpdate?(.failure(error))
             await delegate.onSignUpAttributesRequiredError(error: error)
         }
     }
 
-    func dispatchSignUpAttributesInvalid(attributeNames: [String], newState: SignUpAttributesRequiredState) async {
+    func dispatchSignUpAttributesInvalid(attributeNames: [String], newState: SignUpAttributesRequiredState, correlationId: UUID) async {
         if let onSignUpAttributesInvalid = delegate.onSignUpAttributesInvalid {
             telemetryUpdate?(.success(()))
             await onSignUpAttributesInvalid(attributeNames, newState)
         } else {
-            let error = AttributesRequiredError(message: requiredErrorMessage(for: "onSignUpAttributesInvalid"))
+            let error = AttributesRequiredError(message: requiredErrorMessage(for: "onSignUpAttributesInvalid"), correlationId: correlationId)
             telemetryUpdate?(.failure(error))
             await delegate.onSignUpAttributesRequiredError(error: error)
         }
     }
 
-    func dispatchSignUpCompleted(newState: SignInAfterSignUpState) async {
+    func dispatchSignUpCompleted(newState: SignInAfterSignUpState, correlationId: UUID) async {
         if let onSignUpCompleted = delegate.onSignUpCompleted {
             telemetryUpdate?(.success(()))
             await onSignUpCompleted(newState)
         } else {
-            let error = AttributesRequiredError(message: requiredErrorMessage(for: "onSignUpCompleted"))
+            let error = AttributesRequiredError(message: requiredErrorMessage(for: "onSignUpCompleted"), correlationId: correlationId)
             telemetryUpdate?(.failure(error))
             await delegate.onSignUpAttributesRequiredError(error: error)
         }
diff --git a/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift b/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift
index 17106d5d00..72a3d56edb 100644
--- a/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift
+++ b/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift
@@ -30,9 +30,21 @@ public class MSALNativeAuthError: NSObject, LocalizedError {
     /// Describes why an error occurred and provides more information about the error.
     public var errorDescription: String? { message }
 
+    /// Correlation ID used for the request
+    public let correlationId: UUID
+
+    /// Error codes returned along with the error
+    public let errorCodes: [Int]
+
+    /// Error uri that can be followed to get more information about the error returned by the server
+    public let errorUri: String?
+
     private let message: String?
 
-    init(message: String? = nil) {
+    init(message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) {
         self.message = message
+        self.correlationId = correlationId
+        self.errorCodes = errorCodes
+        self.errorUri = errorUri
     }
 }
diff --git a/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift b/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift
index 23b27a455d..1fb85cd100 100644
--- a/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift
+++ b/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift
@@ -35,21 +35,31 @@ public class PasswordRequiredError: MSALNativeAuthError {
 
     let type: ErrorType
 
-    init(type: ErrorType, message: String? = nil) {
+    init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) {
         self.type = type
-        super.init(message: message)
+        super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri)
     }
 
     init(signInStartError: SignInStartError) {
+        let errorDescription: String?
+
         switch signInStartError.type {
         case .browserRequired:
             self.type = .browserRequired
+            errorDescription = MSALNativeAuthErrorMessage.browserRequired
         case .invalidCredentials:
             self.type = .invalidPassword
+            errorDescription = MSALNativeAuthErrorMessage.invalidPassword
         default:
             self.type = .generalError
+            errorDescription = signInStartError.errorDescription
         }
-        super.init(message: signInStartError.errorDescription)
+        super.init(
+            message: errorDescription,
+            correlationId: signInStartError.correlationId,
+            errorCodes: signInStartError.errorCodes,
+            errorUri: signInStartError.errorUri
+        )
     }
 
     /// Describes why an error occurred and provides more information about the error.
diff --git a/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift b/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift
index ca01c1f5d8..d47464aa76 100644
--- a/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift
+++ b/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift
@@ -37,9 +37,9 @@ public class ResetPasswordStartError: MSALNativeAuthError {
 
     let type: ErrorType
 
-    init(type: ErrorType, message: String? = nil) {
+    init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) {
         self.type = type
-        super.init(message: message)
+        super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri)
     }
 
     /// Describes why an error occurred and provides more information about the error.
diff --git a/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift b/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift
index c82619fc70..4407609508 100644
--- a/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift
+++ b/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift
@@ -36,9 +36,9 @@ public class RetrieveAccessTokenError: MSALNativeAuthError {
 
     let type: ErrorType
 
-    init(type: ErrorType, message: String? = nil) {
+    init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) {
         self.type = type
-        super.init(message: message)
+        super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri)
     }
 
     /// Describes why an error occurred and provides more information about the error.
diff --git a/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift
index 2b34a011ee..cfec543b91 100644
--- a/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift
+++ b/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift
@@ -37,9 +37,9 @@ public class SignInStartError: MSALNativeAuthError {
 
     let type: ErrorType
 
-    init(type: ErrorType, message: String? = nil) {
+    init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) {
         self.type = type
-        super.init(message: message)
+        super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri)
     }
 
     /// Describes why an error occurred and provides more information about the error.
diff --git a/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift
index b3c22f0d81..0ef525d2dc 100644
--- a/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift
+++ b/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift
@@ -37,9 +37,9 @@ public class SignUpStartError: MSALNativeAuthError {
 
     let type: ErrorType
 
-    init(type: ErrorType, message: String? = nil) {
+    init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) {
         self.type = type
-        super.init(message: message)
+        super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri)
     }
 
     /// Describes why an error occurred and provides more information about the error.
diff --git a/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift b/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift
index 8b74b65e03..9bbbf34ccd 100644
--- a/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift
+++ b/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift
@@ -35,9 +35,9 @@ public class VerifyCodeError: MSALNativeAuthError {
 
     let type: ErrorType
 
-    init(type: ErrorType, message: String? = nil) {
+    init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) {
         self.type = type
-        super.init(message: message)
+        super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri)
     }
 
     /// Describes why an error occurred and provides more information about the error.
diff --git a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift
index 583456bb8b..b1cae1bf9b 100644
--- a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift
+++ b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates+Internal.swift
@@ -36,7 +36,10 @@ extension ResetPasswordCodeRequiredState {
 
         guard inputValidator.isInputValid(code) else {
             MSALLogger.log(level: .error, context: context, format: "ResetPassword flow, invalid code")
-            return .init(.error(error: VerifyCodeError(type: .invalidCode), newState: self))
+            return .init(
+                .error(error: VerifyCodeError(type: .invalidCode, correlationId: correlationId), newState: self), 
+                correlationId: correlationId
+            )
         }
 
         return await controller.submitCode(code: code, username: username, continuationToken: continuationToken, context: context)
@@ -50,7 +53,10 @@ extension ResetPasswordRequiredState {
 
         guard inputValidator.isInputValid(password) else {
             MSALLogger.log(level: .error, context: context, format: "ResetPassword flow, invalid password")
-            return .init(.error(error: PasswordRequiredError(type: .invalidPassword), newState: self))
+            return .init(
+                .error(error: PasswordRequiredError(type: .invalidPassword, correlationId: correlationId), newState: self), 
+                correlationId: correlationId
+            )
         }
 
         return await controller.submitPassword(password: password, username: username, continuationToken: continuationToken, context: context)
diff --git a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift
index 20210da777..68ede1e79b 100644
--- a/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift
+++ b/MSAL/src/native_auth/public/state_machine/state/ResetPasswordStates.swift
@@ -63,7 +63,8 @@ public class ResetPasswordBaseState: MSALNativeAuthBaseState {
                     newState: newState,
                     sentTo: sentTo,
                     channelTargetType: channelTargetType,
-                    codeLength: codeLength
+                    codeLength: codeLength,
+                    correlationId: controllerResponse.correlationId
                 )
             case .error(let error, let newState):
                 await delegate.onResetPasswordResendCodeError(error: error, newState: newState)
@@ -85,7 +86,7 @@ public class ResetPasswordBaseState: MSALNativeAuthBaseState {
 
             switch controllerResponse.result {
             case .passwordRequired(let newState):
-                await delegateDispatcher.dispatchPasswordRequired(newState: newState)
+                await delegateDispatcher.dispatchPasswordRequired(newState: newState, correlationId: controllerResponse.correlationId)
             case .error(let error, let newState):
                 await delegate.onResetPasswordVerifyCodeError(error: error, newState: newState)
             }
@@ -106,7 +107,7 @@ public class ResetPasswordBaseState: MSALNativeAuthBaseState {
 
             switch controllerResponse.result {
             case .completed(let newState):
-                await delegateDispatcher.dispatchResetPasswordCompleted(newState: newState)
+                await delegateDispatcher.dispatchResetPasswordCompleted(newState: newState, correlationId: controllerResponse.correlationId)
             case .error(let error, let newState):
                 await delegate.onResetPasswordRequiredError(error: error, newState: newState)
             }
diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterResetPasswordState.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterResetPasswordState.swift
index 7c0cb98529..976e7ba0b6 100644
--- a/MSAL/src/native_auth/public/state_machine/state/SignInAfterResetPasswordState.swift
+++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterResetPasswordState.swift
@@ -40,9 +40,14 @@ import Foundation
 
             switch controllerResponse.result {
             case .success(let accountResult):
-                await delegateDispatcher.dispatchSignInCompleted(result: accountResult)
+                await delegateDispatcher.dispatchSignInCompleted(result: accountResult, correlationId: controllerResponse.correlationId)
             case .failure(let error):
-                await delegate.onSignInAfterResetPasswordError(error: SignInAfterResetPasswordError(message: error.errorDescription))
+                let error = SignInAfterResetPasswordError(
+                    message: error.errorDescription,
+                    correlationId: error.correlationId,
+                    errorCodes: error.errorCodes
+                )
+                await delegate.onSignInAfterResetPasswordError(error: error)
             }
         }
     }
diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift
index e08b2f5922..d0b4ce98a6 100644
--- a/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift
+++ b/MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift
@@ -37,9 +37,11 @@ import Foundation
 
             switch controllerResponse.result {
             case .success(let accountResult):
-                await delegateDispatcher.dispatchSignInCompleted(result: accountResult)
+                await delegateDispatcher.dispatchSignInCompleted(result: accountResult, correlationId: controllerResponse.correlationId)
             case .failure(let error):
-                await delegate.onSignInAfterSignUpError(error: SignInAfterSignUpError(message: error.errorDescription))
+                await delegate.onSignInAfterSignUpError(
+                    error: SignInAfterSignUpError(message: error.errorDescription, correlationId: error.correlationId, errorCodes: error.errorCodes)
+                )
             }
         }
     }
diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift
index a4e78052d0..532810f737 100644
--- a/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift
+++ b/MSAL/src/native_auth/public/state_machine/state/SignInStates+Internal.swift
@@ -31,7 +31,7 @@ extension SignInCodeRequiredState {
         MSALLogger.log(level: .verbose, context: context, format: "SignIn flow, code submitted")
         guard inputValidator.isInputValid(code) else {
             MSALLogger.log(level: .error, context: context, format: "SignIn flow, invalid code")
-            return .init(.error(error: VerifyCodeError(type: .invalidCode), newState: self))
+            return .init(.error(error: VerifyCodeError(type: .invalidCode, correlationId: correlationId), newState: self), correlationId: context.correlationId())
         }
 
         return await controller.submitCode(code, continuationToken: continuationToken, context: context, scopes: scopes)
@@ -53,7 +53,10 @@ extension SignInPasswordRequiredState {
 
         guard inputValidator.isInputValid(password) else {
             MSALLogger.log(level: .error, context: context, format: "SignIn flow, invalid password")
-            return .init(.error(error: PasswordRequiredError(type: .invalidPassword), newState: self))
+            return .init(
+                .error(error: PasswordRequiredError(type: .invalidPassword, correlationId: correlationId), newState: self),
+                correlationId: context.correlationId()
+            )
         }
 
         return await controller.submitPassword(password, username: username, continuationToken: continuationToken, context: context, scopes: scopes)
diff --git a/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift b/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift
index 1a85a23da9..750c1da498 100644
--- a/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift
+++ b/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift
@@ -68,7 +68,8 @@ import Foundation
                     newState: newState,
                     sentTo: sentTo,
                     channelTargetType: channelTargetType,
-                    codeLength: codeLength
+                    codeLength: codeLength,
+                    correlationId: controllerResponse.correlationId
                 )
             case .error(let error, let newState):
                 await delegate.onSignInResendCodeError(error: error, newState: newState)
@@ -87,7 +88,7 @@ import Foundation
 
             switch controllerResponse.result {
             case .completed(let accountResult):
-                await delegateDispatcher.dispatchSignInCompleted(result: accountResult)
+                await delegateDispatcher.dispatchSignInCompleted(result: accountResult, correlationId: controllerResponse.correlationId)
             case .error(let error, let newState):
                 await delegate.onSignInVerifyCodeError(error: error, newState: newState)
             }
@@ -124,7 +125,7 @@ import Foundation
 
             switch controllerResponse.result {
             case .completed(let accountResult):
-                await delegateDispatcher.dispatchSignInCompleted(result: accountResult)
+                await delegateDispatcher.dispatchSignInCompleted(result: accountResult, correlationId: controllerResponse.correlationId)
             case .error(let error, let newState):
                 await delegate.onSignInPasswordRequiredError(error: error, newState: newState)
             }
diff --git a/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift b/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift
index 3ac4affea0..b522b62236 100644
--- a/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift
+++ b/MSAL/src/native_auth/public/state_machine/state/SignUpStates+Internal.swift
@@ -36,7 +36,10 @@ extension SignUpCodeRequiredState {
 
         guard inputValidator.isInputValid(code) else {
             MSALLogger.log(level: .error, context: context, format: "SignUp flow, invalid code")
-            return .init(.error(error: VerifyCodeError(type: .invalidCode), newState: self))
+            return .init(
+                .error(error: VerifyCodeError(type: .invalidCode, correlationId: correlationId), newState: self),
+                correlationId: correlationId
+            )
         }
 
         return await controller.submitCode(code, username: username, continuationToken: continuationToken, context: context)
@@ -50,7 +53,10 @@ extension SignUpPasswordRequiredState {
 
         guard inputValidator.isInputValid(password) else {
             MSALLogger.log(level: .error, context: context, format: "SignUp flow, invalid password")
-            return .init(.error(error: PasswordRequiredError(type: .invalidPassword), newState: self))
+            return .init(
+                .error(error: PasswordRequiredError(type: .invalidPassword, correlationId: correlationId), newState: self),
+                correlationId: correlationId
+            )
         }
 
         return await controller.submitPassword(password, username: username, continuationToken: continuationToken, context: context)
diff --git a/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift b/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift
index 9ef55e0ac4..b421718cb8 100644
--- a/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift
+++ b/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift
@@ -52,6 +52,7 @@ public class SignUpBaseState: MSALNativeAuthBaseState {
     public func resendCode(delegate: SignUpResendCodeDelegate) {
         Task {
             let controllerResponse = await resendCodeInternal()
+
             let delegateDispatcher = SignUpResendCodeDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate)
 
             switch controllerResponse.result {
@@ -60,7 +61,8 @@ public class SignUpBaseState: MSALNativeAuthBaseState {
                     newState: newState,
                     sentTo: sentTo,
                     channelTargetType: channelTargetType,
-                    codeLength: codeLength
+                    codeLength: codeLength,
+                    correlationId: controllerResponse.correlationId
                 )
             case .error(let error, let newState):
                 await delegate.onSignUpResendCodeError(error: error, newState: newState)
@@ -75,15 +77,20 @@ public class SignUpBaseState: MSALNativeAuthBaseState {
     public func submitCode(code: String, delegate: SignUpVerifyCodeDelegate) {
         Task {
             let controllerResponse = await submitCodeInternal(code: code)
+            
             let delegateDispatcher = SignUpVerifyCodeDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate)
 
             switch controllerResponse.result {
             case .completed(let state):
-                await delegateDispatcher.dispatchSignUpCompleted(newState: state)
+                await delegateDispatcher.dispatchSignUpCompleted(newState: state, correlationId: controllerResponse.correlationId)
             case .passwordRequired(let state):
-                await delegateDispatcher.dispatchSignUpPasswordRequired(newState: state)
+                await delegateDispatcher.dispatchSignUpPasswordRequired(newState: state, correlationId: controllerResponse.correlationId)
             case .attributesRequired(let attributes, let state):
-                await delegateDispatcher.dispatchSignUpAttributesRequired(attributes: attributes, newState: state)
+                await delegateDispatcher.dispatchSignUpAttributesRequired(
+                    attributes: attributes,
+                    newState: state,
+                    correlationId: controllerResponse.correlationId
+                )
             case .error(let error, let state):
                 await delegate.onSignUpVerifyCodeError(error: error, newState: state)
             }
@@ -101,13 +108,18 @@ public class SignUpBaseState: MSALNativeAuthBaseState {
     public func submitPassword(password: String, delegate: SignUpPasswordRequiredDelegate) {
         Task {
             let controllerResponse = await submitPasswordInternal(password: password)
+
             let delegateDispatcher = SignUpPasswordRequiredDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate)
 
             switch controllerResponse.result {
             case .completed(let state):
-                await delegateDispatcher.dispatchSignUpCompleted(newState: state)
+                await delegateDispatcher.dispatchSignUpCompleted(newState: state, correlationId: controllerResponse.correlationId)
             case .attributesRequired(let attributes, let state):
-                await delegateDispatcher.dispatchSignUpAttributesRequired(attributes: attributes, newState: state)
+                await delegateDispatcher.dispatchSignUpAttributesRequired(
+                    attributes: attributes,
+                    newState: state,
+                    correlationId: controllerResponse.correlationId
+                )
             case .error(let error, let state):
                 await delegate.onSignUpPasswordRequiredError(error: error, newState: state)
             }
@@ -127,6 +139,7 @@ public class SignUpBaseState: MSALNativeAuthBaseState {
     ) {
         Task {
             let controllerResponse = await submitAttributesInternal(attributes: attributes)
+            
             let delegateDispatcher = SignUpAttributesRequiredDelegateDispatcher(
                 delegate: delegate,
                 telemetryUpdate: controllerResponse.telemetryUpdate
@@ -134,13 +147,21 @@ public class SignUpBaseState: MSALNativeAuthBaseState {
 
             switch controllerResponse.result {
             case .completed(let state):
-                await delegateDispatcher.dispatchSignUpCompleted(newState: state)
+                await delegateDispatcher.dispatchSignUpCompleted(newState: state, correlationId: controllerResponse.correlationId)
             case .error(let error):
                 await delegate.onSignUpAttributesRequiredError(error: error)
             case .attributesRequired(let attributes, let state):
-                await delegateDispatcher.dispatchSignUpAttributesRequired(attributes: attributes, newState: state)
+                await delegateDispatcher.dispatchSignUpAttributesRequired(
+                    attributes: attributes,
+                    newState: state,
+                    correlationId: controllerResponse.correlationId
+                )
             case .attributesInvalid(let attributes, let state):
-                await delegateDispatcher.dispatchSignUpAttributesInvalid(attributeNames: attributes, newState: state)
+                await delegateDispatcher.dispatchSignUpAttributesInvalid(
+                    attributeNames: attributes,
+                    newState: state,
+                    correlationId: controllerResponse.correlationId
+                )
             }
         }
     }
diff --git a/MSAL/test/integration/native_auth/common/MSALNativeAuthIntegrationBaseTests.swift b/MSAL/test/integration/native_auth/common/MSALNativeAuthIntegrationBaseTests.swift
index 7d6d394c36..2e745ea452 100644
--- a/MSAL/test/integration/native_auth/common/MSALNativeAuthIntegrationBaseTests.swift
+++ b/MSAL/test/integration/native_auth/common/MSALNativeAuthIntegrationBaseTests.swift
@@ -76,7 +76,7 @@ class MSALNativeAuthIntegrationBaseTests: XCTestCase {
         try await mockResponse(response, endpoint: endpoint)
         let response: Error = try await perform_uncheckedTestFail()
 
-        XCTAssertEqual(response.error.rawValue, expectedError.error.rawValue)
+        XCTAssertEqual(response.error?.rawValue, expectedError.error?.rawValue)
 
         // TODO: Fix these checks
         if expectedError.errorDescription != nil {
diff --git a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift
index c15207861a..0b2cb0d26f 100644
--- a/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift
+++ b/MSAL/test/integration/native_auth/requests/sign_up/MSALNativeAuthSignUpContinueIntegrationTests.swift
@@ -29,7 +29,7 @@ import XCTest
 final class MSALNativeAuthSignUpContinueIntegrationTests: MSALNativeAuthIntegrationBaseTests {
 
     private var provider: MSALNativeAuthSignUpRequestProvider!
-    private var context: MSIDRequestContext!
+    private var context: MSALNativeAuthRequestContext!
 
     override func setUpWithError() throws {
         try super.setUpWithError()
diff --git a/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift
index 1adfb53c08..6c72140241 100644
--- a/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift
+++ b/MSAL/test/integration/native_auth/requests/token/MSALNativeAuthTokenIntegrationTests.swift
@@ -170,7 +170,7 @@ class MSALNativeAuthTokenIntegrationTests: MSALNativeAuthIntegrationBaseTests {
 
         let expectedError = createError(.slowDown)
 
-        XCTAssertEqual(result.error.rawValue, expectedError.error.rawValue)
+        XCTAssertEqual(result.error?.rawValue, expectedError.error?.rawValue)
     }
 
     private func createError(_ code: MSALNativeAuthTokenOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, errorCodes: [MSALNativeAuthESTSApiErrorCodes]? = nil) -> Error {
diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthBaseControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthBaseControllerTests.swift
index ada9c8301d..4d5f3d74cb 100644
--- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthBaseControllerTests.swift
+++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthBaseControllerTests.swift
@@ -265,4 +265,74 @@ final class MSALNativeAuthBaseControllerTests: MSALNativeAuthTestCase {
             XCTFail("Unexpected response")
         }
     }
+
+    // MARK: - Integration tests
+
+    func test_performRequest_500_error_updatesContextCorrelationId() async {
+        await performTestContext(statusCode: 500)
+    }
+
+    func test_performRequest_400_error_updatesContextCorrelationId() async {
+        await performTestContext(statusCode: 400)
+    }
+
+    private func performTestContext(statusCode: Int) async {
+        let localCorrelationId = UUID()
+
+        let headerCorrelationIdString = "82398bb3-0a88-475a-bfd6-c28d5eef42d4"
+        let headerCorrelationId = UUID(uuidString: headerCorrelationIdString)!
+
+        let context = MSALNativeAuthRequestContext(correlationId: localCorrelationId)
+
+        let baseUrl = URL(string: "https://www.contoso.com")!
+
+        let parameters = ["p1": "v1"]
+
+        let httpResponse = HTTPURLResponse(
+            url: baseUrl,
+            statusCode: statusCode,
+            httpVersion: nil,
+            headerFields: [
+                "client-request-id": headerCorrelationIdString
+            ]
+        )
+
+        var urlRequest = URLRequest(url: baseUrl)
+        urlRequest.httpMethod = "POST"
+
+        let testUrlResponse = MSIDTestURLResponse.request(baseUrl, reponse: httpResponse)
+
+        testUrlResponse?.setUrlFormEncodedBody(parameters)
+        MSIDTestURLSession.add(testUrlResponse)
+
+        let request = MSIDHttpRequest()
+
+        request.errorHandler = MSALNativeAuthResponseErrorHandler()
+        request.urlRequest = urlRequest
+        request.parameters = parameters
+        request.retryCounter = 0
+
+        let result: Result = await sut.performRequest(request, context: context)
+
+        switch result {
+        case .failure:
+            XCTAssertEqual(context.correlationId(), headerCorrelationId)
+        case .success:
+            XCTFail("Unexpected response")
+        }
+    }
+}
+
+extension String: MSALNativeAuthResponseCorrelatable {
+    public var correlationId: UUID? {
+        get { nil }
+        set {}
+    }
+}
+
+extension Array: MSALNativeAuthResponseCorrelatable {
+    public var correlationId: UUID? {
+        get { nil }
+        set {}
+    }
 }
diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift
index 75f5db4063..1fd52887c5 100644
--- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift
+++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift
@@ -38,6 +38,7 @@ final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase {
     private var tokenResult = MSIDTokenResult()
     private var tokenResponse = MSIDCIAMTokenResponse()
     private var defaultUUID = UUID(uuidString: DEFAULT_TEST_UID)!
+    private var apiErrorStub: MSALNativeAuthTokenResponseError!
 
     override func setUpWithError() throws {
         requestProviderMock = .init()
@@ -57,10 +58,19 @@ final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase {
         tokenResponse.scope = "openid profile email"
         tokenResponse.idToken = "idToken"
         tokenResponse.refreshToken = "refreshToken"
-        
+        apiErrorStub = MSALNativeAuthTokenResponseError(
+            error: .userNotFound,
+            subError: nil,
+            errorDescription: nil,
+            errorCodes: nil,
+            errorURI: nil,
+            innerErrors: nil,
+            continuationToken: nil
+        )
+
         try super.setUpWithError()
     }
-    
+
     // MARK: get native user account tests
 
     func test_whenNoAccountPresent_shouldReturnNoAccounts() {
@@ -117,7 +127,7 @@ final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase {
         requestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, continuationToken: nil, grantType: MSALNativeAuthGrantType.refreshToken, scope: "" , password: nil, oobCode: nil, includeChallengeType: true, refreshToken: "refreshToken")
         requestProviderMock.throwingRefreshTokenError = ErrorMock.error
 
-        let helper = CredentialsTestValidatorHelper(expectation: expectation, expectedError: RetrieveAccessTokenError(type: .generalError))
+        let helper = CredentialsTestValidatorHelper(expectation: expectation, expectedError: RetrieveAccessTokenError(type: .generalError, correlationId: defaultUUID))
 
         let result = await sut.refreshToken(context: expectedContext, authTokens: authTokens)
         helper.onAccessTokenRetrieveError(result)
@@ -157,17 +167,16 @@ final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase {
     }
 
     func test_whenErrorIsReturnedFromValidator_itIsCorrectlyTranslatedToDelegateError() async  {
-        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .generalError)
-        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .expiredToken(message: nil))
-        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .authorizationPending(message: nil))
-        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .slowDown(message: nil))
-        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError), validatorError: .invalidRequest(message: nil))
-        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Invalid Client ID"), validatorError: .unauthorizedClient(message: "Invalid Client ID"))
-        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Unexpected response body received"), validatorError: .unexpectedError(message: "Unexpected response body received"))
-        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Unsupported challenge type"), validatorError: .unsupportedChallengeType(message: "Unsupported challenge type"))
-        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Invalid scope"), validatorError: .invalidScope(message: "Invalid scope"))
-        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .refreshTokenExpired), validatorError: .expiredRefreshToken(message: nil))
-        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .browserRequired, message: "MFA currently not supported. Use the browser instead"), validatorError: .strongAuthRequired(message: "MFA currently not supported. Use the browser instead"))
+        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, correlationId: defaultUUID), validatorError: .generalError(apiErrorStub))
+        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, correlationId: defaultUUID), validatorError: .expiredToken(apiErrorStub))
+        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, correlationId: defaultUUID), validatorError: .authorizationPending(apiErrorStub))
+        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, correlationId: defaultUUID), validatorError: .slowDown(apiErrorStub))
+        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, correlationId: defaultUUID), validatorError: .invalidRequest(apiErrorStub))
+        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Invalid Client ID", correlationId: defaultUUID), validatorError: .unauthorizedClient(createApiErrorStub(message: "Invalid Client ID")))
+        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Unsupported challenge type", correlationId: defaultUUID), validatorError: .unsupportedChallengeType(createApiErrorStub(message: "Unsupported challenge type")))
+        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .generalError, message: "Invalid scope", correlationId: defaultUUID), validatorError: .invalidScope(createApiErrorStub(message: "Invalid scope")))
+        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .refreshTokenExpired, correlationId: defaultUUID), validatorError: .expiredRefreshToken(apiErrorStub))
+        await checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError(type: .browserRequired, message: "MFA currently not supported. Use the browser instead", correlationId: defaultUUID), validatorError: .strongAuthRequired(createApiErrorStub(message: "MFA currently not supported. Use the browser instead")))
     }
 
     private func checkPublicErrorWithValidatorError(publicError: RetrieveAccessTokenError, validatorError: MSALNativeAuthTokenValidatedErrorType) async {
@@ -206,4 +215,16 @@ final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase {
         XCTAssertNotNil(telemetryEventDict["stop_time"])
         XCTAssertNotNil(telemetryEventDict["response_time"])
     }
+
+    private func createApiErrorStub(message: String) -> MSALNativeAuthTokenResponseError {
+        return MSALNativeAuthTokenResponseError(
+            error: .userNotFound,
+            subError: nil,
+            errorDescription: message,
+            errorCodes: nil,
+            errorURI: nil,
+            innerErrors: nil,
+            continuationToken: nil
+        )
+    }
 }
diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift
index aff6b0ef7d..9b6995cc3f 100644
--- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift
+++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift
@@ -33,7 +33,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
     private var contextMock: MSALNativeAuthRequestContext!
     private var requestProviderMock: MSALNativeAuthResetPasswordRequestProviderMock!
     private var validatorMock: MSALNativeAuthResetPasswordResponseValidatorMock!
-
+    private var correlationId: UUID!
 
     private var resetPasswordStartParams: MSALNativeAuthResetPasswordStartRequestProviderParameters {
         .init(
@@ -48,6 +48,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
         contextMock = .init(correlationId: .init(uuidString: DEFAULT_TEST_UID)!)
         requestProviderMock = .init()
         validatorMock = .init()
+        correlationId = .init(uuidString: DEFAULT_TEST_UID)!
 
         sut = .init(config: MSALNativeAuthConfigStubs.configuration,
                     requestProvider: requestProviderMock,
@@ -85,7 +86,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
         validatorMock.mockValidateResetPasswordStartFunc(.success(continuationToken: "continuationToken"))
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams()
-        validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError(message: nil))
+        validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError(nil))
         _ = prepareResetPasswordStartValidatorHelper()
 
         _ = await sut.resetPassword(parameters: resetPasswordStartParams)
@@ -118,7 +119,15 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
     func test_whenResetPasswordStart_returns_error_it_returnsCorrectError() async {
         requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams
-        validatorMock.mockValidateResetPasswordStartFunc(.error(.userNotFound(message: nil)))
+        let apiError = MSALNativeAuthResetPasswordStartResponseError(
+            error: .userNotFound,
+            errorDescription: nil,
+            errorCodes: nil,
+            errorURI: nil,
+            innerErrors: nil,
+            target: nil
+        )
+        validatorMock.mockValidateResetPasswordStartFunc(.error(.userNotFound(apiError)))
 
         let exp = expectation(description: "ResetPasswordController expectation")
         let helper = prepareResetPasswordStartValidatorHelper(exp)
@@ -140,7 +149,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
     func test_whenValidatorInResetPasswordStart_returns_unexpectedError_it_returnsGeneralError() async {
         requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedStartRequestParameters = resetPasswordStartParams
-        validatorMock.mockValidateResetPasswordStartFunc(.unexpectedError(message: "Error description"))
+        validatorMock.mockValidateResetPasswordStartFunc(.unexpectedError(.init(errorDescription: "Error description")))
 
         let exp = expectation(description: "ResetPasswordController expectation")
         let helper = prepareResetPasswordStartValidatorHelper(exp)
@@ -276,7 +285,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
         validatorMock.mockValidateResetPasswordStartFunc(.success(continuationToken: "continuationToken"))
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams()
-        validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError(message: "Error description"))
+        validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError(.init(errorDescription: "Error description")))
 
         let exp = expectation(description: "ResetPasswordController expectation")
         let helper = prepareResetPasswordStartValidatorHelper(exp)
@@ -394,7 +403,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
     func test_whenResetPasswordResendCode_returns_unexpectedError_it_returnsCorrectError() async {
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams()
-        validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError(message: "Error description"))
+        validatorMock.mockValidateResetPasswordChallengeFunc(.unexpectedError(.init(errorDescription: "Error description")))
 
         let exp = expectation(description: "ResetPasswordController expectation")
         let helper = prepareResetPasswordResendCodeValidatorHelper(exp)
@@ -458,7 +467,17 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
     func test_whenResetPasswordSubmitCode_returns_invalidOOB_it_returnsInvalidCode() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
-        validatorMock.mockValidateResetPasswordContinueFunc(.invalidOOB)
+        let apiError = MSALNativeAuthResetPasswordContinueResponseError(
+            error: .invalidGrant,
+            subError: nil,
+            errorDescription: nil,
+            errorCodes: nil,
+            errorURI: nil,
+            innerErrors: nil,
+            target: nil,
+            continuationToken: nil
+        )
+        validatorMock.mockValidateResetPasswordContinueFunc(.invalidOOB(apiError))
 
         let exp = expectation(description: "ResetPasswordController expectation")
         let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp)
@@ -507,7 +526,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
     func test_whenResetPasswordSubmitCode_returns_unexpectedError_it_returnsCorrectError() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
-        validatorMock.mockValidateResetPasswordContinueFunc(.unexpectedError(message: "Error description"))
+        validatorMock.mockValidateResetPasswordContinueFunc(.unexpectedError(.init(errorDescription: "Error description")))
 
         let exp = expectation(description: "ResetPasswordController expectation")
         let helper = prepareResetPasswordSubmitCodeValidatorHelper(exp)
@@ -626,7 +645,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
     func test_whenResetPasswordSubmitPassword_returns_unexpectedError_it_returnsCorrectError() async {
         requestProviderMock.mockSubmitRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedSubmitRequestParameters = expectedSubmitParams()
-        validatorMock.mockValidateResetPasswordSubmitFunc(.unexpectedError(message: "Error description"))
+        validatorMock.mockValidateResetPasswordSubmitFunc(.unexpectedError(.init(errorDescription: "Error description")))
 
         let exp = expectation(description: "ResetPasswordController expectation")
         let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp)
@@ -651,7 +670,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
         validatorMock.mockValidateResetPasswordSubmitFunc(.success(continuationToken: "continuationToken", pollInterval: 0))
         requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters()
-        validatorMock.mockValidateResetPasswordPollCompletionFunc(.unexpectedError(message: "Error description"))
+        validatorMock.mockValidateResetPasswordPollCompletionFunc(.unexpectedError(.init(errorDescription: "Error description")))
 
         let exp = expectation(description: "ResetPasswordController expectation")
         let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp)
@@ -673,7 +692,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
         validatorMock.mockValidateResetPasswordSubmitFunc(.success(continuationToken: "continuationToken", pollInterval: 0))
         requestProviderMock.mockPollCompletionRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedPollCompletionParameters = expectedPollCompletionParameters()
-        validatorMock.mockValidateResetPasswordPollCompletionFunc(.unexpectedError(message: "Error description"))
+        validatorMock.mockValidateResetPasswordPollCompletionFunc(.unexpectedError(.init(errorDescription: "Error description")))
 
         let exp = expectation(description: "ResetPasswordController expectation")
         let helper = prepareResetPasswordSubmitPasswordValidatorHelper(exp)
@@ -863,7 +882,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
 
         let exp2 = expectation(description: "SignInAfterResetPassword expectation")
         signInControllerMock.expectation = exp2
-        signInControllerMock.continuationTokenResult = .init(.failure(.init()))
+        signInControllerMock.continuationTokenResult = .init(.failure(SignInAfterResetPasswordError(correlationId: correlationId)), correlationId: correlationId)
 
         helper.signInAfterResetPasswordState?.signIn(delegate: SignInAfterResetPasswordDelegateStub())
         await fulfillment(of: [exp2], timeout: 1)
diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift
index 897573fda5..86556d8b05 100644
--- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift
+++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift
@@ -41,6 +41,24 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
     private var defaultUUID = UUID(uuidString: DEFAULT_TEST_UID)!
     private let defaultScopes = "openid profile offline_access"
 
+    private var signInInitiateApiErrorStub: MSALNativeAuthSignInInitiateResponseError {
+        .init(error: .invalidRequest, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil)
+    }
+
+    private var signInChallengeApiErrorStub: MSALNativeAuthSignInChallengeResponseError {
+        .init(
+            error: .expiredToken,
+            errorDescription: nil,
+            errorCodes: nil,
+            errorURI: nil,
+            innerErrors: nil
+        )
+    }
+
+    private var signInTokenApiErrorStub: MSALNativeAuthTokenResponseError {
+        .init(error: .expiredToken, subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil)
+    }
+
     override func setUpWithError() throws {
         signInRequestProviderMock = .init()
         tokenRequestProviderMock = .init()
@@ -81,7 +99,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         signInRequestProviderMock.expectedContext = expectedContext
         signInRequestProviderMock.throwingInitError = ErrorMock.error
 
-        let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError))
+        let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError, correlationId: defaultUUID))
 
         let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil))
 
@@ -111,7 +129,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, continuationToken: continuationToken, grantType: MSALNativeAuthGrantType.password, scope: expectedScopes, password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil)
 
-        let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError))
+        let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError, correlationId: defaultUUID))
 
         let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: ["scope1", "scope2"]))
 
@@ -140,7 +158,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, continuationToken: continuationToken, grantType: MSALNativeAuthGrantType.password, scope: expectedScopes, password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil)
         tokenRequestProviderMock.throwingTokenError = ErrorMock.error
 
-        let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError))
+        let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError, correlationId: defaultUUID))
 
         let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: ["scope1", "openid", "profile"]))
 
@@ -207,7 +225,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         tokenRequestProviderMock.expectedUsername = expectedUsername
         tokenRequestProviderMock.expectedContext = expectedContext
 
-        let delegateError = SignInStartError(type: .generalError)
+        let delegateError = SignInStartError(type: .generalError, correlationId: defaultUUID)
         let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: delegateError)
         tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse)
         tokenResponseValidatorMock.expectedTokenResponse = tokenResponse
@@ -230,7 +248,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         let expectation = expectation(description: "SignInController")
 
         signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: continuationToken)
-        signInResponseValidatorMock.challengeValidatedResponse = .error(.invalidToken(message: nil))
+        signInResponseValidatorMock.challengeValidatedResponse = .error(.invalidToken(signInChallengeApiErrorStub))
 
         signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
@@ -241,7 +259,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         tokenRequestProviderMock.expectedUsername = expectedUsername
         tokenRequestProviderMock.expectedContext = expectedContext
 
-        let delegateError = SignInStartError(type: .generalError)
+        let delegateError = SignInStartError(type: .generalError, correlationId: defaultUUID)
         let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: delegateError)
         tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse)
         tokenResponseValidatorMock.expectedTokenResponse = tokenResponse
@@ -255,18 +273,18 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
     }
     
     func test_whenErrorIsReturnedFromValidator_itIsCorrectlyTranslatedToDelegateError() async  {
-        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .generalError)
-        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .expiredToken(message: nil))
-        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .authorizationPending(message: nil))
-        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .slowDown(message: nil))
-        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidRequest(message: nil))
-        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Invalid Client ID"), validatorError: .unauthorizedClient(message: "Invalid Client ID"))
-        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Unexpected response body received"), validatorError: .unexpectedError(message: "Unexpected response body received"))
-        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Unsupported challenge type"), validatorError: .unsupportedChallengeType(message: "Unsupported challenge type"))
-        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Invalid scope"), validatorError: .invalidScope(message: "Invalid scope"))
-        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .userNotFound), validatorError: .userNotFound(message: nil))
-        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .invalidCredentials), validatorError: .invalidPassword(message: nil))
-        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Error message"), validatorError: .unexpectedError(message: "Error message"))
+        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, correlationId: defaultUUID), validatorError: .generalError(signInTokenApiErrorStub))
+        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, correlationId: defaultUUID), validatorError: .expiredToken(signInTokenApiErrorStub))
+        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, correlationId: defaultUUID), validatorError: .authorizationPending(signInTokenApiErrorStub))
+        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, correlationId: defaultUUID), validatorError: .slowDown(signInTokenApiErrorStub))
+        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, correlationId: defaultUUID), validatorError: .invalidRequest(signInTokenApiErrorStub))
+        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Invalid Client ID", correlationId: defaultUUID), validatorError: .unauthorizedClient(createSignInTokenApiError(message: "Invalid Client ID")))
+        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Unexpected response body received", correlationId: defaultUUID), validatorError: .unexpectedError(.init(errorDescription: "Unexpected response body received")))
+        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Unsupported challenge type", correlationId: defaultUUID), validatorError: .unsupportedChallengeType(createSignInTokenApiError(message: "Unsupported challenge type")))
+        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Invalid scope", correlationId: defaultUUID), validatorError: .invalidScope(createSignInTokenApiError(message: "Invalid scope")))
+        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .userNotFound, correlationId: defaultUUID), validatorError: .userNotFound(signInTokenApiErrorStub))
+        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .invalidCredentials, correlationId: defaultUUID), validatorError: .invalidPassword(signInTokenApiErrorStub))
+        await checkDelegateErrorWithValidatorError(delegateError: SignInStartError(type: .generalError, message: "Error message", correlationId: defaultUUID), validatorError: .unexpectedError(.init(errorDescription: "Error message")))
     }
     
     func test_whenCredentialsAreRequired_browserRequiredErrorIsReturned() async {
@@ -289,9 +307,9 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
 
         let expectation = expectation(description: "SignInController")
 
-        let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: .init(type: .browserRequired, message: MSALNativeAuthErrorMessage.unsupportedMFA))
+        let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: .init(type: .browserRequired, message: MSALNativeAuthErrorMessage.unsupportedMFA, correlationId: defaultUUID))
 
-        tokenResponseValidatorMock.tokenValidatedResponse = .error(.strongAuthRequired(message: "MFA currently not supported. Use the browser instead"))
+        tokenResponseValidatorMock.tokenValidatedResponse = .error(.strongAuthRequired(.init(error: .unauthorizedClient, subError: nil, errorDescription: MSALNativeAuthErrorMessage.unsupportedMFA, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil)))
 
         let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil))
 
@@ -361,7 +379,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         helper.expectedCodeLength = expectedCodeLength
 
         let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil))
-        result.telemetryUpdate?(.failure(.init(message: "error")))
+        result.telemetryUpdate?(.failure(.init(message: "error", correlationId: defaultUUID)))
 
         helper.onSignInCodeRequired(result)
 
@@ -439,7 +457,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         cacheAccessorMock.expectedMSIDTokenResult = nil
 
         let state = SignInCodeRequiredState(scopes: ["openid","profile","offline_access"], controller: sut, inputValidator: MSALNativeAuthInputValidator(), continuationToken: continuationToken, correlationId: defaultUUID)
-        state.submitCode(code: "code", delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedError: VerifyCodeError(type: .generalError)))
+        state.submitCode(code: "code", delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedError: VerifyCodeError(type: .generalError, correlationId: defaultUUID)))
 
         wait(for: [expectation], timeout: 1)
 
@@ -454,9 +472,9 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
 
         signInRequestProviderMock.expectedUsername = expectedUsername
         signInRequestProviderMock.expectedContext = expectedContext
-        signInRequestProviderMock.throwingInitError = MSALNativeAuthError(message: nil)
+        signInRequestProviderMock.throwingInitError = MSALNativeAuthError(message: nil, correlationId: defaultUUID)
 
-        let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError))
+        let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError, correlationId: defaultUUID))
 
         let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: nil, context: expectedContext, scopes: nil))
 
@@ -467,13 +485,13 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
     }
     
     func test_whenSignInWithCodeStartAndInitiateReturnError_properErrorShouldBeReturned() async {
-        await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .browserRequired), validatorError: .redirect)
-        await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError, message: nil), validatorError: .unauthorizedClient(message: nil))
-        await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .userNotFound), validatorError: .userNotFound(message: nil))
-        await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .unsupportedChallengeType(message: nil))
-        await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidRequest(message: nil))
-        await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError, message: "Unexpected response body received"), validatorError: .unexpectedError(message: "Unexpected response body received"))
-        await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError, message: "Error message"), validatorError: .unexpectedError(message: "Error message"))
+        await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .browserRequired, correlationId: defaultUUID), validatorError: .redirect)
+        await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError, correlationId: defaultUUID), validatorError: .unauthorizedClient(signInInitiateApiErrorStub))
+        await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .userNotFound, correlationId: defaultUUID), validatorError: .userNotFound(signInInitiateApiErrorStub))
+        await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError, correlationId: defaultUUID), validatorError: .unsupportedChallengeType(signInInitiateApiErrorStub))
+        await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError, correlationId: defaultUUID), validatorError: .invalidRequest(createSignInInitiateApiError(correlationId: defaultUUID)))
+        await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError, message: "Unexpected response body received", correlationId: defaultUUID), validatorError: .unexpectedError(.init(errorDescription: "Unexpected response body received")))
+        await checkCodeStartDelegateErrorWithInitiateValidatorError(delegateError: SignInStartError(type: .generalError, message: "Error message", correlationId: defaultUUID), validatorError: .unexpectedError(.init(errorDescription: "Error message")))
     }
     
     func test_whenSignInWithCodeChallengeRequestCreationFail_errorShouldBeReturned() async {
@@ -483,10 +501,10 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
 
         signInRequestProviderMock.mockInitiateRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         signInRequestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
-        signInRequestProviderMock.throwingChallengeError = MSALNativeAuthError(message: nil)
+        signInRequestProviderMock.throwingChallengeError = MSALNativeAuthError(message: nil, correlationId: defaultUUID)
         signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: "continuationToken")
-        
-        let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError))
+
+        let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError, correlationId: defaultUUID))
 
         let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: nil, context: expectedContext, scopes: nil))
 
@@ -497,15 +515,15 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
     }
     
     func test_whenSignInWithCodeChallengeReturnsError_properErrorShouldBeReturned() async {
-        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .browserRequired), validatorError: .redirect)
-        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .expiredToken(message: nil))
-        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidToken(message: nil))
-        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError), validatorError: .invalidRequest(message: nil))
-        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: nil), validatorError: .unauthorizedClient(message: nil))
-        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: "Unexpected response body received"), validatorError: .unexpectedError(message: "Unexpected response body received"))
-        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .userNotFound), validatorError: .userNotFound(message: nil))
-        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: nil), validatorError: .unsupportedChallengeType(message: nil))
-        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: "Error message"), validatorError: .unexpectedError(message: "Error message"))
+        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .browserRequired, correlationId: defaultUUID), validatorError: .redirect)
+        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, correlationId: defaultUUID), validatorError: .expiredToken(signInChallengeApiErrorStub))
+        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, correlationId: defaultUUID), validatorError: .invalidToken(signInChallengeApiErrorStub))
+        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, correlationId: defaultUUID), validatorError: .invalidRequest(createSignInChallengeApiError(correlationId: defaultUUID)))
+        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, correlationId: defaultUUID), validatorError: .unauthorizedClient(signInChallengeApiErrorStub))
+        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: "Unexpected response body received", correlationId: defaultUUID), validatorError: .unexpectedError(.init(errorDescription: "Unexpected response body received")))
+        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .userNotFound, correlationId: defaultUUID), validatorError: .userNotFound(signInChallengeApiErrorStub))
+        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, correlationId: defaultUUID), validatorError: .unsupportedChallengeType(signInChallengeApiErrorStub))
+        await checkCodeStartDelegateErrorWithChallengeValidatorError(delegateError: SignInStartError(type: .generalError, message: "Error message", correlationId: defaultUUID), validatorError: .unexpectedError(.init(errorDescription: "Error message")))
     }
     
     func test_whenSignInWithCodePasswordIsRequired_newStateIsPropagatedToUser() async {
@@ -547,7 +565,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         let helper = SignInCodeStartWithPasswordRequiredTestsValidatorHelper(expectation: expectation)
 
         let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: nil, context: expectedContext, scopes: nil))
-        result.telemetryUpdate?(.failure(.init(message: "error")))
+        result.telemetryUpdate?(.failure(.init(message: "error", correlationId: defaultUUID)))
 
         helper.onSignInPasswordRequired(result.result)
 
@@ -596,7 +614,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         tokenRequestProviderMock.expectedContext = expectedContext
         tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: expectedUsername, continuationToken: expectedCredentialToken, grantType: MSALNativeAuthGrantType.password, scope: "", password: expectedPassword, oobCode: nil, includeChallengeType: true, refreshToken: nil)
 
-        let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: PasswordRequiredError(type: .generalError))
+        let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: PasswordRequiredError(type: .generalError, correlationId: defaultUUID))
         tokenResponseValidatorMock.tokenValidatedResponse = .success(tokenResponse)
         tokenResponseValidatorMock.expectedTokenResponse = tokenResponse
         cacheAccessorMock.expectedMSIDTokenResult = nil
@@ -616,10 +634,10 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
 
         let exp = expectation(description: "SignInController")
         
-        tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError(message: nil)
+        tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError(message: nil, correlationId: defaultUUID)
         signInRequestProviderMock.expectedContext = expectedContext
         
-        let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: PasswordRequiredError(type: .generalError))
+        let mockDelegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: PasswordRequiredError(type: .generalError, correlationId: defaultUUID))
 
         let state = SignInPasswordRequiredState(scopes: [], username: expectedUsername, controller: sut, continuationToken: expectedCredentialToken, correlationId: defaultUUID)
         state.submitPassword(password: expectedPassword, delegate: mockDelegate)
@@ -631,20 +649,20 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
     }
     
     func test_whenSignInWithCodeSubmitPasswordTokenAPIReturnError_correctErrorShouldBeReturned() async {
-        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .generalError)
-        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .expiredToken(message: nil))
-        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .unauthorizedClient(message: nil))
-        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidRequest(message: nil))
-        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, message: "Unexpected response body received"), validatorError: .unexpectedError(message: "Unexpected response body received"))
-        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, message: "User not found"), validatorError: .userNotFound(message: "User not found"))
-        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidOOBCode(message: nil))
-        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .unsupportedChallengeType(message: nil))
-        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .browserRequired), validatorError: .strongAuthRequired(message: nil))
-        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .invalidScope(message: nil))
-        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .authorizationPending(message: nil))
-        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError), validatorError: .slowDown(message: nil))
-        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .invalidPassword), validatorError: .invalidPassword(message: "Invalid password"))
-        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, message: "Error message"), validatorError: .unexpectedError(message: "Error message"))
+        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, correlationId: defaultUUID), validatorError: .generalError(signInTokenApiErrorStub))
+        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, correlationId: defaultUUID), validatorError: .expiredToken(signInTokenApiErrorStub))
+        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, correlationId: defaultUUID), validatorError: .unauthorizedClient(signInTokenApiErrorStub))
+        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, correlationId: defaultUUID), validatorError: .invalidRequest(signInTokenApiErrorStub))
+        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, message: "Unexpected response body received", correlationId: defaultUUID), validatorError: .unexpectedError(.init(errorDescription: "Unexpected response body received")))
+        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, message: "User does not exist", correlationId: defaultUUID), validatorError: .userNotFound(signInTokenApiErrorStub))
+        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, correlationId: defaultUUID), validatorError: .invalidOOBCode(signInTokenApiErrorStub))
+        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, correlationId: defaultUUID), validatorError: .unsupportedChallengeType(signInTokenApiErrorStub))
+        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .browserRequired, correlationId: defaultUUID), validatorError: .strongAuthRequired(signInTokenApiErrorStub))
+        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, correlationId: defaultUUID), validatorError: .invalidScope(signInTokenApiErrorStub))
+        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, correlationId: defaultUUID), validatorError: .authorizationPending(signInTokenApiErrorStub))
+        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, correlationId: defaultUUID), validatorError: .slowDown(signInTokenApiErrorStub))
+        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .invalidPassword, correlationId: defaultUUID), validatorError: .invalidPassword(signInTokenApiErrorStub))
+        await checkSubmitPasswordPublicErrorWithTokenValidatorError(publicError: PasswordRequiredError(type: .generalError, message: "Error message", correlationId: defaultUUID), validatorError: .unexpectedError(.init(errorDescription: "Error message")))
     }
     
     func test_signInWithCodeSubmitCodeTokenRequestFailCreation_errorShouldBeReturned() {
@@ -654,10 +672,10 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         let expectation = expectation(description: "SignInController")
 
         signInRequestProviderMock.expectedContext = expectedContext
-        tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError(message: nil)
+        tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError(message: nil, correlationId: defaultUUID)
 
         let state = SignInCodeRequiredState(scopes: [], controller: sut, continuationToken: continuationToken, correlationId: defaultUUID)
-        state.submitCode(code: "code", delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedError: VerifyCodeError(type: .generalError)))
+        state.submitCode(code: "code", delegate: SignInVerifyCodeDelegateSpy(expectation: expectation, expectedError: VerifyCodeError(type: .generalError, correlationId: defaultUUID)))
 
         wait(for: [expectation], timeout: 1)
         XCTAssertFalse(cacheAccessorMock.validateAndSaveTokensWasCalled)
@@ -665,19 +683,19 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
     }
     
     func test_signInWithCodeSubmitCodeReturnError_correctResultShouldReturned() {
-        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .generalError)
-        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .expiredToken(message: nil))
-        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .unauthorizedClient(message: nil))
-        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidRequest(message: nil))
-        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .unexpectedError(message: "Unexpected response body received"))
-        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .userNotFound(message: nil))
-        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .invalidCode, validatorError: .invalidOOBCode(message: nil))
-        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .unsupportedChallengeType(message: nil))
-        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .browserRequired, validatorError: .strongAuthRequired(message: nil))
-        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidScope(message: nil))
-        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .authorizationPending(message: nil))
-        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .slowDown(message: nil))
-        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidPassword(message: nil))
+        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .generalError(signInTokenApiErrorStub))
+        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .expiredToken(signInTokenApiErrorStub))
+        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .unauthorizedClient(signInTokenApiErrorStub))
+        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidRequest(signInTokenApiErrorStub))
+        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .unexpectedError(.init(errorDescription: "Unexpected response body received")))
+        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .userNotFound(signInTokenApiErrorStub))
+        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .invalidCode, validatorError: .invalidOOBCode(signInTokenApiErrorStub))
+        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .unsupportedChallengeType(signInTokenApiErrorStub))
+        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .browserRequired, validatorError: .strongAuthRequired(signInTokenApiErrorStub))
+        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidScope(signInTokenApiErrorStub))
+        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .authorizationPending(signInTokenApiErrorStub))
+        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .slowDown(signInTokenApiErrorStub))
+        checkSubmitCodeDelegateErrorWithTokenValidatorError(delegateError: .generalError, validatorError: .invalidPassword(signInTokenApiErrorStub))
     }
         
     func test_signInWithCodeResendCode_shouldSendNewCode() async {
@@ -713,7 +731,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         
         let expectation = expectation(description: "SignInController")
 
-        signInRequestProviderMock.throwingChallengeError = MSALNativeAuthError(message: nil)
+        signInRequestProviderMock.throwingChallengeError = MSALNativeAuthError(message: nil, correlationId: defaultUUID)
 
         let helper = SignInResendCodeTestsValidatorHelper(expectation: expectation)
 
@@ -759,7 +777,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
 
         let helper = SignInResendCodeTestsValidatorHelper(expectation: expectation)
 
-        signInResponseValidatorMock.challengeValidatedResponse = .error(.userNotFound(message: nil))
+        signInResponseValidatorMock.challengeValidatedResponse = .error(.userNotFound(signInChallengeApiErrorStub))
 
         let result = await sut.resendCode(continuationToken: continuationToken, context: expectedContext, scopes: [])
 
@@ -804,10 +822,10 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
 
         let exp = expectation(description: "SignInController")
         
-        tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError(message: nil)
+        tokenRequestProviderMock.throwingTokenError = MSALNativeAuthError(message: nil, correlationId: defaultUUID)
         signInRequestProviderMock.expectedContext = expectedContext
         
-        let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: exp, expectedError: SignInAfterSignUpError())
+        let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: exp, expectedError: SignInAfterSignUpError(correlationId: defaultUUID))
 
         let state = SignInAfterSignUpState(controller: sut, username: "", continuationToken: continuationToken, correlationId: defaultUUID)
         state.signIn(delegate: mockDelegate)
@@ -826,9 +844,9 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         tokenRequestProviderMock.expectedContext = expectedContext
 
-        let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: expectation, expectedError: SignInAfterSignUpError(message: "Invalid Client ID"))
+        let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: expectation, expectedError: SignInAfterSignUpError(message: MSALNativeAuthErrorMessage.generalError, correlationId: defaultUUID))
 
-        tokenResponseValidatorMock.tokenValidatedResponse = .error(.unauthorizedClient(message: "Invalid Client ID"))
+        tokenResponseValidatorMock.tokenValidatedResponse = .error(.unauthorizedClient(signInTokenApiErrorStub))
 
         let state = SignInAfterSignUpState(controller: sut, username: "", continuationToken: continuationToken, correlationId: defaultUUID)
         state.signIn(delegate: mockDelegate)
@@ -841,7 +859,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
     func test_whenSignInWithContinuationTokenHaveTokenNil_shouldReturnAnError() {
         let expectation = expectation(description: "SignInController")
 
-        let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: expectation, expectedError: SignInAfterSignUpError(message: "Sign In is not available at this point, please use the standalone sign in methods"))
+        let mockDelegate = SignInAfterSignUpDelegateSpy(expectation: expectation, expectedError: SignInAfterSignUpError(message: "Sign In is not available at this point, please use the standalone sign in methods", correlationId: defaultUUID))
 
         let state = SignInAfterSignUpState(controller: sut, username: "username", continuationToken: nil, correlationId: defaultUUID)
         state.signIn(delegate: mockDelegate)
@@ -864,7 +882,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         tokenRequestProviderMock.mockRequestTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         tokenRequestProviderMock.expectedContext = expectedContext
         tokenRequestProviderMock.expectedTokenParams = MSALNativeAuthTokenRequestParameters(context: expectedContext, username: nil, continuationToken: expectedCredentialToken, grantType: MSALNativeAuthGrantType.oobCode, scope: "", password: nil, oobCode: expectedOOBCode, includeChallengeType: true, refreshToken: nil)
-        let mockDelegate = SignInVerifyCodeDelegateSpy(expectation: exp, expectedError: VerifyCodeError(type: delegateError))
+        let mockDelegate = SignInVerifyCodeDelegateSpy(expectation: exp, expectedError: VerifyCodeError(type: delegateError, correlationId: defaultUUID))
         tokenResponseValidatorMock.tokenValidatedResponse = .error(validatorError)
         
         let state = SignInCodeRequiredState(scopes: [], controller: sut, continuationToken: expectedCredentialToken, correlationId: defaultUUID)
@@ -951,7 +969,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
 
         signInResponseValidatorMock.initiateValidatedResponse = .success(continuationToken: continuationToken)
         signInResponseValidatorMock.challengeValidatedResponse = .passwordRequired(continuationToken: continuationToken)
-        
+
         signInRequestProviderMock.mockInitiateRequestFunc((MSALNativeAuthHTTPRequestMock.prepareMockRequest()))
         signInRequestProviderMock.mockChallengeRequestFunc((MSALNativeAuthHTTPRequestMock.prepareMockRequest()))
         signInRequestProviderMock.expectedUsername = expectedUsername
@@ -992,4 +1010,20 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         XCTAssertNotNil(telemetryEventDict["response_time"])
     }
 
+
+    private func createSignInTokenApiError(message: String) -> MSALNativeAuthTokenResponseError {
+        .init(error: .expiredToken, subError: nil, errorDescription: message, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil)
+    }
+
+    private func createSignInInitiateApiError(correlationId: UUID) -> MSALNativeAuthSignInInitiateResponseError {
+        var error = MSALNativeAuthSignInInitiateResponseError()
+        error.correlationId = correlationId
+        return error
+    }
+
+    private func createSignInChallengeApiError(correlationId: UUID) -> MSALNativeAuthSignInChallengeResponseError {
+        var error = MSALNativeAuthSignInChallengeResponseError()
+        error.correlationId = correlationId
+        return error
+    }
 }
diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift
index a5de9ac5f5..45c113d4ef 100644
--- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift
+++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignUpControllerTests.swift
@@ -34,6 +34,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     private var requestProviderMock: MSALNativeAuthSignUpRequestProviderMock!
     private var validatorMock: MSALNativeAuthSignUpResponseValidatorMock!
     private var signInControllerMock: MSALNativeAuthSignInControllerMock!
+    private var correlationId: UUID!
 
     private var signUpStartPasswordParams: MSALNativeAuthSignUpStartRequestProviderParameters {
         .init(
@@ -60,6 +61,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
         requestProviderMock = .init()
         validatorMock = .init()
         signInControllerMock = .init()
+        correlationId = .init(uuidString: DEFAULT_TEST_UID)!
 
         sut = MSALNativeAuthSignUpController(
             config: MSALNativeAuthConfigStubs.configuration,
@@ -99,7 +101,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
         validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken"))
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams()
-        validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(message: nil))
+        validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(nil))
 
         let helper = prepareSignUpPasswordStartValidatorHelper()
 
@@ -115,7 +117,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
         let invalidAttributes = ["name"]
         requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams
-        validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(invalidAttributes: invalidAttributes))
+        validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(error: createInitiateApiError(type: .attributesRequired), invalidAttributes: invalidAttributes))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpPasswordStartValidatorHelper(exp)
@@ -140,13 +142,13 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
         let invalidAttributes = ["name"]
         requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams
-        validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(invalidAttributes: invalidAttributes))
+        validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(error: createInitiateApiError(type: .invalidGrant), invalidAttributes: invalidAttributes))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpPasswordStartValidatorHelper(exp)
 
         let result = await sut.signUpStart(parameters: signUpStartPasswordParams)
-        result.telemetryUpdate?(.failure(.init(message: "error")))
+        result.telemetryUpdate?(.failure(.init(message: "error", correlationId: correlationId)))
 
         helper.onSignUpAttributesInvalid(result)
 
@@ -282,7 +284,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenValidatorInSignUpStartPassword_returns_unexpectedError_it_returnsGeneralError() async {
         requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedStartRequestParameters = signUpStartPasswordParams
-        validatorMock.mockValidateSignUpStartFunc(.unexpectedError(message: "Error message"))
+        validatorMock.mockValidateSignUpStartFunc(.unexpectedError(.init(errorDescription: "Error message")))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpPasswordStartValidatorHelper(exp)
@@ -442,7 +444,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
         validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken"))
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams()
-        validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(message: "Error message"))
+        validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(.init(errorDescription: "Error message")))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpPasswordStartValidatorHelper(exp)
@@ -491,7 +493,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
         validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken"))
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams()
-        validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(message: nil))
+        validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(nil))
 
         let helper = prepareSignUpCodeStartValidatorHelper()
 
@@ -507,7 +509,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
         let invalidAttributes = ["name"]
         requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams
-        validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(invalidAttributes: invalidAttributes))
+        validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(error: createInitiateApiError(type: .invalidGrant), invalidAttributes: invalidAttributes))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpCodeStartValidatorHelper(exp)
@@ -531,13 +533,13 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
         let invalidAttributes = ["name"]
         requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams
-        validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(invalidAttributes: invalidAttributes))
+        validatorMock.mockValidateSignUpStartFunc(.attributeValidationFailed(error: createInitiateApiError(type: .invalidGrant), invalidAttributes: invalidAttributes))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpCodeStartValidatorHelper(exp)
 
         let result = await sut.signUpStart(parameters: signUpStartCodeParams)
-        result.telemetryUpdate?(.failure(.init(message: "error")))
+        result.telemetryUpdate?(.failure(.init(message: "error", correlationId: correlationId)))
         helper.onSignUpAttributesInvalid(result)
 
         await fulfillment(of: [exp], timeout: 1)
@@ -672,7 +674,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenValidatorInSignUpStartCode_returns_unexpectedError_it_returnsGeneralError() async {
         requestProviderMock.mockStartRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedStartRequestParameters = signUpStartCodeParams
-        validatorMock.mockValidateSignUpStartFunc(.unexpectedError(message: "Error Message"))
+        validatorMock.mockValidateSignUpStartFunc(.unexpectedError(.init(errorDescription: "Error Message")))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpCodeStartValidatorHelper(exp)
@@ -832,7 +834,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
         validatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken"))
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams()
-        validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(message: "Error message"))
+        validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(.init(errorDescription: "Error message")))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpCodeStartValidatorHelper(exp)
@@ -969,7 +971,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpResendCode_returns_unexpectedError_it_returnsCorrectError() async {
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams()
-        validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(message: "Error message"))
+        validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(.init(errorDescription: "Error message")))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpResendCodeValidatorHelper(exp)
@@ -1012,7 +1014,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
 
     func test_whenSubmitCode_succeeds_it_continuesTheFlow() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
-        validatorMock.mockValidateSignUpContinueFunc(.success(""))
+        validatorMock.mockValidateSignUpContinueFunc(.success(continuationToken: ""))
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
 
         let exp = expectation(description: "SignUpController expectation")
@@ -1065,7 +1067,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
 
     func test_whenSignUpSubmitCode_returns_attributesRequired_it_returnsAttributesRequired() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
-        validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken", requiredAttributes: []))
+        validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken", requiredAttributes: [], error: .init()))
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
 
         let exp = expectation(description: "SignUpController expectation")
@@ -1088,14 +1090,14 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
 
     func test_whenSignUpSubmitCode_returns_attributesRequired_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
-        validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken", requiredAttributes: []))
+        validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken", requiredAttributes: [], error: .init()))
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitCodeValidatorHelper(exp)
 
         let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock)
-        result.telemetryUpdate?(.failure(.init(message: "error")))
+        result.telemetryUpdate?(.failure(.init(message: "error", correlationId: correlationId)))
 
         helper.onSignUpAttributesRequired(result)
 
@@ -1112,7 +1114,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpSubmitCode_returns_attributeValidationFailed_returnsCorrectError() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
-        validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(invalidAttributes: ["name"]))
+        validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(error: createContinueApiError(type: .invalidGrant), invalidAttributes: ["name"]))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitCodeValidatorHelper(exp)
@@ -1165,7 +1167,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpSubmitCode_returns_unexpectedError_it_returnsCorrectError() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
-        validatorMock.mockValidateSignUpContinueFunc(.unexpectedError(message: "Error description"))
+        validatorMock.mockValidateSignUpContinueFunc(.unexpectedError(.init(errorDescription: "Error description")))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitCodeValidatorHelper(exp)
@@ -1189,10 +1191,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
-        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2"))
+        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2", error: .init()))
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2")
-        validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(message: nil))
+        validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(nil))
 
         XCTAssertFalse(requestProviderMock.challengeCalled)
 
@@ -1211,7 +1213,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andCantCreateRequest() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
-        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2"))
+        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2", error: .init()))
         requestProviderMock.mockChallengeRequestFunc(nil, throwError: true)
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2")
 
@@ -1234,7 +1236,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andSucceeds() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
-        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2"))
+        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2", error: .init()))
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2")
         validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("continuationToken 3"))
@@ -1263,7 +1265,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
-        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2"))
+        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2", error: .init()))
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2")
         validatorMock.mockValidateSignUpChallengeFunc(.passwordRequired("continuationToken 3"))
@@ -1274,7 +1276,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
         let helper = prepareSignUpSubmitCodeValidatorHelper(exp)
 
         let result = await sut.submitCode("1234", username: "", continuationToken: "continuationToken", context: contextMock)
-        result.telemetryUpdate?(.failure(.init(message: "error")))
+        result.telemetryUpdate?(.failure(.init(message: "error", correlationId: correlationId)))
 
         helper.onSignUpPasswordRequired(result)
 
@@ -1291,7 +1293,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
 
     func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andSucceedOOB_returnsCorrectError() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
-        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2"))
+        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2", error: .init()))
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2")
@@ -1315,7 +1317,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andRedirects() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
-        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2"))
+        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2", error: .init()))
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2")
         validatorMock.mockValidateSignUpChallengeFunc(.redirect)
@@ -1341,7 +1343,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andReturnsError() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
-        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2"))
+        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2", error: .init()))
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2")
         let error : MSALNativeAuthSignUpChallengeValidatedResponse = .error(
@@ -1373,10 +1375,10 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpSubmitCode_returns_credentialRequired_it_returnsChallengeEndpoint_andReturnsUnexpectedError() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams()
-        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2"))
+        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2", error: .init()))
         requestProviderMock.mockChallengeRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedChallengeRequestParameters = expectedChallengeParams(token: "continuationToken 2")
-        validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(message: nil))
+        validatorMock.mockValidateSignUpChallengeFunc(.unexpectedError(nil))
 
         XCTAssertFalse(requestProviderMock.challengeCalled)
 
@@ -1420,7 +1422,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSubmitPassword_succeeds_it_continuesTheFlow() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil)
-        validatorMock.mockValidateSignUpContinueFunc(.success("continuationToken"))
+        validatorMock.mockValidateSignUpContinueFunc(.success(continuationToken: "continuationToken"))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitPasswordValidatorHelper(exp)
@@ -1472,7 +1474,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpSubmitPassword_returns_attributesRequired_it_returnsCorrectError() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil)
-        validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken 2", requiredAttributes: []))
+        validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken 2", requiredAttributes: [], error: .init()))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitPasswordValidatorHelper(exp)
@@ -1494,13 +1496,13 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpSubmitPassword_returns_attributesRequired_butTelemetryUpdateFails_it_updatesTelemetryCorrectly() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil)
-        validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken 2", requiredAttributes: []))
+        validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken 2", requiredAttributes: [], error: .init()))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitPasswordValidatorHelper(exp)
 
         let result = await sut.submitPassword("password", username: "", continuationToken: "continuationToken", context: contextMock)
-        result.telemetryUpdate?(.failure(.init(message: "error")))
+        result.telemetryUpdate?(.failure(.init(message: "error", correlationId: correlationId)))
 
         helper.onSignUpAttributesRequired(result)
 
@@ -1547,7 +1549,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpSubmitPassword_returns_credentialRequired_it_returnsCorrectError() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil)
-        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2"))
+        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2", error: .init()))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitPasswordValidatorHelper(exp)
@@ -1567,7 +1569,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpSubmitPassword_returns_unexpectedError_it_returnsCorrectError() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil)
-        validatorMock.mockValidateSignUpContinueFunc(.unexpectedError(message: "Error description"))
+        validatorMock.mockValidateSignUpContinueFunc(.unexpectedError(.init(errorDescription: "Error description")))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitPasswordValidatorHelper(exp)
@@ -1588,7 +1590,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
     func test_whenSignUpSubmitPassword_returns_attributeValidationFailed_it_returnsCorrectError() async {
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil)
-        validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(invalidAttributes: ["key"]))
+        validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(error: createContinueApiError(type: .invalidGrant), invalidAttributes: ["key"]))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitPasswordValidatorHelper(exp)
@@ -1636,7 +1638,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
             oobCode: nil,
             attributes: ["key": "value"]
         )
-        validatorMock.mockValidateSignUpContinueFunc(.success(""))
+        validatorMock.mockValidateSignUpContinueFunc(.success(continuationToken: ""))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitAttributesValidatorHelper(exp)
@@ -1725,7 +1727,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
             oobCode: nil,
             attributes: ["key": "value"]
         )
-        validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken 2", requiredAttributes: []))
+        validatorMock.mockValidateSignUpContinueFunc(.attributesRequired(continuationToken: "continuationToken 2", requiredAttributes: [], error: .init()))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitAttributesValidatorHelper(exp)
@@ -1748,7 +1750,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
             oobCode: nil,
             attributes: ["key": "value"]
         )
-        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2"))
+        validatorMock.mockValidateSignUpContinueFunc(.credentialRequired(continuationToken: "continuationToken 2", error: .init()))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitAttributesValidatorHelper(exp)
@@ -1770,7 +1772,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
             oobCode: nil,
             attributes: ["key": "value"]
         )
-        validatorMock.mockValidateSignUpContinueFunc(.unexpectedError(message: nil))
+        validatorMock.mockValidateSignUpContinueFunc(.unexpectedError(nil))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitAttributesValidatorHelper(exp)
@@ -1792,7 +1794,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
             oobCode: nil,
             attributes: ["key": "value"]
         )
-        validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(invalidAttributes: ["attribute"]))
+        validatorMock.mockValidateSignUpContinueFunc(.attributeValidationFailed(error: createContinueApiError(type: .invalidGrant), invalidAttributes: ["attribute"]))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitAttributesValidatorHelper(exp)
@@ -1822,7 +1824,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
 
         requestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
         requestProviderMock.expectedContinueRequestParameters = expectedContinueParams(grantType: .password, password: "password", oobCode: nil)
-        validatorMock.mockValidateSignUpContinueFunc(.success(continuationToken))
+        validatorMock.mockValidateSignUpContinueFunc(.success(continuationToken: continuationToken))
 
         let exp = expectation(description: "SignUpController expectation")
         let helper = prepareSignUpSubmitPasswordValidatorHelper(exp)
@@ -1840,7 +1842,7 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
 
         let exp2 = expectation(description: "SignInAfterSignUp expectation")
         signInControllerMock.expectation = exp2
-        signInControllerMock.continuationTokenResult = .init(.failure(.init()))
+        signInControllerMock.continuationTokenResult = .init(.init(.failure(SignInAfterSignUpError(correlationId: correlationId)), correlationId: correlationId))
         helper.signInAfterSignUpState?.signIn(delegate: SignInAfterSignUpDelegateStub())
         await fulfillment(of: [exp2], timeout: 1)
 
@@ -1963,4 +1965,33 @@ final class MSALNativeAuthSignUpControllerTests: MSALNativeAuthTestCase {
             context: contextMock
         )
     }
+
+    private func createInitiateApiError(type: MSALNativeAuthSignUpStartOauth2ErrorCode) -> MSALNativeAuthSignUpStartResponseError {
+        return .init(
+            error: type,
+            subError: nil,
+            errorDescription: nil,
+            errorCodes: nil,
+            errorURI: nil,
+            innerErrors: nil,
+            continuationToken: nil,
+            unverifiedAttributes: nil,
+            invalidAttributes: nil
+        )
+    }
+
+    private func createContinueApiError(type: MSALNativeAuthSignUpContinueOauth2ErrorCode) -> MSALNativeAuthSignUpContinueResponseError {
+        return .init(
+            error: type,
+            subError: nil,
+            errorDescription: nil,
+            errorCodes: nil,
+            errorURI: nil,
+            innerErrors: nil,
+            continuationToken: nil,
+            requiredAttributes: nil,
+            unverifiedAttributes: nil,
+            invalidAttributes: nil
+        )
+    }
 }
diff --git a/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift b/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift
index 4255380bd1..51568ecaf7 100644
--- a/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift
+++ b/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift
@@ -52,6 +52,8 @@ open class CredentialsDelegateSpy: CredentialsDelegate {
             XCTAssertTrue(Thread.isMainThread)
             XCTAssertEqual(error.type, expectedError.type)
             XCTAssertEqual(error.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error.correlationId, expectedError.correlationId)
+            XCTAssertEqual(error.errorCodes, expectedError.errorCodes)
             expectation.fulfill()
             return
         }
diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift
index ec56f1292d..cf18358841 100644
--- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift
+++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthNetworkMocks.swift
@@ -47,7 +47,7 @@ struct MSALNativeAuthNetworkStubs {
     }
 }
 
-class MSALNativeAuthRequestContextMock: MSIDRequestContext {
+class MSALNativeAuthRequestContextMock: MSALNativeAuthRequestContext {
 
     let mockCorrelationId: UUID
     var mockTelemetryRequestId = ""
@@ -58,19 +58,19 @@ class MSALNativeAuthRequestContextMock: MSIDRequestContext {
         self.mockCorrelationId = correlationId
     }
 
-    func correlationId() -> UUID {
+    override func correlationId() -> UUID {
         return mockCorrelationId
     }
 
-    func logComponent() -> String {
+    override func logComponent() -> String {
         return mockLogComponent
     }
 
-    func telemetryRequestId() -> String {
+    override func telemetryRequestId() -> String {
         return mockTelemetryRequestId
     }
 
-    func appRequestMetadata() -> [AnyHashable: Any] {
+    override func appRequestMetadata() -> [AnyHashable: Any] {
         return mockAppRequestMetadata
     }
 }
@@ -82,11 +82,15 @@ class MSALNativeAuthSignInResponseValidatorMock: MSALNativeAuthSignInResponseVal
     var expectedChallengeResponse: MSALNativeAuthSignInChallengeResponse?
     var expectedInitiateResponse: MSALNativeAuthSignInInitiateResponse?
     var expectedResponseError: Error?
-    var initiateValidatedResponse: MSALNativeAuthSignInInitiateValidatedResponse = .error(.userNotFound(message: nil))
-    var challengeValidatedResponse: MSALNativeAuthSignInChallengeValidatedResponse = .error(.expiredToken(message: nil))
+    var initiateValidatedResponse: MSALNativeAuthSignInInitiateValidatedResponse = .error(.userNotFound(.init(
+        error: .userNotFound))
+    )
+    var challengeValidatedResponse: MSALNativeAuthSignInChallengeValidatedResponse = .error(.expiredToken(.init(
+        error: .expiredToken)
+    ))
 
     
-    func validate(context: MSAL.MSALNativeAuthRequestContext, result: Result) -> MSAL.MSALNativeAuthSignInChallengeValidatedResponse {
+    func validate(context: MSIDRequestContext, result: Result) -> MSAL.MSALNativeAuthSignInChallengeValidatedResponse {
         checkConfAndContext(context)
         if case .success(let successChallengeResponse) = result, let expectedChallengeResponse = expectedChallengeResponse {
             XCTAssertEqual(successChallengeResponse.challengeType, expectedChallengeResponse.challengeType)
@@ -102,7 +106,7 @@ class MSALNativeAuthSignInResponseValidatorMock: MSALNativeAuthSignInResponseVal
         return challengeValidatedResponse
     }
     
-    func validate(context: MSAL.MSALNativeAuthRequestContext, result: Result) -> MSAL.MSALNativeAuthSignInInitiateValidatedResponse {
+    func validate(context: MSIDRequestContext, result: Result) -> MSAL.MSALNativeAuthSignInInitiateValidatedResponse {
         checkConfAndContext(context)
         if case .success(let successInitiateResponse) = result, let expectedInitiateResponse = expectedInitiateResponse {
             XCTAssertEqual(successInitiateResponse.challengeType, expectedInitiateResponse.challengeType)
@@ -115,7 +119,7 @@ class MSALNativeAuthSignInResponseValidatorMock: MSALNativeAuthSignInResponseVal
         return initiateValidatedResponse
     }
     
-    private func checkConfAndContext(_ context: MSAL.MSALNativeAuthRequestContext, config: MSIDConfiguration? = nil) {
+    private func checkConfAndContext(_ context: MSIDRequestContext, config: MSIDConfiguration? = nil) {
         if let expectedRequestContext = expectedRequestContext {
             XCTAssertEqual(expectedRequestContext.correlationId(), context.correlationId())
             XCTAssertEqual(expectedRequestContext.telemetryRequestId(), context.telemetryRequestId())
@@ -132,9 +136,9 @@ class MSALNativeAuthTokenResponseValidatorMock: MSALNativeAuthTokenResponseValid
     var expectedConfiguration: MSIDConfiguration?
     var expectedTokenResponse: MSIDCIAMTokenResponse?
     var expectedResponseError: Error?
-    var tokenValidatedResponse: MSALNativeAuthTokenValidatedResponse = .error(.generalError)
+    var tokenValidatedResponse: MSALNativeAuthTokenValidatedResponse = .error(.generalError(.init()))
 
-    func validate(context: MSAL.MSALNativeAuthRequestContext, msidConfiguration: MSIDConfiguration, result: Result) -> MSAL.MSALNativeAuthTokenValidatedResponse {
+    func validate(context: MSIDRequestContext, msidConfiguration: MSIDConfiguration, result: Result) -> MSAL.MSALNativeAuthTokenValidatedResponse {
         checkConfAndContext(context, config: msidConfiguration)
         if case .success(let successTokenResponse) = result, let expectedTokenResponse = expectedTokenResponse {
             XCTAssertEqual(successTokenResponse.accessToken, expectedTokenResponse.accessToken)
@@ -153,7 +157,7 @@ class MSALNativeAuthTokenResponseValidatorMock: MSALNativeAuthTokenResponseValid
         true
     }
 
-    private func checkConfAndContext(_ context: MSAL.MSALNativeAuthRequestContext, config: MSIDConfiguration? = nil) {
+    private func checkConfAndContext(_ context: MSIDRequestContext, config: MSIDConfiguration? = nil) {
         if let expectedRequestContext = expectedRequestContext {
             XCTAssertEqual(expectedRequestContext.correlationId(), context.correlationId())
             XCTAssertEqual(expectedRequestContext.telemetryRequestId(), context.telemetryRequestId())
diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift
index 90cb8f8fcb..0719b37590 100644
--- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift
+++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthResetPasswordControllerMock.swift
@@ -37,15 +37,15 @@ class MSALNativeAuthResetPasswordControllerMock: MSALNativeAuthResetPasswordCont
         return resetPasswordResponse
     }
 
-    func resendCode(username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse {
+    func resendCode(username: String, continuationToken: String, context: MSALNativeAuthRequestContext) async -> ResetPasswordResendCodeControllerResponse {
         return resendCodeResponse
     }
 
-    func submitCode(code: String, username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse {
+    func submitCode(code: String, username: String, continuationToken: String, context: MSALNativeAuthRequestContext) async -> ResetPasswordSubmitCodeControllerResponse {
         return submitCodeResponse
     }
 
-    func submitPassword(password: String, username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitPasswordControllerResponse {
+    func submitPassword(password: String, username: String, continuationToken: String, context: MSALNativeAuthRequestContext) async -> ResetPasswordSubmitPasswordControllerResponse {
         return submitPasswordResponse
     }
 }
diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift
index 33482b7c89..1eb861d524 100644
--- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift
+++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerMock.swift
@@ -40,19 +40,19 @@ class MSALNativeAuthSignUpControllerMock: MSALNativeAuthSignUpControlling {
         return startResult
     }
 
-    func resendCode(username: String, context: MSIDRequestContext, continuationToken: String) async -> SignUpResendCodeControllerResponse {
+    func resendCode(username: String, context: MSALNativeAuthRequestContext, continuationToken: String) async -> SignUpResendCodeControllerResponse {
         return resendCodeResult
     }
 
-    func submitCode(_ code: String, username: String, continuationToken: String, context: MSIDRequestContext) async -> MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse {
+    func submitCode(_ code: String, username: String, continuationToken: String, context: MSALNativeAuthRequestContext) async -> MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse {
         return submitCodeResult
     }
 
-    func submitPassword(_ password: String, username: String, continuationToken: String, context: MSIDRequestContext) async -> MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse {
+    func submitPassword(_ password: String, username: String, continuationToken: String, context: MSALNativeAuthRequestContext) async -> MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse {
         return submitPasswordResult
     }
 
-    func submitAttributes(_ attributes: [String : Any], username: String, continuationToken: String, context: MSIDRequestContext) async -> SignUpSubmitAttributesControllerResponse {
+    func submitAttributes(_ attributes: [String : Any], username: String, continuationToken: String, context: MSALNativeAuthRequestContext) async -> SignUpSubmitAttributesControllerResponse {
         return submitAttributesResult
     }
 }
diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift
index d64ae99fe1..d870d359af 100644
--- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift
+++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpControllerSpy.swift
@@ -46,7 +46,7 @@ class MSALNativeAuthSignUpControllerSpy: MSALNativeAuthSignUpControlling {
         self.context = parameters.context
         signUpStartPasswordCalled = true
         expectation.fulfill()
-        return .init(.error(.init(type: .generalError)))
+        return .init(.error(.init(type: .generalError, correlationId: parameters.context.correlationId())), correlationId: parameters.context.correlationId())
     }
 
     func signUpStart(
@@ -55,53 +55,53 @@ class MSALNativeAuthSignUpControllerSpy: MSALNativeAuthSignUpControlling {
         self.context = parameters.context
         signUpStartCalled = true
         expectation.fulfill()
-        return .init(.error(.init(type: .generalError)))
+        return .init(.error(.init(type: .generalError, correlationId: parameters.context.correlationId())), correlationId: parameters.context.correlationId())
     }
 
     func resendCode(
         username: String,
-        context: MSIDRequestContext,
+        context: MSALNativeAuthRequestContext,
         continuationToken: String
     ) async -> SignUpResendCodeControllerResponse {
         self.context = context
         resendCodeCalled = true
         expectation.fulfill()
-        return .init(.error(error: .init(), newState: nil))
+        return .init(.error(error: .init(correlationId: context.correlationId()), newState: nil), correlationId: context.correlationId())
     }
 
     func submitCode(
         _ code: String,
         username: String,
         continuationToken: String,
-        context: MSIDRequestContext
+        context: MSALNativeAuthRequestContext
     ) async -> MSALNativeAuthSignUpControlling.SignUpSubmitCodeControllerResponse {
         self.context = context
         submitCodeCalled = true
         expectation.fulfill()
-        return .init(.error(error: .init(type: .generalError), newState: nil))
+        return .init(.error(error: .init(type: .generalError, correlationId: context.correlationId()), newState: nil), correlationId: context.correlationId())
     }
 
     func submitPassword(
         _ password: String,
         username: String,
         continuationToken: String,
-        context: MSIDRequestContext
+        context: MSALNativeAuthRequestContext
     ) async -> MSALNativeAuthSignUpControlling.SignUpSubmitPasswordControllerResponse {
         self.context = context
         submitPasswordCalled = true
         expectation.fulfill()
-        return .init(.error(error: .init(type: .generalError), newState: nil))
+        return .init(.error(error: .init(type: .generalError, correlationId: context.correlationId()), newState: nil), correlationId: context.correlationId())
     }
 
     func submitAttributes(
         _ attributes: [String: Any],
         username: String,
         continuationToken: String,
-        context: MSIDRequestContext
+        context: MSALNativeAuthRequestContext
     ) async -> SignUpSubmitAttributesControllerResponse {
         self.context = context
         submitAttributesCalled = true
         expectation.fulfill()
-        return .init(.error(error: .init()))
+        return .init(.error(error: .init(correlationId: context.correlationId())), correlationId: context.correlationId())
     }
 }
diff --git a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift
index 6219473797..6145dda04a 100644
--- a/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift
+++ b/MSAL/test/unit/native_auth/mock/MSALNativeAuthSignUpRequestProviderMock.swift
@@ -71,7 +71,7 @@ class MSALNativeAuthSignUpRequestProviderMock: MSALNativeAuthSignUpRequestProvid
         self.throwErrorChallenge = throwError
     }
 
-    func challenge(token: String, context: MSIDRequestContext) throws -> MSIDHttpRequest {
+    func challenge(token: String, context: MSALNativeAuthRequestContext) throws -> MSIDHttpRequest {
         challengeCalled = true
         checkChallengeParameters(token: token, context: context)
 
diff --git a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift
index c48a4c8863..d754bc56d7 100644
--- a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift
+++ b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift
@@ -43,8 +43,7 @@ open class SignInPasswordStartDelegateSpy: SignInStartDelegate {
     public func onSignInStartError(error: MSAL.SignInStartError) {
         if let expectedError = expectedError {
             XCTAssertTrue(Thread.isMainThread)
-            XCTAssertEqual(error.type, expectedError.type)
-            XCTAssertEqual(error.errorDescription, expectedError.errorDescription)
+            checkErrors(error: error, expectedError: expectedError)
             expectation.fulfill()
             return
         }
@@ -90,8 +89,7 @@ class SignInPasswordRequiredDelegateSpy: SignInPasswordRequiredDelegate {
 
     func onSignInPasswordRequiredError(error: MSAL.PasswordRequiredError, newState: MSAL.SignInPasswordRequiredState?) {
         XCTAssertTrue(Thread.isMainThread)
-        XCTAssertEqual(error.type, expectedError?.type)
-        XCTAssertEqual(error.errorDescription, expectedError?.errorDescription)
+        checkErrors(error: error, expectedError: expectedError)
         newPasswordRequiredState = newState
         expectation.fulfill()
     }
@@ -318,7 +316,7 @@ open class SignInAfterSignUpDelegateSpy: SignInAfterSignUpDelegate {
     }
 
     public func onSignInAfterSignUpError(error: MSAL.SignInAfterSignUpError) {
-        XCTAssertEqual(error.errorDescription, expectedError?.errorDescription)
+        checkErrors(error: error, expectedError: expectedError)
         XCTAssertTrue(Thread.isMainThread)
         expectation.fulfill()
     }
@@ -350,7 +348,7 @@ class SignInAfterResetPasswordDelegateSpy: SignInAfterResetPasswordDelegate {
     }
 
     func onSignInAfterResetPasswordError(error: SignInAfterResetPasswordError) {
-        XCTAssertEqual(error.errorDescription, expectedError?.errorDescription)
+        checkErrors(error: error, expectedError: expectedError)
         XCTAssertTrue(Thread.isMainThread)
         expectation.fulfill()
     }
@@ -380,7 +378,7 @@ final class SignInAfterSignUpDelegateOptionalMethodsNotImplemented: SignInAfterS
     }
 
     public func onSignInAfterSignUpError(error: MSAL.SignInAfterSignUpError) {
-        XCTAssertEqual(error.errorDescription, expectedError?.errorDescription)
+        checkErrors(error: error, expectedError: expectedError)
         XCTAssertTrue(Thread.isMainThread)
         expectation.fulfill()
     }
@@ -400,8 +398,7 @@ final class SignInPasswordStartDelegateOptionalMethodNotImplemented: SignInStart
     func onSignInStartError(error: MSAL.SignInStartError) {
         if let expectedError = expectedError {
             XCTAssertTrue(Thread.isMainThread)
-            XCTAssertEqual(error.type, expectedError.type)
-            XCTAssertEqual(error.errorDescription, expectedError.errorDescription)
+            checkErrors(error: error, expectedError: expectedError)
             expectation.fulfill()
             return
         }
@@ -421,9 +418,38 @@ final class SignInCodeStartDelegateOptionalMethodNotImplemented: SignInStartDele
     }
 
     public func onSignInStartError(error: SignInStartError) {
-        XCTAssertEqual(error.type, expectedError?.type)
-        XCTAssertEqual(error.localizedDescription, expectedError?.localizedDescription)
+        checkErrors(error: error, expectedError: expectedError)
         XCTAssertTrue(Thread.isMainThread)
         expectation.fulfill()
     }
 }
+
+fileprivate func checkErrors(error: SignInStartError, expectedError: SignInStartError?) {
+    XCTAssertEqual(error.type, expectedError?.type)
+    XCTAssertEqual(error.errorDescription, expectedError?.errorDescription)
+    XCTAssertEqual(error.errorCodes, expectedError?.errorCodes)
+    XCTAssertEqual(error.errorUri, expectedError?.errorUri)
+    XCTAssertEqual(error.correlationId, expectedError?.correlationId)
+}
+
+fileprivate func checkErrors(error: PasswordRequiredError, expectedError: PasswordRequiredError?) {
+    XCTAssertEqual(error.type, expectedError?.type)
+    XCTAssertEqual(error.errorDescription, expectedError?.errorDescription)
+    XCTAssertEqual(error.errorCodes, expectedError?.errorCodes)
+    XCTAssertEqual(error.errorUri, expectedError?.errorUri)
+    XCTAssertEqual(error.correlationId, expectedError?.correlationId)
+}
+
+fileprivate func checkErrors(error: SignInAfterSignUpError, expectedError: SignInAfterSignUpError?) {
+    XCTAssertEqual(error.errorDescription, expectedError?.errorDescription)
+    XCTAssertEqual(error.errorCodes, expectedError?.errorCodes)
+    XCTAssertEqual(error.errorUri, expectedError?.errorUri)
+    XCTAssertEqual(error.correlationId, expectedError?.correlationId)
+}
+
+fileprivate func checkErrors(error: SignInAfterResetPasswordError, expectedError: SignInAfterResetPasswordError?) {
+    XCTAssertEqual(error.errorDescription, expectedError?.errorDescription)
+    XCTAssertEqual(error.errorCodes, expectedError?.errorCodes)
+    XCTAssertEqual(error.errorUri, expectedError?.errorUri)
+    XCTAssertEqual(error.correlationId, expectedError?.correlationId)
+}
diff --git a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift
index 46217c1c3b..4254b008ca 100644
--- a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift
+++ b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordControllerSpy.swift
@@ -45,36 +45,36 @@ class MSALNativeAuthResetPasswordControllerSpy: MSALNativeAuthResetPasswordContr
         resetPasswordCalled = true
         expectation.fulfill()
 
-        return .init(.error(.init(type: .generalError)))
+        return .init(.error(.init(type: .generalError, correlationId: .init())), correlationId: parameters.context.correlationId())
     }
 
-    func resendCode(username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordResendCodeControllerResponse {
+    func resendCode(username: String, continuationToken: String, context: MSALNativeAuthRequestContext) async -> ResetPasswordResendCodeControllerResponse {
         self.continuationToken = continuationToken
         self.username = username
         self.context = context
         resendCodeCalled = true
         expectation.fulfill()
 
-        return .init(.error(error: .init(), newState: nil))
+        return .init(.error(error: .init(correlationId: .init()), newState: nil), correlationId: context.correlationId())
     }
 
-    func submitCode(code: String, username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitCodeControllerResponse {
+    func submitCode(code: String, username: String, continuationToken: String, context: MSALNativeAuthRequestContext) async -> ResetPasswordSubmitCodeControllerResponse {
         self.continuationToken = continuationToken
         self.username = username
         self.context = context
         submitCodeCalled = true
         expectation.fulfill()
 
-        return .init(.error(error: .init(type: .generalError), newState: nil))
+        return .init(.error(error: .init(type: .generalError, correlationId: .init()), newState: nil), correlationId: context.correlationId())
     }
 
-    func submitPassword(password: String, username: String, continuationToken: String, context: MSIDRequestContext) async -> ResetPasswordSubmitPasswordControllerResponse {
+    func submitPassword(password: String, username: String, continuationToken: String, context: MSALNativeAuthRequestContext) async -> ResetPasswordSubmitPasswordControllerResponse {
         self.continuationToken = continuationToken
         self.username = username
         self.context = context
         submitPasswordCalled = true
         expectation.fulfill()
 
-        return .init(.error(error: .init(type: .generalError), newState: nil))
+        return .init(.error(error: .init(type: .generalError, correlationId: .init()), newState: nil), correlationId: context.correlationId())
     }
 }
diff --git a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordRequestProviderMock.swift b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordRequestProviderMock.swift
index c5fbd5d2ee..5b5bf42cb4 100644
--- a/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordRequestProviderMock.swift
+++ b/MSAL/test/unit/native_auth/mock/reset_password/MSALNativeAuthResetPasswordRequestProviderMock.swift
@@ -69,7 +69,7 @@ class MSALNativeAuthResetPasswordRequestProviderMock: MSALNativeAuthResetPasswor
         throwErrorChallenge = throwError
     }
 
-    func challenge(token: String, context: MSIDRequestContext) throws -> MSIDHttpRequest {
+    func challenge(token: String, context: MSALNativeAuthRequestContext) throws -> MSIDHttpRequest {
         challengeCalled = true
         checkParameters(token: token, context: context)
 
diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthCustomErrorSerializerTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthCustomErrorSerializerTests.swift
new file mode 100644
index 0000000000..a4ff930964
--- /dev/null
+++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthCustomErrorSerializerTests.swift
@@ -0,0 +1,56 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+
+import XCTest
+@testable import MSAL
+
+final class MSALNativeAuthCustomErrorSerializerTests: XCTestCase {
+
+    func test_errorDeserializer_usesCorrelationIdFromHeaders() {
+        let headers = [
+            "client-request-id": "9958D9BC-D9D1-43E4-B5CA-5A7B0C3F28B0",
+            "header2": "value2"
+        ]
+        let responseString = """
+        {
+          "error": "invalid_grant",
+          "error_description": "New password is weak",
+          "suberror": "password_too_weak",
+          "correlation_id": "081f5395-539f-498d-8175-1d71e52601de"
+        }
+        """
+
+        let sut = MSALNativeAuthCustomErrorSerializer()
+        
+        let httpResponse = HTTPURLResponse(url: URL(string: "https://contoso.com")!, statusCode: 400, httpVersion: nil, headerFields: headers)
+
+        do {
+            _ = try sut.responseObject(for: httpResponse, data: responseString.data(using: .utf8), context: nil)
+        } catch {
+            let result = (error as? MSALNativeAuthSignUpStartResponseError)?.correlationId
+            XCTAssertEqual(result?.uuidString, "9958D9BC-D9D1-43E4-B5CA-5A7B0C3F28B0")
+        }
+    }
+}
diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift
index cb07889a84..988195f8e2 100644
--- a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift
+++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift
@@ -33,11 +33,7 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase {
     let baseUrl = URL(string: DEFAULT_TEST_AUTHORITY)!
     var config: MSALNativeAuthConfiguration! = nil
     
-    let context = MSALNativeAuthRequestContext(
-        correlationId: .init(
-            UUID(uuidString: DEFAULT_TEST_UID)!
-        )
-    )
+    let context = MSALNativeAuthRequestContext(correlationId: UUID(uuidString: DEFAULT_TEST_UID)!)
 
     func test_signInInititate_getsConfiguredSuccessfully() throws {
         XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [.password]))
diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestableTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestableTests.swift
index 5be2a8782c..32a7835655 100644
--- a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestableTests.swift
+++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestableTests.swift
@@ -31,11 +31,7 @@ final class MSALNativeAuthRequestableTests: XCTestCase {
     var request: MSALNativeAuthResetPasswordStartRequestParameters! = nil
 
     override func setUpWithError() throws {
-        let context = MSALNativeAuthRequestContext(
-                correlationId: .init(
-                UUID(uuidString: DEFAULT_TEST_UID)!
-            )
-        )
+        let context = MSALNativeAuthRequestContext(correlationId: UUID(uuidString: DEFAULT_TEST_UID)!)
         
         request = MSALNativeAuthResetPasswordStartRequestParameters(context: context, username: DEFAULT_TEST_ID_TOKEN_USERNAME)
     }
diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthResponseCorrelatableTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthResponseCorrelatableTests.swift
new file mode 100644
index 0000000000..489b873e46
--- /dev/null
+++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthResponseCorrelatableTests.swift
@@ -0,0 +1,55 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+
+import XCTest
+@testable import MSAL
+@_implementationOnly import MSAL_Unit_Test_Private
+
+final class MSALNativeAuthResponseCorrelatableTests: XCTestCase {
+
+    private var sut: ResponseCorrelatableClass!
+
+    override func setUp() async throws {
+        try await super.setUp()
+        sut = ResponseCorrelatableClass()
+    }
+
+    func test_serializeExpectedCorrelationId() {
+        let originalHeaders = [
+            "client-request-id": "9958D9BC-D9D1-43E4-B5CA-5A7B0C3F28B0",
+            "header2": "value2",
+        ]
+
+        let httpResponse = HTTPURLResponse(url: URL(string: "http://contoso.com")!, statusCode: 200, httpVersion: nil, headerFields: originalHeaders)
+
+        let correlationIdString = ResponseCorrelatableClass.retrieveCorrelationIdFromHeaders(from: httpResponse)
+
+        XCTAssertEqual(correlationIdString, UUID(uuidString: "9958D9BC-D9D1-43E4-B5CA-5A7B0C3F28B0"))
+    }
+}
+
+private class ResponseCorrelatableClass: MSALNativeAuthResponseCorrelatable {
+    var correlationId: UUID?
+}
diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthResponseSerializerTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthResponseSerializerTests.swift
index a896ddb1e4..cfc00cc950 100644
--- a/MSAL/test/unit/native_auth/network/MSALNativeAuthResponseSerializerTests.swift
+++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthResponseSerializerTests.swift
@@ -67,9 +67,37 @@ final class MSALNativeAuthResponseSerializerTests: XCTestCase {
         """
         XCTAssertThrowsError(try serializer.responseObject(for: nil, data: wrongResponseString.data(using: .utf8) , context: nil))
     }
+
+    func testSerialize_headersCorrelationId() throws {
+        let originalHeaders = [
+            "client-request-id": "9958D9BC-D9D1-43E4-B5CA-5A7B0C3F28B0",
+            "header2": "value2"
+        ]
+        let responseString = """
+        {
+          "token_type": "Bearer",
+          "scope": "scope",
+          "expires_in": 4141,
+          "extended_expires_in": 4141,
+          "access_token": "access",
+          "refresh_token": "refresh",
+          "id_token": "id"
+        }
+        """
+
+        let httpResponse = HTTPURLResponse(url: URL(string: "https://contoso.com")!, statusCode: 200, httpVersion: nil, headerFields: originalHeaders)
+
+        let serializer = MSALNativeAuthResponseSerializer()
+
+        let result = try serializer.responseObject(for: httpResponse, data: responseString.data(using: .utf8), context: nil)
+
+        let resultCorrelationId = (result as? MSALNativeAuthResponseCorrelatable)?.correlationId
+
+        XCTAssertEqual(resultCorrelationId?.uuidString, "9958D9BC-D9D1-43E4-B5CA-5A7B0C3F28B0")
+    }
 }
 
-private struct ResponseStub: Decodable {
+private struct ResponseStub: Decodable, MSALNativeAuthResponseCorrelatable {
     let tokenType: String
     let scope: String
     let expiresIn: Int
@@ -77,4 +105,5 @@ private struct ResponseStub: Decodable {
     let accessToken: String
     let refreshToken: String
     let idToken: String
+    var correlationId: UUID?
 }
diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift
index 8d533fe0fc..80e619a5c9 100644
--- a/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift
+++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthSignUpRequestProviderTests.swift
@@ -31,11 +31,11 @@ final class MSALNativeAuthSignUpRequestProviderTests: XCTestCase {
 
     private var sut: MSALNativeAuthSignUpRequestProvider!
     private var telemetryProvider: MSALNativeAuthTelemetryProvider!
-    private var context: MSIDRequestContext!
+    private var context: MSALNativeAuthRequestContextMock!
 
     override func setUpWithError() throws {
         telemetryProvider = MSALNativeAuthTelemetryProvider()
-        context = MSALNativeAuthRequestContext(correlationId: .init(uuidString: DEFAULT_TEST_UID)!)
+        context = MSALNativeAuthRequestContextMock(correlationId: .init(uuidString: DEFAULT_TEST_UID)!)
 
         sut = .init(requestConfigurator: MSALNativeAuthRequestConfigurator(config: MSALNativeAuthConfigStubs.configuration),
                     telemetryProvider: telemetryProvider)
diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift
index 02a9922f40..516d32d911 100644
--- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift
@@ -29,60 +29,113 @@ final class MSALNativeAuthResetPasswordChallengeResponseErrorTests: XCTestCase {
 
     private var sut: MSALNativeAuthResetPasswordChallengeResponseError!
     private let testDescription = "testDescription"
+    private let testErrorCodes = [1, 2, 3]
+    private let correlationId = UUID()
+    private let testErrorUri = "test error uri"
+
+    private func createApiChallengeError(type: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode) -> MSALNativeAuthResetPasswordChallengeResponseError {
+        .init(
+            error: type,
+            errorDescription: testDescription,
+            errorCodes: testErrorCodes,
+            errorURI: testErrorUri,
+            correlationId: correlationId
+        )
+    }
+
+    private func createApiResendCodeError(type: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode) -> MSALNativeAuthResetPasswordChallengeResponseError {
+        .init(
+            error: type,
+            errorDescription: testDescription,
+            errorCodes: testErrorCodes,
+            errorURI: testErrorUri,
+            correlationId: correlationId
+        )
+    }
 
     // MARK: - to ResetPasswordStartError tests
 
     func test_toResetPasswordStartPublicError_unauthorizedClient() {
-        sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .unauthorizedClient, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil)
-        let error = sut.toResetPasswordStartPublicError()
+        sut = createApiChallengeError(type: .unauthorizedClient)
+        let error = sut.toResetPasswordStartPublicError(correlationId: correlationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 
     func test_toResetPasswordStartPublicError_invalidRequest() {
-        sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .invalidRequest, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil)
-        let error = sut.toResetPasswordStartPublicError()
+        sut = createApiChallengeError(type: .invalidRequest)
+        let error = sut.toResetPasswordStartPublicError(correlationId: correlationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertNotNil(error.errorDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
     }
 
     func test_toResetPasswordStartPublicError_expiredToken() {
-        sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .expiredToken, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil)
-        let error = sut.toResetPasswordStartPublicError()
+        sut = createApiChallengeError(type: .expiredToken)
+        let error = sut.toResetPasswordStartPublicError(correlationId: correlationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 
     func test_toResetPasswordStartPublicError_unsupportedChallengeType() {
-        sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .unsupportedChallengeType, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil)
-        let error = sut.toResetPasswordStartPublicError()
+        sut = createApiChallengeError(type: .unsupportedChallengeType)
+        let error = sut.toResetPasswordStartPublicError(correlationId: correlationId)
+        
         XCTAssertEqual(error.type, .generalError)
-        XCTAssertNotNil(error.errorDescription)
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 
     // MARK: - to ResendCodePublicError tests
 
     func test_toResendCodePublicError_unauthorizedClient() {
-        sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .unauthorizedClient, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil)
-        let error = sut.toResendCodePublicError()
+        sut = createApiResendCodeError(type: .unauthorizedClient)
+        let error = sut.toResendCodePublicError(correlationId: correlationId)
+        
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 
     func test_toResendCodePublicError_invalidRequest() {
-        sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .invalidRequest, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil)
-        let error = sut.toResendCodePublicError()
+        sut = createApiResendCodeError(type: .invalidRequest)
+        let error = sut.toResendCodePublicError(correlationId: correlationId)
+
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 
     func test_toResendCodePublicError_expiredToken() {
-        sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .expiredToken, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil)
-        let error = sut.toResendCodePublicError()
+        sut = createApiResendCodeError(type: .expiredToken)
+        let error = sut.toResendCodePublicError(correlationId: correlationId)
+        
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 
     func test_toResendCodePublicError_unsupportedChallengeType() {
-        sut = MSALNativeAuthResetPasswordChallengeResponseError(error: .unsupportedChallengeType, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil)
-        let error = sut.toResendCodePublicError()
+        sut = createApiResendCodeError(type: .unsupportedChallengeType)
+        let error = sut.toResendCodePublicError(correlationId: correlationId)
+        
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 }
diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift
index 7359144745..92216c2715 100644
--- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift
@@ -29,48 +29,86 @@ final class MSALNativeAuthResetPasswordContinueResponseErrorTests: XCTestCase {
 
     private var sut: MSALNativeAuthResetPasswordContinueResponseError!
     private let testDescription = "testDescription"
+    private let testErrorCodes = [1, 2, 3]
+    private let correlationId = UUID()
+    private let testErrorUri = "test error uri"
+
+    private func createApiError(type: MSALNativeAuthResetPasswordContinueOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil) -> MSALNativeAuthResetPasswordContinueResponseError {
+        .init(
+            error: type,
+            subError: subError,
+            errorDescription: testDescription,
+            errorCodes: testErrorCodes,
+            errorURI: testErrorUri,
+            correlationId: correlationId
+        )
+    }
 
     // MARK: - to toVerifyCodePublicError tests
     
     func test_toResetPasswordStartPublicError_invalidRequest() {
-        sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidRequest, subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil)
-        let error = sut.toVerifyCodePublicError()
+        sut = createApiError(type: .invalidRequest)
+        let error = sut.toVerifyCodePublicError(correlationId: correlationId)
+
         XCTAssertEqual(error.type, .generalError)
-        XCTAssertNotNil(error.errorDescription)
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_toResetPasswordStartPublicError_unauthorizedClient() {
-        sut = MSALNativeAuthResetPasswordContinueResponseError(error: .unauthorizedClient, subError: nil, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil)
-        let error = sut.toVerifyCodePublicError()
+        sut = createApiError(type: .unauthorizedClient)
+        let error = sut.toVerifyCodePublicError(correlationId: correlationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 
     func test_toResetPasswordStartPublicError_invalidGrant() {
-        sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidGrant, subError: nil, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil)
-        let error = sut.toVerifyCodePublicError()
+        sut = createApiError(type: .invalidGrant)
+        let error = sut.toVerifyCodePublicError(correlationId: correlationId)
+        
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_toResetPasswordStartPublicError_expiredToken() {
-        sut = MSALNativeAuthResetPasswordContinueResponseError(error: .expiredToken, subError: nil, errorDescription: testDescription, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil)
-        let error = sut.toVerifyCodePublicError()
+        sut = createApiError(type: .expiredToken)
+        let error = sut.toVerifyCodePublicError(correlationId: correlationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 
     func test_toResetPasswordStartPublicError_unsupportedChallengeType() {
-        sut = MSALNativeAuthResetPasswordContinueResponseError(error: .verificationRequired, subError: nil, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil)
-        let error = sut.toVerifyCodePublicError()
+        sut = createApiError(type: .verificationRequired)
+        let error = sut.toVerifyCodePublicError(correlationId: correlationId)
+        
         XCTAssertEqual(error.type, .generalError)
-        XCTAssertNotNil(error.errorDescription)
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_toResetPasswordStartPublicError_invalidOOBValue() {
-        sut = MSALNativeAuthResetPasswordContinueResponseError(error: .invalidGrant, subError: .invalidOOBValue, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil, continuationToken: nil)
-        let error = sut.toVerifyCodePublicError()
+        sut = createApiError(type: .invalidGrant, subError: .invalidOOBValue)
+        let error = sut.toVerifyCodePublicError(correlationId: correlationId)
+
         XCTAssertEqual(error.type, .invalidCode)
-        XCTAssertNotNil(error.errorDescription)
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 }
diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift
index 4e9044f5d2..57511ef43e 100644
--- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift
@@ -29,51 +29,59 @@ final class MSALNativeAuthResetPasswordPollCompletionResponseErrorTests: XCTestC
 
     private var sut: MSALNativeAuthResetPasswordPollCompletionResponseError!
     private let testDescription = "testDescription"
+    private let testErrorCodes = [1, 2, 3]
+    private let testCorrelationId = UUID()
+    private let testErrorUri = "test error uri"
 
     // MARK: - toPasswordRequiredPublicError tests
     
     func test_toPasswordRequiredPublicError_invalidRequest() {
-        testPasswordRequiredError(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError)
+        testPasswordRequiredError(code: .invalidRequest, expectedErrorType: .generalError)
     }
 
     func test_toPasswordRequiredPublicError_unauthorizedClient() {
-        testPasswordRequiredError(code: .unauthorizedClient, description: "General error", expectedErrorType: .generalError)
+        testPasswordRequiredError(code: .unauthorizedClient, expectedErrorType: .generalError)
     }
 
     func test_toPasswordRequiredPublicError_expiredToken() {
-        testPasswordRequiredError(code: .expiredToken, description: testDescription, expectedErrorType: .generalError)
+        testPasswordRequiredError(code: .expiredToken, expectedErrorType: .generalError)
     }
 
     func test_toPasswordRequiredPublicError_passwordTooWeak() {
-        testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword)
+        testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooWeak, expectedErrorType: .invalidPassword)
     }
 
     func test_toPasswordRequiredPublicError_passwordTooShort() {
-        testPasswordRequiredError(code: .invalidGrant,subError: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword)
+        testPasswordRequiredError(code: .invalidGrant,subError: .passwordTooShort, expectedErrorType: .invalidPassword)
     }
 
     func test_toPasswordRequiredPublicError_passwordTooLong() {
-        testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooLong, description: "General error", expectedErrorType: .invalidPassword)
+        testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooLong, expectedErrorType: .invalidPassword)
     }
 
     func test_toPasswordRequiredPublicError_passwordRecentlyUsed() {
-        testPasswordRequiredError(code: .invalidGrant, subError: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword)
+        testPasswordRequiredError(code: .invalidGrant, subError: .passwordRecentlyUsed, expectedErrorType: .invalidPassword)
     }
 
     func test_toPasswordRequiredPublicError_passwordBanned() {
-        testPasswordRequiredError(code: .invalidGrant, subError: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword)
+        testPasswordRequiredError(code: .invalidGrant, subError: .passwordBanned, expectedErrorType: .invalidPassword)
     }
     
     func test_toPasswordRequiredPublicError_userNotFound() {
-        testPasswordRequiredError(code: .userNotFound, description: testDescription, expectedErrorType: .generalError)
+        testPasswordRequiredError(code: .userNotFound, expectedErrorType: .generalError)
     }
     
     // MARK: private methods
     
-    private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) {
-        sut = MSALNativeAuthResetPasswordPollCompletionResponseError(error: code, subError: subError, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil)
-        let error = sut.toPasswordRequiredPublicError()
+    private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, expectedErrorType: PasswordRequiredError.ErrorType) {
+
+        sut = MSALNativeAuthResetPasswordPollCompletionResponseError(error: code, subError: subError, errorDescription: testDescription, errorCodes: testErrorCodes, errorURI: testErrorUri, correlationId: testCorrelationId)
+        let error = sut.toPasswordRequiredPublicError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, expectedErrorType)
-        XCTAssertEqual(error.errorDescription, description)
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 }
diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift
index 2c21c5e709..1c0419b986 100644
--- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift
@@ -29,47 +29,53 @@ final class MSALNativeAuthResetPasswordSubmitResponseErrorTests: XCTestCase {
 
     private var sut: MSALNativeAuthResetPasswordSubmitResponseError!
     private let testDescription = "testDescription"
+    private let testErrorCodes = [1, 2, 3]
+    private let testCorrelationId = UUID()
+    private let testErrorUri = "test error uri"
 
     // MARK: - toPasswordRequiredPublicError tests
 
     func test_toPasswordRequiredPublicError_invalidRequest() {
-        testPasswordRequiredError(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError)
+        testPasswordRequiredError(code: .invalidRequest, expectedErrorType: .generalError)
     }
 
     func test_toPasswordRequiredPublicError_unauthorizedClient() {
-        testPasswordRequiredError(code: .unauthorizedClient, description: "General error", expectedErrorType: .generalError)
+        testPasswordRequiredError(code: .unauthorizedClient, expectedErrorType: .generalError)
     }
 
     func test_toPasswordRequiredPublicError_expiredToken() {
-        testPasswordRequiredError(code: .expiredToken, description: testDescription, expectedErrorType: .generalError)
+        testPasswordRequiredError(code: .expiredToken, expectedErrorType: .generalError)
     }
 
     func test_toPasswordRequiredPublicError_passwordTooWeak() {
-        testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword)
+        testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooWeak, expectedErrorType: .invalidPassword)
     }
 
     func test_toPasswordRequiredPublicError_passwordTooShort() {
-        testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword)
+        testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooShort, expectedErrorType: .invalidPassword)
     }
 
     func test_toPasswordRequiredPublicError_passwordTooLong() {
-        testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooLong, description: "General error", expectedErrorType: .invalidPassword)
+        testPasswordRequiredError(code: .invalidGrant, subError: .passwordTooLong, expectedErrorType: .invalidPassword)
     }
 
     func test_toPasswordRequiredPublicError_passwordRecentlyUsed() {
-        testPasswordRequiredError(code: .invalidGrant, subError: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword)
+        testPasswordRequiredError(code: .invalidGrant, subError: .passwordRecentlyUsed, expectedErrorType: .invalidPassword)
     }
 
     func test_toPasswordRequiredPublicError_passwordBanned() {
-        testPasswordRequiredError(code: .invalidGrant, subError: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword)
+        testPasswordRequiredError(code: .invalidGrant, subError: .passwordBanned, expectedErrorType: .invalidPassword)
     }
     
     // MARK: private methods
     
-    private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) {
-        sut = MSALNativeAuthResetPasswordSubmitResponseError(error: code, subError: subError, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, target: nil)
-        let error = sut.toPasswordRequiredPublicError()
+    private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, expectedErrorType: PasswordRequiredError.ErrorType) {
+        sut = MSALNativeAuthResetPasswordSubmitResponseError(error: code, subError: subError, errorDescription: testDescription, errorCodes: testErrorCodes, errorURI: testErrorUri, correlationId: testCorrelationId)
+        let error = sut.toPasswordRequiredPublicError(correlationId: testCorrelationId)
         XCTAssertEqual(error.type, expectedErrorType)
-        XCTAssertEqual(error.errorDescription, description)
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 }
diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift
index be12219c02..913efd14c3 100644
--- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift
@@ -29,81 +29,97 @@ final class MSALNativeAuthSignUpChallengeResponseErrorTests: XCTestCase {
 
     private var sut: MSALNativeAuthSignUpChallengeResponseError!
     private let testDescription = "testDescription"
+    private let testErrorCodes = [1, 2, 3]
+    private let testCorrelationId = UUID()
+    private let testErrorUri = "test error uri"
 
     // MARK: - to SignUpCodeStartError tests
 
     func test_toSignUpCodeStartPublicError_unauthorizedClient() {
-        testSignUpChallengeErrorToSignUpStart(code: .unauthorizedClient, description: testDescription, expectedErrorType: .generalError)
+        testSignUpChallengeErrorToSignUpStart(code: .unauthorizedClient, expectedErrorType: .generalError)
     }
 
     func test_toSignUpCodeStartPublicError_unsupportedChallengeType() {
-        testSignUpChallengeErrorToSignUpStart(code: .unsupportedChallengeType, description: "General error", expectedErrorType: .generalError)
+        testSignUpChallengeErrorToSignUpStart(code: .unsupportedChallengeType, expectedErrorType: .generalError)
     }
 
     func test_toSignUpCodeStartPublicError_expiredToken() {
-        testSignUpChallengeErrorToSignUpStart(code: .expiredToken, description: testDescription, expectedErrorType: .generalError)
+        testSignUpChallengeErrorToSignUpStart(code: .expiredToken, expectedErrorType: .generalError)
     }
 
     func test_toSignUpCodeStartPublicError_invalidRequest() {
-        testSignUpChallengeErrorToSignUpStart(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError)
+        testSignUpChallengeErrorToSignUpStart(code: .invalidRequest, expectedErrorType: .generalError)
     }
 
     // MARK: - to ResendCodeError tests
 
     func test_toResendCodePublicError_unauthorizedClient() {
-        testSignUpChallengeErrorToResendCodePublic(code: .unauthorizedClient, description: testDescription)
+        testSignUpChallengeErrorToResendCodePublic(code: .unauthorizedClient)
     }
 
     func test_toResendCodePublicError_unsupportedChallengeType() {
-        testSignUpChallengeErrorToResendCodePublic(code: .unsupportedChallengeType, description: "General error")
+        testSignUpChallengeErrorToResendCodePublic(code: .unsupportedChallengeType)
     }
 
     func test_toResendCodePublicError_expiredToken() {
-        testSignUpChallengeErrorToResendCodePublic(code: .expiredToken, description: testDescription)
+        testSignUpChallengeErrorToResendCodePublic(code: .expiredToken)
     }
 
     func test_toResendCodePublicError_invalidRequest() {
-        testSignUpChallengeErrorToResendCodePublic(code: .invalidRequest, description: testDescription)
+        testSignUpChallengeErrorToResendCodePublic(code: .invalidRequest)
     }
 
     // MARK: - to PasswordRequiredError tests
 
     func test_toPasswordRequiredPublicError_unauthorizedClient() {
-        testSignUpChallengeErrorToPasswordRequired(code: .unauthorizedClient, description: testDescription, expectedErrorType: .generalError)
+        testSignUpChallengeErrorToPasswordRequired(code: .unauthorizedClient, expectedErrorType: .generalError)
     }
 
     func test_toPasswordRequiredPublicError_unsupportedChallengeType() {
-        testSignUpChallengeErrorToPasswordRequired(code: .unsupportedChallengeType, description: "General error", expectedErrorType: .generalError)
+        testSignUpChallengeErrorToPasswordRequired(code: .unsupportedChallengeType, expectedErrorType: .generalError)
     }
 
     func test_toPasswordRequiredPublicError_expiredToken() {
-        testSignUpChallengeErrorToPasswordRequired(code: .expiredToken, description: testDescription, expectedErrorType: .generalError)
+        testSignUpChallengeErrorToPasswordRequired(code: .expiredToken, expectedErrorType: .generalError)
     }
 
     func test_toPasswordRequiredPublicError_invalidRequest() {
-        testSignUpChallengeErrorToPasswordRequired(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError)
+        testSignUpChallengeErrorToPasswordRequired(code: .invalidRequest, expectedErrorType: .generalError)
     }
         
     // MARK: private methods
     
-    private func testSignUpChallengeErrorToSignUpStart(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?, expectedErrorType: SignUpStartError.ErrorType) {
-        sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil)
-        let error = sut.toSignUpStartPublicError()
+    private func testSignUpChallengeErrorToSignUpStart(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, expectedErrorType: SignUpStartError.ErrorType) {
+        sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: testDescription, errorCodes: testErrorCodes, errorURI: testErrorUri, innerErrors: nil)
+
+        let error = sut.toSignUpStartPublicError(correlationId: testCorrelationId)
         XCTAssertEqual(error.type, expectedErrorType)
-        XCTAssertEqual(error.errorDescription, description)
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
-    private func testSignUpChallengeErrorToResendCodePublic(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?) {
-        sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil)
-        let error = sut.toResendCodePublicError()
-        XCTAssertEqual(error.errorDescription, description)
+    private func testSignUpChallengeErrorToResendCodePublic(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode) {
+        sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: testDescription, errorCodes: testErrorCodes, errorURI: testErrorUri, innerErrors: nil)
+
+        let error = sut.toResendCodePublicError(correlationId: testCorrelationId)
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
-    private func testSignUpChallengeErrorToPasswordRequired(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) {
-        sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil)
-        let error = sut.toPasswordRequiredPublicError()
+    private func testSignUpChallengeErrorToPasswordRequired(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, expectedErrorType: PasswordRequiredError.ErrorType) {
+
+        sut = MSALNativeAuthSignUpChallengeResponseError(error: code, errorDescription: testDescription, errorCodes: testErrorCodes, errorURI: testErrorUri, innerErrors: nil)
+
+        let error = sut.toPasswordRequiredPublicError(correlationId: testCorrelationId)
         XCTAssertEqual(error.type, expectedErrorType)
-        XCTAssertEqual(error.errorDescription, description)
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
 }
diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift
index 6891d2062f..eab177da1b 100644
--- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift
@@ -29,212 +29,228 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase {
     
     private var sut: MSALNativeAuthSignUpContinueResponseError!
     private let testDescription = "testDescription"
-    
+    private let testErrorCodes = [1, 2, 3]
+    private let testCorrelationId = UUID()
+    private let testErrorUri = "test error uri"
+
     // MARK: - to toVerifyCodePublicError tests
     
     func test_toVerifyCodePublicError_invalidRequest() {
-        testSignUpContinueErrorToVerifyCode(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToVerifyCode(code: .invalidRequest, expectedErrorType: .generalError)
     }
     
     func test_toVerifyCodePublicError_unauthorizedClient() {
-        testSignUpContinueErrorToVerifyCode(code: .unauthorizedClient, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToVerifyCode(code: .unauthorizedClient, expectedErrorType: .generalError)
     }
     
     func test_toVerifyCodePublicError_invalidGrant() {
-        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, expectedErrorType: .generalError)
     }
     
     func test_toVerifyCodePublicError_expiredToken() {
-        testSignUpContinueErrorToVerifyCode(code: .expiredToken, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToVerifyCode(code: .expiredToken, expectedErrorType: .generalError)
     }
     
     func test_toVerifyCodePublicError_passwordTooWeak() {
-        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordTooWeak, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordTooWeak, expectedErrorType: .generalError)
     }
     
     func test_toVerifyCodePublicError_passwordTooShort() {
-        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordTooShort, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordTooShort, expectedErrorType: .generalError)
     }
     
     func test_toVerifyCodePublicError_passwordTooLong() {
-        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordTooLong, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordTooLong, expectedErrorType: .generalError)
     }
     
     func test_toVerifyCodePublicError_passwordRecentlyUsed() {
-        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordRecentlyUsed, expectedErrorType: .generalError)
     }
     
     func test_toVerifyCodePublicError_passwordBanned() {
-        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordBanned, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .passwordBanned, expectedErrorType: .generalError)
     }
     
     func test_toVerifyCodePublicError_userAlreadyExists() {
-        testSignUpContinueErrorToVerifyCode(code: .userAlreadyExists, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToVerifyCode(code: .userAlreadyExists, expectedErrorType: .generalError)
     }
     
     func test_toVerifyCodePublicError_attributesRequired() {
-        testSignUpContinueErrorToVerifyCode(code: .attributesRequired, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToVerifyCode(code: .attributesRequired, expectedErrorType: .generalError)
     }
     
     func test_toVerifyCodePublicError_verificationRequired() {
-        testSignUpContinueErrorToVerifyCode(code: .verificationRequired, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToVerifyCode(code: .verificationRequired, expectedErrorType: .generalError)
     }
     
     func test_toVerifyCodePublicError_attributeValidationFailed() {
-        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .attributeValidationFailed, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .attributeValidationFailed, expectedErrorType: .generalError)
     }
     
     func test_toVerifyCodePublicError_credentialRequired() {
-        testSignUpContinueErrorToVerifyCode(code: .credentialRequired, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToVerifyCode(code: .credentialRequired, expectedErrorType: .generalError)
     }
     
     func test_toVerifyCodePublicError_invalidOOBValue() {
-        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .invalidOOBValue, description: testDescription, expectedErrorType: .invalidCode)
+        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .invalidOOBValue, expectedErrorType: .invalidCode)
     }
     
     // MARK: - toPasswordRequiredPublicError tests
     
     func test_toPasswordRequiredPublicError_invalidRequest() {
-        testSignUpContinueErrorToPasswordRequired(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToPasswordRequired(code: .invalidRequest, expectedErrorType: .generalError)
     }
     
     func test_toPasswordRequiredPublicError_unauthorizedClient() {
-        testSignUpContinueErrorToPasswordRequired(code: .unauthorizedClient, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToPasswordRequired(code: .unauthorizedClient, expectedErrorType: .generalError)
     }
     
     func test_toPasswordRequiredPublicError_invalidGrant() {
-        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, expectedErrorType: .generalError)
     }
     
     func test_toPasswordRequiredPublicError_expiredToken() {
-        testSignUpContinueErrorToPasswordRequired(code: .expiredToken, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToPasswordRequired(code: .expiredToken, expectedErrorType: .generalError)
     }
     
     func test_toPasswordRequiredPublicError_passwordTooWeak() {
-        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword)
+        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordTooWeak, expectedErrorType: .invalidPassword)
     }
     
     func test_toPasswordRequiredPublicError_passwordTooShort() {
-        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword)
+        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordTooShort, expectedErrorType: .invalidPassword)
     }
     
     func test_toPasswordRequiredPublicError_passwordTooLong() {
-        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordTooLong, description: testDescription, expectedErrorType: .invalidPassword)
+        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordTooLong, expectedErrorType: .invalidPassword)
     }
     
     func test_toPasswordRequiredPublicError_passwordRecentlyUsed() {
-        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword)
+        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordRecentlyUsed, expectedErrorType: .invalidPassword)
     }
     
     func test_toPasswordRequiredPublicError_passwordBanned() {
-        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword)
+        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .passwordBanned, expectedErrorType: .invalidPassword)
     }
     
     func test_toPasswordRequiredPublicError_userAlreadyExists() {
-        testSignUpContinueErrorToPasswordRequired(code: .userAlreadyExists, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToPasswordRequired(code: .userAlreadyExists, expectedErrorType: .generalError)
     }
     
     func test_toPasswordRequiredPublicError_attributesRequired() {
-        testSignUpContinueErrorToPasswordRequired(code: .attributesRequired, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToPasswordRequired(code: .attributesRequired, expectedErrorType: .generalError)
     }
     
     func test_toPasswordRequiredPublicError_verificationRequired() {
-        testSignUpContinueErrorToPasswordRequired(code: .verificationRequired, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToPasswordRequired(code: .verificationRequired, expectedErrorType: .generalError)
     }
     
     func test_toPasswordRequiredPublicError_attributeValidationFailed() {
-        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .attributeValidationFailed, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .attributeValidationFailed, expectedErrorType: .generalError)
     }
     
     func test_toPasswordRequiredPublicError_credentialRequired() {
-        testSignUpContinueErrorToPasswordRequired(code: .credentialRequired, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToPasswordRequired(code: .credentialRequired, expectedErrorType: .generalError)
     }
     
     func test_toPasswordRequiredPublicError_invalidOOBValue() {
-        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .invalidOOBValue, description: testDescription, expectedErrorType: .generalError)
+        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .invalidOOBValue, expectedErrorType: .generalError)
     }
     
     // MARK: - toAttributesRequiredPublicError tests
     
     func test_toAttributesRequiredPublicError_invalidRequest() {
-        testSignUpContinueErrorToAttributesRequired(code: .invalidRequest, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .invalidRequest)
     }
     
     func test_toAttributesRequiredPublicError_unauthorizedClien() {
-        testSignUpContinueErrorToAttributesRequired(code: .unauthorizedClient, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .unauthorizedClient)
     }
     
     func test_toAttributesRequiredPublicError_invalidGrant() {
-        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant)
     }
     
     func test_toAttributesRequiredPublicError_expiredToken() {
-        testSignUpContinueErrorToAttributesRequired(code: .expiredToken, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .expiredToken)
     }
     
     func test_toAttributesRequiredPublicError_passwordTooWeak() {
-        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordTooWeak, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordTooWeak)
     }
     
     func test_toAttributesRequiredPublicError_passwordTooShort() {
-        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordTooShort, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordTooShort)
     }
     
     func test_toAttributesRequiredPublicError_passwordTooLong() {
-        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordTooLong, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordTooLong)
     }
     
     func test_toAttributesRequiredPublicError_passwordRecentlyUsed() {
-        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordRecentlyUsed, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordRecentlyUsed)
     }
     
     func test_toAttributesRequiredPublicError_passwordBanned() {
-        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordBanned, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .passwordBanned)
     }
     
     func test_toAttributesRequiredPublicError_userAlreadyExists() {
-        testSignUpContinueErrorToAttributesRequired(code: .userAlreadyExists, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .userAlreadyExists)
     }
     
     func test_toAttributesRequiredPublicError_attributesRequired() {
-        testSignUpContinueErrorToAttributesRequired(code: .attributesRequired, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .attributesRequired)
     }
     
     func test_toAttributesRequiredPublicError_verificationRequired() {
-        testSignUpContinueErrorToAttributesRequired(code: .verificationRequired, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .verificationRequired)
     }
     
     func test_toAttributesRequiredPublicError_attributeValidationFailed() {
-        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .attributeValidationFailed, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .attributeValidationFailed)
     }
     
     func test_toAttributesRequiredPublicError_credentialRequired() {
-        testSignUpContinueErrorToAttributesRequired(code: .credentialRequired, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .credentialRequired)
     }
     
     func test_toAttributesRequiredPublicError_invalidOOBValue() {
-        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .invalidOOBValue, description: testDescription)
+        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .invalidOOBValue)
     }
     
     // MARK: private methods
     
-    private func testSignUpContinueErrorToVerifyCode(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, description: String?, expectedErrorType: VerifyCodeError.ErrorType) {
-        sut = MSALNativeAuthSignUpContinueResponseError(error: code, subError: subError, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil)
-        let error = sut.toVerifyCodePublicError()
+    private func testSignUpContinueErrorToVerifyCode(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, expectedErrorType: VerifyCodeError.ErrorType) {
+        sut = MSALNativeAuthSignUpContinueResponseError(error: code, subError: subError, errorDescription: testDescription, errorCodes: testErrorCodes, errorURI: testErrorUri, correlationId: testCorrelationId)
+        
+        let error = sut.toVerifyCodePublicError(correlationId: testCorrelationId)
         XCTAssertEqual(error.type, expectedErrorType)
-        XCTAssertEqual(error.errorDescription, description)
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
-    private func testSignUpContinueErrorToPasswordRequired(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, description: String?, expectedErrorType: PasswordRequiredError.ErrorType) {
-        sut = MSALNativeAuthSignUpContinueResponseError(error: code, subError: subError, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil)
-        let error = sut.toPasswordRequiredPublicError()
+    private func testSignUpContinueErrorToPasswordRequired(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, expectedErrorType: PasswordRequiredError.ErrorType) {
+        sut = MSALNativeAuthSignUpContinueResponseError(error: code, subError: subError, errorDescription: testDescription, errorCodes: testErrorCodes, errorURI: testErrorUri, correlationId: testCorrelationId)
+
+        let error = sut.toPasswordRequiredPublicError(correlationId: testCorrelationId)
         XCTAssertEqual(error.type, expectedErrorType)
-        XCTAssertEqual(error.errorDescription, description)
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
+
     }
     
-    private func testSignUpContinueErrorToAttributesRequired(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, description: String?) {
-        sut = MSALNativeAuthSignUpContinueResponseError(error: code, subError: subError, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, requiredAttributes: nil, unverifiedAttributes: nil, invalidAttributes: nil)
-        let error = sut.toAttributesRequiredPublicError()
-        XCTAssertEqual(error.errorDescription, description)
+    private func testSignUpContinueErrorToAttributesRequired(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil) {
+        sut = MSALNativeAuthSignUpContinueResponseError(error: code, subError: subError, errorDescription: testDescription, errorCodes: testErrorCodes, errorURI: testErrorUri, correlationId: testCorrelationId)
+        let error = sut.toAttributesRequiredPublicError(correlationId: testCorrelationId)
+
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 }
diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift
index 811cb04ad7..d47129017d 100644
--- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift
@@ -29,63 +29,70 @@ final class MSALNativeAuthSignUpStartResponseErrorTests: XCTestCase {
 
     private var sut: MSALNativeAuthSignUpStartResponseError!
     private let testDescription = "testDescription"
+    private let testErrorCodes = [1, 2, 3]
+    private let testCorrelationId = UUID()
+    private let testErrorUri = "test error uri"
 
     // MARK: - to toSignUpStartPublicError tests
 
     func test_toSignUpStartPublicError_invalidRequest() {
-        testSignUpStartErrorToSignUpStart(code: .invalidRequest, description: testDescription, expectedErrorType: .generalError)
+        testSignUpStartErrorToSignUpStart(code: .invalidRequest, expectedErrorType: .generalError)
     }
     
     func test_toSignUpStartPublicError_unauthorizedClient() {
-        testSignUpStartErrorToSignUpStart(code: .unauthorizedClient, description: testDescription, expectedErrorType: .generalError)
+        testSignUpStartErrorToSignUpStart(code: .unauthorizedClient, expectedErrorType: .generalError)
     }
 
     func test_toSignUpStartPublicError_unsupportedChallengeType() {
-        testSignUpStartErrorToSignUpStart(code: .unsupportedChallengeType, description: "General error", expectedErrorType: .generalError)
+        testSignUpStartErrorToSignUpStart(code: .unsupportedChallengeType, expectedErrorType: .generalError)
     }
     
     func test_toSignUpStartPublicError_passwordTooWeak() {
-        testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordTooWeak, description: testDescription, expectedErrorType: .invalidPassword)
+        testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordTooWeak, expectedErrorType: .invalidPassword)
     }
     
     func test_toSignUpStartPublicError_passwordTooShort() {
-        testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordTooShort, description: testDescription, expectedErrorType: .invalidPassword)
+        testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordTooShort, expectedErrorType: .invalidPassword)
     }
     
     func test_toSignUpStartPublicError_passwordTooLong() {
-        testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordTooLong, description: testDescription, expectedErrorType: .invalidPassword)
+        testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordTooLong, expectedErrorType: .invalidPassword)
     }
     
     func test_toSignUpStartPublicError_passwordRecentlyUsed() {
-        testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordRecentlyUsed, description: testDescription, expectedErrorType: .invalidPassword)
+        testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordRecentlyUsed, expectedErrorType: .invalidPassword)
     }
     
     func test_toSignUpStartPublicError_passwordBanned() {
-        testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordBanned, description: testDescription, expectedErrorType: .invalidPassword)
+        testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .passwordBanned, expectedErrorType: .invalidPassword)
     }
     
     func test_toSignUpStartPublicError_userAlreadyExists() {
-        testSignUpStartErrorToSignUpStart(code: .userAlreadyExists, description: testDescription, expectedErrorType: .userAlreadyExists)
+        testSignUpStartErrorToSignUpStart(code: .userAlreadyExists, expectedErrorType: .userAlreadyExists)
     }
     
     func test_toSignUpStartPublicError_attributesRequired() {
-        testSignUpStartErrorToSignUpStart(code: .attributesRequired, description: testDescription, expectedErrorType: .generalError)
+        testSignUpStartErrorToSignUpStart(code: .attributesRequired, expectedErrorType: .generalError)
     }
     
     func test_toSignUpStartPublicError_unsupportedAuthMethod() {
-        testSignUpStartErrorToSignUpStart(code: .unsupportedAuthMethod, description: testDescription, expectedErrorType: .generalError)
+        testSignUpStartErrorToSignUpStart(code: .unsupportedAuthMethod, expectedErrorType: .generalError)
     }
     
     func test_toSignUpStartPublicError_attributeValidationFailed() {
-        testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .attributeValidationFailed, description: testDescription, expectedErrorType: .generalError)
+        testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .attributeValidationFailed, expectedErrorType: .generalError)
     }
 
     // MARK: private methods
     
-    private func testSignUpStartErrorToSignUpStart(code: MSALNativeAuthSignUpStartOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, description: String?, expectedErrorType: SignUpStartError.ErrorType) {
-        sut = MSALNativeAuthSignUpStartResponseError(error: code, subError: subError, errorDescription: description, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: nil, unverifiedAttributes: nil, invalidAttributes: nil)
-        let error = sut.toSignUpStartPublicError()
+    private func testSignUpStartErrorToSignUpStart(code: MSALNativeAuthSignUpStartOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, expectedErrorType: SignUpStartError.ErrorType) {
+        sut = MSALNativeAuthSignUpStartResponseError(error: code, subError: subError, errorDescription: testDescription, errorCodes: testErrorCodes, errorURI: testErrorUri, correlationId: testCorrelationId)
+        let error = sut.toSignUpStartPublicError(correlationId: testCorrelationId)
+        
         XCTAssertEqual(error.type, expectedErrorType)
-        XCTAssertEqual(error.errorDescription, description)
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 }
diff --git a/MSAL/test/unit/native_auth/network/parameters/MSALNativeAuthRequestContextTests.swift b/MSAL/test/unit/native_auth/network/parameters/MSALNativeAuthRequestContextTests.swift
new file mode 100644
index 0000000000..c6304d7d6f
--- /dev/null
+++ b/MSAL/test/unit/native_auth/network/parameters/MSALNativeAuthRequestContextTests.swift
@@ -0,0 +1,55 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import XCTest
+@testable import MSAL
+
+final class MSALNativeAuthRequestContextTests: XCTestCase {
+
+    func test_setServerCorrelationId() {
+        let requestCorrelationId = UUID()
+        let sut = MSALNativeAuthRequestContext(correlationId: requestCorrelationId)
+
+        XCTAssertEqual(sut.correlationId(), requestCorrelationId)
+
+        let serverCorrelationId = UUID()
+        sut.setServerCorrelationId(serverCorrelationId)
+        XCTAssertEqual(sut.correlationId(), serverCorrelationId)
+    }
+
+    func test_setServerCorrelationIdNil_worksAsExpected() {
+        let requestCorrelationId = UUID()
+        let sut = MSALNativeAuthRequestContext(correlationId: requestCorrelationId)
+
+        XCTAssertEqual(sut.correlationId(), requestCorrelationId)
+
+        let serverCorrelationId1 = UUID()
+        sut.setServerCorrelationId(serverCorrelationId1)
+        XCTAssertEqual(sut.correlationId(), serverCorrelationId1)
+
+        let serverCorrelationId2: UUID? = nil
+        sut.setServerCorrelationId(serverCorrelationId2)
+        XCTAssertEqual(sut.correlationId(), requestCorrelationId)
+    }
+}
diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift
index 3198d1a52d..cf35d25eaa 100644
--- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift
+++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift
@@ -84,7 +84,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .error(.unexpectedError(message: "API error message")))
+        XCTAssertEqual(result, .error(.unexpectedError(.init(errorDescription: "API error message"))))
     }
 
     func test_whenResetPasswordStartErrorResponseUserNotFound_itReturnsRelatedError() {
@@ -196,7 +196,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
         )
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "Unexpected response body received")))
     }
 
     func test_whenResetPasswordChallengeSuccessResponseHasInvalidChallengeChannel_itReturnsUnexpectedError() {
@@ -210,7 +210,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
         )
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: nil))
+        XCTAssertEqual(result, .unexpectedError(.init()))
     }
 
     func test_whenResetPasswordChallengeErrorResponseIsNotExpected_itReturnsUnexpectedError() {
@@ -221,7 +221,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: "API error message"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "API error message")))
     }
 
     func test_whenResetPasswordChallengeErrorResponseIsExpected_itReturnsError() {
@@ -260,19 +260,23 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: "API error message"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "API error message")))
     }
 
     func test_whenResetPasswordContinueErrorResponseIs_invalidOOBValue_itReturnsExpectedError() {
+        let apiError = MSALNativeAuthResetPasswordContinueResponseError(
+            error: .invalidGrant,
+            subError: .invalidOOBValue
+        )
         let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .invalidOOBValue)
 
-        XCTAssertEqual(result, .invalidOOB)
+        XCTAssertEqual(result, .invalidOOB(apiError))
     }
 
     func test_whenResetPasswordContinueErrorResponseIs_verificationRequired_itReturnsUnexpectedError() {
         let result = buildContinueErrorResponse(expectedError: .verificationRequired)
 
-        XCTAssertEqual(result, .unexpectedError(message: nil))
+        XCTAssertEqual(result, .unexpectedError(nil))
     }
 
     func test_whenResetPasswordContinueErrorResponseIs_unauthorizedClient_itReturnsExpectedError() {
@@ -430,7 +434,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: "API error message"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "API error message")))
     }
 
     // MARK: - Poll Completion Response
@@ -544,7 +548,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: "API error message"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "API error message")))
     }
 
     // MARK: - Helper methods
diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift
index d76e16adcf..929c698b9e 100644
--- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift
+++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift
@@ -28,37 +28,65 @@ import XCTest
 final class MSALNativeAuthResetPasswordStartValidatedErrorTypeTests: XCTestCase {
 
     private typealias sut = MSALNativeAuthResetPasswordStartValidatedErrorType
-    private let testDescription = "testDescription"
+    private var testDescription = "testDescription"
+    private let testErrorCodes = [1, 2, 3]
+    private let testCorrelationId = UUID()
+    private let testErrorUri = "test error uri"
+    private var apiErrorStub: MSALNativeAuthResetPasswordStartResponseError {
+        .init(
+            error: .unauthorizedClient,
+            errorDescription: testDescription,
+            errorCodes: testErrorCodes,
+            errorURI: testErrorUri,
+            correlationId: testCorrelationId
+        )
+    }
 
     // MARK: - to ResetPasswordStartError tests
 
     func test_toResetPasswordStartPublicError_unauthorizedClient() {
-        let error = sut.unauthorizedClient(message: testDescription).toResetPasswordStartPublicError()
+        let error = sut.unauthorizedClient(apiErrorStub).toResetPasswordStartPublicError(context: MSALNativeAuthRequestContextMock(correlationId: testCorrelationId))
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
     }
 
     func test_toResetPasswordStartPublicError_invalidRequest() {
-        let error = sut.invalidRequest(message: "General error").toResetPasswordStartPublicError()
+        let error = sut.invalidRequest(apiErrorStub).toResetPasswordStartPublicError(context: MSALNativeAuthRequestContextMock(correlationId: testCorrelationId))
+
         XCTAssertEqual(error.type, .generalError)
-        XCTAssertEqual(error.errorDescription, "General error")
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
     }
     
     func test_toResetPasswordStartPublicError_userDoesNotHavePassword() {
-        let error = sut.userDoesNotHavePassword.toResetPasswordStartPublicError()
+        testDescription = MSALNativeAuthErrorMessage.userDoesNotHavePassword
+        let error = sut.userDoesNotHavePassword(apiErrorStub).toResetPasswordStartPublicError(context: MSALNativeAuthRequestContextMock(correlationId: testCorrelationId))
+
         XCTAssertEqual(error.type, .userDoesNotHavePassword)
         XCTAssertEqual(error.errorDescription, MSALNativeAuthErrorMessage.userDoesNotHavePassword)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
     }
 
     func test_toResetPasswordStartPublicError_userNotFound() {
-        let error = sut.userNotFound(message: testDescription).toResetPasswordStartPublicError()
+        let error = sut.userNotFound(apiErrorStub).toResetPasswordStartPublicError(context: MSALNativeAuthRequestContextMock(correlationId: testCorrelationId))
+
         XCTAssertEqual(error.type, .userNotFound)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
     }
 
     func test_toResetPasswordStartPublicError_unsupportedChallengeType() {
-        let error = sut.unsupportedChallengeType(message: nil).toResetPasswordStartPublicError()
+        let error = sut.unsupportedChallengeType(apiErrorStub).toResetPasswordStartPublicError(context: MSALNativeAuthRequestContextMock(correlationId: testCorrelationId))
+
         XCTAssertEqual(error.type, .generalError)
-        XCTAssertEqual(error.errorDescription, "General error")
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
     }
 }
diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift
index 69e85d8ed5..05e5ac75dd 100644
--- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift
+++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift
@@ -30,81 +30,76 @@ final class MSALNativeAuthSignInInitiateValidatedErrorTypeTests: XCTestCase {
     
     private typealias sut = MSALNativeAuthSignInInitiateValidatedErrorType
     private let testDescription = "testDescription"
-    
+    private let testErrorCodes = [1, 2, 3]
+    private let testCorrelationId = UUID()
+    private let testErrorUri = "test error uri"
+    private var apiErrorStub: MSALNativeAuthSignInInitiateResponseError {
+        .init(
+            error: .invalidRequest,
+            errorDescription: testDescription,
+            errorCodes: testErrorCodes,
+            errorURI: testErrorUri,
+            correlationId: testCorrelationId
+        )
+    }
+
     // MARK: - convertToSignInStartError tests
     
     func test_convertToSignInStartError_redirect() {
-        let error = sut.redirect.convertToSignInStartError()
+        let error = sut.redirect.convertToSignInStartError(correlationId: testCorrelationId)
+        
         XCTAssertEqual(error.type, .browserRequired)
         XCTAssertEqual(error.errorDescription, MSALNativeAuthErrorMessage.browserRequired)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
     }
     
     func test_convertToSignInStartError_unauthorizedClient() {
-        let error = sut.unauthorizedClient(message: testDescription).convertToSignInStartError()
+        let error = sut.unauthorizedClient(apiErrorStub).convertToSignInStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInStartError_invalidRequest() {
-        let error = sut.invalidRequest(message: testDescription).convertToSignInStartError()
+        let error = sut.invalidRequest(apiErrorStub).convertToSignInStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInStartError_invalidServerResponse() {
-        let error = sut.unexpectedError(message: "Unexpected response body received").convertToSignInStartError()
+        let error = sut.unexpectedError(apiErrorStub).convertToSignInStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
-        XCTAssertEqual(error.errorDescription, "Unexpected response body received")
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInStartError_userNotFound() {
-        let error = sut.userNotFound(message: testDescription).convertToSignInStartError()
+        let error = sut.userNotFound(apiErrorStub).convertToSignInStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .userNotFound)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInStartError_unsupportedChallengeType() {
-        let error = sut.unsupportedChallengeType(message: testDescription).convertToSignInStartError()
-        XCTAssertEqual(error.type, .generalError)
-        XCTAssertEqual(error.errorDescription, testDescription)
-    }
-    
-    // MARK: - convertToSignInPasswordStartError tests
-    
-    func test_convertToSignInPasswordStartError_redirect() {
-        let error = sut.redirect.convertToSignInPasswordStartError()
-        XCTAssertEqual(error.type, .browserRequired)
-        XCTAssertEqual(error.errorDescription, MSALNativeAuthErrorMessage.browserRequired)
-    }
-    
-    func test_convertToSignInPasswordStartError_unauthorizedClient() {
-        let error = sut.unauthorizedClient(message: testDescription).convertToSignInPasswordStartError()
-        XCTAssertEqual(error.type, .generalError)
-        XCTAssertEqual(error.errorDescription, testDescription)
-    }
-    
-    func test_convertToSignInPasswordStartError_invalidRequest() {
-        let error = sut.invalidRequest(message: testDescription).convertToSignInPasswordStartError()
-        XCTAssertEqual(error.type, .generalError)
-        XCTAssertEqual(error.errorDescription, testDescription)
-    }
-    
-    func test_convertToSignInPasswordStartError_invalidServerResponse() {
-        let error = sut.unexpectedError(message: "Unexpected response body received").convertToSignInPasswordStartError()
-        XCTAssertEqual(error.type, .generalError)
-        XCTAssertEqual(error.errorDescription, "Unexpected response body received")
-    }
-    
-    func test_convertToSignInPasswordStartError_userNotFound() {
-        let error = sut.userNotFound(message: testDescription).convertToSignInPasswordStartError()
-        XCTAssertEqual(error.type, .userNotFound)
-        XCTAssertEqual(error.errorDescription, testDescription)
-    }
-    
-    func test_convertToSignInPasswordStartError_unsupportedChallengeType() {
-        let error = sut.unsupportedChallengeType(message: testDescription).convertToSignInPasswordStartError()
+        let error = sut.unsupportedChallengeType(apiErrorStub).convertToSignInStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
-    
 }
diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift
index f464d83109..876698de0b 100644
--- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift
+++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift
@@ -66,7 +66,7 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase {
         let context = MSALNativeAuthRequestContext(correlationId: defaultUUID)
         let challengeResponse = MSALNativeAuthSignInChallengeResponse(continuationToken: nil, challengeType: .password, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: nil, codeLength: nil, interval: nil)
         let result = sut.validate(context: context, result: .success(challengeResponse))
-        if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else {
+        if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else {
             XCTFail("Unexpected result: \(result)")
         }
     }
@@ -92,22 +92,22 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase {
         let channelType = MSALNativeAuthInternalChannelType.email
         let missingCredentialToken = MSALNativeAuthSignInChallengeResponse(continuationToken: nil, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: channelType, codeLength: codeLength, interval: nil)
         var result = sut.validate(context: context, result: .success(missingCredentialToken))
-        if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else {
+        if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else {
             XCTFail("Unexpected result: \(result)")
         }
         let missingTargetLabel = MSALNativeAuthSignInChallengeResponse(continuationToken: continuationToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: nil, challengeChannel: channelType, codeLength: codeLength, interval: nil)
         result = sut.validate(context: context, result: .success(missingTargetLabel))
-        if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else {
+        if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else {
             XCTFail("Unexpected result: \(result)")
         }
         let missingChannelType = MSALNativeAuthSignInChallengeResponse(continuationToken: continuationToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: nil, codeLength: codeLength, interval: nil)
         result = sut.validate(context: context, result: .success(missingChannelType))
-        if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else {
+        if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else {
             XCTFail("Unexpected result: \(result)")
         }
         let missingCodeLength = MSALNativeAuthSignInChallengeResponse(continuationToken: continuationToken, challengeType: .oob, bindingMethod: nil, challengeTargetLabel: targetLabel, challengeChannel: channelType, codeLength: nil, interval: nil)
         result = sut.validate(context: context, result: .success(missingCodeLength))
-        if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else {
+        if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else {
             XCTFail("Unexpected result: \(result)")
         }
     }
@@ -116,7 +116,7 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase {
         let context = MSALNativeAuthRequestContext(correlationId: defaultUUID)
         let challengeResponse = MSALNativeAuthSignInChallengeResponse(continuationToken: "something", challengeType: .otp, bindingMethod: nil, challengeTargetLabel: "some", challengeChannel: .email, codeLength: 2, interval: nil)
         let result = sut.validate(context: context, result: .success(challengeResponse))
-        if case .error(.unexpectedError(message: "Unexpected challenge type")) = result {} else {
+        if case .error(.unexpectedError(.init(errorDescription: "Unexpected challenge type"))) = result {} else {
             XCTFail("Unexpected result: \(result)")
         }
     }
@@ -137,7 +137,7 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase {
         let context = MSALNativeAuthRequestContext(correlationId: defaultUUID)
         let initiateResponse = MSALNativeAuthSignInInitiateResponse(continuationToken: nil, challengeType: nil)
         let result = sut.validate(context: context, result: .success(initiateResponse))
-        if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else {
+        if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else {
             XCTFail("Unexpected result: \(result)")
         }
     }
@@ -155,17 +155,17 @@ final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase {
         let context = MSALNativeAuthRequestContext(correlationId: defaultUUID)
         var initiateResponse = MSALNativeAuthSignInInitiateResponse(continuationToken: nil, challengeType: .oob)
         var result = sut.validate(context: context, result: .success(initiateResponse))
-        if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else {
+        if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else {
             XCTFail("Unexpected result: \(result)")
         }
         initiateResponse = MSALNativeAuthSignInInitiateResponse(continuationToken: nil, challengeType: .otp)
         result = sut.validate(context: context, result: .success(initiateResponse))
-        if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else {
+        if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else {
             XCTFail("Unexpected result: \(result)")
         }
         initiateResponse = MSALNativeAuthSignInInitiateResponse(continuationToken: nil, challengeType: .password)
         result = sut.validate(context: context, result: .success(initiateResponse))
-        if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else {
+        if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else {
             XCTFail("Unexpected result: \(result)")
         }
     }
diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift
index 0a62ad952e..3264adc183 100644
--- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift
+++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift
@@ -55,7 +55,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         )
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "Unexpected response body received")))
     }
 
     func test_whenSignUpStartErrorResponseIsNotExpected_it_returns_unexpectedError() {
@@ -66,7 +66,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: "API error message"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "API error message")))
     }
 
     func test_whenSignUpStart_succeedsWithContinuationToken_it_returns_success() {
@@ -91,7 +91,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
 
         let result = sut.validate(response, with: context)
 
-        guard case .attributeValidationFailed(let invalidAttributes) = result else {
+        guard case .attributeValidationFailed(let error, let invalidAttributes) = result else {
             return XCTFail("Unexpected response")
         }
 
@@ -107,7 +107,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: nil))
+        XCTAssertEqual(result, .unexpectedError(.init()))
     }
 
     func test_whenSignUpStart_attributeValidationFailed_but_invalidAttributesIsNil_it_returns_attributeValidationFailed() {
@@ -119,7 +119,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: nil))
+        XCTAssertEqual(result, .unexpectedError(.init()))
     }
 
     func test_whenSignUpStartErrorResponseIsExpected_it_returns_error() {
@@ -225,7 +225,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         )
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "Unexpected response body received")))
     }
 
     func test_whenSignUpChallengeSuccessResponseContainsRedirect_it_returns_redirect() {
@@ -298,7 +298,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         )
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "Unexpected response body received")))
     }
 
     func test_whenSignUpChallengeSuccessResponseContainsValidAttributesAndOTP_it_returns_unexpectedError() {
@@ -313,7 +313,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         )
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "Unexpected response body received")))
     }
 
     func test_whenSignUpChallengeSuccessResponseOmitsSomeAttributes_it_returns_unexpectedError() {
@@ -328,7 +328,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         )
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "Unexpected response body received")))
     }
 
     func test_whenSignUpChallengeErrorResponseIsNotExpected_it_returns_unexpectedError() {
@@ -339,7 +339,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: "API error message"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "API error message")))
     }
 
     func test_whenSignUpChallengeErrorResponseIsExpected_it_returns_error() {
@@ -364,7 +364,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         )
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .success(""))
+        XCTAssertEqual(result, .success(continuationToken: ""))
     }
 
     func test_whenSignUpStartSuccessResponseButDoesNotContainContinuationToken_it_returns_successWithNoContinuationToken() throws {
@@ -373,7 +373,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         )
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .success(nil))
+        XCTAssertEqual(result, .success(continuationToken: nil))
     }
 
     func test_whenSignUpContinueErrorResponseIsNotExpected_it_returns_unexpectedError() {
@@ -384,7 +384,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(message: "API error message"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "API error message")))
     }
 
     func test_whenSignUpContinueErrorResponseIs_invalidOOBValue_it_returns_expectedError() {
@@ -474,7 +474,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
     func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_it_returns_expectedError() {
         let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .attributeValidationFailed, invalidAttributes: [MSALNativeAuthErrorBasicAttribute(name: "email")])
 
-        guard case .attributeValidationFailed(let invalidAttributes) = result else {
+        guard case .attributeValidationFailed(_, let invalidAttributes) = result else {
             return XCTFail("Unexpected response")
         }
 
@@ -495,19 +495,19 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
     func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_but_invalidAttributesIsNil_it_returns_unexpectedError() {
         let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .attributeValidationFailed, invalidAttributes: nil)
 
-        XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "Unexpected response body received")))
     }
 
     func test_whenSignUpContinueErrorResponseIs_attributeValidationFailed_but_invalidAttributesIsEmpty_it_returns_unexpectedError() {
         let result = buildContinueErrorResponse(expectedError: .invalidGrant, expectedSubError: .attributeValidationFailed, invalidAttributes: [])
 
-        XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "Unexpected response body received")))
     }
 
     func test_whenSignUpContinueErrorResponseIs_credentialRequired_it_returns_expectedError() {
         let result = buildContinueErrorResponse(expectedError: .credentialRequired, expectedContinuationToken: "continuation-token")
 
-        guard case .credentialRequired(let continuationToken) = result else {
+        guard case .credentialRequired(let continuationToken, _) = result else {
             return XCTFail("Unexpected response")
         }
 
@@ -516,13 +516,13 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
 
     func test_whenSignUpContinueErrorResponseIs_credentialRequired_but_continuationToken_isNil_it_returns_unexpectedError() {
         let result = buildContinueErrorResponse(expectedError: .credentialRequired, expectedContinuationToken: nil)
-        XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "Unexpected response body received")))
     }
 
     func test_whenSignUpContinueErrorResponseIs_attributesRequired_it_returns_expectedError() {
         let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedContinuationToken: "continuation-token", requiredAttributes: [.init(name: "email", type: "", required: true), .init(name: "city", type: "", required: false)])
 
-        guard case .attributesRequired(let continuationToken, let requiredAttributes) = result else {
+        guard case .attributesRequired(let continuationToken, let requiredAttributes, _) = result else {
             return XCTFail("Unexpected response")
         }
 
@@ -535,24 +535,24 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
     func test_whenSignUpContinueErrorResponseIs_attributesRequired_but_continuationToken_IsNil_it_returns_expectedError() {
         let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedContinuationToken: nil, requiredAttributes: [.init(name: "email", type: "", required: true), .init(name: "city", type: "", required: false)])
 
-        XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "Unexpected response body received")))
     }
 
     func test_whenSignUpContinueErrorResponseIs_attributesRequired_but_requiredAttributesIsNil_it_returns_expectedError() {
         let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedContinuationToken: "continuation-token", requiredAttributes: nil)
 
-        XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "Unexpected response body received")))
     }
 
     func test_whenSignUpContinueErrorResponseIs_attributesRequired_but_requiredAttributes_IsEmpty_it_returns_expectedError() {
         let result = buildContinueErrorResponse(expectedError: .attributesRequired, expectedContinuationToken: "continuation-token", requiredAttributes: [])
 
-        XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "Unexpected response body received")))
     }
 
     func test_whenSignUpContinueErrorResponseIs_verificationRequired_it_returns_unexpectedError() {
         let result = buildContinueErrorResponse(expectedError: .attributesRequired)
-        XCTAssertEqual(result, .unexpectedError(message: "Unexpected response body received"))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "Unexpected response body received")))
     }
 
     func test_whenSignUpContinueErrorResponseIs_unauthorizedClient_it_returns_expectedError() {
diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift
index a012ed41c8..d983c185fd 100644
--- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift
+++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift
@@ -77,7 +77,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase {
     func test_whenInvalidErrorTokenResponse_anErrorIsReturned() {
         let context = MSALNativeAuthRequestContext(correlationId: defaultUUID)
         let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(MSALNativeAuthInternalError.headerNotSerialized))
-        if case .error(.unexpectedError(message: "Unexpected response body received")) = result {} else {
+        if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else {
             XCTFail("Unexpected result: \(result)")
         }
     }
@@ -112,7 +112,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase {
             return XCTFail("Unexpected response")
         }
         
-        if case .unauthorizedClient(message: nil) = innerError {} else {
+        if case .unauthorizedClient(error) = innerError {} else {
             XCTFail("Unexpected Error")
         }
     }
@@ -127,31 +127,31 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase {
             return XCTFail("Unexpected response")
         }
         
-        if case .unauthorizedClient(message: nil) = innerError {} else {
+        if case .unauthorizedClient(error) = innerError {} else {
             XCTFail("Unexpected Error")
         }
     }
     
 
     func test_invalidGrantTokenResponse_withKnownError_andSeveralUnknownErrorCodes_isProperlyHandled() {
-        let description = "description"
         let unknownErrorCode1 = Int.max
         let unknownErrorCode2 = unknownErrorCode1 - 1
 
         var errorCodes: [Int] = [MSALNativeAuthESTSApiErrorCodes.userNotFound.rawValue, unknownErrorCode1, unknownErrorCode2]
-        guard case .userNotFound(message: description) = checkErrorCodes() else {
+
+        guard case .userNotFound(createError(errorCodes)) = checkErrorCodes() else {
             return XCTFail("Unexpected Error")
         }
         errorCodes = [MSALNativeAuthESTSApiErrorCodes.strongAuthRequired.rawValue, unknownErrorCode1, unknownErrorCode2]
-        guard case .strongAuthRequired(message: description) = checkErrorCodes() else {
+        guard case .strongAuthRequired(createError(errorCodes)) = checkErrorCodes() else {
             return XCTFail("Unexpected Error")
         }
         errorCodes = [MSALNativeAuthESTSApiErrorCodes.strongAuthRequired.rawValue, unknownErrorCode1, unknownErrorCode2]
-        guard case .strongAuthRequired(message: description) = checkErrorCodes() else {
+        guard case .strongAuthRequired(createError(errorCodes)) = checkErrorCodes() else {
             return XCTFail("Unexpected Error")
         }
         errorCodes = [MSALNativeAuthESTSApiErrorCodes.invalidCredentials.rawValue, unknownErrorCode1, unknownErrorCode2]
-        guard case .invalidPassword(message: description) = checkErrorCodes() else {
+        guard case .invalidPassword(createError(errorCodes)) = checkErrorCodes() else {
             return XCTFail("Unexpected Error")
         }
         errorCodes = [MSALNativeAuthESTSApiErrorCodes.userNotHaveAPassword.rawValue, unknownErrorCode1, unknownErrorCode2]
@@ -159,8 +159,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase {
             return XCTFail("Unexpected Error")
         }
         func checkErrorCodes() -> MSALNativeAuthTokenValidatedErrorType? {
-            let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, subError: nil, errorDescription: description, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil)
-
+            let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, subError: nil, errorDescription: nil, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil)
             let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error))
             
             guard case .error(let innerError) = result else {
@@ -168,6 +167,9 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase {
             }
             return innerError
         }
+        func createError(_ errorCodes: [Int]) -> MSALNativeAuthTokenResponseError {
+            MSALNativeAuthTokenResponseError(error: .invalidGrant, subError: nil, errorDescription: nil, errorCodes: errorCodes, errorURI: nil, innerErrors: nil, continuationToken: nil)
+        }
     }
 
     func test_invalidGrantTokenResponse_withUnknownErrorCode_andKnownErrorCodes_isProperlyHandled() {
@@ -211,7 +213,7 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase {
                 return XCTFail("Unexpected response")
             }
             
-            guard case .invalidRequest(message: description) = innerError else {
+            guard case .invalidRequest(error) = innerError else {
                 return XCTFail("Unexpected Error")
             }
         }
diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift
index e60fde9b7a..d46bf6076a 100644
--- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift
+++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenValidatedErrorTypeTests.swift
@@ -30,90 +30,160 @@ final class MSALNativeAuthTokenValidatedErrorTypeTests: XCTestCase {
     
     private typealias sut = MSALNativeAuthTokenValidatedErrorType
     private let testDescription = "testDescription"
-    
+    private let testErrorCodes = [1, 2, 3]
+    private let testCorrelationId = UUID()
+    private let testErrorUri = "test error uri"
+    private var apiErrorStub: MSALNativeAuthTokenResponseError {
+        .init(
+            error: .invalidRequest,
+            subError: .attributeValidationFailed,
+            errorDescription: testDescription,
+            errorCodes: testErrorCodes,
+            errorURI: testErrorUri,
+            correlationId: testCorrelationId
+        )
+    }
+
     // MARK: - convertToSignInPasswordStartError tests
     
     func test_convertToSignInPasswordStartError_generalError() {
-        let error = sut.generalError.convertToSignInPasswordStartError()
+
+        let error = sut.generalError(apiErrorStub).convertToSignInPasswordStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
-        XCTAssertEqual(error.errorDescription, "General error")
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInPasswordStartError_expiredToken() {
-        let error = sut.expiredToken(message: testDescription).convertToSignInPasswordStartError()
+        let error = sut.expiredToken(apiErrorStub).convertToSignInPasswordStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInPasswordStartError_expiredRefreshToken() {
-        let error = sut.expiredRefreshToken(message: testDescription).convertToSignInPasswordStartError()
+        let error = sut.expiredRefreshToken(apiErrorStub).convertToSignInPasswordStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInPasswordStartError_unauthorizedClient() {
-        let error = sut.unauthorizedClient(message: testDescription).convertToSignInPasswordStartError()
+        let error = sut.unauthorizedClient(apiErrorStub).convertToSignInPasswordStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInPasswordStartError_invalidRequest() {
-        let error = sut.invalidRequest(message: testDescription).convertToSignInPasswordStartError()
+        let error = sut.invalidRequest(apiErrorStub).convertToSignInPasswordStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInPasswordStartError_invalidServerResponse() {
-        let error = sut.unexpectedError(message: "Unexpected response body received").convertToSignInPasswordStartError()
+        let error = sut.unexpectedError(.init(apiErrorStub)).convertToSignInPasswordStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
-        XCTAssertEqual(error.errorDescription, "Unexpected response body received")
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInPasswordStartError_userNotFound() {
-        let error = sut.userNotFound(message: testDescription).convertToSignInPasswordStartError()
+        let error = sut.userNotFound(apiErrorStub).convertToSignInPasswordStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .userNotFound)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInPasswordStartError_invalidPassword() {
-        let error = sut.invalidPassword(message: testDescription).convertToSignInPasswordStartError()
+        let error = sut.invalidPassword(apiErrorStub).convertToSignInPasswordStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .invalidCredentials)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInPasswordStartError_invalidOOBCode() {
-        let error = sut.invalidOOBCode(message: testDescription).convertToSignInPasswordStartError()
+        let error = sut.invalidOOBCode(apiErrorStub).convertToSignInPasswordStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInPasswordStartError_unsupportedChallengeType() {
-        let error = sut.unsupportedChallengeType(message: testDescription).convertToSignInPasswordStartError()
+        let error = sut.unsupportedChallengeType(apiErrorStub).convertToSignInPasswordStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInPasswordStartError_strongAuthRequired() {
-        let error = sut.strongAuthRequired(message: testDescription).convertToSignInPasswordStartError()
+        let error = sut.strongAuthRequired(apiErrorStub).convertToSignInPasswordStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .browserRequired)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInPasswordStartError_invalidScope() {
-        let error = sut.invalidScope(message: testDescription).convertToSignInPasswordStartError()
+        let error = sut.invalidScope(apiErrorStub).convertToSignInPasswordStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInPasswordStartError_authorizationPending() {
-        let error = sut.authorizationPending(message: testDescription).convertToSignInPasswordStartError()
+        let error = sut.authorizationPending(apiErrorStub).convertToSignInPasswordStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
     
     func test_convertToSignInPasswordStartError_slowDown() {
-        let error = sut.slowDown(message: testDescription).convertToSignInPasswordStartError()
+        let error = sut.slowDown(apiErrorStub).convertToSignInPasswordStartError(correlationId: testCorrelationId)
+
         XCTAssertEqual(error.type, .generalError)
         XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.correlationId, testCorrelationId)
+        XCTAssertEqual(error.errorUri, testErrorUri)
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift
index 6c57b12a4a..196ffc0c1a 100644
--- a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift
+++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift
@@ -105,7 +105,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
             channelTargetType: .email,
             codeLength: 1
         )
-        controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signUpController.startResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -128,7 +128,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
             channelTargetType: .email,
             codeLength: 1
         )
-        controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signUpController.startResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
         
@@ -141,6 +141,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
             delegate.error?.errorDescription,
             String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCodeRequired")
         )
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     func testSignUpPassword_delegate_whenSendAttributes_shouldReturnAttributesInvalid() {
@@ -150,7 +151,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         let expectedInvalidAttributes = ["attribute"]
 
         let expectedResult: SignUpStartResult = .attributesInvalid(expectedInvalidAttributes)
-        controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signUpController.startResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -168,7 +169,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         let expectedInvalidAttributes = ["attribute"]
 
         let expectedResult: SignUpStartResult = .attributesInvalid(expectedInvalidAttributes)
-        controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signUpController.startResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -181,6 +182,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
             delegate.error?.errorDescription, 
             String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid")
         )
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     // Sign Up with code
@@ -204,7 +206,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
             channelTargetType: .email,
             codeLength: 1
         )
-        controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signUpController.startResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -227,7 +229,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
             channelTargetType: .email,
             codeLength: 1
         )
-        controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signUpController.startResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -240,6 +242,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
             delegate.error?.errorDescription,
             String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCodeRequired")
         )
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     func testSignUp_delegate_whenSendAttributes_shouldReturnAttributesInvalid() {
@@ -249,7 +252,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         let expectedInvalidAttributes = ["attribute"]
 
         let expectedResult: SignUpStartResult = .attributesInvalid(expectedInvalidAttributes)
-        controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signUpController.startResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -267,7 +270,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         let expectedInvalidAttributes = ["attribute"]
 
         let expectedResult: SignUpStartResult = .attributesInvalid(expectedInvalidAttributes)
-        controllerFactoryMock.signUpController.startResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signUpController.startResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -280,21 +283,22 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
             delegate.error?.errorDescription,
             String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid")
         )
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     // Sign in with password
 
     func testSignInPassword_delegate_whenInvalidUsernameUsed_shouldReturnCorrectError() {
         let expectation = expectation(description: "sign-in public interface")
-        let delegate = SignInPasswordStartDelegateSpy(expectation: expectation, expectedError: .init(type: .invalidUsername))
-        sut.signIn(username: "", password: "", delegate: delegate)
+        let delegate = SignInPasswordStartDelegateSpy(expectation: expectation, expectedError: .init(type: .invalidUsername, correlationId: correlationId))
+        sut.signIn(username: "", password: "", correlationId: correlationId, delegate: delegate)
         wait(for: [expectation], timeout: 1)
     }
     
     func testSignInPassword_delegate_whenInvalidPasswordUsed_shouldReturnCorrectError() {
         let expectation = expectation(description: "sign-in public interface")
-        let delegate = SignInPasswordStartDelegateSpy(expectation: expectation, expectedError: .init(type: .invalidCredentials))
-        sut.signIn(username: "correct", password: "", delegate: delegate)
+        let delegate = SignInPasswordStartDelegateSpy(expectation: expectation, expectedError: .init(type: .invalidCredentials, correlationId: correlationId))
+        sut.signIn(username: "correct", password: "", correlationId: correlationId, delegate: delegate)
         wait(for: [expectation], timeout: 1)
     }
 
@@ -303,7 +307,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         let exp2 = expectation(description: "expectation Telemetry")
         let delegate = SignInPasswordStartDelegateSpy(expectation: exp1, expectedUserAccountResult: MSALNativeAuthUserAccountResultStub.result)
 
-        controllerFactoryMock.signInController.signInStartResult = .init(.init(.completed(MSALNativeAuthUserAccountResultStub.result), telemetryUpdate: { _ in
+        controllerFactoryMock.signInController.signInStartResult = .init(.init(.completed(MSALNativeAuthUserAccountResultStub.result), correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         }))
         sut.signIn(username: "correct", password: "correct", delegate: delegate)
@@ -315,12 +319,12 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         let exp = expectation(description: "sign-in public interface")
         let exp2 = expectation(description: "expectation Telemetry")
 
-        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted"))
+        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted"), correlationId: correlationId)
         let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: exp, expectedError: expectedError)
 
         let expectedResult: SignInStartResult = .completed(MSALNativeAuthUserAccountResultStub.result)
 
-        controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -345,7 +349,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
             codeLength: 1
         )
         
-        controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -358,7 +362,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         let exp = expectation(description: "sign-in public interface")
         let exp2 = expectation(description: "expectation Telemetry")
 
-        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired"))
+        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired"), correlationId: correlationId)
         let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: exp, expectedError: expectedError)
 
         let expectedResult: SignInStartResult = .codeRequired(
@@ -368,7 +372,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
             codeLength: 1
         )
 
-        controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -381,7 +385,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
 
     func testSignIn_delegate_whenInvalidUser_shouldReturnCorrectError() {
         let expectation = expectation(description: "sign-in public interface")
-        let delegate = SignInCodeStartDelegateSpy(expectation: expectation, expectedError: .init(type: .invalidUsername))
+        let delegate = SignInCodeStartDelegateSpy(expectation: expectation, expectedError: .init(type: .invalidUsername, correlationId: correlationId))
         sut.signIn(username: "", delegate: delegate)
         wait(for: [expectation], timeout: 1)
     }
@@ -401,7 +405,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
             codeLength: 1
         )
 
-        controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
         sut.signIn(username: "correct", delegate: delegate)
@@ -413,7 +417,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         let exp = expectation(description: "sign-in public interface")
         let exp2 = expectation(description: "expectation Telemetry")
 
-        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired"))
+        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired"), correlationId: correlationId)
         let delegate = SignInCodeStartDelegateOptionalMethodNotImplemented(expectation: exp, expectedError: expectedError)
 
         let expectedResult: SignInStartResult = .codeRequired(
@@ -423,7 +427,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
             codeLength: 1
         )
 
-        controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -441,7 +445,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         let expectedState = SignInPasswordRequiredState(scopes: [], username: "", controller: controllerFactoryMock.signInController, continuationToken: "continuationToken", correlationId: correlationId)
         let expectedResult: SignInStartResult = .passwordRequired(newState: expectedState)
 
-        controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -456,14 +460,14 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         let exp = expectation(description: "sign-in public interface")
         let exp2 = expectation(description: "expectation Telemetry")
 
-        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInPasswordRequired"))
+        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInPasswordRequired"), correlationId: correlationId)
         let delegate = SignInCodeStartDelegateSpy(expectation: exp, expectedError: expectedError)
 
         let expectedResult: SignInStartResult = .passwordRequired(
             newState: SignInPasswordRequiredState(scopes: [], username: "", controller: controllerFactoryMock.signInController, continuationToken: "", correlationId: correlationId)
         )
 
-        controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.signInController.signInStartResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -494,7 +498,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
             codeLength: 1
         )
 
-        controllerFactoryMock.resetPasswordController.resetPasswordResponse = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.resetPasswordController.resetPasswordResponse = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
         sut.resetPassword(username: "correct", delegate: delegate)
@@ -519,7 +523,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
             channelTargetType: .email,
             codeLength: 1
         )
-        controllerFactoryMock.resetPasswordController.resetPasswordResponse = .init(expectedResult, telemetryUpdate: { _ in
+        controllerFactoryMock.resetPasswordController.resetPasswordResponse = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -558,8 +562,8 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         let signUpResponseValidatorMock = MSALNativeAuthSignUpResponseValidatorMock()
         signUpResponseValidatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken"))
         signUpResponseValidatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "continuationToken 2"))
-        signUpResponseValidatorMock.mockValidateSignUpContinueFunc(.success("continuationToken"))
-        
+        signUpResponseValidatorMock.mockValidateSignUpContinueFunc(.success(continuationToken: "continuationToken"))
+
         let signInRequestProviderMock = MSALNativeAuthSignInRequestProviderMock()
         
         let expectedUsername = "username"
@@ -660,8 +664,8 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         let signUpResponseValidatorMock = MSALNativeAuthSignUpResponseValidatorMock()
         signUpResponseValidatorMock.mockValidateSignUpStartFunc(.success(continuationToken: "continuationToken"))
         signUpResponseValidatorMock.mockValidateSignUpChallengeFunc(.codeRequired("sentTo", .email, 4, "continuationToken 2"))
-        signUpResponseValidatorMock.mockValidateSignUpContinueFunc(.success("continuationToken"))
-        
+        signUpResponseValidatorMock.mockValidateSignUpContinueFunc(.success(continuationToken: "continuationToken"))
+
         let signInRequestProviderMock = MSALNativeAuthSignInRequestProviderMock()
         
         let expectedUsername = "username"
diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthUserAccountResultTests.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthUserAccountResultTests.swift
index d0382a0db4..73ec596553 100644
--- a/MSAL/test/unit/native_auth/public/MSALNativeAuthUserAccountResultTests.swift
+++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthUserAccountResultTests.swift
@@ -71,8 +71,9 @@ class MSALNativeAuthUserAccountResultTests: XCTestCase {
             configuration: MSALNativeAuthConfigStubs.configuration,
             cacheAccessor: MSALNativeAuthCacheAccessorMock()
         )
-        let mockDelegate = CredentialsDelegateSpy(expectation: expectation, expectedError: RetrieveAccessTokenError(type: .tokenNotFound))
-        sut.getAccessToken(delegate: mockDelegate)
+        let correlationId = UUID()
+        let mockDelegate = CredentialsDelegateSpy(expectation: expectation, expectedError: RetrieveAccessTokenError(type: .tokenNotFound, correlationId: correlationId, errorCodes: []))
+        sut.getAccessToken(correlationId: correlationId, delegate: mockDelegate)
         wait(for: [expectation], timeout: 1)
     }
 
diff --git a/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift b/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift
index b72ea24235..a45f69a76a 100644
--- a/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift
@@ -30,6 +30,7 @@ final class DispatchAccessTokenRetrieveCompletedTests: XCTestCase {
     private var telemetryExp: XCTestExpectation!
     private var delegateExp: XCTestExpectation!
     private var sut: CredentialsDelegateDispatcher!
+    private let correlationId = UUID()
 
     override func setUp() {
         super.setUp()
@@ -48,7 +49,7 @@ final class DispatchAccessTokenRetrieveCompletedTests: XCTestCase {
             self.telemetryExp.fulfill()
         })
 
-        await sut.dispatchAccessTokenRetrieveCompleted(accessToken: expectedToken)
+        await sut.dispatchAccessTokenRetrieveCompleted(accessToken: expectedToken, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -56,7 +57,7 @@ final class DispatchAccessTokenRetrieveCompletedTests: XCTestCase {
     }
 
     func test_dispatchAccessTokenRetrieveCompleted_whenDelegateOptionalMethodsNotImplemented() async {
-        let expectedError = RetrieveAccessTokenError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onAccessTokenRetrieveCompleted"))
+        let expectedError = RetrieveAccessTokenError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onAccessTokenRetrieveCompleted"), correlationId: correlationId)
         let delegate = CredentialsDelegateOptionalMethodsNotImplemented(expectation: delegateExp, expectedError: expectedError)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
@@ -68,7 +69,7 @@ final class DispatchAccessTokenRetrieveCompletedTests: XCTestCase {
             self.telemetryExp.fulfill()
         })
 
-        await sut.dispatchAccessTokenRetrieveCompleted(accessToken: "token")
+        await sut.dispatchAccessTokenRetrieveCompleted(accessToken: "token", correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.expectedError)
@@ -76,6 +77,7 @@ final class DispatchAccessTokenRetrieveCompletedTests: XCTestCase {
         func checkError(_ error: RetrieveAccessTokenError?) {
             XCTAssertEqual(error?.type, .generalError)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/SignInAfterSignUpDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/SignInAfterSignUpDelegateDispatcherTests.swift
index c01727ef48..c79a094c6e 100644
--- a/MSAL/test/unit/native_auth/public/delegate/SignInAfterSignUpDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/SignInAfterSignUpDelegateDispatcherTests.swift
@@ -30,6 +30,7 @@ final class SignInAfterSignUpDelegateDispatcherTests: XCTestCase {
     private var telemetryExp: XCTestExpectation!
     private var delegateExp: XCTestExpectation!
     private var sut: SignInAfterSignUpDelegateDispatcher!
+    private let correlationId = UUID()
 
     override func setUp() {
         super.setUp()
@@ -48,7 +49,7 @@ final class SignInAfterSignUpDelegateDispatcherTests: XCTestCase {
             self.telemetryExp.fulfill()
         })
 
-        await sut.dispatchSignInCompleted(result: expectedResult)
+        await sut.dispatchSignInCompleted(result: expectedResult, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -56,7 +57,7 @@ final class SignInAfterSignUpDelegateDispatcherTests: XCTestCase {
     }
 
     func test_dispatchSignInCompleted_whenDelegateOptionalMethodsNotImplemented() async {
-        let expectedError = SignInAfterSignUpError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted"))
+        let expectedError = SignInAfterSignUpError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted"), correlationId: correlationId)
         let delegate = SignInAfterSignUpDelegateOptionalMethodsNotImplemented(expectation: delegateExp, expectedError: expectedError)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
@@ -70,13 +71,14 @@ final class SignInAfterSignUpDelegateDispatcherTests: XCTestCase {
 
         let expectedResult = MSALNativeAuthUserAccountResultStub.result
 
-        await sut.dispatchSignInCompleted(result: expectedResult)
+        await sut.dispatchSignInCompleted(result: expectedResult, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.expectedError)
 
         func checkError(_ error: SignInAfterSignUpError?) {
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift
index b7b8e0d0d9..c4aaaca769 100644
--- a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordRequiredDelegateDispatcherTests.swift
@@ -56,7 +56,7 @@ final class ResetPasswordRequiredDelegateDispatcherTests: XCTestCase {
             correlationId: correlationId
         )
 
-        await sut.dispatchResetPasswordCompleted(newState: expectedState)
+        await sut.dispatchResetPasswordCompleted(newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -66,7 +66,7 @@ final class ResetPasswordRequiredDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchPasswordRequired_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = ResetPasswordRequiredDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = PasswordRequiredError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onResetPasswordCompleted"))
+        let expectedError = PasswordRequiredError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onResetPasswordCompleted"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? PasswordRequiredError else {
@@ -84,7 +84,7 @@ final class ResetPasswordRequiredDelegateDispatcherTests: XCTestCase {
             correlationId: correlationId
         )
 
-        await sut.dispatchResetPasswordCompleted(newState: expectedState)
+        await sut.dispatchResetPasswordCompleted(newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.error)
@@ -92,6 +92,7 @@ final class ResetPasswordRequiredDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: PasswordRequiredError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift
index be7c261f60..d3ccaeb6e4 100644
--- a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordResendCodeDelegateDispatcherTests.swift
@@ -58,7 +58,8 @@ final class ResetPasswordResendCodeDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -71,7 +72,7 @@ final class ResetPasswordResendCodeDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchResetPasswordResendCodeRequired_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = ResetPasswordResendCodeDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = ResendCodeError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onResetPasswordResendCodeRequired"))
+        let expectedError = ResendCodeError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onResetPasswordResendCodeRequired"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? ResendCodeError else {
@@ -91,7 +92,8 @@ final class ResetPasswordResendCodeDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -99,6 +101,7 @@ final class ResetPasswordResendCodeDelegateDispatcherTests: XCTestCase {
 
         func checkError(_ error: ResendCodeError?) {
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift
index f595aa02e9..6632ecd19b 100644
--- a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordStartDelegateDispatcherTests.swift
@@ -58,7 +58,8 @@ final class ResetPasswordStartDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -71,7 +72,7 @@ final class ResetPasswordStartDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchResetPasswordCodeRequired_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = ResetPasswordStartDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = ResetPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onResetPasswordCodeRequired"))
+        let expectedError = ResetPasswordStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onResetPasswordCodeRequired"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? ResetPasswordStartError else {
@@ -91,7 +92,8 @@ final class ResetPasswordStartDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -100,6 +102,7 @@ final class ResetPasswordStartDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: ResetPasswordStartError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift
index aa7ee163da..40d48ba5d2 100644
--- a/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/ResetPasswordVerifyCodeDelegateDispatcherTests.swift
@@ -51,7 +51,7 @@ final class ResetPasswordVerifyCodeDelegateDispatcherTests: XCTestCase {
 
         let expectedState = ResetPasswordRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "username", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchPasswordRequired(newState: expectedState)
+        await sut.dispatchPasswordRequired(newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -60,7 +60,7 @@ final class ResetPasswordVerifyCodeDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchPasswordRequired_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = ResetPasswordVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onPasswordRequired"))
+        let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onPasswordRequired"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? VerifyCodeError else {
@@ -73,7 +73,7 @@ final class ResetPasswordVerifyCodeDelegateDispatcherTests: XCTestCase {
 
         let expectedState = ResetPasswordRequiredState(controller: controllerFactoryMock.resetPasswordController, username: "username", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchPasswordRequired(newState: expectedState)
+        await sut.dispatchPasswordRequired(newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.error)
@@ -81,6 +81,7 @@ final class ResetPasswordVerifyCodeDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: VerifyCodeError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/reset_password/SignInAfterResetPasswordDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/reset_password/SignInAfterResetPasswordDelegateDispatcherTests.swift
index 57cfefd442..6e7c1eb917 100644
--- a/MSAL/test/unit/native_auth/public/delegate/reset_password/SignInAfterResetPasswordDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/reset_password/SignInAfterResetPasswordDelegateDispatcherTests.swift
@@ -30,6 +30,7 @@ final class SignInAfterResetPasswordDelegateDispatcherTests: XCTestCase {
     private var telemetryExp: XCTestExpectation!
     private var delegateExp: XCTestExpectation!
     private var sut: SignInAfterResetPasswordDelegateDispatcher!
+    private var correlationId = UUID()
 
     override func setUp() {
         super.setUp()
@@ -48,7 +49,7 @@ final class SignInAfterResetPasswordDelegateDispatcherTests: XCTestCase {
             self.telemetryExp.fulfill()
         })
 
-        await sut.dispatchSignInCompleted(result: expectedResult)
+        await sut.dispatchSignInCompleted(result: expectedResult, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -56,7 +57,7 @@ final class SignInAfterResetPasswordDelegateDispatcherTests: XCTestCase {
     }
 
     func test_dispatchSignInCompleted_whenDelegateOptionalMethodsNotImplemented() async {
-        let expectedError = SignInAfterResetPasswordError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted"))
+        let expectedError = SignInAfterResetPasswordError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted"), correlationId: correlationId)
         let delegate = SignInAfterResetPasswordDelegateOptionalMethodsNotImplemented(expectation: delegateExp, expectedError: expectedError)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
@@ -70,12 +71,13 @@ final class SignInAfterResetPasswordDelegateDispatcherTests: XCTestCase {
 
         let expectedResult = MSALNativeAuthUserAccountResultStub.result
 
-        await sut.dispatchSignInCompleted(result: expectedResult)
+        await sut.dispatchSignInCompleted(result: expectedResult, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
         func checkError(_ error: SignInAfterResetPasswordError?) {
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordRequiredDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordRequiredDelegateDispatcherTests.swift
index c394755896..d6bc0ce04a 100644
--- a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordRequiredDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordRequiredDelegateDispatcherTests.swift
@@ -30,6 +30,7 @@ final class SignInPasswordRequiredDelegateDispatcherTests: XCTestCase {
     private var delegateExp: XCTestExpectation!
     private var sut: SignInPasswordRequiredDelegateDispatcher!
     private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock()
+    private let correlationId = UUID()
 
     override func setUp() {
         super.setUp()
@@ -48,7 +49,7 @@ final class SignInPasswordRequiredDelegateDispatcherTests: XCTestCase {
             self.telemetryExp.fulfill()
         })
 
-        await sut.dispatchSignInCompleted(result: expectedResult)
+        await sut.dispatchSignInCompleted(result: expectedResult, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -56,7 +57,7 @@ final class SignInPasswordRequiredDelegateDispatcherTests: XCTestCase {
     }
 
     func test_dispatchSignInCompleted_whenDelegateOptionalMethodsNotImplemented() async {
-        let expectedError = PasswordRequiredError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted"))
+        let expectedError = PasswordRequiredError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted"), correlationId: correlationId)
         let delegate = SignInPasswordRequiredDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
 
 
@@ -71,7 +72,7 @@ final class SignInPasswordRequiredDelegateDispatcherTests: XCTestCase {
 
         let expectedResult = MSALNativeAuthUserAccountResultStub.result
 
-        await sut.dispatchSignInCompleted(result: expectedResult)
+        await sut.dispatchSignInCompleted(result: expectedResult, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.delegateError)
@@ -79,6 +80,7 @@ final class SignInPasswordRequiredDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: PasswordRequiredError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift
index 8c1fecae3b..c1ff275498 100644
--- a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInPasswordStartDelegateDispatcherTests.swift
@@ -58,7 +58,8 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -70,7 +71,7 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase {
     }
 
     func test_dispatchSignInCodeRequired_whenDelegateOptionalMethodsNotImplemented() async {
-        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired"))
+        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired"), correlationId: correlationId)
         let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: delegateExp, expectedError: expectedError)
 
 
@@ -92,7 +93,8 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -101,6 +103,7 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: SignInStartError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 
@@ -115,7 +118,7 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase {
             self.telemetryExp.fulfill()
         })
 
-        await sut.dispatchSignInCompleted(result: expectedResult)
+        await sut.dispatchSignInCompleted(result: expectedResult, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -123,7 +126,7 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase {
     }
 
     func test_dispatchSignInCompleted_whenDelegateOptionalMethodsNotImplemented() async {
-        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted"))
+        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted"), correlationId: correlationId)
         let delegate = SignInPasswordStartDelegateOptionalMethodNotImplemented(expectation: delegateExp, expectedError: expectedError)
 
 
@@ -138,7 +141,7 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase {
 
         let expectedResult = MSALNativeAuthUserAccountResultStub.result
 
-        await sut.dispatchSignInCompleted(result: expectedResult)
+        await sut.dispatchSignInCompleted(result: expectedResult, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.expectedError)
@@ -146,6 +149,7 @@ final class SignInPasswordStartDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: SignInStartError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInResendCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInResendCodeDelegateDispatcherTests.swift
index 61f5fead5e..7acea4d591 100644
--- a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInResendCodeDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInResendCodeDelegateDispatcherTests.swift
@@ -58,7 +58,8 @@ final class SignInResendCodeDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -68,7 +69,7 @@ final class SignInResendCodeDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchSignInResendCodeCodeRequired_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = SignInResendCodeDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = ResendCodeError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInResendCodeCodeRequired"))
+        let expectedError = ResendCodeError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInResendCodeCodeRequired"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? ResendCodeError else {
@@ -88,7 +89,8 @@ final class SignInResendCodeDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -96,6 +98,7 @@ final class SignInResendCodeDelegateDispatcherTests: XCTestCase {
 
         func checkError(_ error: ResendCodeError?) {
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInStartDelegateDispatcherTests.swift
index c7047a70b8..12bd00da63 100644
--- a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInStartDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInStartDelegateDispatcherTests.swift
@@ -57,7 +57,8 @@ final class SignInStartDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -69,7 +70,7 @@ final class SignInStartDelegateDispatcherTests: XCTestCase {
     }
 
     func test_dispatchSignInCodeRequired_whenDelegateOptionalMethodsNotImplemented() async {
-        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired"))
+        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCodeRequired"), correlationId: correlationId)
         let delegate = SignInCodeStartDelegateOptionalMethodNotImplemented(expectation: delegateExp, expectedError: expectedError)
 
 
@@ -91,7 +92,8 @@ final class SignInStartDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -100,6 +102,7 @@ final class SignInStartDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: SignInStartError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 
@@ -115,7 +118,7 @@ final class SignInStartDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignInPasswordRequiredState(scopes: [], username: "username", controller: controllerFactoryMock.signInController, continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignInPasswordRequired(newState: expectedState)
+        await sut.dispatchSignInPasswordRequired(newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -123,7 +126,7 @@ final class SignInStartDelegateDispatcherTests: XCTestCase {
     }
 
     func test_dispatchSignInPasswordRequired_whenDelegateOptionalMethodsNotImplemented() async {
-        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInPasswordRequired"))
+        let expectedError = SignInStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInPasswordRequired"), correlationId: correlationId)
         let delegate = SignInCodeStartDelegateOptionalMethodNotImplemented(expectation: delegateExp, expectedError: expectedError)
 
 
@@ -138,7 +141,7 @@ final class SignInStartDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignInPasswordRequiredState(scopes: [], username: "username", controller: controllerFactoryMock.signInController, continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignInPasswordRequired(newState: expectedState)
+        await sut.dispatchSignInPasswordRequired(newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.expectedError)
@@ -146,6 +149,7 @@ final class SignInStartDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: SignInStartError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInVerifyCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInVerifyCodeDelegateDispatcherTests.swift
index a1d04bac36..f520f8d6b0 100644
--- a/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInVerifyCodeDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/sign_in/SignInVerifyCodeDelegateDispatcherTests.swift
@@ -31,6 +31,7 @@ final class SignInVerifyCodeDelegateDispatcherTests: XCTestCase {
     private var delegateExp: XCTestExpectation!
     private var sut: SignInVerifyCodeDelegateDispatcher!
     private let controllerFactoryMock = MSALNativeAuthControllerFactoryMock()
+    private let correlationId = UUID()
 
     override func setUp() {
         super.setUp()
@@ -49,7 +50,7 @@ final class SignInVerifyCodeDelegateDispatcherTests: XCTestCase {
             self.telemetryExp.fulfill()
         })
 
-        await sut.dispatchSignInCompleted(result: expectedResult)
+        await sut.dispatchSignInCompleted(result: expectedResult, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -57,7 +58,7 @@ final class SignInVerifyCodeDelegateDispatcherTests: XCTestCase {
     }
 
     func test_dispatchSignInCompleted_whenDelegateOptionalMethodsNotImplemented() async {
-        let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted"))
+        let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted"), correlationId: correlationId)
         let delegate = SignInVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
 
 
@@ -72,7 +73,7 @@ final class SignInVerifyCodeDelegateDispatcherTests: XCTestCase {
 
         let expectedResult = MSALNativeAuthUserAccountResultStub.result
 
-        await sut.dispatchSignInCompleted(result: expectedResult)
+        await sut.dispatchSignInCompleted(result: expectedResult, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.expectedError)
@@ -80,6 +81,7 @@ final class SignInVerifyCodeDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: VerifyCodeError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift
index e9827bf514..2249ec9b91 100644
--- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpAttributesRequiredDelegateDispatcherTests.swift
@@ -56,7 +56,7 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState)
+        await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -66,7 +66,7 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchSignUpAttributesRequired_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = SignUpAttributesRequiredDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = AttributesRequiredError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired"))
+        let expectedError = AttributesRequiredError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? AttributesRequiredError else {
@@ -84,13 +84,14 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState)
+        await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.error)
 
         func checkError(_ error: AttributesRequiredError?) {
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 
@@ -108,7 +109,7 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames, newState: expectedState)
+        await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames, newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -118,7 +119,7 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchSignUpAttributesInvalid_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = SignUpAttributesRequiredDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = AttributesRequiredError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid"))
+        let expectedError = AttributesRequiredError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? AttributesRequiredError else {
@@ -133,13 +134,14 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames, newState: expectedState)
+        await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames, newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.error)
 
         func checkError(_ error: AttributesRequiredError?) {
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 
@@ -155,7 +157,7 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpCompleted(newState: expectedState)
+        await sut.dispatchSignUpCompleted(newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -164,7 +166,7 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchSignUpCompleted_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = SignUpAttributesRequiredDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = AttributesRequiredError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted"))
+        let expectedError = AttributesRequiredError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? AttributesRequiredError else {
@@ -177,13 +179,14 @@ final class SignUpAttributesRequiredDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpCompleted(newState: expectedState)
+        await sut.dispatchSignUpCompleted(newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.error)
 
         func checkError(_ error: AttributesRequiredError?) {
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift
index c6978e31f3..bd8f03fd4e 100644
--- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordRequiredDelegateDispatcherTests.swift
@@ -56,7 +56,7 @@ final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState)
+        await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -66,7 +66,7 @@ final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchSignUpVerifyCode_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = SignUpPasswordRequiredDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = PasswordRequiredError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired"))
+        let expectedError = PasswordRequiredError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? PasswordRequiredError else {
@@ -84,7 +84,7 @@ final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState)
+        await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.error)
@@ -92,6 +92,7 @@ final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: PasswordRequiredError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 
@@ -107,7 +108,7 @@ final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpCompleted(newState: expectedState)
+        await sut.dispatchSignUpCompleted(newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -116,7 +117,7 @@ final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchSignUpCompleted_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = SignUpPasswordRequiredDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = PasswordRequiredError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted"))
+        let expectedError = PasswordRequiredError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? PasswordRequiredError else {
@@ -129,7 +130,7 @@ final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpCompleted(newState: expectedState)
+        await sut.dispatchSignUpCompleted(newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.error)
@@ -137,6 +138,7 @@ final class SignUpPasswordRequiredDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: PasswordRequiredError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift
index 810ee5a175..71c3e9046a 100644
--- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpPasswordStartDelegateDispatcherTests.swift
@@ -58,7 +58,8 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -71,7 +72,7 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchSignUpPasswordCodeRequired_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = SignUpPasswordStartDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = SignUpStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCodeRequired"))
+        let expectedError = SignUpStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCodeRequired"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? SignUpStartError else {
@@ -91,7 +92,8 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -100,6 +102,7 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: SignUpStartError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 
@@ -115,7 +118,7 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase {
 
         let expectedAttributeNames = ["attribute1", "attribute2"]
 
-        await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames)
+        await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -124,7 +127,7 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchSignUpAttributesInvalid_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = SignUpPasswordStartDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = SignUpStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid"))
+        let expectedError = SignUpStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? SignUpStartError else {
@@ -137,7 +140,7 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase {
 
         let expectedAttributeNames = ["attribute1", "attribute2"]
 
-        await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames)
+        await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.error)
@@ -145,6 +148,7 @@ final class SignUpPasswordStartDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: SignUpStartError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpResendCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpResendCodeDelegateDispatcherTests.swift
index edfe6906ca..94229ba5ec 100644
--- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpResendCodeDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpResendCodeDelegateDispatcherTests.swift
@@ -58,7 +58,8 @@ final class SignUpResendCodeDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -71,7 +72,7 @@ final class SignUpResendCodeDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchSignUpResendCode_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = SignUpResendCodeDelegateMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = ResendCodeError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpResendCodeCodeRequired"))
+        let expectedError = ResendCodeError(message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpResendCodeCodeRequired"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? ResendCodeError else {
@@ -91,7 +92,8 @@ final class SignUpResendCodeDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -99,6 +101,7 @@ final class SignUpResendCodeDelegateDispatcherTests: XCTestCase {
 
         func checkError(_ error: ResendCodeError?) {
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpStartDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpStartDelegateDispatcherTests.swift
index c5d1ba7bc9..5357f1f311 100644
--- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpStartDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpStartDelegateDispatcherTests.swift
@@ -58,7 +58,8 @@ final class SignUpStartDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -71,7 +72,7 @@ final class SignUpStartDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchSignUpCodeRequired_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = SignUpStartDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = SignUpStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCodeRequired"))
+        let expectedError = SignUpStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCodeRequired"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? SignUpStartError else {
@@ -91,7 +92,8 @@ final class SignUpStartDelegateDispatcherTests: XCTestCase {
             newState: expectedState,
             sentTo: expectedSentTo,
             channelTargetType: expectedChannelTargetType,
-            codeLength: expectedCodeLength
+            codeLength: expectedCodeLength,
+            correlationId: correlationId
         )
 
         await fulfillment(of: [telemetryExp, delegateExp])
@@ -100,6 +102,7 @@ final class SignUpStartDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: SignUpStartError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 
@@ -115,7 +118,7 @@ final class SignUpStartDelegateDispatcherTests: XCTestCase {
 
         let expectedAttributeNames = ["attribute1", "attribute2"]
 
-        await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames)
+        await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -124,7 +127,7 @@ final class SignUpStartDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchSignUpAttributesInvalid_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = SignUpStartDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = SignUpStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid"))
+        let expectedError = SignUpStartError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? SignUpStartError else {
@@ -137,7 +140,7 @@ final class SignUpStartDelegateDispatcherTests: XCTestCase {
 
         let expectedAttributeNames = ["attribute1", "attribute2"]
 
-        await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames)
+        await sut.dispatchSignUpAttributesInvalid(attributeNames: expectedAttributeNames, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.error)
@@ -145,6 +148,7 @@ final class SignUpStartDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: SignUpStartError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift
index e42cc2a23b..75455859a9 100644
--- a/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/sign_up/SignUpVerifyCodeDelegateDispatcherTests.swift
@@ -56,7 +56,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState)
+        await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -66,7 +66,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchSignUpVerifyCode_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = SignUpVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired"))
+        let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? VerifyCodeError else {
@@ -84,7 +84,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignUpAttributesRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState)
+        await sut.dispatchSignUpAttributesRequired(attributes: expectedAttributes, newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.error)
@@ -92,6 +92,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: VerifyCodeError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 
@@ -107,7 +108,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignUpPasswordRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpPasswordRequired(newState: expectedState)
+        await sut.dispatchSignUpPasswordRequired(newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -116,7 +117,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchSignUpPasswordRequired_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = SignUpVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpPasswordRequired"))
+        let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpPasswordRequired"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? VerifyCodeError else {
@@ -129,7 +130,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignUpPasswordRequiredState(controller: controllerFactoryMock.signUpController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpPasswordRequired(newState: expectedState)
+        await sut.dispatchSignUpPasswordRequired(newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.error)
@@ -137,6 +138,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: VerifyCodeError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 
@@ -152,7 +154,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpCompleted(newState: expectedState)
+        await sut.dispatchSignUpCompleted(newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
@@ -161,7 +163,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase {
 
     func test_dispatchSignUpCompleted_whenDelegateOptionalMethodsNotImplemented() async {
         let delegate = SignUpVerifyCodeDelegateOptionalMethodsNotImplemented(expectation: delegateExp)
-        let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted"))
+        let expectedError = VerifyCodeError(type: .generalError, message: String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted"), correlationId: correlationId)
 
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case let .failure(error) = result, let customError = error as? VerifyCodeError else {
@@ -174,7 +176,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase {
 
         let expectedState = SignInAfterSignUpState(controller: controllerFactoryMock.signInController, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
-        await sut.dispatchSignUpCompleted(newState: expectedState)
+        await sut.dispatchSignUpCompleted(newState: expectedState, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.error)
@@ -182,6 +184,7 @@ final class SignUpVerifyCodeDelegateDispatcherTests: XCTestCase {
         func checkError(_ error: VerifyCodeError?) {
             XCTAssertEqual(error?.type, expectedError.type)
             XCTAssertEqual(error?.errorDescription, expectedError.errorDescription)
+            XCTAssertEqual(error?.correlationId, expectedError.correlationId)
         }
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/error/AttributesRequiredErrorTests.swift b/MSAL/test/unit/native_auth/public/error/AttributesRequiredErrorTests.swift
index 9a3ec5deee..85a80ab607 100644
--- a/MSAL/test/unit/native_auth/public/error/AttributesRequiredErrorTests.swift
+++ b/MSAL/test/unit/native_auth/public/error/AttributesRequiredErrorTests.swift
@@ -24,6 +24,7 @@
 
 import XCTest
 @testable import MSAL
+@_implementationOnly import MSAL_Unit_Test_Private
 
 final class AttributesRequiredErrorTests: XCTestCase {
 
@@ -31,12 +32,20 @@ final class AttributesRequiredErrorTests: XCTestCase {
 
     func test_customErrorDescription() {
         let expectedMessage = "Custom error message"
-        sut = .init(message: expectedMessage)
+        let uuid = UUID(uuidString: DEFAULT_TEST_UID)!
+
+        sut = .init(message: expectedMessage, correlationId: uuid)
+        
         XCTAssertEqual(sut.errorDescription, expectedMessage)
+        XCTAssertEqual(sut.correlationId, uuid)
     }
 
     func test_defaultErrorDescription() {
-        sut = .init()
+        let uuid = UUID(uuidString: DEFAULT_TEST_UID)!
+
+        sut = .init(correlationId: uuid)
+
         XCTAssertEqual(sut.errorDescription, MSALNativeAuthErrorMessage.generalError)
+        XCTAssertEqual(sut.correlationId, uuid)
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/error/PasswordRequiredErrorTests.swift b/MSAL/test/unit/native_auth/public/error/PasswordRequiredErrorTests.swift
index 780fddeabb..72ef8f40a9 100644
--- a/MSAL/test/unit/native_auth/public/error/PasswordRequiredErrorTests.swift
+++ b/MSAL/test/unit/native_auth/public/error/PasswordRequiredErrorTests.swift
@@ -35,15 +35,15 @@ final class PasswordRequiredErrorTests: XCTestCase {
 
     func test_customErrorDescription() {
         let expectedMessage = "Custom error message"
-        sut = .init(type: .generalError, message: expectedMessage)
+        sut = .init(type: .generalError, message: expectedMessage, correlationId: .init())
         XCTAssertEqual(sut.errorDescription, expectedMessage)
     }
 
     func test_defaultErrorDescription() {
         let sut: [PasswordRequiredError] = [
-            .init(type: .browserRequired),
-            .init(type: .invalidPassword),
-            .init(type: .generalError)
+            .init(type: .browserRequired, correlationId: .init()),
+            .init(type: .invalidPassword, correlationId: .init()),
+            .init(type: .generalError, correlationId: .init())
         ]
 
         let expectedErrorDescriptions = [
@@ -60,13 +60,13 @@ final class PasswordRequiredErrorTests: XCTestCase {
     }
 
     func test_isBrowserRequired() {
-        sut = .init(type: .browserRequired)
+        sut = .init(type: .browserRequired, correlationId: .init())
         XCTAssertTrue(sut.isBrowserRequired)
         XCTAssertFalse(sut.isInvalidPassword)
     }
 
     func test_isInvalidPassword() {
-        sut = .init(type: .invalidPassword)
+        sut = .init(type: .invalidPassword, correlationId: .init())
         XCTAssertTrue(sut.isInvalidPassword)
         XCTAssertFalse(sut.isBrowserRequired)
     }
diff --git a/MSAL/test/unit/native_auth/public/error/ResendCodeErrorTests.swift b/MSAL/test/unit/native_auth/public/error/ResendCodeErrorTests.swift
index 7dc8ae6709..ef23395e5e 100644
--- a/MSAL/test/unit/native_auth/public/error/ResendCodeErrorTests.swift
+++ b/MSAL/test/unit/native_auth/public/error/ResendCodeErrorTests.swift
@@ -31,12 +31,12 @@ final class ResendCodeErrorTests: XCTestCase {
 
     func test_customErrorDescription() {
         let expectedMessage = "Custom error message"
-        sut = .init(message: expectedMessage)
+        sut = .init(message: expectedMessage, correlationId: .init())
         XCTAssertEqual(sut.errorDescription, expectedMessage)
     }
 
     func test_defaultErrorDescription() {
-        sut = .init()
+        sut = .init(correlationId: .init())
         XCTAssertEqual(sut.errorDescription, MSALNativeAuthErrorMessage.generalError)
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/error/ResetPasswordStartErrorTests.swift b/MSAL/test/unit/native_auth/public/error/ResetPasswordStartErrorTests.swift
index 7e6abcb651..f7d3574239 100644
--- a/MSAL/test/unit/native_auth/public/error/ResetPasswordStartErrorTests.swift
+++ b/MSAL/test/unit/native_auth/public/error/ResetPasswordStartErrorTests.swift
@@ -35,17 +35,17 @@ final class ResetPasswordStartErrorTests: XCTestCase {
 
     func test_customErrorDescription() {
         let expectedMessage = "Custom error message"
-        sut = .init(type: .generalError, message: expectedMessage)
+        sut = .init(type: .generalError, message: expectedMessage, correlationId: .init())
         XCTAssertEqual(sut.errorDescription, expectedMessage)
     }
 
     func test_defaultErrorDescription() {
         let sut: [ResetPasswordStartError] = [
-            .init(type: .browserRequired),
-            .init(type: .userDoesNotHavePassword),
-            .init(type: .userNotFound),
-            .init(type: .invalidUsername),
-            .init(type: .generalError)
+            .init(type: .browserRequired, correlationId: .init()),
+            .init(type: .userDoesNotHavePassword, correlationId: .init()),
+            .init(type: .userNotFound, correlationId: .init()),
+            .init(type: .invalidUsername, correlationId: .init()),
+            .init(type: .generalError, correlationId: .init())
         ]
 
         let expectedIdentifiers = [
@@ -64,7 +64,7 @@ final class ResetPasswordStartErrorTests: XCTestCase {
     }
 
     func test_isBrowserRequired() {
-        sut = .init(type: .browserRequired)
+        sut = .init(type: .browserRequired, correlationId: .init())
         XCTAssertTrue(sut.isBrowserRequired)
         XCTAssertFalse(sut.isUserDoesNotHavePassword)
         XCTAssertFalse(sut.isUserNotFound)
@@ -72,7 +72,7 @@ final class ResetPasswordStartErrorTests: XCTestCase {
     }
 
     func test_isUserDoesNotHaveAPassword() {
-        sut = .init(type: .userDoesNotHavePassword)
+        sut = .init(type: .userDoesNotHavePassword, correlationId: .init())
         XCTAssertTrue(sut.isUserDoesNotHavePassword)
         XCTAssertFalse(sut.isBrowserRequired)
         XCTAssertFalse(sut.isUserNotFound)
@@ -80,7 +80,7 @@ final class ResetPasswordStartErrorTests: XCTestCase {
     }
 
     func test_isUserNotFound() {
-        sut = .init(type: .userNotFound)
+        sut = .init(type: .userNotFound, correlationId: .init())
         XCTAssertTrue(sut.isUserNotFound)
         XCTAssertFalse(sut.isBrowserRequired)
         XCTAssertFalse(sut.isUserDoesNotHavePassword)
@@ -88,7 +88,7 @@ final class ResetPasswordStartErrorTests: XCTestCase {
     }
 
     func test_isInvalidUsername() {
-        sut = .init(type: .invalidUsername)
+        sut = .init(type: .invalidUsername, correlationId: .init())
         XCTAssertTrue(sut.isInvalidUsername)
         XCTAssertFalse(sut.isBrowserRequired)
         XCTAssertFalse(sut.isUserDoesNotHavePassword)
diff --git a/MSAL/test/unit/native_auth/public/error/RetrieveAccessTokenErrorTests.swift b/MSAL/test/unit/native_auth/public/error/RetrieveAccessTokenErrorTests.swift
index 46e0808fb1..26040a55b8 100644
--- a/MSAL/test/unit/native_auth/public/error/RetrieveAccessTokenErrorTests.swift
+++ b/MSAL/test/unit/native_auth/public/error/RetrieveAccessTokenErrorTests.swift
@@ -35,16 +35,16 @@ final class RetrieveAccessTokenErrorTests: XCTestCase {
 
     func test_customErrorDescription() {
         let expectedMessage = "Custom error message"
-        sut = .init(type: .generalError, message: expectedMessage)
+        sut = .init(type: .generalError, message: expectedMessage, correlationId: .init())
         XCTAssertEqual(sut.errorDescription, expectedMessage)
     }
 
     func test_defaultErrorDescription() {
         let sut: [RetrieveAccessTokenError] = [
-            .init(type: .browserRequired),
-            .init(type: .refreshTokenExpired),
-            .init(type: .tokenNotFound),
-            .init(type: .generalError)
+            .init(type: .browserRequired, correlationId: .init()),
+            .init(type: .refreshTokenExpired, correlationId: .init()),
+            .init(type: .tokenNotFound, correlationId: .init()),
+            .init(type: .generalError, correlationId: .init())
         ]
 
         let expectedIdentifiers = [
@@ -62,21 +62,21 @@ final class RetrieveAccessTokenErrorTests: XCTestCase {
     }
 
     func test_isBrowserRequired() {
-        sut = .init(type: .browserRequired)
+        sut = .init(type: .browserRequired, correlationId: .init())
         XCTAssertTrue(sut.isBrowserRequired)
         XCTAssertFalse(sut.isRefreshTokenExpired)
         XCTAssertFalse(sut.isTokenNotFound)
     }
 
     func test_isRefreshTokenExpired() {
-        sut = .init(type: .refreshTokenExpired)
+        sut = .init(type: .refreshTokenExpired, correlationId: .init())
         XCTAssertTrue(sut.isRefreshTokenExpired)
         XCTAssertFalse(sut.isBrowserRequired)
         XCTAssertFalse(sut.isTokenNotFound)
     }
 
     func test_isTokenNotFound() {
-        sut = .init(type: .tokenNotFound)
+        sut = .init(type: .tokenNotFound, correlationId: .init())
         XCTAssertTrue(sut.isTokenNotFound)
         XCTAssertFalse(sut.isBrowserRequired)
         XCTAssertFalse(sut.isRefreshTokenExpired)
diff --git a/MSAL/test/unit/native_auth/public/error/SignInAfterResetPasswordErrorTests.swift b/MSAL/test/unit/native_auth/public/error/SignInAfterResetPasswordErrorTests.swift
index b36ebdf1e6..9e42ba891d 100644
--- a/MSAL/test/unit/native_auth/public/error/SignInAfterResetPasswordErrorTests.swift
+++ b/MSAL/test/unit/native_auth/public/error/SignInAfterResetPasswordErrorTests.swift
@@ -31,12 +31,12 @@ final class SignInAfterResetPasswordErrorTests: XCTestCase {
 
     func test_customErrorDescription() {
         let expectedMessage = "Custom error message"
-        sut = .init(message: expectedMessage)
+        sut = .init(message: expectedMessage, correlationId: .init())
         XCTAssertEqual(sut.errorDescription, expectedMessage)
     }
 
     func test_defaultErrorDescription() {
-        sut = .init()
+        sut = .init(correlationId: .init())
         XCTAssertEqual(sut.errorDescription, MSALNativeAuthErrorMessage.generalError)
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/error/SignInAfterSignUpErrorTests.swift b/MSAL/test/unit/native_auth/public/error/SignInAfterSignUpErrorTests.swift
index 96932cbba1..5fa73cb0aa 100644
--- a/MSAL/test/unit/native_auth/public/error/SignInAfterSignUpErrorTests.swift
+++ b/MSAL/test/unit/native_auth/public/error/SignInAfterSignUpErrorTests.swift
@@ -31,12 +31,12 @@ final class SignInAfterSignUpErrorTests: XCTestCase {
 
     func test_customErrorDescription() {
         let expectedMessage = "Custom error message"
-        sut = .init(message: expectedMessage)
+        sut = .init(message: expectedMessage, correlationId: .init())
         XCTAssertEqual(sut.errorDescription, expectedMessage)
     }
 
     func test_defaultErrorDescription() {
-        sut = .init()
+        sut = .init(correlationId: .init())
         XCTAssertEqual(sut.errorDescription, MSALNativeAuthErrorMessage.generalError)
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/error/SignInStartErrorTests.swift b/MSAL/test/unit/native_auth/public/error/SignInStartErrorTests.swift
index d6629f74a2..b1189b6935 100644
--- a/MSAL/test/unit/native_auth/public/error/SignInStartErrorTests.swift
+++ b/MSAL/test/unit/native_auth/public/error/SignInStartErrorTests.swift
@@ -35,17 +35,17 @@ final class SignInPasswordStartErrorTests: XCTestCase {
 
     func test_customErrorDescription() {
         let expectedMessage = "Custom error message"
-        sut = .init(type: .generalError, message: expectedMessage)
+        sut = .init(type: .generalError, message: expectedMessage, correlationId: .init())
         XCTAssertEqual(sut.errorDescription, expectedMessage)
     }
 
     func test_defaultErrorDescription() {
         let sut: [SignInStartError] = [
-            .init(type: .browserRequired),
-            .init(type: .userNotFound),
-            .init(type: .invalidCredentials),
-            .init(type: .invalidUsername),
-            .init(type: .generalError)
+            .init(type: .browserRequired, correlationId: .init()),
+            .init(type: .userNotFound, correlationId: .init()),
+            .init(type: .invalidCredentials, correlationId: .init()),
+            .init(type: .invalidUsername, correlationId: .init()),
+            .init(type: .generalError, correlationId: .init())
         ]
 
         let expectedDescriptions = [
@@ -64,7 +64,7 @@ final class SignInPasswordStartErrorTests: XCTestCase {
     }
 
     func test_isBrowserRequired() {
-        sut = .init(type: .browserRequired)
+        sut = .init(type: .browserRequired, correlationId: .init())
         XCTAssertTrue(sut.isBrowserRequired)
         XCTAssertFalse(sut.isUserNotFound)
         XCTAssertFalse(sut.isInvalidCredentials)
@@ -72,7 +72,7 @@ final class SignInPasswordStartErrorTests: XCTestCase {
     }
 
     func test_isUserNotFound() {
-        sut = .init(type: .userNotFound)
+        sut = .init(type: .userNotFound, correlationId: .init())
         XCTAssertTrue(sut.isUserNotFound)
         XCTAssertFalse(sut.isBrowserRequired)
         XCTAssertFalse(sut.isInvalidCredentials)
@@ -80,7 +80,7 @@ final class SignInPasswordStartErrorTests: XCTestCase {
     }
 
     func test_isInvalidPassword() {
-        sut = .init(type: .invalidCredentials)
+        sut = .init(type: .invalidCredentials, correlationId: .init())
         XCTAssertTrue(sut.isInvalidCredentials)
         XCTAssertFalse(sut.isBrowserRequired)
         XCTAssertFalse(sut.isUserNotFound)
@@ -88,7 +88,7 @@ final class SignInPasswordStartErrorTests: XCTestCase {
     }
 
     func test_isInvalidUsername() {
-        sut = .init(type: .invalidUsername)
+        sut = .init(type: .invalidUsername, correlationId: .init())
         XCTAssertTrue(sut.isInvalidUsername)
         XCTAssertFalse(sut.isBrowserRequired)
         XCTAssertFalse(sut.isUserNotFound)
diff --git a/MSAL/test/unit/native_auth/public/error/SignUpStartErrorTests.swift b/MSAL/test/unit/native_auth/public/error/SignUpStartErrorTests.swift
index a455e8a00d..1ed6746e92 100644
--- a/MSAL/test/unit/native_auth/public/error/SignUpStartErrorTests.swift
+++ b/MSAL/test/unit/native_auth/public/error/SignUpStartErrorTests.swift
@@ -35,17 +35,17 @@ final class SignUpStartErrorTests: XCTestCase {
 
     func test_customErrorDescription() {
         let expectedMessage = "Custom error message"
-        sut = .init(type: .generalError, message: expectedMessage)
+        sut = .init(type: .generalError, message: expectedMessage, correlationId: .init())
         XCTAssertEqual(sut.errorDescription, expectedMessage)
     }
 
     func test_defaultErrorDescription() {
         let sut: [SignUpStartError] = [
-            .init(type: .browserRequired),
-            .init(type: .userAlreadyExists),
-            .init(type: .invalidUsername),
-            .init(type: .invalidPassword),
-            .init(type: .generalError)
+            .init(type: .browserRequired, correlationId: .init()),
+            .init(type: .userAlreadyExists, correlationId: .init()),
+            .init(type: .invalidUsername, correlationId: .init()),
+            .init(type: .invalidPassword, correlationId: .init()),
+            .init(type: .generalError, correlationId: .init())
         ]
 
         let expectedDescriptions = [
@@ -64,7 +64,7 @@ final class SignUpStartErrorTests: XCTestCase {
     }
 
     func test_isBrowserRequired() {
-        sut = .init(type: .browserRequired)
+        sut = .init(type: .browserRequired, correlationId: .init())
         XCTAssertTrue(sut.isBrowserRequired)
         XCTAssertFalse(sut.isUserAlreadyExists)
         XCTAssertFalse(sut.isInvalidUsername)
@@ -72,7 +72,7 @@ final class SignUpStartErrorTests: XCTestCase {
     }
 
     func test_isUserAlreadyExists() {
-        sut = .init(type: .userAlreadyExists)
+        sut = .init(type: .userAlreadyExists, correlationId: .init())
         XCTAssertTrue(sut.isUserAlreadyExists)
         XCTAssertFalse(sut.isBrowserRequired)
         XCTAssertFalse(sut.isInvalidUsername)
@@ -80,7 +80,7 @@ final class SignUpStartErrorTests: XCTestCase {
     }
 
     func test_isInvalidUsername() {
-        sut = .init(type: .invalidUsername)
+        sut = .init(type: .invalidUsername, correlationId: .init())
         XCTAssertTrue(sut.isInvalidUsername)
         XCTAssertFalse(sut.isBrowserRequired)
         XCTAssertFalse(sut.isUserAlreadyExists)
@@ -88,7 +88,7 @@ final class SignUpStartErrorTests: XCTestCase {
     }
     
     func test_isInvalidPassword() {
-        sut = .init(type: .invalidPassword)
+        sut = .init(type: .invalidPassword, correlationId: .init())
         XCTAssertTrue(sut.isInvalidPassword)
         XCTAssertFalse(sut.isBrowserRequired)
         XCTAssertFalse(sut.isUserAlreadyExists)
diff --git a/MSAL/test/unit/native_auth/public/error/VerifyCodeErrorTests.swift b/MSAL/test/unit/native_auth/public/error/VerifyCodeErrorTests.swift
index c45b9eb1c9..7e270ea62a 100644
--- a/MSAL/test/unit/native_auth/public/error/VerifyCodeErrorTests.swift
+++ b/MSAL/test/unit/native_auth/public/error/VerifyCodeErrorTests.swift
@@ -35,15 +35,15 @@ final class VerifyCodeErrorTests: XCTestCase {
 
     func test_customErrorDescription() {
         let expectedMessage = "Custom error message"
-        sut = .init(type: .generalError, message: expectedMessage)
+        sut = .init(type: .generalError, message: expectedMessage, correlationId: .init())
         XCTAssertEqual(sut.errorDescription, expectedMessage)
     }
 
     func test_defaultErrorDescription() {
         let sut: [VerifyCodeError] = [
-            .init(type: .browserRequired),
-            .init(type: .invalidCode),
-            .init(type: .generalError)
+            .init(type: .browserRequired, correlationId: .init()),
+            .init(type: .invalidCode, correlationId: .init()),
+            .init(type: .generalError, correlationId: .init())
         ]
 
         let expectedDescriptions = [
@@ -60,13 +60,13 @@ final class VerifyCodeErrorTests: XCTestCase {
     }
 
     func test_isBrowserRequired() {
-        sut = .init(type: .browserRequired)
+        sut = .init(type: .browserRequired, correlationId: .init())
         XCTAssertTrue(sut.isBrowserRequired)
         XCTAssertFalse(sut.isInvalidCode)
     }
 
     func test_isInvalidCode() {
-        sut = .init(type: .invalidCode)
+        sut = .init(type: .invalidCode, correlationId: .init())
         XCTAssertTrue(sut.isInvalidCode)
         XCTAssertFalse(sut.isBrowserRequired)
     }
diff --git a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift
index 73f82de377..106a1079ab 100644
--- a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift
+++ b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordCodeSentStateTests.swift
@@ -44,11 +44,11 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase {
     // ResendCode
 
     func test_resendCode_delegate_whenError_shouldReturnCorrectError() {
-        let expectedError = ResendCodeError(message: "test error")
+        let expectedError = ResendCodeError(message: "test error", correlationId: correlationId)
         let expectedState = ResetPasswordCodeRequiredState(controller: controller, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
         let expectedResult: ResetPasswordResendCodeResult = .error(error: expectedError, newState: expectedState)
-        controller.resendCodeResponse = .init(expectedResult)
+        controller.resendCodeResponse = .init(expectedResult, correlationId: correlationId)
 
         let exp = expectation(description: "reset password states")
         let delegate = ResetPasswordResendCodeDelegateSpy(expectation: exp)
@@ -57,6 +57,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase {
         wait(for: [exp])
 
         XCTAssertEqual(delegate.error, expectedError)
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
         XCTAssertEqual(delegate.newState, expectedState)
     }
 
@@ -71,7 +72,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase {
             channelTargetType: .email,
             codeLength: 1
         )
-        controller.resendCodeResponse = .init(expectedResult, telemetryUpdate: { _ in
+        controller.resendCodeResponse = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -97,7 +98,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase {
             channelTargetType: .email,
             codeLength: 1
         )
-        controller.resendCodeResponse = .init(expectedResult, telemetryUpdate: { _ in
+        controller.resendCodeResponse = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -107,16 +108,17 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase {
         wait(for: [exp, exp2])
 
         XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onResetPasswordResendCodeRequired"))
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     // SubmitCode
 
     func test_submitCode_delegate_whenError_shouldReturnCorrectError() {
-        let expectedError = VerifyCodeError(type: .invalidCode)
+        let expectedError = VerifyCodeError(type: .invalidCode, correlationId: correlationId)
         let expectedState = ResetPasswordCodeRequiredState(controller: controller, username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
         let expectedResult: ResetPasswordSubmitCodeResult = .error(error: expectedError, newState: expectedState)
-        controller.submitCodeResponse = .init(expectedResult)
+        controller.submitCodeResponse = .init(expectedResult, correlationId: correlationId)
 
         let exp = expectation(description: "reset password states")
         let delegate = ResetPasswordVerifyCodeDelegateSpy(expectation: exp)
@@ -126,6 +128,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase {
 
         XCTAssertEqual(delegate.error, expectedError)
         XCTAssertEqual(delegate.newCodeRequiredState, expectedState)
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     func test_submitCode_delegate_success_shouldReturnPasswordRequired() {
@@ -134,7 +137,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase {
         let expectedState = ResetPasswordRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId)
 
         let expectedResult: ResetPasswordSubmitCodeResult = .passwordRequired(newState: expectedState)
-        controller.submitCodeResponse = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitCodeResponse = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -152,7 +155,7 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase {
         let expectedState = ResetPasswordRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId)
 
         let expectedResult: ResetPasswordSubmitCodeResult = .passwordRequired(newState: expectedState)
-        controller.submitCodeResponse = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitCodeResponse = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -163,5 +166,6 @@ final class ResetPasswordCodeRequiredStateTests: XCTestCase {
 
         XCTAssertEqual(delegate.error?.type, .generalError)
         XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onPasswordRequired"))
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift
index 9685650ede..09295d82c2 100644
--- a/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift
+++ b/MSAL/test/unit/native_auth/public/state_machine/reset_password/ResetPasswordRequiredStateTests.swift
@@ -55,10 +55,10 @@ final class ResetPasswordRequiredStateTests: XCTestCase {
         controllerMock = MSALNativeAuthResetPasswordControllerMock()
         let sut = ResetPasswordRequiredState(controller: controllerMock, username: "username", continuationToken: "", correlationId: correlationId)
 
-        let expectedError = PasswordRequiredError(type: .invalidPassword, message: nil)
+        let expectedError = PasswordRequiredError(type: .invalidPassword, message: nil, correlationId: correlationId)
         let expectedState = ResetPasswordRequiredState(controller: controllerMock, username: "username", continuationToken: "continuationToken", correlationId: correlationId)
 
-        let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.error(error: expectedError, newState: expectedState))
+        let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.error(error: expectedError, newState: expectedState), correlationId: correlationId)
         controllerMock.submitPasswordResponse = expectedResult
 
         let exp = expectation(description: "reset password states")
@@ -68,6 +68,7 @@ final class ResetPasswordRequiredStateTests: XCTestCase {
         wait(for: [exp])
 
         XCTAssertEqual(delegate.error?.type, expectedError.type)
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
         XCTAssertEqual(delegate.newPasswordRequiredState, expectedState)
     }
 
@@ -78,7 +79,7 @@ final class ResetPasswordRequiredStateTests: XCTestCase {
         let sut = ResetPasswordRequiredState(controller: controllerMock, username: "", continuationToken: "", correlationId: correlationId)
         let expectedState = SignInAfterResetPasswordState(controller: controllerFactoryMock.signInController, username: "", continuationToken: nil, correlationId: correlationId)
 
-        let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.completed(expectedState), telemetryUpdate: { _ in
+        let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.completed(expectedState), correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
         controllerMock.submitPasswordResponse = expectedResult
@@ -99,7 +100,7 @@ final class ResetPasswordRequiredStateTests: XCTestCase {
         let sut = ResetPasswordRequiredState(controller: controllerMock, username: "", continuationToken: "", correlationId: correlationId)
         let state = SignInAfterResetPasswordState(controller: controllerFactoryMock.signInController, username: "", continuationToken: nil, correlationId: correlationId)
 
-        let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.completed(state), telemetryUpdate: { _ in
+        let expectedResult: MSALNativeAuthResetPasswordControlling.ResetPasswordSubmitPasswordControllerResponse = .init(.completed(state), correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
         controllerMock.submitPasswordResponse = expectedResult
@@ -110,6 +111,7 @@ final class ResetPasswordRequiredStateTests: XCTestCase {
         wait(for: [exp, exp2])
 
         XCTAssertEqual(delegate.error?.type, .generalError)
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
         XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onResetPasswordCompleted"))
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift
index 6a422fbd3b..a29aa0228d 100644
--- a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift
+++ b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInCodeRequiredStateTests.swift
@@ -45,14 +45,14 @@ final class SignInCodeRequiredStateTests: XCTestCase {
     func test_resendCode_delegate_withError_shouldReturnSignInResendCodeError() {
         let exp = expectation(description: "sign-in states")
 
-        let expectedError = ResendCodeError(message: "test error")
+        let expectedError = ResendCodeError(message: "test error", correlationId: correlationId)
         let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, continuationToken: "continuationToken 2", correlationId: correlationId)
 
         let expectedResult: SignInResendCodeResult = .error(
             error: expectedError,
             newState: expectedState
         )
-        controller.resendCodeResult = .init(expectedResult)
+        controller.resendCodeResult = .init(expectedResult, correlationId: correlationId)
 
         let delegate = SignInResendCodeDelegateSpy(expectation: exp)
 
@@ -61,6 +61,7 @@ final class SignInCodeRequiredStateTests: XCTestCase {
 
         XCTAssertEqual(delegate.newSignInResendCodeError, expectedError)
         XCTAssertEqual(delegate.newSignInCodeRequiredState?.continuationToken, expectedState.continuationToken)
+        XCTAssertEqual(delegate.newSignInResendCodeError?.correlationId, correlationId)
     }
 
     func test_resendCode_delegate_success_shouldReturnSignInResendCodeCodeRequired() {
@@ -74,7 +75,7 @@ final class SignInCodeRequiredStateTests: XCTestCase {
             channelTargetType: .email,
             codeLength: 1
         )
-        controller.resendCodeResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.resendCodeResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -96,7 +97,7 @@ final class SignInCodeRequiredStateTests: XCTestCase {
             channelTargetType: .email,
             codeLength: 1
         )
-        controller.resendCodeResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.resendCodeResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -105,20 +106,21 @@ final class SignInCodeRequiredStateTests: XCTestCase {
         sut.resendCode(delegate: delegate)
         wait(for: [exp, exp2])
         XCTAssertEqual(delegate.newSignInResendCodeError?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInResendCodeCodeRequired"))
+        XCTAssertEqual(delegate.newSignInResendCodeError?.correlationId, correlationId)
     }
 
     // SubmitCode
 
     func test_submitCode_delegate_withError_shouldReturnSignInVerifyCodeError() {
         let exp = expectation(description: "sign-in states")
-        let expectedError = VerifyCodeError(type: .invalidCode)
+        let expectedError = VerifyCodeError(type: .invalidCode, correlationId: .init())
         let expectedState = SignInCodeRequiredState(scopes: [], controller: controller, continuationToken: "continuationToken 2", correlationId: correlationId)
 
         let expectedResult: SignInVerifyCodeResult = .error(
             error: expectedError,
             newState: expectedState
         )
-        controller.submitCodeResult = .init(expectedResult)
+        controller.submitCodeResult = .init(expectedResult, correlationId: correlationId)
 
         let delegate = SignInVerifyCodeDelegateSpy(expectation: exp, expectedError: expectedError)
         delegate.expectedNewState = expectedState
@@ -133,7 +135,7 @@ final class SignInCodeRequiredStateTests: XCTestCase {
         let expectedAccountResult = MSALNativeAuthUserAccountResultStub.result
 
         let expectedResult: SignInVerifyCodeResult = .completed(expectedAccountResult)
-        controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitCodeResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -149,7 +151,7 @@ final class SignInCodeRequiredStateTests: XCTestCase {
         let expectedAccountResult = MSALNativeAuthUserAccountResultStub.result
 
         let expectedResult: SignInVerifyCodeResult = .completed(expectedAccountResult)
-        controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitCodeResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -159,5 +161,6 @@ final class SignInCodeRequiredStateTests: XCTestCase {
         wait(for: [exp, exp2])
         XCTAssertEqual(delegate.expectedError?.type, .generalError)
         XCTAssertEqual(delegate.expectedError?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted"))
+        XCTAssertEqual(delegate.expectedError?.correlationId, correlationId)
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift
index 478103f312..af33aa6de1 100644
--- a/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift
+++ b/MSAL/test/unit/native_auth/public/state_machine/sign_in/SignInPasswordRequiredStateTests.swift
@@ -41,14 +41,14 @@ final class SignInPasswordRequiredStateTests: XCTestCase {
     // MARK: - Delegates
 
     func test_submitPassword_delegate_withError_shouldReturnError() {
-        let expectedError = PasswordRequiredError(type: .invalidPassword)
+        let expectedError = PasswordRequiredError(type: .invalidPassword, correlationId: .init())
         let expectedState = SignInPasswordRequiredState(scopes: [], username: "", controller: controller, continuationToken: "continuationToken 2", correlationId: correlationId)
 
         let expectedResult: SignInPasswordRequiredResult = .error(
             error: expectedError,
             newState: expectedState
         )
-        controller.submitPasswordResult = .init(expectedResult)
+        controller.submitPasswordResult = .init(expectedResult, correlationId: correlationId)
 
         let exp = expectation(description: "sign-in states")
         let delegate = SignInPasswordRequiredDelegateSpy(expectation: exp, expectedError: expectedError)
@@ -65,7 +65,7 @@ final class SignInPasswordRequiredStateTests: XCTestCase {
         let expectedAccountResult = MSALNativeAuthUserAccountResultStub.result
 
         let expectedResult: SignInPasswordRequiredResult = .completed(expectedAccountResult)
-        controller.submitPasswordResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitPasswordResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -81,7 +81,7 @@ final class SignInPasswordRequiredStateTests: XCTestCase {
         let expectedAccountResult = MSALNativeAuthUserAccountResultStub.result
 
         let expectedResult: SignInPasswordRequiredResult = .completed(expectedAccountResult)
-        controller.submitPasswordResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitPasswordResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -92,5 +92,6 @@ final class SignInPasswordRequiredStateTests: XCTestCase {
 
         XCTAssertNil(delegate.newPasswordRequiredState)
         XCTAssertEqual(delegate.delegateError?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignInCompleted"))
+        XCTAssertEqual(delegate.delegateError?.correlationId, correlationId)
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift
index 7b26d52cf5..7e64716e92 100644
--- a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift
+++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpAttributesRequiredStateTests.swift
@@ -43,10 +43,10 @@ final class SignUpAttributesRequiredStateTests: XCTestCase {
     // MARK: - Delegate
 
     func test_submitPassword_delegate_whenError_shouldReturnAttributesRequiredError() {
-        let expectedError = AttributesRequiredError()
+        let expectedError = AttributesRequiredError(correlationId: correlationId)
 
         let expectedResult: SignUpAttributesRequiredResult = .error(error: expectedError)
-        controller.submitAttributesResult = .init(expectedResult)
+        controller.submitAttributesResult = .init(expectedResult, correlationId: correlationId)
 
         let exp = expectation(description: "sign-up states")
         let delegate = SignUpAttributesRequiredDelegateSpy(expectation: exp)
@@ -55,6 +55,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase {
         wait(for: [exp])
 
         XCTAssertEqual(delegate.error, expectedError)
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     func test_submitPassword_delegate_whenSuccess_shouldReturnCompleted() {
@@ -63,7 +64,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase {
         let expectedState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
         let expectedResult: SignUpAttributesRequiredResult = .completed(expectedState)
-        controller.submitAttributesResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitAttributesResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -81,7 +82,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase {
         let expectedState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", continuationToken: "continuationToken", correlationId: UUID())
 
         let expectedResult: SignUpAttributesRequiredResult = .completed(expectedState)
-        controller.submitAttributesResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitAttributesResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -91,6 +92,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase {
         wait(for: [exp, exp2])
 
         XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted"))
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     func test_submitPassword_delegate_whenAttributesRequired_shouldReturnAttributesRequired() {
@@ -102,7 +104,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase {
         ]
 
         let expectedResult: SignUpAttributesRequiredResult = .attributesRequired(attributes: expectedAttributes, state: expectedState)
-        controller.submitAttributesResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitAttributesResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -124,7 +126,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase {
         ]
 
         let expectedResult: SignUpAttributesRequiredResult = .attributesRequired(attributes: expectedAttributes, state: expectedState)
-        controller.submitAttributesResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitAttributesResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -134,6 +136,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase {
         wait(for: [exp, exp2])
 
         XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired"))
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     func test_submitPassword_delegate_whenAttributesAreInvalid_shouldReturnAttributesInvalid() {
@@ -143,7 +146,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase {
         let expectedAttributes = ["anAttribute"]
 
         let expectedResult: SignUpAttributesRequiredResult = .attributesInvalid(attributes: expectedAttributes, newState: expectedState)
-        controller.submitAttributesResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitAttributesResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -163,7 +166,7 @@ final class SignUpAttributesRequiredStateTests: XCTestCase {
         let expectedAttributes = ["anAttribute"]
 
         let expectedResult: SignUpAttributesRequiredResult = .attributesInvalid(attributes: expectedAttributes, newState: expectedState)
-        controller.submitAttributesResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitAttributesResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -173,5 +176,6 @@ final class SignUpAttributesRequiredStateTests: XCTestCase {
         wait(for: [exp, exp2])
 
         XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesInvalid"))
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift
index ddc9fe8237..ded37afd55 100644
--- a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift
+++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpCodeSentStateTests.swift
@@ -44,10 +44,10 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
     // ResendCode
 
     func test_resendCode_delegate_whenError_shouldReturnCorrectError() {
-        let expectedError = ResendCodeError(message: "test error")
+        let expectedError = ResendCodeError(message: "test error", correlationId: correlationId)
 
         let expectedResult: SignUpResendCodeResult = .error(error: expectedError, newState: nil)
-        controller.resendCodeResult = .init(expectedResult)
+        controller.resendCodeResult = .init(expectedResult, correlationId: correlationId)
 
         let exp = expectation(description: "sign-up states")
         let delegate = SignUpResendCodeDelegateSpy(expectation: exp)
@@ -56,6 +56,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
         wait(for: [exp])
 
         XCTAssertEqual(delegate.error, expectedError)
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     func test_resendCode_delegate_success_shouldReturnCodeRequired() {
@@ -69,7 +70,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
             channelTargetType: .email,
             codeLength: 1
         )
-        controller.resendCodeResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.resendCodeResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -95,7 +96,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
             channelTargetType: .email,
             codeLength: 1
         )
-        controller.resendCodeResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.resendCodeResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -105,19 +106,20 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
         wait(for: [exp, exp2])
 
         XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpResendCodeCodeRequired"))
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     // SubmitCode
 
     func test_submitCode_delegate_whenError_shouldReturnCorrectError() {
-        let expectedError = VerifyCodeError(type: .invalidCode)
+        let expectedError = VerifyCodeError(type: .invalidCode, correlationId: correlationId)
         let expectedState = SignUpCodeRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId)
 
         let expectedResult: SignUpVerifyCodeResult = .error(
             error: expectedError,
             newState: expectedState
         )
-        controller.submitCodeResult = .init(expectedResult)
+        controller.submitCodeResult = .init(expectedResult, correlationId: correlationId)
 
         let exp = expectation(description: "sign-up states")
         let delegate = SignUpVerifyCodeDelegateSpy(expectation: exp)
@@ -127,6 +129,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
 
         XCTAssertEqual(delegate.error, expectedError)
         XCTAssertEqual(delegate.newCodeRequiredState?.continuationToken, expectedState.continuationToken)
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     func test_submitCode_delegate_whenPasswordRequired_AndUserHasImplementedOptionalDelegate_shouldReturnPasswordRequired() {
@@ -136,7 +139,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
         let exp2 = expectation(description: "exp telemetry is called")
 
         let expectedResult: SignUpVerifyCodeResult = .passwordRequired(expectedPasswordRequiredState)
-        controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitCodeResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -153,7 +156,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
         let exp2 = expectation(description: "exp telemetry is called")
 
         let expectedResult: SignUpVerifyCodeResult = .passwordRequired(.init(controller: controller, username: "", continuationToken: "", correlationId: correlationId))
-        controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitCodeResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -167,6 +170,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
             delegate.error?.errorDescription,
             String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpPasswordRequired")
         )
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     func test_submitCode_delegate_whenAttributesRequired_AndUserHasImplementedOptionalDelegate_shouldReturnAttributesRequired() {
@@ -176,7 +180,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
         let exp2 = expectation(description: "exp telemetry is called")
 
         let expectedResult: SignUpVerifyCodeResult = .attributesRequired(attributes: [], newState: expectedAttributesRequiredState)
-        controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitCodeResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -193,7 +197,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
         let exp2 = expectation(description: "exp telemetry is called")
 
         let expectedResult: SignUpVerifyCodeResult = .attributesRequired(attributes: [], newState: .init(controller: controller, username: "", continuationToken: "", correlationId: correlationId))
-        controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitCodeResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -207,6 +211,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
             delegate.error?.errorDescription,
             String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired")
         )
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     func test_submitCode_delegate_whenSuccess_shouldReturnAccountResult() {
@@ -215,7 +220,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
         let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", continuationToken: "continuationToken", correlationId: correlationId)
 
         let expectedResult: SignUpVerifyCodeResult = .completed(expectedSignInAfterSignUpState)
-        controller.submitCodeResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitCodeResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -232,7 +237,7 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
         let exp2 = expectation(description: "telemetry expectation")
         let expectedSignInAfterSignUpState = SignInAfterSignUpState(controller: MSALNativeAuthSignInControllerMock(), username: "", continuationToken: "continuationToken", correlationId: correlationId)
         let result: SignUpVerifyCodeResult = .completed(expectedSignInAfterSignUpState)
-        controller.submitCodeResult = .init(result, telemetryUpdate: { _ in
+        controller.submitCodeResult = .init(result, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -246,5 +251,6 @@ final class SignUpCodeRequiredStateTests: XCTestCase {
             delegate.error?.errorDescription,
             String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted")
         )
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 }
diff --git a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift
index 22ea5cfb5f..d1f0c7f9b9 100644
--- a/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift
+++ b/MSAL/test/unit/native_auth/public/state_machine/sign_up/SignUpPasswordRequiredStateTests.swift
@@ -43,11 +43,11 @@ final class SignUpPasswordRequiredStateTests: XCTestCase {
     // MARK: - Delegate
 
     func test_submitPassword_delegate_whenError_shouldReturnPasswordRequiredError() {
-        let expectedError = PasswordRequiredError(type: .invalidPassword)
+        let expectedError = PasswordRequiredError(type: .invalidPassword, correlationId: correlationId)
         let expectedState = SignUpPasswordRequiredState(controller: controller, username: "", continuationToken: "continuationToken 2", correlationId: correlationId)
 
         let expectedResult: SignUpPasswordRequiredResult = .error(error: expectedError, newState: expectedState)
-        controller.submitPasswordResult = .init(expectedResult)
+        controller.submitPasswordResult = .init(expectedResult, correlationId: correlationId)
 
         let exp = expectation(description: "sign-up states")
         let delegate = SignUpPasswordRequiredDelegateSpy(expectation: exp)
@@ -57,6 +57,7 @@ final class SignUpPasswordRequiredStateTests: XCTestCase {
 
         XCTAssertEqual(delegate.error, expectedError)
         XCTAssertEqual(delegate.newPasswordRequiredState?.continuationToken, expectedState.continuationToken)
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     func test_submitCode_delegate_whenAttributesRequired_AndUserHasImplementedOptionalDelegate_shouldReturnAttributesRequired() {
@@ -66,7 +67,7 @@ final class SignUpPasswordRequiredStateTests: XCTestCase {
         let exp2 = expectation(description: "exp telemetry is called")
 
         let expectedResult: SignUpPasswordRequiredResult = .attributesRequired(attributes: [], newState: expectedAttributesRequiredState)
-        controller.submitPasswordResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitPasswordResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -85,7 +86,7 @@ final class SignUpPasswordRequiredStateTests: XCTestCase {
         let exp2 = expectation(description: "exp telemetry is called")
 
         let expectedResult: SignUpPasswordRequiredResult = .attributesRequired(attributes: [], newState: expectedAttributesRequiredState)
-        controller.submitPasswordResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitPasswordResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -96,6 +97,7 @@ final class SignUpPasswordRequiredStateTests: XCTestCase {
 
         XCTAssertEqual(delegate.error?.type, .generalError)
         XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpAttributesRequired"))
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 
     func test_submitCode_delegate_whenSuccess_shouldReturnSignUpCompleted() {
@@ -105,7 +107,7 @@ final class SignUpPasswordRequiredStateTests: XCTestCase {
         let exp2 = expectation(description: "telemetry expectation")
 
         let expectedResult: SignUpPasswordRequiredResult = .completed(expectedSignInAfterSignUpState)
-        controller.submitPasswordResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitPasswordResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -124,7 +126,7 @@ final class SignUpPasswordRequiredStateTests: XCTestCase {
         let exp2 = expectation(description: "telemetry expectation")
 
         let expectedResult: SignUpPasswordRequiredResult = .completed(expectedSignInAfterSignUpState)
-        controller.submitPasswordResult = .init(expectedResult, telemetryUpdate: { _ in
+        controller.submitPasswordResult = .init(expectedResult, correlationId: correlationId, telemetryUpdate: { _ in
             exp2.fulfill()
         })
 
@@ -135,5 +137,6 @@ final class SignUpPasswordRequiredStateTests: XCTestCase {
 
         XCTAssertEqual(delegate.error?.type, .generalError)
         XCTAssertEqual(delegate.error?.errorDescription, String(format: MSALNativeAuthErrorMessage.delegateNotImplemented, "onSignUpCompleted"))
+        XCTAssertEqual(delegate.error?.correlationId, correlationId)
     }
 }

From 8353db788662557a791f28d8e512c6f9c1dc9474 Mon Sep 17 00:00:00 2001
From: Swasti Gupta 
Date: Tue, 6 Feb 2024 20:30:18 -0800
Subject: [PATCH 49/84] Skipping Account Validation based on request parameters

---
 MSAL/IdentityCore                      | 2 +-
 MSAL/src/MSALPublicClientApplication.m | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 3b1d8bddad..af79e4bd0f 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 3b1d8bddad1ac3616a9d00f2ba7576702160fcdd
+Subproject commit af79e4bd0f7e63e7240939fa61908b123881f406
diff --git a/MSAL/src/MSALPublicClientApplication.m b/MSAL/src/MSALPublicClientApplication.m
index d2908688f8..1263b11fa6 100644
--- a/MSAL/src/MSALPublicClientApplication.m
+++ b/MSAL/src/MSALPublicClientApplication.m
@@ -1206,6 +1206,15 @@ - (void)acquireTokenWithParameters:(MSALInteractiveTokenParameters *)parameters
     msidParams.currentRequestTelemetry.apiId = [msidParams.telemetryApiId integerValue];
     msidParams.currentRequestTelemetry.tokenCacheRefreshType = TokenCacheRefreshTypeNoCacheLookupInvolved;
     
+#if TARGET_OS_OSX
+    msidParams.clientSku = MSID_CLIENT_SKU_MSAL_OSX;
+                        
+#else
+    msidParams.clientSku = MSID_CLIENT_SKU_MSAL_IOS;
+#endif
+    
+    msidParams.skipValidateResultAccount = NO;
+    
     MSIDAccountMetadataState signInState = [self accountStateForParameters:msidParams error:nil];
     
     if (signInState == MSIDAccountMetadataStateSignedOut && msidParams.promptType != MSIDPromptTypeConsent)

From ce25a8784bf7b2df32f32f6a5899176d3ed26fbf Mon Sep 17 00:00:00 2001
From: Swasti Gupta 
Date: Wed, 7 Feb 2024 13:25:58 -0800
Subject: [PATCH 50/84] update submodule after fixing unit tests

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index af79e4bd0f..54ac389e6e 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit af79e4bd0f7e63e7240939fa61908b123881f406
+Subproject commit 54ac389e6ef428ed71e21e1b7d3dba67d8784cb4

From 073c4d0f77e7562a303f0693d308341e27270e8b Mon Sep 17 00:00:00 2001
From: Olga Dalton 
Date: Thu, 8 Feb 2024 15:26:03 -0800
Subject: [PATCH 51/84] Added phone number

---
 MSAL/PrivacyInfo.xcprivacy | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/MSAL/PrivacyInfo.xcprivacy b/MSAL/PrivacyInfo.xcprivacy
index 101b80857f..265db14518 100644
--- a/MSAL/PrivacyInfo.xcprivacy
+++ b/MSAL/PrivacyInfo.xcprivacy
@@ -100,6 +100,18 @@
 				NSPrivacyCollectedDataTypePurposeAppFunctionality
 			
 		
+		
+			NSPrivacyCollectedDataType
+			NSPrivacyCollectedDataTypePhoneNumber
+			NSPrivacyCollectedDataTypeLinked
+			
+			NSPrivacyCollectedDataTypeTracking
+			
+			NSPrivacyCollectedDataTypePurposes
+			
+				NSPrivacyCollectedDataTypePurposeAppFunctionality
+			
+		
 	
 
 

From 11ba205c6eecb22ccccac3c8f0c0f0f58a14c50d Mon Sep 17 00:00:00 2001
From: Diego Jerez <109726904+diegojerezba@users.noreply.github.com>
Date: Fri, 9 Feb 2024 14:47:50 +0000
Subject: [PATCH 52/84] Fix unknown cases in Oauth2ErrorCode and SubErrorCode
 enums (#1994)

* Add UnknownCaseProtocol

* Remove CaseIterable from errors. Make tests more domain specific

* Make `error` property non-optional.
---
 MSAL/MSAL.xcodeproj/project.pbxproj           |   8 +
 .../MSALNativeAuthSignInController.swift      |  11 +-
 .../MSALNativeAuthUnknownCaseProtocol.swift   |  46 +++++
 .../errors/MSALNativeAuthResponseError.swift  |   4 +-
 .../errors/MSALNativeAuthSubErrorCode.swift   |   6 +-
 ...esetPasswordChallengeOauth2ErrorCode.swift |   3 +-
 ...hResetPasswordChallengeResponseError.swift |   8 +-
 ...ResetPasswordContinueOauth2ErrorCode.swift |   3 +-
 ...thResetPasswordContinueResponseError.swift |   6 +-
 ...asswordPollCompletionOauth2ErrorCode.swift |   3 +-
 ...tPasswordPollCompletionResponseError.swift |   6 +-
 ...uthResetPasswordStartOauth2ErrorCode.swift |   3 +-
 ...eAuthResetPasswordStartResponseError.swift |   4 +-
 ...thResetPasswordSubmitOauth2ErrorCode.swift |   3 +-
 ...AuthResetPasswordSubmitResponseError.swift |   6 +-
 ...veAuthSignInChallengeOauth2ErrorCode.swift |   3 +-
 ...tiveAuthSignInChallengeResponseError.swift |   4 +-
 ...iveAuthSignInInitiateOauth2ErrorCode.swift |   3 +-
 ...ativeAuthSignInInitiateResponseError.swift |   4 +-
 ...veAuthSignUpChallengeOauth2ErrorCode.swift |   3 +-
 ...tiveAuthSignUpChallengeResponseError.swift |  10 +-
 ...iveAuthSignUpContinueOauth2ErrorCode.swift |   3 +-
 ...ativeAuthSignUpContinueResponseError.swift |   8 +-
 ...NativeAuthSignUpStartOauth2ErrorCode.swift |   3 +-
 ...ALNativeAuthSignUpStartResponseError.swift |   6 +-
 .../MSALNativeAuthTokenOauth2ErrorCode.swift  |   3 +-
 .../MSALNativeAuthTokenResponseError.swift    |   4 +-
 ...veAuthResetPasswordResponseValidator.swift |  45 ++---
 ...SALNativeAuthSignInResponseValidator.swift |  18 +-
 ...SALNativeAuthSignUpResponseValidator.swift |  26 +--
 ...MSALNativeAuthTokenResponseValidator.swift |   9 +-
 .../MSALNativeAuthSignInControllerTests.swift |   4 +-
 ...ALNativeAuthRequestErrorHandlerTests.swift |  64 +++++-
 ...ALNativeAuthUnknownCaseProtocolTests.swift |  79 ++++++++
 .../MSALNativeAuthSubErrorCodeTests.swift     |   2 +-
 ...asswordChallengeOauth2ErrorCodeTests.swift |   2 +-
 ...tPasswordChallengeResponseErrorTests.swift |  10 +
 ...PasswordContinueOauth2ErrorCodeTests.swift |   2 +-
 ...etPasswordContinueResponseErrorTests.swift |  22 +++
 ...rdPollCompletionOauth2ErrorCodeTests.swift |   2 +-
 ...wordPollCompletionResponseErrorTests.swift |  10 +-
 ...setPasswordStartOauth2ErrorCodeTests.swift |   2 +-
 ...etPasswordSubmitOauth2ErrorCodeTests.swift |   2 +-
 ...esetPasswordSubmitResponseErrorTests.swift |  10 +-
 ...hSignUpChallengeOauth2ErrorCodeTests.swift |   2 +-
 ...uthSignUpChallengeResponseErrorTests.swift |   6 +-
 ...thSignUpContinueOauth2ErrorCodeTests.swift |   2 +-
 ...AuthSignUpContinueResponseErrorTests.swift |  30 ++-
 ...eAuthSignUpStartOauth2ErrorCodeTests.swift |   2 +-
 ...iveAuthSignUpStartResponseErrorTests.swift |   8 +
 ...hResetPasswordResponseValidatorTests.swift | 187 ++++--------------
 ...tiveAuthSignUpResponseValidatorTests.swift | 134 +++----------
 52 files changed, 452 insertions(+), 402 deletions(-)
 create mode 100644 MSAL/src/native_auth/network/MSALNativeAuthUnknownCaseProtocol.swift
 create mode 100644 MSAL/test/unit/native_auth/network/MSALNativeAuthUnknownCaseProtocolTests.swift

diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj
index f15895ceec..f906d41700 100644
--- a/MSAL/MSAL.xcodeproj/project.pbxproj
+++ b/MSAL/MSAL.xcodeproj/project.pbxproj
@@ -1143,6 +1143,8 @@
 		E2F626AD2A78119900C4A303 /* ResetPasswordStates+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AC2A78119900C4A303 /* ResetPasswordStates+Internal.swift */; };
 		E2F626B02A78130700C4A303 /* SignInAfterPreviousFlowBaseState+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626AF2A78130700C4A303 /* SignInAfterPreviousFlowBaseState+Internal.swift */; };
 		E2F626B32A781CE300C4A303 /* SignInDelegatesSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F626B22A781CE300C4A303 /* SignInDelegatesSpies.swift */; };
+		E2F890052B755355001FBC7C /* MSALNativeAuthUnknownCaseProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F890042B755355001FBC7C /* MSALNativeAuthUnknownCaseProtocol.swift */; };
+		E2F8900E2B75546A001FBC7C /* MSALNativeAuthUnknownCaseProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F8900D2B75546A001FBC7C /* MSALNativeAuthUnknownCaseProtocolTests.swift */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -2161,6 +2163,8 @@
 		E2F626AC2A78119900C4A303 /* ResetPasswordStates+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ResetPasswordStates+Internal.swift"; sourceTree = ""; };
 		E2F626AF2A78130700C4A303 /* SignInAfterPreviousFlowBaseState+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SignInAfterPreviousFlowBaseState+Internal.swift"; sourceTree = ""; };
 		E2F626B22A781CE300C4A303 /* SignInDelegatesSpies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInDelegatesSpies.swift; sourceTree = ""; };
+		E2F890042B755355001FBC7C /* MSALNativeAuthUnknownCaseProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthUnknownCaseProtocol.swift; sourceTree = ""; };
+		E2F8900D2B75546A001FBC7C /* MSALNativeAuthUnknownCaseProtocolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthUnknownCaseProtocolTests.swift; sourceTree = ""; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -2445,6 +2449,7 @@
 				8D61F9A02A66AC9D00468E18 /* MSALNativeAuthRequestableTests.swift */,
 				E26594392B60268400723C1A /* MSALNativeAuthResponseCorrelatableTests.swift */,
 				E2DDF1B22B6A9E1D00E9FAB7 /* MSALNativeAuthCustomErrorSerializerTests.swift */,
+				E2F8900D2B75546A001FBC7C /* MSALNativeAuthUnknownCaseProtocolTests.swift */,
 			);
 			path = network;
 			sourceTree = "";
@@ -4097,6 +4102,7 @@
 				287F650B2982F4AD00ED90BD /* MSALNativeAuthResponseSerializer.swift */,
 				DE0D65B829D1AE02005798B1 /* MSALNativeAuthResponseErrorHandler.swift */,
 				8D2733132AD8346D00AD67FD /* MSALNativeAuthCustomErrorSerializer.swift */,
+				E2F890042B755355001FBC7C /* MSALNativeAuthUnknownCaseProtocol.swift */,
 				E2ACA49B2953576C00E98964 /* MSALNativeAuthUrlRequestSerializer.swift */,
 				DE1D8AA729E6B7D900E11D48 /* MSALNativeAuthRequestConfigurator.swift */,
 				E24320742B58428E005290D0 /* MSALNativeAuthResponseCorrelatable.swift */,
@@ -5747,6 +5753,7 @@
 				E205D62E29B783FF003887BC /* MSALNativeAuthConfiguration.swift in Sources */,
 				D61BD2B21EBD09F90007E484 /* MSALAccount.m in Sources */,
 				DE0D65B629CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift in Sources */,
+				E2F890052B755355001FBC7C /* MSALNativeAuthUnknownCaseProtocol.swift in Sources */,
 				E2EFAD092A69A34300D6C3DE /* CodeRequiredGenericResult.swift in Sources */,
 				E2EFAD0C2A69B45100D6C3DE /* SignUpResults.swift in Sources */,
 				DE0D65AC29CC6A5A005798B1 /* MSALNativeAuthSignInInitiateResponse.swift in Sources */,
@@ -5993,6 +6000,7 @@
 				E22428072B0676970006C55E /* DispatchAccessTokenRetrieveCompletedTests.swift in Sources */,
 				A0274CBE24B432B100BD198D /* MSALAuthSchemeTests.m in Sources */,
 				E22427F22B0668910006C55E /* SignInPasswordStartDelegateDispatcherTests.swift in Sources */,
+				E2F8900E2B75546A001FBC7C /* MSALNativeAuthUnknownCaseProtocolTests.swift in Sources */,
 				E2025D202B2B8EEA00E32871 /* MSALNativeAuthSubErrorCodeTests.swift in Sources */,
 				B286BA00238A08F6007833AD /* MSALB2CPolicyTests.m in Sources */,
 				E22428012B0673290006C55E /* ResetPasswordResendCodeDelegateDispatcherTests.swift in Sources */,
diff --git a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift
index c2bc5784b2..68d827abae 100644
--- a/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift
+++ b/MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift
@@ -334,7 +334,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN
                     sentTo: sentTo,
                     channelTargetType: channelType,
                     codeLength: codeLength
-                ), 
+                ),
                 correlationId: context.correlationId(),
                 telemetryUpdate: { [weak self] result in
                     self?.stopTelemetryEvent(event, context: context, delegateDispatcherResult: result)
@@ -398,7 +398,9 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN
         telemetryInfo: TelemetryInfo
     ) async -> MSALNativeAuthSignInInitiateValidatedResponse {
         guard let request = createInitiateRequest(username: username, context: telemetryInfo.context) else {
-            let error = MSALNativeAuthSignInInitiateValidatedErrorType.invalidRequest(.init())
+            let errorDescription = "SignIn Initiate: Cannot create Initiate request object"
+            MSALLogger.log(level: .error, context: telemetryInfo.context, format: errorDescription)
+            let error = MSALNativeAuthSignInInitiateValidatedErrorType.invalidRequest(.init(errorDescription: errorDescription))
             stopTelemetryEvent(telemetryInfo, error: error)
             return .error(error)
         }
@@ -582,8 +584,9 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN
         context: MSALNativeAuthRequestContext
     ) async -> MSALNativeAuthSignInChallengeValidatedResponse {
         guard let challengeRequest = createChallengeRequest(continuationToken: continuationToken, context: context) else {
-            MSALLogger.log(level: .error, context: context, format: "SignIn ResendCode: Cannot create Challenge request object")
-            return .error(.invalidRequest(.init()))
+            let errorDescription = "SignIn ResendCode: Cannot create Challenge request object"
+            MSALLogger.log(level: .error, context: context, format: errorDescription)
+            return .error(.invalidRequest(.init(errorDescription: errorDescription)))
         }
         let challengeResponse: Result = await performRequest(challengeRequest, context: context)
         return signInResponseValidator.validate(context: context, result: challengeResponse)
diff --git a/MSAL/src/native_auth/network/MSALNativeAuthUnknownCaseProtocol.swift b/MSAL/src/native_auth/network/MSALNativeAuthUnknownCaseProtocol.swift
new file mode 100644
index 0000000000..e30c475c27
--- /dev/null
+++ b/MSAL/src/native_auth/network/MSALNativeAuthUnknownCaseProtocol.swift
@@ -0,0 +1,46 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Conform any decodable enum to this protocol to add an `unknown` case, that will be returned when the backend introduces
+/// a new case that is not registered in the SDK
+
+protocol MSALNativeAuthUnknownCaseProtocol: RawRepresentable, CaseIterable where RawValue: Decodable & Equatable {
+    static var unknown: Self { get }
+}
+
+extension MSALNativeAuthUnknownCaseProtocol {
+    init(rawValue: RawValue) {
+        let value = Self.allCases.first { $0.rawValue == rawValue }
+        self = value ?? Self.unknown
+    }
+
+    init(from decoder: Decoder) throws {
+        let container = try decoder.singleValueContainer()
+        let rawValue = try container.decode(RawValue.self)
+        let value = Self(rawValue: rawValue)
+        self = value ?? Self.unknown
+    }
+}
diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift
index 04236b9037..a9073338a9 100644
--- a/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift
+++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthResponseError.swift
@@ -25,9 +25,9 @@
 import Foundation
 
 protocol MSALNativeAuthResponseError: Error, Decodable, Equatable, MSALNativeAuthResponseCorrelatable {
-    associatedtype ErrorCode: RawRepresentable where ErrorCode.RawValue == String
+    associatedtype ErrorCode: RawRepresentable, MSALNativeAuthUnknownCaseProtocol where ErrorCode.RawValue == String
 
-    var error: ErrorCode? { get }
+    var error: ErrorCode { get }
     var errorDescription: String? { get }
     var errorCodes: [Int]? { get }
     var errorURI: String? { get }
diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthSubErrorCode.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthSubErrorCode.swift
index ff9687addd..7f4c46e9b0 100644
--- a/MSAL/src/native_auth/network/errors/MSALNativeAuthSubErrorCode.swift
+++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthSubErrorCode.swift
@@ -24,7 +24,7 @@
 
 import Foundation
 
-enum MSALNativeAuthSubErrorCode: String, Decodable, CaseIterable, Equatable {
+enum MSALNativeAuthSubErrorCode: String, Decodable, Equatable, MSALNativeAuthUnknownCaseProtocol {
     case passwordTooWeak = "password_too_weak"
     case passwordTooShort = "password_too_short"
     case passwordTooLong = "password_too_long"
@@ -33,6 +33,7 @@ enum MSALNativeAuthSubErrorCode: String, Decodable, CaseIterable, Equatable {
     case passwordBanned = "password_banned"
     case attributeValidationFailed = "attribute_validation_failed"
     case invalidOOBValue = "invalid_oob_value"
+    case unknown
 
     var isAnyPasswordError: Bool {
         switch self {
@@ -44,7 +45,8 @@ enum MSALNativeAuthSubErrorCode: String, Decodable, CaseIterable, Equatable {
              .passwordBanned:
             return true
         case .attributeValidationFailed,
-             .invalidOOBValue:
+             .invalidOOBValue,
+             .unknown:
             return false
         }
     }
diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift
index ec8de747f0..baecbe686e 100644
--- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift
+++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift
@@ -24,9 +24,10 @@
 
 import Foundation
 
-enum MSALNativeAuthResetPasswordChallengeOauth2ErrorCode: String, Decodable, CaseIterable {
+enum MSALNativeAuthResetPasswordChallengeOauth2ErrorCode: String, Decodable, MSALNativeAuthUnknownCaseProtocol {
     case invalidRequest = "invalid_request"
     case unauthorizedClient = "unauthorized_client"
     case expiredToken = "expired_token"
     case unsupportedChallengeType = "unsupported_challenge_type"
+    case unknown
 }
diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift
index 4534e6fc13..691eab82c4 100644
--- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift
+++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseError.swift
@@ -26,7 +26,7 @@ import Foundation
 
 struct MSALNativeAuthResetPasswordChallengeResponseError: MSALNativeAuthResponseError {
 
-    let error: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode?
+    let error: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode
     let errorDescription: String?
     let errorCodes: [Int]?
     let errorURI: String?
@@ -45,7 +45,7 @@ struct MSALNativeAuthResetPasswordChallengeResponseError: MSALNativeAuthResponse
     }
 
     init(
-        error: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode? = nil,
+        error: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode = .unknown,
         errorDescription: String? = nil,
         errorCodes: [Int]? = nil,
         errorURI: String? = nil,
@@ -71,7 +71,7 @@ extension MSALNativeAuthResetPasswordChallengeResponseError {
              .unauthorizedClient,
              .unsupportedChallengeType,
              .expiredToken,
-             .none:
+             .unknown:
             return .init(
                 type: .generalError,
                 message: errorDescription,
@@ -88,7 +88,7 @@ extension MSALNativeAuthResetPasswordChallengeResponseError {
              .unsupportedChallengeType,
              .expiredToken,
              .invalidRequest,
-             .none:
+             .unknown:
             return .init(
                 message: errorDescription,
                 correlationId: correlationId,
diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift
index 94635283ba..a6d353fc97 100644
--- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift
+++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift
@@ -24,10 +24,11 @@
 
 import Foundation
 
-enum MSALNativeAuthResetPasswordContinueOauth2ErrorCode: String, Decodable, CaseIterable {
+enum MSALNativeAuthResetPasswordContinueOauth2ErrorCode: String, Decodable, MSALNativeAuthUnknownCaseProtocol {
     case invalidRequest = "invalid_request"
     case unauthorizedClient = "unauthorized_client"
     case invalidGrant = "invalid_grant"
     case expiredToken = "expired_token"
     case verificationRequired = "verification_required"
+    case unknown
 }
diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift
index 663fea097a..87b31edf8e 100644
--- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift
+++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseError.swift
@@ -26,7 +26,7 @@ import Foundation
 
 struct MSALNativeAuthResetPasswordContinueResponseError: MSALNativeAuthResponseError {
 
-    let error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode?
+    let error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode
     let subError: MSALNativeAuthSubErrorCode?
     let errorDescription: String?
     let errorCodes: [Int]?
@@ -49,7 +49,7 @@ struct MSALNativeAuthResetPasswordContinueResponseError: MSALNativeAuthResponseE
     }
 
     init(
-        error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode? = nil,
+        error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode = .unknown,
         subError: MSALNativeAuthSubErrorCode? = nil,
         errorDescription: String? = nil,
         errorCodes: [Int]? = nil,
@@ -87,7 +87,7 @@ extension MSALNativeAuthResetPasswordContinueResponseError {
              .expiredToken,
              .invalidRequest,
              .verificationRequired,
-             .none:
+             .unknown:
             return .init(
                 type: .generalError,
                 message: errorDescription,
diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift
index 8007bdc8c0..aff7374316 100644
--- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift
+++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode.swift
@@ -24,10 +24,11 @@
 
 import Foundation
 
-enum MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode: String, Decodable, CaseIterable {
+enum MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode: String, Decodable, MSALNativeAuthUnknownCaseProtocol {
     case invalidGrant = "invalid_grant"
     case invalidRequest = "invalid_request"
     case unauthorizedClient = "unauthorized_client"
     case expiredToken = "expired_token"
     case userNotFound = "user_not_found"
+    case unknown
 }
diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift
index c37a7f4115..f53b657add 100644
--- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift
+++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseError.swift
@@ -26,7 +26,7 @@ import Foundation
 
 struct MSALNativeAuthResetPasswordPollCompletionResponseError: MSALNativeAuthResponseError {
 
-    let error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode?
+    let error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode
     let subError: MSALNativeAuthSubErrorCode?
     let errorDescription: String?
     let errorCodes: [Int]?
@@ -47,7 +47,7 @@ struct MSALNativeAuthResetPasswordPollCompletionResponseError: MSALNativeAuthRes
     }
 
     init(
-        error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode? = nil,
+        error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode = .unknown,
         subError: MSALNativeAuthSubErrorCode? = nil,
         errorDescription: String? = nil,
         errorCodes: [Int]? = nil,
@@ -83,7 +83,7 @@ extension MSALNativeAuthResetPasswordPollCompletionResponseError {
              .expiredToken,
              .invalidRequest,
              .userNotFound,
-             .none:
+             .unknown:
             return .init(
                 type: .generalError,
                 message: errorDescription,
diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift
index 4a413ec5fe..eb049db12b 100644
--- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift
+++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCode.swift
@@ -24,9 +24,10 @@
 
 import Foundation
 
-enum MSALNativeAuthResetPasswordStartOauth2ErrorCode: String, Decodable, CaseIterable {
+enum MSALNativeAuthResetPasswordStartOauth2ErrorCode: String, Decodable, MSALNativeAuthUnknownCaseProtocol {
     case invalidRequest = "invalid_request"
     case unauthorizedClient = "unauthorized_client"
     case userNotFound = "user_not_found"
     case unsupportedChallengeType = "unsupported_challenge_type"
+    case unknown
 }
diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift
index 393acf8a95..f7e22546a3 100644
--- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift
+++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartResponseError.swift
@@ -26,7 +26,7 @@ import Foundation
 
 struct MSALNativeAuthResetPasswordStartResponseError: MSALNativeAuthResponseError {
 
-    let error: MSALNativeAuthResetPasswordStartOauth2ErrorCode?
+    let error: MSALNativeAuthResetPasswordStartOauth2ErrorCode
     let errorDescription: String?
     let errorCodes: [Int]?
     let errorURI: String?
@@ -45,7 +45,7 @@ struct MSALNativeAuthResetPasswordStartResponseError: MSALNativeAuthResponseErro
     }
 
     init(
-        error: MSALNativeAuthResetPasswordStartOauth2ErrorCode? = nil,
+        error: MSALNativeAuthResetPasswordStartOauth2ErrorCode = .unknown,
         errorDescription: String? = nil,
         errorCodes: [Int]? = nil,
         errorURI: String? = nil,
diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift
index 702bdce34c..72906db94e 100644
--- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift
+++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCode.swift
@@ -24,9 +24,10 @@
 
 import Foundation
 
-enum MSALNativeAuthResetPasswordSubmitOauth2ErrorCode: String, Decodable, CaseIterable {
+enum MSALNativeAuthResetPasswordSubmitOauth2ErrorCode: String, Decodable, MSALNativeAuthUnknownCaseProtocol {
     case invalidRequest = "invalid_request"
     case unauthorizedClient = "unauthorized_client"
     case expiredToken = "expired_token"
     case invalidGrant = "invalid_grant"
+    case unknown
 }
diff --git a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift
index 3da234e5ee..f4f6a2e781 100644
--- a/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift
+++ b/MSAL/src/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseError.swift
@@ -26,7 +26,7 @@ import Foundation
 
 struct MSALNativeAuthResetPasswordSubmitResponseError: MSALNativeAuthResponseError {
 
-    let error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode?
+    let error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode
     let subError: MSALNativeAuthSubErrorCode?
     let errorDescription: String?
     let errorCodes: [Int]?
@@ -47,7 +47,7 @@ struct MSALNativeAuthResetPasswordSubmitResponseError: MSALNativeAuthResponseErr
     }
 
     init(
-        error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode? = nil,
+        error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode = .unknown,
         subError: MSALNativeAuthSubErrorCode? = nil,
         errorDescription: String? = nil,
         errorCodes: [Int]? = nil,
@@ -82,7 +82,7 @@ extension MSALNativeAuthResetPasswordSubmitResponseError {
         case .unauthorizedClient,
              .expiredToken,
              .invalidRequest,
-             .none:
+             .unknown:
             return .init(
                 type: .generalError,
                 message: errorDescription,
diff --git a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeOauth2ErrorCode.swift
index 62f0afad5a..1712196c43 100644
--- a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeOauth2ErrorCode.swift
+++ b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeOauth2ErrorCode.swift
@@ -24,10 +24,11 @@
 
 import Foundation
 
-enum MSALNativeAuthSignInChallengeOauth2ErrorCode: String, Decodable {
+enum MSALNativeAuthSignInChallengeOauth2ErrorCode: String, Decodable, MSALNativeAuthUnknownCaseProtocol {
     case invalidRequest = "invalid_request"
     case unauthorizedClient = "unauthorized_client"
     case invalidGrant = "invalid_grant"
     case expiredToken = "expired_token"
     case unsupportedChallengeType = "unsupported_challenge_type"
+    case unknown
 }
diff --git a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift
index 8e86273168..140e573eb5 100644
--- a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift
+++ b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInChallengeResponseError.swift
@@ -26,7 +26,7 @@ import Foundation
 
 struct MSALNativeAuthSignInChallengeResponseError: MSALNativeAuthResponseError {
 
-    let error: MSALNativeAuthSignInChallengeOauth2ErrorCode?
+    let error: MSALNativeAuthSignInChallengeOauth2ErrorCode
     let errorDescription: String?
     let errorCodes: [Int]?
     let errorURI: String?
@@ -43,7 +43,7 @@ struct MSALNativeAuthSignInChallengeResponseError: MSALNativeAuthResponseError {
     }
 
     init(
-        error: MSALNativeAuthSignInChallengeOauth2ErrorCode? = nil,
+        error: MSALNativeAuthSignInChallengeOauth2ErrorCode = .unknown,
         errorDescription: String? = nil,
         errorCodes: [Int]? = nil,
         errorURI: String? = nil,
diff --git a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateOauth2ErrorCode.swift
index 3dab73e028..c4a4980323 100644
--- a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateOauth2ErrorCode.swift
+++ b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateOauth2ErrorCode.swift
@@ -24,9 +24,10 @@
 
 import Foundation
 
-enum MSALNativeAuthSignInInitiateOauth2ErrorCode: String, Decodable, CaseIterable {
+enum MSALNativeAuthSignInInitiateOauth2ErrorCode: String, Decodable, MSALNativeAuthUnknownCaseProtocol {
     case invalidRequest = "invalid_request"
     case unauthorizedClient = "unauthorized_client"
     case userNotFound = "user_not_found"
     case unsupportedChallengeType = "unsupported_challenge_type"
+    case unknown
 }
diff --git a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift
index 5440c03494..2edadf43e5 100644
--- a/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift
+++ b/MSAL/src/native_auth/network/errors/sign_in/MSALNativeAuthSignInInitiateResponseError.swift
@@ -26,7 +26,7 @@ import Foundation
 
 struct MSALNativeAuthSignInInitiateResponseError: MSALNativeAuthResponseError {
 
-    let error: MSALNativeAuthSignInInitiateOauth2ErrorCode?
+    let error: MSALNativeAuthSignInInitiateOauth2ErrorCode
     let errorDescription: String?
     let errorCodes: [Int]?
     let errorURI: String?
@@ -43,7 +43,7 @@ struct MSALNativeAuthSignInInitiateResponseError: MSALNativeAuthResponseError {
     }
 
     init(
-        error: MSALNativeAuthSignInInitiateOauth2ErrorCode? = nil,
+        error: MSALNativeAuthSignInInitiateOauth2ErrorCode = .unknown,
         errorDescription: String? = nil,
         errorCodes: [Int]? = nil,
         errorURI: String? = nil,
diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift
index 1ae84bcc4c..6889630148 100644
--- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift
+++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCode.swift
@@ -24,9 +24,10 @@
 
 import Foundation
 
-enum MSALNativeAuthSignUpChallengeOauth2ErrorCode: String, Decodable, CaseIterable {
+enum MSALNativeAuthSignUpChallengeOauth2ErrorCode: String, Decodable, MSALNativeAuthUnknownCaseProtocol {
     case invalidRequest = "invalid_request"
     case unauthorizedClient = "unauthorized_client"
     case unsupportedChallengeType = "unsupported_challenge_type"
     case expiredToken = "expired_token"
+    case unknown
 }
diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift
index e20c5f4981..d09e75126d 100644
--- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift
+++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseError.swift
@@ -25,7 +25,7 @@
 import Foundation
 
 struct MSALNativeAuthSignUpChallengeResponseError: MSALNativeAuthResponseError {
-    let error: MSALNativeAuthSignUpChallengeOauth2ErrorCode?
+    let error: MSALNativeAuthSignUpChallengeOauth2ErrorCode
     let errorDescription: String?
     let errorCodes: [Int]?
     let errorURI: String?
@@ -42,7 +42,7 @@ struct MSALNativeAuthSignUpChallengeResponseError: MSALNativeAuthResponseError {
     }
 
     init(
-        error: MSALNativeAuthSignUpChallengeOauth2ErrorCode? = nil,
+        error: MSALNativeAuthSignUpChallengeOauth2ErrorCode = .unknown,
         errorDescription: String? = nil,
         errorCodes: [Int]? = nil,
         errorURI: String? = nil,
@@ -66,7 +66,7 @@ extension MSALNativeAuthSignUpChallengeResponseError {
              .unsupportedChallengeType,
              .expiredToken,
              .invalidRequest,
-             .none:
+             .unknown:
             return .init(
                 type: .generalError,
                 message: errorDescription,
@@ -83,7 +83,7 @@ extension MSALNativeAuthSignUpChallengeResponseError {
              .unsupportedChallengeType,
              .expiredToken,
              .invalidRequest,
-             .none:
+             .unknown:
             return .init(
                 message: errorDescription,
                 correlationId: correlationId,
@@ -99,7 +99,7 @@ extension MSALNativeAuthSignUpChallengeResponseError {
              .unsupportedChallengeType,
              .expiredToken,
              .invalidRequest,
-             .none:
+             .unknown:
             return .init(
                 type: .generalError,
                 message: errorDescription,
diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCode.swift
index 80c8f9789f..05e28ebad1 100644
--- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCode.swift
+++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCode.swift
@@ -24,7 +24,7 @@
 
 import Foundation
 
-enum MSALNativeAuthSignUpContinueOauth2ErrorCode: String, Decodable, CaseIterable {
+enum MSALNativeAuthSignUpContinueOauth2ErrorCode: String, Decodable, MSALNativeAuthUnknownCaseProtocol {
     case invalidRequest = "invalid_request"
     case unauthorizedClient = "unauthorized_client"
     case invalidGrant = "invalid_grant"
@@ -33,4 +33,5 @@ enum MSALNativeAuthSignUpContinueOauth2ErrorCode: String, Decodable, CaseIterabl
     case attributesRequired = "attributes_required"
     case verificationRequired = "verification_required"
     case credentialRequired = "credential_required"
+    case unknown
 }
diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift
index 837344454e..aa1e555003 100644
--- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift
+++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseError.swift
@@ -25,7 +25,7 @@
 import Foundation
 
 struct MSALNativeAuthSignUpContinueResponseError: MSALNativeAuthResponseError {
-    let error: MSALNativeAuthSignUpContinueOauth2ErrorCode?
+    let error: MSALNativeAuthSignUpContinueOauth2ErrorCode
     let subError: MSALNativeAuthSubErrorCode?
     let errorDescription: String?
     let errorCodes: [Int]?
@@ -52,7 +52,7 @@ struct MSALNativeAuthSignUpContinueResponseError: MSALNativeAuthResponseError {
     }
 
     init(
-        error: MSALNativeAuthSignUpContinueOauth2ErrorCode? = nil,
+        error: MSALNativeAuthSignUpContinueOauth2ErrorCode = .unknown,
         subError: MSALNativeAuthSubErrorCode? = nil,
         errorDescription: String? = nil,
         errorCodes: [Int]? = nil,
@@ -97,7 +97,7 @@ extension MSALNativeAuthSignUpContinueResponseError {
              .attributesRequired,
              .verificationRequired,
              .credentialRequired,
-             .none:
+             .unknown:
             return .init(
                 type: .generalError,
                 message: errorDescription,
@@ -126,7 +126,7 @@ extension MSALNativeAuthSignUpContinueResponseError {
              .attributesRequired,
              .verificationRequired,
              .credentialRequired,
-             .none:
+             .unknown:
             return .init(
                 type: .generalError,
                 message: errorDescription,
diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCode.swift
index 4997bcd815..134c29ec95 100644
--- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCode.swift
+++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCode.swift
@@ -24,7 +24,7 @@
 
 import Foundation
 
-enum MSALNativeAuthSignUpStartOauth2ErrorCode: String, Decodable, CaseIterable, Equatable {
+enum MSALNativeAuthSignUpStartOauth2ErrorCode: String, Decodable, Equatable, MSALNativeAuthUnknownCaseProtocol {
     case invalidGrant = "invalid_grant"
     case invalidRequest = "invalid_request"
     case unauthorizedClient = "unauthorized_client"
@@ -32,4 +32,5 @@ enum MSALNativeAuthSignUpStartOauth2ErrorCode: String, Decodable, CaseIterable,
     case userAlreadyExists = "user_already_exists"
     case attributesRequired = "attributes_required"
     case unsupportedAuthMethod = "unsupported_auth_method"
+    case unknown
 }
diff --git a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift
index e39fa3fc11..403dc40940 100644
--- a/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift
+++ b/MSAL/src/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseError.swift
@@ -26,7 +26,7 @@ import Foundation
 
 struct MSALNativeAuthSignUpStartResponseError: MSALNativeAuthResponseError {
 
-    let error: MSALNativeAuthSignUpStartOauth2ErrorCode?
+    let error: MSALNativeAuthSignUpStartOauth2ErrorCode
     let subError: MSALNativeAuthSubErrorCode?
     let errorDescription: String?
     let errorCodes: [Int]?
@@ -51,7 +51,7 @@ struct MSALNativeAuthSignUpStartResponseError: MSALNativeAuthResponseError {
     }
 
     init(
-        error: MSALNativeAuthSignUpStartOauth2ErrorCode? = nil,
+        error: MSALNativeAuthSignUpStartOauth2ErrorCode = .unknown,
         subError: MSALNativeAuthSubErrorCode? = nil,
         errorDescription: String? = nil,
         errorCodes: [Int]? = nil,
@@ -100,7 +100,7 @@ extension MSALNativeAuthSignUpStartResponseError {
              .unsupportedChallengeType,
              .unsupportedAuthMethod,
              .invalidRequest,
-             .none:
+             .unknown:
             return .init(
                 type: .generalError,
                 message: message ?? errorDescription,
diff --git a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenOauth2ErrorCode.swift
index 5b98c1b08f..41ad364cba 100644
--- a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenOauth2ErrorCode.swift
+++ b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenOauth2ErrorCode.swift
@@ -24,7 +24,7 @@
 
 import Foundation
 
-enum MSALNativeAuthTokenOauth2ErrorCode: String, Decodable {
+enum MSALNativeAuthTokenOauth2ErrorCode: String, Decodable, MSALNativeAuthUnknownCaseProtocol {
     case invalidRequest = "invalid_request"
     case unauthorizedClient = "unauthorized_client"
     case invalidClient = "invalid_client"
@@ -36,4 +36,5 @@ enum MSALNativeAuthTokenOauth2ErrorCode: String, Decodable {
     case authorizationPending = "authorization_pending"
     case slowDown = "slow_down"
     case userNotFound = "user_not_found"
+    case unknown
 }
diff --git a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift
index 4d74b2798b..28061f68ad 100644
--- a/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift
+++ b/MSAL/src/native_auth/network/errors/token/MSALNativeAuthTokenResponseError.swift
@@ -26,7 +26,7 @@ import Foundation
 
 struct MSALNativeAuthTokenResponseError: MSALNativeAuthResponseError {
 
-    let error: MSALNativeAuthTokenOauth2ErrorCode?
+    let error: MSALNativeAuthTokenOauth2ErrorCode
     let subError: MSALNativeAuthSubErrorCode?
     let errorDescription: String?
     let errorCodes: [Int]?
@@ -47,7 +47,7 @@ struct MSALNativeAuthTokenResponseError: MSALNativeAuthResponseError {
     }
 
     init(
-        error: MSALNativeAuthTokenOauth2ErrorCode? = nil,
+        error: MSALNativeAuthTokenOauth2ErrorCode = .unknown,
         subError: MSALNativeAuthSubErrorCode? = nil,
         errorDescription: String? = nil,
         errorCodes: [Int]? = nil,
diff --git a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift
index 09231cdb79..5626ee6b87 100644
--- a/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift
+++ b/MSAL/src/native_auth/network/responses/validator/reset_password/MSALNativeAuthResetPasswordResponseValidator.swift
@@ -89,13 +89,8 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas
             return .error(.userNotFound(apiError))
         case .unsupportedChallengeType:
             return .error(.unsupportedChallengeType(apiError))
-        case .none:
-            return .error(.unexpectedError(.init(
-                errorDescription: apiError.errorDescription,
-                errorCodes: apiError.errorCodes,
-                errorURI: apiError.errorURI,
-                correlationId: apiError.correlationId
-            )))
+        case .unknown:
+            return .error(.unexpectedError(apiError))
         }
     }
 
@@ -137,8 +132,9 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas
             }
         case .password,
              .otp:
-            MSALLogger.log(level: .error, context: context, format: "ChallengeType not expected")
-            return .unexpectedError(.init())
+            let errorDescription = MSALNativeAuthErrorMessage.unexpectedChallengeType
+            MSALLogger.log(level: .error, context: context, format: errorDescription)
+            return .unexpectedError(.init(errorDescription: errorDescription))
         }
     }
 
@@ -147,8 +143,8 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas
             MSALLogger.log(level: .info, context: context, format: "resetpassword/challenge: Unable to decode error response: \(error)")
             return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))
         }
-        if apiError.error == .none {
-            return .unexpectedError(.init(errorDescription: apiError.errorDescription))
+        if apiError.error == .unknown {
+            return .unexpectedError(apiError)
         }
         return .error(apiError)
     }
@@ -189,13 +185,8 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas
         case .verificationRequired:
             MSALLogger.log(level: .error, context: context, format: "verificationRequired is not supported yet")
             return .unexpectedError(nil)
-        case .none:
-            return .unexpectedError(.init(
-                errorDescription: apiError.errorDescription,
-                errorCodes: apiError.errorCodes,
-                errorURI: apiError.errorURI,
-                correlationId: apiError.correlationId
-            ))
+        case .unknown:
+            return .unexpectedError(apiError)
         }
     }
 
@@ -236,13 +227,8 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas
              .unauthorizedClient,
              .expiredToken:
             return .error(apiError)
-        case .none:
-            return .unexpectedError(.init(
-                errorDescription: apiError.errorDescription,
-                errorCodes: apiError.errorCodes,
-                errorURI: apiError.errorURI,
-                correlationId: apiError.correlationId
-            ))
+        case .unknown:
+            return .unexpectedError(apiError)
         }
     }
 
@@ -288,13 +274,8 @@ final class MSALNativeAuthResetPasswordResponseValidator: MSALNativeAuthResetPas
              .unauthorizedClient,
              .expiredToken:
             return .error(apiError)
-        case .none:
-            return .unexpectedError(.init(
-                errorDescription: apiError.errorDescription,
-                errorCodes: apiError.errorCodes,
-                errorURI: apiError.errorURI,
-                correlationId: apiError.correlationId
-            ))
+        case .unknown:
+            return .unexpectedError(apiError)
         }
     }
 }
diff --git a/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift
index 720eeb5592..216761b958 100644
--- a/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift
+++ b/MSAL/src/native_auth/network/responses/validator/sign_in/MSALNativeAuthSignInResponseValidator.swift
@@ -139,13 +139,8 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV
                 return .error(.expiredToken(error))
             case .unsupportedChallengeType:
                 return .error(.unsupportedChallengeType(error))
-            case .none:
-                return .error(.unexpectedError(.init(
-                    errorDescription: error.errorDescription,
-                    errorCodes: error.errorCodes,
-                    errorURI: error.errorURI,
-                    correlationId: error.correlationId
-                )))
+            case .unknown:
+                return .error(.unexpectedError(error))
             }
     }
 
@@ -159,13 +154,8 @@ final class MSALNativeAuthSignInResponseValidator: MSALNativeAuthSignInResponseV
                 return .error(.unsupportedChallengeType(error))
             case .userNotFound:
                 return .error(.userNotFound(error))
-            case .none:
-                return .error(.unexpectedError(.init(
-                    errorDescription: error.errorDescription,
-                    errorCodes: error.errorCodes,
-                    errorURI: error.errorURI,
-                    correlationId: error.correlationId
-                )))
+            case .unknown:
+                return .error(.unexpectedError(error))
             }
     }
 }
diff --git a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift
index 8f3322616e..33fa02808f 100644
--- a/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift
+++ b/MSAL/src/native_auth/network/responses/validator/sign_up/MSALNativeAuthSignUpResponseValidator.swift
@@ -82,7 +82,7 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV
                     context: context,
                     format: "Missing expected fields in signup/start for attribute_validation_failed error"
                 )
-                return .unexpectedError(.init(errorDescription: apiError.errorDescription))
+                return .unexpectedError(apiError)
             }
         case .invalidRequest where isSignUpStartInvalidRequestParameter(
             apiError,
@@ -92,13 +92,8 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV
             apiError,
             knownErrorDescription: MSALNativeAuthESTSApiErrorDescriptions.clientIdParameterIsEmptyOrNotValid.rawValue):
             return .unauthorizedClient(apiError)
-        case .none:
-            return .unexpectedError(.init(
-                errorDescription: apiError.errorDescription,
-                errorCodes: apiError.errorCodes,
-                errorURI: apiError.errorURI,
-                correlationId: apiError.correlationId
-            ))
+        case .unknown:
+            return .unexpectedError(apiError)
         default:
             return .error(apiError)
         }
@@ -158,8 +153,8 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV
             MSALLogger.log(level: .error, context: context, format: "signup/challenge: Unable to decode error response: \(error)")
             return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))
         }
-        if apiError.error == .none {
-            return .unexpectedError(.init(errorDescription: apiError.errorDescription))
+        if apiError.error == .unknown {
+            return .unexpectedError(apiError)
         }
 
         return .error(apiError)
@@ -218,13 +213,8 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV
              .userAlreadyExists,
              .invalidRequest:
             return .error(apiError)
-        case .none:
-            return .unexpectedError(.init(
-                errorDescription: apiError.errorDescription,
-                errorCodes: apiError.errorCodes,
-                errorURI: apiError.errorURI,
-                correlationId: apiError.correlationId
-            ))
+        case .unknown:
+            return .unexpectedError(apiError)
         }
     }
 
@@ -256,6 +246,8 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV
                 )
                 return .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))
             }
+        case .unknown:
+            return .unexpectedError(apiError)
         }
     }
 
diff --git a/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift
index 3693659eee..f904569864 100644
--- a/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift
+++ b/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift
@@ -119,13 +119,8 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal
                 return .error(.slowDown(responseError))
             case .userNotFound:
                 return .error(.userNotFound(responseError))
-            case .none:
-                return .error(.unexpectedError(.init(
-                    errorDescription: responseError.errorDescription,
-                    errorCodes: responseError.errorCodes,
-                    errorURI: responseError.errorURI,
-                    correlationId: responseError.correlationId
-                )))
+            case .unknown:
+                return .error(.unexpectedError(responseError))
             }
         }
 
diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift
index 86556d8b05..67ec6beeb6 100644
--- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift
+++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthSignInControllerTests.swift
@@ -99,7 +99,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         signInRequestProviderMock.expectedContext = expectedContext
         signInRequestProviderMock.throwingInitError = ErrorMock.error
 
-        let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError, correlationId: defaultUUID))
+        let helper = SignInPasswordStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError, message: "SignIn Initiate: Cannot create Initiate request object", correlationId: defaultUUID))
 
         let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: expectedPassword, context: expectedContext, scopes: nil))
 
@@ -474,7 +474,7 @@ final class MSALNativeAuthSignInControllerTests: MSALNativeAuthTestCase {
         signInRequestProviderMock.expectedContext = expectedContext
         signInRequestProviderMock.throwingInitError = MSALNativeAuthError(message: nil, correlationId: defaultUUID)
 
-        let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError, correlationId: defaultUUID))
+        let helper = SignInCodeStartTestsValidatorHelper(expectation: expectation, expectedError: SignInStartError(type: .generalError, message: "SignIn Initiate: Cannot create Initiate request object", correlationId: defaultUUID))
 
         let result = await sut.signIn(params: MSALNativeAuthSignInParameters(username: expectedUsername, password: nil, context: expectedContext, scopes: nil))
 
diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift
index 6221acc7a9..cd872f2445 100644
--- a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift
+++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestErrorHandlerTests.swift
@@ -271,7 +271,8 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase {
         let httpRequest = MSALNativeAuthHTTPRequestMock.prepareMockRequest()
 
         var dictionary = [String: Any]()
-        dictionary["error_code"] = "invalid code"
+        dictionary["error"] = "invalid code"
+        dictionary["suberror"] = "invalid suberror code"
         dictionary["error_description"] = "API Description"
         dictionary["error_uri"] = HttpModuleMockConfigurator.baseUrl.absoluteString
         dictionary["continuation_token"] = "abcdef"
@@ -293,7 +294,8 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase {
                 expectation.fulfill()
                 return
             }
-            XCTAssertEqual(error.error, .none)
+            XCTAssertEqual(error.error, .unknown)
+            XCTAssertEqual(error.subError, .unknown)
             XCTAssertEqual(error.errorDescription, "API Description")
             XCTAssertEqual(error.errorURI, HttpModuleMockConfigurator.baseUrl.absoluteString)
             expectation.fulfill()
@@ -301,7 +303,49 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase {
         wait(for: [expectation], timeout: 1)
     }
 
-    func test_shouldNotFailWithDecodeError_whenStatusCode400AndJSONMissing() throws {
+    func test_shouldFailDecoding_whenErrorResponseIsMalformed() throws {
+        let expectation = expectation(description: "Handle Error Retry Success")
+
+        let httpResponse = HTTPURLResponse(
+            url: HttpModuleMockConfigurator.baseUrl,
+            statusCode: 400,
+            httpVersion: nil,
+            headerFields: nil
+        )
+
+        let httpRequest = MSALNativeAuthHTTPRequestMock.prepareMockRequest()
+
+        // `error` field is missing
+        var dictionary = [String: Any]()
+        dictionary["suberror"] = "suberror_code"
+        dictionary["error_description"] = "API Description"
+        dictionary["error_uri"] = HttpModuleMockConfigurator.baseUrl.absoluteString
+        dictionary["continuation_token"] = "abcdef"
+
+        let data = try JSONSerialization.data(withJSONObject: dictionary)
+
+        let errorHandler = MSALNativeAuthResponseErrorHandler()
+        errorHandler.handleError(
+            error,
+            httpResponse: httpResponse,
+            data: data,
+            httpRequest: httpRequest,
+            responseSerializer: MSIDHttpResponseSerializer(), // Some transient response serializer
+            externalSSOContext: nil,
+            context: context
+        ) { result, error in
+            guard let error = error as? MSALNativeAuthInternalError else {
+                XCTFail("Error is expected to be returned")
+                expectation.fulfill()
+                return
+            }
+            XCTAssertEqual(error, .responseSerializationError(headerCorrelationId: nil))
+            expectation.fulfill()
+        }
+        wait(for: [expectation], timeout: 1)
+    }
+
+    func test_shouldFailWithDecodeError_whenStatusCode400AndJSONMissing() throws {
         let expectation = expectation(description: "Handle Error Retry Success")
 
         let httpResponse = HTTPURLResponse(
@@ -325,18 +369,18 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase {
             externalSSOContext: nil,
             context: context
         ) { result, error in
-            guard let error = error as? MSALNativeAuthSignInInitiateResponseError else {
-                XCTFail("Error is expected to be returned, even with empty data")
+            guard let error = error as? MSALNativeAuthInternalError else {
+                XCTFail("Error is expected to be returned")
                 expectation.fulfill()
                 return
             }
-            XCTAssertEqual(error.error,.none)
+            XCTAssertEqual(error, .responseSerializationError(headerCorrelationId: nil))
             expectation.fulfill()
         }
         wait(for: [expectation], timeout: 1)
     }
 
-    func test_shouldNotFailWithDecodeError_whenStatusCode400AndJSONInvalid() throws {
+    func test_shouldFailWithDecodeError_whenStatusCode400AndJSONInvalid() throws {
         let expectation = expectation(description: "Handle Error Retry Success")
 
         let httpResponse = HTTPURLResponse(
@@ -361,12 +405,12 @@ class MSALNativeAuthResponseErrorHandlerTests: XCTestCase {
             externalSSOContext: nil,
             context: context
         ) { result, error in
-            guard let error = error as? MSALNativeAuthSignInInitiateResponseError else {
-                XCTFail("Error is expected to be returned, even with empty data")
+            guard let error = error as? MSALNativeAuthInternalError else {
+                XCTFail("Error is expected to be returned")
                 expectation.fulfill()
                 return
             }
-            XCTAssertEqual(error.error,.none)
+            XCTAssertEqual(error, .responseSerializationError(headerCorrelationId: nil))
             expectation.fulfill()
         }
         wait(for: [expectation], timeout: 1)
diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthUnknownCaseProtocolTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthUnknownCaseProtocolTests.swift
new file mode 100644
index 0000000000..66ae948dea
--- /dev/null
+++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthUnknownCaseProtocolTests.swift
@@ -0,0 +1,79 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import XCTest
+@testable import MSAL
+
+final class MSALNativeAuthUnknownCaseProtocolTests: XCTestCase {
+
+    func test_decodeKnownValue() throws {
+        let json = """
+        {
+            "errorType": "invalid_grant",
+            "errorDescription": "This is an error description",
+            "errorCodes": [50076]
+        }
+        """
+
+        let data = json.data(using: .utf8)!
+
+        let apiError = try JSONDecoder().decode(ApiErrorResponse.self, from: data)
+
+        XCTAssertNotNil(apiError)
+        XCTAssertEqual(apiError.errorType, .invalidGrant)
+        XCTAssertEqual(apiError.errorDescription, "This is an error description")
+        XCTAssertEqual(apiError.errorCodes, [50076])
+    }
+
+    func test_decodingAnUnknownValue_produces_aNotNilApiModel() throws {
+        let json = """
+        {
+            "errorType": "new_error_type_unknown_to_the_SDK",
+            "errorDescription": "This is an error description",
+            "errorCodes": [50076]
+        }
+        """
+
+        let data = json.data(using: .utf8)!
+
+        let apiError = try JSONDecoder().decode(ApiErrorResponse.self, from: data)
+
+        XCTAssertNotNil(apiError)
+        XCTAssertEqual(apiError.errorType, .unknown)
+        XCTAssertEqual(apiError.errorDescription, "This is an error description")
+        XCTAssertEqual(apiError.errorCodes, [50076])
+    }
+}
+
+private struct ApiErrorResponse: Decodable {
+    let errorType: ApiErrorTypeEnum
+    let errorDescription: String
+    let errorCodes: [Int]
+}
+
+private enum ApiErrorTypeEnum: String, Decodable, Equatable, MSALNativeAuthUnknownCaseProtocol {
+    case invalidGrant = "invalid_grant"
+    case unauthorizedClient = "unauthorized_client"
+    case unknown
+}
diff --git a/MSAL/test/unit/native_auth/network/errors/MSALNativeAuthSubErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/MSALNativeAuthSubErrorCodeTests.swift
index 81e0ce2c3e..58b09289ed 100644
--- a/MSAL/test/unit/native_auth/network/errors/MSALNativeAuthSubErrorCodeTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/MSALNativeAuthSubErrorCodeTests.swift
@@ -29,7 +29,7 @@ final class MSALNativeAuthSubErrorCodeTests: XCTestCase {
     private typealias sut = MSALNativeAuthSubErrorCode
 
     func test_allCases() {
-        XCTAssertEqual(sut.allCases.count, 8)
+        XCTAssertEqual(sut.allCases.count, 9)
     }
 
     func test_passwordTooWeak() {
diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift
index 5cd00827ba..70749ba82e 100644
--- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests.swift
@@ -30,7 +30,7 @@ final class MSALNativeAuthResetPasswordChallengeOauth2ErrorCodeTests: XCTestCase
     private typealias sut = MSALNativeAuthResetPasswordChallengeOauth2ErrorCode
     
     func test_allCases() {
-        XCTAssertEqual(sut.allCases.count, 4)
+        XCTAssertEqual(sut.allCases.count, 5)
     }
     
     func test_invalidRequest() {
diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift
index 516d32d911..2abed9d221 100644
--- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordChallengeResponseErrorTests.swift
@@ -138,4 +138,14 @@ final class MSALNativeAuthResetPasswordChallengeResponseErrorTests: XCTestCase {
         XCTAssertEqual(error.errorCodes, testErrorCodes)
         XCTAssertEqual(error.errorUri, testErrorUri)
     }
+
+    func test_toResendCodePublicError_errorUnknown() {
+        sut = createApiResendCodeError(type: .unknown)
+        let error = sut.toResendCodePublicError(correlationId: correlationId)
+
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
+    }
 }
diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift
index 6de5119040..9c5081f207 100644
--- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests.swift
@@ -30,7 +30,7 @@ final class MSALNativeAuthResetPasswordContinueOauth2ErrorCodeTests: XCTestCase
     private typealias sut = MSALNativeAuthResetPasswordContinueOauth2ErrorCode
 
     func test_allCases() {
-        XCTAssertEqual(sut.allCases.count, 5)
+        XCTAssertEqual(sut.allCases.count, 6)
     }
     
     func test_invalidRequest() {
diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift
index 92216c2715..5d69e47d47 100644
--- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordContinueResponseErrorTests.swift
@@ -111,4 +111,26 @@ final class MSALNativeAuthResetPasswordContinueResponseErrorTests: XCTestCase {
         XCTAssertEqual(error.errorCodes, testErrorCodes)
         XCTAssertEqual(error.errorUri, testErrorUri)
     }
+
+    func test_toResetPasswordStartPublicError_errorUnknown() {
+        sut = createApiError(type: .unknown, subError: .invalidOOBValue)
+        let error = sut.toVerifyCodePublicError(correlationId: correlationId)
+
+        XCTAssertEqual(error.type, .generalError)
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
+    }
+
+    func test_toResetPasswordStartPublicError_suberrorUnknown() {
+        sut = createApiError(type: .invalidGrant, subError: .unknown)
+        let error = sut.toVerifyCodePublicError(correlationId: correlationId)
+
+        XCTAssertEqual(error.type, .generalError)
+        XCTAssertEqual(error.errorDescription, testDescription)
+        XCTAssertEqual(error.correlationId, correlationId)
+        XCTAssertEqual(error.errorCodes, testErrorCodes)
+        XCTAssertEqual(error.errorUri, testErrorUri)
+    }
 }
diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift
index 5efaa3ec29..2875056acc 100644
--- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests.swift
@@ -30,7 +30,7 @@ final class MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCodeTests: XCTes
     private typealias sut = MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode
 
     func test_allCases() {
-        XCTAssertEqual(sut.allCases.count, 5)
+        XCTAssertEqual(sut.allCases.count, 6)
     }
 
     func test_invalidGrant() {
diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift
index 57511ef43e..86cca8e6dc 100644
--- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordPollCompletionResponseErrorTests.swift
@@ -70,7 +70,15 @@ final class MSALNativeAuthResetPasswordPollCompletionResponseErrorTests: XCTestC
     func test_toPasswordRequiredPublicError_userNotFound() {
         testPasswordRequiredError(code: .userNotFound, expectedErrorType: .generalError)
     }
-    
+
+    func test_toPasswordRequiredPublicError_errorUnknown() {
+        testPasswordRequiredError(code: .unknown, expectedErrorType: .generalError)
+    }
+
+    func test_toPasswordRequiredPublicError_suberrorUnknown() {
+        testPasswordRequiredError(code: .userNotFound, subError: .unknown, expectedErrorType: .generalError)
+    }
+
     // MARK: private methods
     
     private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, expectedErrorType: PasswordRequiredError.ErrorType) {
diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift
index 4b938e476b..c7b59d8c70 100644
--- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests.swift
@@ -30,7 +30,7 @@ final class MSALNativeAuthResetPasswordStartOauth2ErrorCodeTests: XCTestCase {
     private typealias sut = MSALNativeAuthResetPasswordStartOauth2ErrorCode
 
     func test_allCases() {
-        XCTAssertEqual(sut.allCases.count, 4)
+        XCTAssertEqual(sut.allCases.count, 5)
     }
     
     func test_invalidRequest() {
diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift
index 28add44966..b2edd44f0d 100644
--- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests.swift
@@ -30,7 +30,7 @@ final class MSALNativeAuthResetPasswordSubmitOauth2ErrorCodeTests: XCTestCase {
     private typealias sut = MSALNativeAuthResetPasswordSubmitOauth2ErrorCode
     
     func test_allCases() {
-        XCTAssertEqual(sut.allCases.count, 4)
+        XCTAssertEqual(sut.allCases.count, 5)
     }
     
     func test_invalidRequest() {
diff --git a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift
index 1c0419b986..d2b2b5a872 100644
--- a/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/reset_password/MSALNativeAuthResetPasswordSubmitResponseErrorTests.swift
@@ -66,7 +66,15 @@ final class MSALNativeAuthResetPasswordSubmitResponseErrorTests: XCTestCase {
     func test_toPasswordRequiredPublicError_passwordBanned() {
         testPasswordRequiredError(code: .invalidGrant, subError: .passwordBanned, expectedErrorType: .invalidPassword)
     }
-    
+
+    func test_toPasswordRequiredPublicError_errorUnknown() {
+        testPasswordRequiredError(code: .unknown, subError: .passwordBanned, expectedErrorType: .generalError)
+    }
+
+    func test_toPasswordRequiredPublicError_suberrorUnknown() {
+        testPasswordRequiredError(code: .invalidGrant, subError: .unknown, expectedErrorType: .generalError)
+    }
+
     // MARK: private methods
     
     private func testPasswordRequiredError(code: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, expectedErrorType: PasswordRequiredError.ErrorType) {
diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift
index 22f5c1c901..a60f34e9b6 100644
--- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests.swift
@@ -30,7 +30,7 @@ final class MSALNativeAuthSignUpChallengeOauth2ErrorCodeTests: XCTestCase {
     private typealias sut = MSALNativeAuthSignUpChallengeOauth2ErrorCode
     
     func test_allCases() {
-        XCTAssertEqual(sut.allCases.count, 4)
+        XCTAssertEqual(sut.allCases.count, 5)
     }
     
     func test_invalidRequest() {
diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift
index 913efd14c3..93e4435166 100644
--- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpChallengeResponseErrorTests.swift
@@ -86,7 +86,11 @@ final class MSALNativeAuthSignUpChallengeResponseErrorTests: XCTestCase {
     func test_toPasswordRequiredPublicError_invalidRequest() {
         testSignUpChallengeErrorToPasswordRequired(code: .invalidRequest, expectedErrorType: .generalError)
     }
-        
+
+    func test_toPasswordRequiredPublicError_errorUnknown() {
+        testSignUpChallengeErrorToPasswordRequired(code: .unknown, expectedErrorType: .generalError)
+    }
+
     // MARK: private methods
     
     private func testSignUpChallengeErrorToSignUpStart(code: MSALNativeAuthSignUpChallengeOauth2ErrorCode, expectedErrorType: SignUpStartError.ErrorType) {
diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift
index d2e22c2bb4..ca51b3c4a7 100644
--- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueOauth2ErrorCodeTests.swift
@@ -30,7 +30,7 @@ final class MSALNativeAuthSignUpContinueOauth2ErrorCodeTests: XCTestCase {
     private typealias sut = MSALNativeAuthSignUpContinueOauth2ErrorCode
 
     func test_allCases() {
-        XCTAssertEqual(sut.allCases.count, 8)
+        XCTAssertEqual(sut.allCases.count, 9)
     }
 
     func test_invalidRequest() {
diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift
index eab177da1b..22d5999fcd 100644
--- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpContinueResponseErrorTests.swift
@@ -94,7 +94,15 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase {
     func test_toVerifyCodePublicError_invalidOOBValue() {
         testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .invalidOOBValue, expectedErrorType: .invalidCode)
     }
-    
+
+    func test_toVerifyCodePublicError_errorUnknown() {
+        testSignUpContinueErrorToVerifyCode(code: .unknown, expectedErrorType: .generalError)
+    }
+
+    func test_toVerifyCodePublicError_suberrorUnknown() {
+        testSignUpContinueErrorToVerifyCode(code: .invalidGrant, subError: .unknown, expectedErrorType: .generalError)
+    }
+
     // MARK: - toPasswordRequiredPublicError tests
     
     func test_toPasswordRequiredPublicError_invalidRequest() {
@@ -156,7 +164,15 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase {
     func test_toPasswordRequiredPublicError_invalidOOBValue() {
         testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .invalidOOBValue, expectedErrorType: .generalError)
     }
-    
+
+    func test_toPasswordRequiredPublicError_errorUnknown() {
+        testSignUpContinueErrorToPasswordRequired(code: .unknown, subError: .invalidOOBValue, expectedErrorType: .generalError)
+    }
+
+    func test_toPasswordRequiredPublicError_suberrorUnknown() {
+        testSignUpContinueErrorToPasswordRequired(code: .invalidGrant, subError: .unknown, expectedErrorType: .generalError)
+    }
+
     // MARK: - toAttributesRequiredPublicError tests
     
     func test_toAttributesRequiredPublicError_invalidRequest() {
@@ -218,7 +234,15 @@ final class MSALNativeAuthSignUpContinueResponseErrorTests: XCTestCase {
     func test_toAttributesRequiredPublicError_invalidOOBValue() {
         testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .invalidOOBValue)
     }
-    
+
+    func test_toAttributesRequiredPublicError_errorUnknown() {
+        testSignUpContinueErrorToAttributesRequired(code: .unknown, subError: .invalidOOBValue)
+    }
+
+    func test_toAttributesRequiredPublicError_suberrorUnknown() {
+        testSignUpContinueErrorToAttributesRequired(code: .invalidGrant, subError: .unknown)
+    }
+
     // MARK: private methods
     
     private func testSignUpContinueErrorToVerifyCode(code: MSALNativeAuthSignUpContinueOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, expectedErrorType: VerifyCodeError.ErrorType) {
diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift
index 01829d6761..9a75e6d81e 100644
--- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartOauth2ErrorCodeTests.swift
@@ -30,7 +30,7 @@ final class MSALNativeAuthSignUpStartOauth2ErrorCodeTests: XCTestCase {
     private typealias sut = MSALNativeAuthSignUpStartOauth2ErrorCode
 
     func test_allCases() {
-        XCTAssertEqual(sut.allCases.count, 7)
+        XCTAssertEqual(sut.allCases.count, 8)
     }
 
     func test_invalidGrant() {
diff --git a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift
index d47129017d..5573791110 100644
--- a/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift
+++ b/MSAL/test/unit/native_auth/network/errors/sign_up/MSALNativeAuthSignUpStartResponseErrorTests.swift
@@ -83,6 +83,14 @@ final class MSALNativeAuthSignUpStartResponseErrorTests: XCTestCase {
         testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .attributeValidationFailed, expectedErrorType: .generalError)
     }
 
+    func test_toSignUpStartPublicError_errorUnknown() {
+        testSignUpStartErrorToSignUpStart(code: .unknown, subError: .attributeValidationFailed, expectedErrorType: .generalError)
+    }
+
+    func test_toSignUpStartPublicError_suberrorUnknown() {
+        testSignUpStartErrorToSignUpStart(code: .invalidGrant, subError: .unknown, expectedErrorType: .generalError)
+    }
+
     // MARK: private methods
     
     private func testSignUpStartErrorToSignUpStart(code: MSALNativeAuthSignUpStartOauth2ErrorCode, subError: MSALNativeAuthSubErrorCode? = nil, expectedErrorType: SignUpStartError.ErrorType) {
diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift
index cf35d25eaa..8a3ff3b238 100644
--- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift
+++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthResetPasswordResponseValidatorTests.swift
@@ -77,10 +77,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
     }
 
     func test_whenResetPasswordStartErrorResponseIsNotExpected_itReturnsUnexpectedError() {
-        let error = createResetPasswordStartError(
-            error: nil,
-            errorDescription: "API error message"
-        )
+        let error = MSALNativeAuthResetPasswordStartResponseError(errorDescription: "API error message")
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
@@ -88,7 +85,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
     }
 
     func test_whenResetPasswordStartErrorResponseUserNotFound_itReturnsRelatedError() {
-        let error = createResetPasswordStartError(error: .userNotFound)
+        let error = MSALNativeAuthResetPasswordStartResponseError(error: .userNotFound)
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
@@ -98,7 +95,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
     }
     
     func test_whenResetPasswordStartErrorResponseUnauthorizedClient_itReturnsRelatedError() {
-        let error = createResetPasswordStartError(error: .unauthorizedClient)
+        let error = MSALNativeAuthResetPasswordStartResponseError(error: .unauthorizedClient)
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
@@ -108,7 +105,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
     }
     
     func test_whenResetPasswordStartErrorResponseUnsupportedChallengeType_itReturnsRelatedError() {
-        let error = createResetPasswordStartError(error: .unsupportedChallengeType)
+        let error = MSALNativeAuthResetPasswordStartResponseError(error: .unsupportedChallengeType)
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
@@ -118,7 +115,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
     }
     
     func test_whenResetPasswordStartInvalidRequestUserDoesntHaveAPwd_itReturnsRelatedError() {
-        let error = createResetPasswordStartError(error: .invalidRequest, errorCodes: [500222])
+        let error = MSALNativeAuthResetPasswordStartResponseError(error: .invalidRequest, errorCodes: [500222])
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
@@ -128,7 +125,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
     }
     
     func test_whenResetPasswordStartInvalidRequestGenericErrorCode_itReturnsRelatedError() {
-        let error = createResetPasswordStartError(error: .invalidRequest, errorCodes: [90023])
+        let error = MSALNativeAuthResetPasswordStartResponseError(error: .invalidRequest, errorCodes: [90023])
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
@@ -138,7 +135,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
     }
     
     func test_whenResetPasswordStartInvalidRequestNoErrorCode_itReturnsRelatedError() {
-        let error = createResetPasswordStartError(error: .invalidRequest)
+        let error = MSALNativeAuthResetPasswordStartResponseError(error: .invalidRequest)
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
@@ -210,14 +207,11 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
         )
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(.init()))
+        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedChallengeType)))
     }
 
     func test_whenResetPasswordChallengeErrorResponseIsNotExpected_itReturnsUnexpectedError() {
-        let error = createResetPasswordChallengeError(
-            error: nil,
-            errorDescription: "API error message"
-        )
+        let error = MSALNativeAuthResetPasswordChallengeResponseError(errorDescription: "API error message")
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
@@ -225,7 +219,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
     }
 
     func test_whenResetPasswordChallengeErrorResponseIsExpected_itReturnsError() {
-        let error = createResetPasswordChallengeError(error: .expiredToken)
+        let error = MSALNativeAuthResetPasswordChallengeResponseError(error: .expiredToken)
 
         let response: Result = .failure(error)
 
@@ -234,7 +228,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .expiredToken = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -253,10 +247,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
     }
 
     func test_whenResetPasswordContinueErrorResponseIsNotExpected_itReturnsUnexpectedError() {
-        let error = createResetPasswordContinueError(
-            error: nil,
-            errorDescription: "API error message"
-        )
+        let error = MSALNativeAuthResetPasswordContinueResponseError(errorDescription: "API error message")
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
@@ -286,7 +277,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .unauthorizedClient = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -297,7 +288,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .invalidGrant = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -308,7 +299,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .expiredToken = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -319,7 +310,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .invalidRequest = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -345,7 +336,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .passwordTooWeak = error.subError {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -356,7 +347,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .passwordTooShort = error.subError {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -367,7 +358,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .passwordTooLong = error.subError {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -378,7 +369,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .passwordRecentlyUsed = error.subError {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -389,7 +380,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .passwordBanned = error.subError {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -400,7 +391,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .invalidRequest = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -411,7 +402,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .unauthorizedClient = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -422,15 +413,12 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .expiredToken = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
     func test_whenResetPasswordSubmitErrorResponseIsNotExpected_itReturnsUnexpectedError() {
-        let error = createResetPasswordSubmitError(
-            error: nil,
-            errorDescription: "API error message"
-        )
+        let error = MSALNativeAuthResetPasswordSubmitResponseError(errorDescription: "API error message")
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
@@ -459,7 +447,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .passwordTooWeak = error.subError {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -470,7 +458,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .passwordTooShort = error.subError {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -481,7 +469,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .passwordTooLong = error.subError {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -492,7 +480,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .passwordRecentlyUsed = error.subError {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -503,7 +491,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .passwordBanned = error.subError {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -514,7 +502,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .invalidRequest = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -525,7 +513,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .unauthorizedClient = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -536,15 +524,12 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .expiredToken = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
     func test_whenResetPasswordPollCompletionErrorResponseIsNotExpected_itReturnsUnexpectedError() {
-        let error = createResetPasswordPollCompletionError(
-            error: nil,
-            errorDescription: "API error message"
-        )
+        let error = MSALNativeAuthResetPasswordPollCompletionResponseError(errorDescription: "API error message")
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
@@ -559,7 +544,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
         expectedContinuationToken: String? = nil
     ) -> MSALNativeAuthResetPasswordContinueValidatedResponse {
         let response: Result = .failure(
-            createResetPasswordContinueError(
+            MSALNativeAuthResetPasswordContinueResponseError(
                 error: expectedError,
                 subError: expectedSubError,
                 continuationToken: expectedContinuationToken
@@ -574,7 +559,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
         expectedSubError: MSALNativeAuthSubErrorCode? = nil
     ) -> MSALNativeAuthResetPasswordSubmitValidatedResponse {
         let response: Result = .failure(
-            createResetPasswordSubmitError(
+            MSALNativeAuthResetPasswordSubmitResponseError(
                 error: expectedError,
                 subError: expectedSubError
             )
@@ -588,7 +573,7 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
         expectedSubError: MSALNativeAuthSubErrorCode? = nil
     ) -> MSALNativeAuthResetPasswordPollCompletionValidatedResponse {
         let response: Result = .failure(
-            createResetPasswordPollCompletionError(
+            MSALNativeAuthResetPasswordPollCompletionResponseError(
                 error: expectedError,
                 subError: expectedSubError
             )
@@ -596,102 +581,4 @@ final class MSALNativeAuthResetPasswordResponseValidatorTests: XCTestCase {
 
         return sut.validate(response, with: context)
     }
-
-    private func createResetPasswordStartError(
-        error: MSALNativeAuthResetPasswordStartOauth2ErrorCode? = nil,
-        errorDescription: String? = nil,
-        errorCodes: [Int]? = nil,
-        errorURI: String? = nil,
-        innerErrors: [MSALNativeAuthInnerError]? = nil,
-        target: String? = nil
-    ) -> MSALNativeAuthResetPasswordStartResponseError {
-        .init(
-            error: error,
-            errorDescription: errorDescription,
-            errorCodes: errorCodes,
-            errorURI: errorURI,
-            innerErrors: innerErrors,
-            target: target
-        )
-    }
-
-    private func createResetPasswordChallengeError(
-        error: MSALNativeAuthResetPasswordChallengeOauth2ErrorCode? = nil,
-        errorDescription: String? = nil,
-        errorCodes: [Int]? = nil,
-        errorURI: String? = nil,
-        innerErrors: [MSALNativeAuthInnerError]? = nil,
-        target: String? = nil
-    ) -> MSALNativeAuthResetPasswordChallengeResponseError {
-        .init(
-            error: error,
-            errorDescription: errorDescription,
-            errorCodes: errorCodes,
-            errorURI: errorURI,
-            innerErrors: innerErrors,
-            target: target
-        )
-    }
-
-    private func createResetPasswordContinueError(
-        error: MSALNativeAuthResetPasswordContinueOauth2ErrorCode? = nil,
-        subError: MSALNativeAuthSubErrorCode? = nil,
-        errorDescription: String? = nil,
-        errorCodes: [Int]? = nil,
-        errorURI: String? = nil,
-        innerErrors: [MSALNativeAuthInnerError]? = nil,
-        target: String? = nil,
-        continuationToken: String? = nil
-    ) -> MSALNativeAuthResetPasswordContinueResponseError {
-        .init(
-            error: error,
-            subError: subError,
-            errorDescription: errorDescription,
-            errorCodes: errorCodes,
-            errorURI: errorURI,
-            innerErrors: innerErrors,
-            target: target,
-            continuationToken: continuationToken
-        )
-    }
-
-    private func createResetPasswordSubmitError(
-        error: MSALNativeAuthResetPasswordSubmitOauth2ErrorCode? = nil,
-        subError: MSALNativeAuthSubErrorCode? = nil,
-        errorDescription: String? = nil,
-        errorCodes: [Int]? = nil,
-        errorURI: String? = nil,
-        innerErrors: [MSALNativeAuthInnerError]? = nil,
-        target: String? = nil
-    ) -> MSALNativeAuthResetPasswordSubmitResponseError {
-        .init(
-            error: error,
-            subError: subError,
-            errorDescription: errorDescription,
-            errorCodes: errorCodes,
-            errorURI: errorURI,
-            innerErrors: innerErrors,
-            target: target
-        )
-    }
-
-    private func createResetPasswordPollCompletionError(
-        error: MSALNativeAuthResetPasswordPollCompletionOauth2ErrorCode? = nil,
-        subError: MSALNativeAuthSubErrorCode? = nil,
-        errorDescription: String? = nil,
-        errorCodes: [Int]? = nil,
-        errorURI: String? = nil,
-        innerErrors: [MSALNativeAuthInnerError]? = nil,
-        target: String? = nil
-    ) -> MSALNativeAuthResetPasswordPollCompletionResponseError {
-        .init(
-            error: error,
-            subError: subError,
-            errorDescription: errorDescription,
-            errorCodes: errorCodes,
-            errorURI: errorURI,
-            innerErrors: innerErrors,
-            target: target
-        )
-    }
 }
diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift
index 3264adc183..01b6e596b8 100644
--- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift
+++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignUpResponseValidatorTests.swift
@@ -59,10 +59,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
     }
 
     func test_whenSignUpStartErrorResponseIsNotExpected_it_returns_unexpectedError() {
-        let error = createSignUpStartError(
-            error: nil,
-            errorDescription: "API error message"
-        )
+        let error = MSALNativeAuthSignUpStartResponseError(errorDescription: "API error message")
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
@@ -82,7 +79,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
     }
 
     func test_whenSignUpStart_attributeValidationFailed_it_returns_attributeValidationFailed() {
-        let error = createSignUpStartError(
+        let error = MSALNativeAuthSignUpStartResponseError(
             error: .invalidGrant,
             subError: .attributeValidationFailed,
             invalidAttributes: [MSALNativeAuthErrorBasicAttribute(name: "city")]
@@ -91,7 +88,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
 
         let result = sut.validate(response, with: context)
 
-        guard case .attributeValidationFailed(let error, let invalidAttributes) = result else {
+        guard case .attributeValidationFailed(_, let invalidAttributes) = result else {
             return XCTFail("Unexpected response")
         }
 
@@ -99,7 +96,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
     }
 
     func test_whenSignUpStart_attributeValidationFailed_but_invalidAttributesIsEmpty_it_returns_attributeValidationFailed() {
-        let error = createSignUpStartError(
+        let error = MSALNativeAuthSignUpStartResponseError(
             error: .invalidGrant,
             subError: .attributeValidationFailed,
             invalidAttributes: []
@@ -107,11 +104,11 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(.init()))
+        XCTAssertEqual(result, .unexpectedError(.init(error: .invalidGrant, subError: .attributeValidationFailed, invalidAttributes: [])))
     }
 
     func test_whenSignUpStart_attributeValidationFailed_but_invalidAttributesIsNil_it_returns_attributeValidationFailed() {
-        let error = createSignUpStartError(
+        let error = MSALNativeAuthSignUpStartResponseError(
             error: .invalidGrant,
             subError: .attributeValidationFailed,
             invalidAttributes: nil
@@ -119,11 +116,11 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(.init()))
+        XCTAssertEqual(result, .unexpectedError(.init(error: .invalidGrant, subError: .attributeValidationFailed)))
     }
 
     func test_whenSignUpStartErrorResponseIsExpected_it_returns_error() {
-        let error = createSignUpStartError(error: .userAlreadyExists)
+        let error = MSALNativeAuthSignUpStartResponseError(error: .userAlreadyExists)
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
@@ -131,7 +128,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .userAlreadyExists = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -139,7 +136,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         let attributes = [MSALNativeAuthErrorBasicAttribute(name: "attribute")]
         let errorCodes = [MSALNativeAuthESTSApiErrorCodes.invalidRequestParameter.rawValue, Int.max]
 
-        let apiError = createSignUpStartError(
+        let apiError = MSALNativeAuthSignUpStartResponseError(
             error: .invalidRequest,
             errorDescription: "username parameter is empty or not valid",
             errorCodes: errorCodes,
@@ -162,7 +159,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         let attributes = [MSALNativeAuthErrorBasicAttribute(name: "attribute")]
         let errorCodes = [MSALNativeAuthESTSApiErrorCodes.invalidRequestParameter.rawValue, Int.max]
         
-        let apiError = createSignUpStartError(
+        let apiError = MSALNativeAuthSignUpStartResponseError(
             error: .invalidRequest,
             errorDescription: "client_id parameter is empty or not valid",
             errorCodes: errorCodes,
@@ -185,7 +182,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         let attributes = [MSALNativeAuthErrorBasicAttribute(name: "attribute")]
         let errorCodes = [Int.max]
 
-        let apiError = createSignUpStartError(
+        let apiError = MSALNativeAuthSignUpStartResponseError(
             error: .invalidRequest,
             errorDescription: "aDescription",
             errorCodes: errorCodes,
@@ -332,18 +329,18 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
     }
 
     func test_whenSignUpChallengeErrorResponseIsNotExpected_it_returns_unexpectedError() {
-        let error = createSignUpChallengeError(
-            error: nil,
+        let error = MSALNativeAuthSignUpChallengeResponseError(
+            error: .unknown,
             errorDescription: "API error message"
         )
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
-        XCTAssertEqual(result, .unexpectedError(.init(errorDescription: "API error message")))
+        XCTAssertEqual(result, .unexpectedError(.init(error: .unknown, errorDescription: "API error message")))
     }
 
     func test_whenSignUpChallengeErrorResponseIsExpected_it_returns_error() {
-        let error = createSignUpChallengeError(error: .expiredToken)
+        let error = MSALNativeAuthSignUpChallengeResponseError(error: .expiredToken)
 
         let response: Result = .failure(error)
 
@@ -352,7 +349,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .expiredToken = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -377,10 +374,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
     }
 
     func test_whenSignUpContinueErrorResponseIsNotExpected_it_returns_unexpectedError() {
-        let error = createSignUpContinueError(
-            error: nil,
-            errorDescription: "API error message"
-        )
+        let error = MSALNativeAuthSignUpContinueResponseError(errorDescription: "API error message")
         let response: Result = .failure(error)
 
         let result = sut.validate(response, with: context)
@@ -394,7 +388,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .invalidGrant = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
         if case .invalidOOBValue = error.subError {} else {
             XCTFail("Unexpected suberror: \(String(describing: error.subError))")
@@ -408,7 +402,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .invalidGrant = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
         if case .passwordTooWeak = error.subError {} else {
             XCTFail("Unexpected suberror: \(String(describing: error.subError))")
@@ -422,7 +416,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .invalidGrant = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
         if case .passwordTooShort = error.subError {} else {
             XCTFail("Unexpected suberror: \(String(describing: error.subError))")
@@ -436,7 +430,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .invalidGrant = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
         if case .passwordTooLong = error.subError {} else {
             XCTFail("Unexpected suberror: \(String(describing: error.subError))")
@@ -450,7 +444,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .invalidGrant = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
         if case .passwordRecentlyUsed = error.subError {} else {
             XCTFail("Unexpected suberror: \(String(describing: error.subError))")
@@ -464,7 +458,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .invalidGrant = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
         if case .passwordBanned = error.subError {} else {
             XCTFail("Unexpected suberror: \(String(describing: error.subError))")
@@ -488,7 +482,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .invalidRequest = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -562,7 +556,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .unauthorizedClient = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -573,7 +567,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .invalidGrant = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -584,7 +578,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .expiredToken = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -595,7 +589,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .invalidRequest = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -606,7 +600,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
             return XCTFail("Unexpected response")
         }
         if case .userAlreadyExists = error.error {} else {
-            XCTFail("Unexpected error: \(error.error?.rawValue ?? "Code not decoded")")
+            XCTFail("Unexpected error: \(error.error.rawValue)")
         }
     }
 
@@ -619,7 +613,7 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
         errorCodes: [Int]? = nil
     ) -> MSALNativeAuthSignUpContinueValidatedResponse {
         let response: Result = .failure(
-            createSignUpContinueError(
+            MSALNativeAuthSignUpContinueResponseError(
                 error: expectedError,
                 subError: expectedSubError,
                 errorCodes: errorCodes,
@@ -631,70 +625,4 @@ final class MSALNativeAuthSignUpResponseValidatorTests: XCTestCase {
 
         return sut.validate(response, with: context)
     }
-
-    private func createSignUpStartError(
-        error: MSALNativeAuthSignUpStartOauth2ErrorCode? = nil,
-        subError: MSALNativeAuthSubErrorCode? = nil,
-        errorDescription: String? = nil,
-        errorCodes: [Int]? = nil,
-        errorURI: String? = nil,
-        innerErrors: [MSALNativeAuthInnerError]? = nil,
-        continuationToken: String? = nil,
-        unverifiedAttributes: [MSALNativeAuthErrorBasicAttribute]? = nil,
-        invalidAttributes: [MSALNativeAuthErrorBasicAttribute]? = nil
-    ) -> MSALNativeAuthSignUpStartResponseError {
-        .init(
-            error: error,
-            subError: subError,
-            errorDescription: errorDescription,
-            errorCodes: errorCodes,
-            errorURI: errorURI,
-            innerErrors: innerErrors,
-            continuationToken: continuationToken,
-            unverifiedAttributes: unverifiedAttributes,
-            invalidAttributes: invalidAttributes
-        )
-    }
-
-    private func createSignUpChallengeError(
-        error: MSALNativeAuthSignUpChallengeOauth2ErrorCode? = nil,
-        errorDescription: String? = nil,
-        errorCodes: [Int]? = nil,
-        errorURI: String? = nil,
-        innerErrors: [MSALNativeAuthInnerError]? = nil
-    ) -> MSALNativeAuthSignUpChallengeResponseError {
-        .init(
-            error: error,
-            errorDescription: errorDescription,
-            errorCodes: errorCodes,
-            errorURI: errorURI,
-            innerErrors: innerErrors
-        )
-    }
-
-    private func createSignUpContinueError(
-        error: MSALNativeAuthSignUpContinueOauth2ErrorCode? = nil,
-        subError: MSALNativeAuthSubErrorCode? = nil,
-        errorDescription: String? = nil,
-        errorCodes: [Int]? = nil,
-        errorURI: String? = nil,
-        innerErrors: [MSALNativeAuthInnerError]? = nil,
-        continuationToken: String? = nil,
-        requiredAttributes: [MSALNativeAuthRequiredAttributeInternal]? = nil,
-        unverifiedAttributes: [MSALNativeAuthErrorBasicAttribute]? = nil,
-        invalidAttributes: [MSALNativeAuthErrorBasicAttribute]? = nil
-    ) -> MSALNativeAuthSignUpContinueResponseError {
-        .init(
-            error: error,
-            subError: subError,
-            errorDescription: errorDescription,
-            errorCodes: errorCodes,
-            errorURI: errorURI,
-            innerErrors: innerErrors,
-            continuationToken: continuationToken,
-            requiredAttributes: requiredAttributes,
-            unverifiedAttributes: unverifiedAttributes,
-            invalidAttributes: invalidAttributes
-        )
-    }
 }

From a4343095f87f7ea38371edd167c053d125235505 Mon Sep 17 00:00:00 2001
From: mipetriu 
Date: Fri, 9 Feb 2024 11:28:57 -0800
Subject: [PATCH 53/84] Updated common core for ADBNTLMHandler PR

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 3b1d8bddad..a47bd7434b 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 3b1d8bddad1ac3616a9d00f2ba7576702160fcdd
+Subproject commit a47bd7434bfce63709d3b859a57a960c481d2131

From 32c8ad4fece797689986a96d286451ac9bd80616 Mon Sep 17 00:00:00 2001
From: mipetriu 
Date: Fri, 9 Feb 2024 12:55:14 -0800
Subject: [PATCH 54/84] updated common core after merging PR

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index a47bd7434b..8181084bc3 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit a47bd7434bfce63709d3b859a57a960c481d2131
+Subproject commit 8181084bc32bcd4c6bd4a6e6879fcef058d48aee

From 5cc0ead6d45b02bc5d6be656ad3a51e7ddfb1c89 Mon Sep 17 00:00:00 2001
From: mipetriu 
Date: Fri, 9 Feb 2024 13:41:13 -0800
Subject: [PATCH 55/84] updated to latest dev of common core

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 8181084bc3..3eded3d5b5 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 8181084bc32bcd4c6bd4a6e6879fcef058d48aee
+Subproject commit 3eded3d5b54f2a1c826207a852566e90d2c101b8

From 31149172d3ddb8018b5acd3827e4c1608887f9b7 Mon Sep 17 00:00:00 2001
From: Swasti Gupta 
Date: Fri, 9 Feb 2024 17:30:14 -0800
Subject: [PATCH 56/84] update submodule

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 54ac389e6e..40ad98fe30 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 54ac389e6ef428ed71e21e1b7d3dba67d8784cb4
+Subproject commit 40ad98fe30a1e41b30c876d31b0a892386151979

From b33e2a26943192fb6260d2db9e814b503ec829fd Mon Sep 17 00:00:00 2001
From: Sergei Demchenko 
Date: Tue, 13 Feb 2024 17:46:00 -0800
Subject: [PATCH 57/84] Update core. (#1975)

* Update core.

* Update core.
---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 40ad98fe30..eb123dcba8 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 40ad98fe30a1e41b30c876d31b0a892386151979
+Subproject commit eb123dcba81f7d391cef1a15cdd59ab01215292f

From c0477a651777edd59aaeb6e1b2f02c3e82d63b64 Mon Sep 17 00:00:00 2001
From: Ameya Patil 
Date: Wed, 14 Feb 2024 12:38:14 -0800
Subject: [PATCH 58/84] Update iOS version to test on

---
 azure_pipelines/automation.yml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/azure_pipelines/automation.yml b/azure_pipelines/automation.yml
index 578ed6c3ea..3da6550f7e 100644
--- a/azure_pipelines/automation.yml
+++ b/azure_pipelines/automation.yml
@@ -66,7 +66,7 @@ jobs:
           -workspace MSAL.xcworkspace \
           -scheme "MSAL Test Automation (iOS)" \
           -sdk iphonesimulator \
-          -destination 'platform=iOS Simulator,name=iPhone 14,OS=16.4' \
+          -destination 'platform=iOS Simulator,name=iPhone 14,OS=17.2' \
           -derivedDataPath 'build' \
           | tee xcodebuild.log \
           | xcpretty -c
@@ -78,8 +78,8 @@ jobs:
       script: |
         ls build/Build/Products/
         xcodebuild test-without-building \
-            -xctestrun 'build/Build/Products/MSAL Test Automation (iOS)_iphonesimulator16.4-x86_64.xctestrun' \
-            -destination 'platform=iOS Simulator,name=iPhone 14,OS=16.4' \
+            -xctestrun 'build/Build/Products/MSAL Test Automation (iOS)_iphonesimulator17.2-x86_64.xctestrun' \
+            -destination 'platform=iOS Simulator,name=iPhone 14,OS=17.2' \
             -retry-tests-on-failure \
             -parallel-testing-enabled NO \
             -resultBundlePath '$(Agent.BuildDirectory)/s/test_output/report.xcresult'       

From 40e3ed697cccc90f0605d2d5b50585b2058e80ce Mon Sep 17 00:00:00 2001
From: Ameya Patil 
Date: Wed, 14 Feb 2024 13:14:36 -0800
Subject: [PATCH 59/84] Update xctestrun file name

---
 azure_pipelines/automation.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/azure_pipelines/automation.yml b/azure_pipelines/automation.yml
index 3da6550f7e..864c74bace 100644
--- a/azure_pipelines/automation.yml
+++ b/azure_pipelines/automation.yml
@@ -78,7 +78,7 @@ jobs:
       script: |
         ls build/Build/Products/
         xcodebuild test-without-building \
-            -xctestrun 'build/Build/Products/MSAL Test Automation (iOS)_iphonesimulator17.2-x86_64.xctestrun' \
+            -xctestrun 'build/Build/Products/MSAL Test Automation (iOS)_iphonesimulator17.0-x86_64.xctestrun' \
             -destination 'platform=iOS Simulator,name=iPhone 14,OS=17.2' \
             -retry-tests-on-failure \
             -parallel-testing-enabled NO \

From e14a17422e18bfaeb49f962f6201c015b6fbaeba Mon Sep 17 00:00:00 2001
From: Jason Zeng 
Date: Tue, 20 Feb 2024 11:32:09 -0800
Subject: [PATCH 60/84] Update common core

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index eb123dcba8..da2e70c7e6 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit eb123dcba81f7d391cef1a15cdd59ab01215292f
+Subproject commit da2e70c7e6c99da6a827c9d966777e86f887f2de

From bceaa2cd389186687fc145c34f37e3dfe4dcc659 Mon Sep 17 00:00:00 2001
From: Danilo Raspa <105228698+nilo-ms@users.noreply.github.com>
Date: Wed, 21 Feb 2024 16:53:02 +0000
Subject: [PATCH 61/84] Fix static framework - Add dedicated pod subspec for
 native auth code (#2019)

* Testing cocoapod

* nww file

* New podfile

* remove swift files from extension, add OBJC native auth files to all subspecs

* remove native auth header files for osx

* no need to specify native auth objC files because already included in the first include

* remove trailing spaces

---------

Co-authored-by: Silviu Petrescu 
---
 MSAL.podspec | 33 ++++++++++++++++++++++-----------
 1 file changed, 22 insertions(+), 11 deletions(-)

diff --git a/MSAL.podspec b/MSAL.podspec
index 9dd0f8be9d..01021c433b 100644
--- a/MSAL.podspec
+++ b/MSAL.podspec
@@ -20,34 +20,45 @@ Pod::Spec.new do |s|
     :tag => s.version.to_s,
     :submodules => true
   }
-
-  s.pod_target_xcconfig = { 'CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF' => 'NO', 'HEADER_SEARCH_PATHS' => "$SRCROOT/MSAL"}
+  
   s.default_subspecs ='app-lib'
   
   s.prefix_header_file = "MSAL/src/MSAL.pch"
   s.header_dir = "MSAL"
 
   s.subspec 'app-lib' do |app|
-    app.source_files = "MSAL/src/**/*.{h,m}", "MSAL/src/native_auth/**/*.{h,m,swift}", "MSAL/IdentityCore/IdentityCore/src/**/*.{h,m}", "MSAL/module.modulemap"
+    app.pod_target_xcconfig = { 'CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF' => 'NO' }
+    app.source_files = "MSAL/src/**/*.{h,m}", "MSAL/IdentityCore/IdentityCore/src/**/*.{h,m}"
     app.ios.public_header_files = "MSAL/src/public/*.h","MSAL/src/public/ios/**/*.h", "MSAL/src/public/configuration/**/*.h", "MSAL/src/native_auth/public/*.h"
     app.osx.public_header_files = "MSAL/src/public/mac/*.h","MSAL/src/public/*.h", "MSAL/src/public/configuration/**/*.h"
     app.ios.exclude_files = "MSAL/src/**/mac/*", "MSAL/IdentityCore/IdentityCore/src/**/mac/*"
-    app.osx.exclude_files = "MSAL/src/**/ios/*", "MSAL/IdentityCore/IdentityCore/src/**/ios/*", "MSAL/src/native_auth/**/*", "MSAL/module.modulemap"
+    app.osx.exclude_files = "MSAL/src/**/ios/*", "MSAL/IdentityCore/IdentityCore/src/**/ios/*", "MSAL/src/native_auth/**/*"
     app.requires_arc = true
   end
+
+  s.subspec 'native-auth' do |nat|
+    nat.pod_target_xcconfig = { 'CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF' => 'NO', 'HEADER_SEARCH_PATHS' => "$SRCROOT/MSAL"}
+    nat.source_files = "MSAL/src/**/*.{h,m}", "MSAL/src/native_auth/**/*.{h,m,swift}", "MSAL/IdentityCore/IdentityCore/src/**/*.{h,m}", "MSAL/module.modulemap"
+    nat.ios.public_header_files = "MSAL/src/public/*.h","MSAL/src/public/ios/**/*.h", "MSAL/src/public/configuration/**/*.h", "MSAL/src/native_auth/public/*.h"
+    nat.osx.public_header_files = "MSAL/src/public/mac/*.h","MSAL/src/public/*.h", "MSAL/src/public/configuration/**/*.h"
+    nat.ios.exclude_files = "MSAL/src/**/mac/*", "MSAL/IdentityCore/IdentityCore/src/**/mac/*"
+    nat.osx.exclude_files = "MSAL/src/**/ios/*", "MSAL/IdentityCore/IdentityCore/src/**/ios/*", "MSAL/src/native_auth/**/*", "MSAL/module.modulemap"
+    nat.requires_arc = true
+  end
   
   # Note, MSAL has limited support for running in app extensions.
   s.subspec 'extension' do |ext|
-  	ext.compiler_flags = '-DADAL_EXTENSION_SAFE=1'
-  	ext.source_files = "MSAL/src/**/*.{h,m}", "MSAL/src/native_auth/**/*.{h,m,swift}", "MSAL/IdentityCore/IdentityCore/src/**/*.{h,m}", "MSAL/module.modulemap"
+    ext.pod_target_xcconfig = { 'CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF' => 'NO' }
+    ext.compiler_flags = '-DADAL_EXTENSION_SAFE=1'
+    ext.source_files = "MSAL/src/**/*.{h,m}", "MSAL/IdentityCore/IdentityCore/src/**/*.{h,m}"
     ext.ios.public_header_files = "MSAL/src/public/*.h","MSAL/src/public/ios/**/*.h", "MSAL/src/public/configuration/**/*.h", "MSAL/src/native_auth/public/*.h"
     ext.osx.public_header_files = "MSAL/src/public/mac/*.h","MSAL/src/public/*.h", "MSAL/src/public/configuration/**/*.h"
   
-  	# There is currently a bug in CocoaPods where it doesn't combine the public headers
-  	# for both the platform and overall.
-  	ext.ios.exclude_files = "MSAL/src/**/mac/*", "MSAL/IdentityCore/IdentityCore/src/**/mac/*"
-  	ext.osx.exclude_files = "MSAL/src/**/ios/*", "MSAL/IdentityCore/IdentityCore/src/**/ios/*", "MSAL/src/native_auth/**/*", "MSAL/module.modulemap"
-  	ext.requires_arc = true
+    # There is currently a bug in CocoaPods where it doesn't combine the public headers
+    # for both the platform and overall.
+    ext.ios.exclude_files = "MSAL/src/**/mac/*", "MSAL/IdentityCore/IdentityCore/src/**/mac/*"
+    ext.osx.exclude_files = "MSAL/src/**/ios/*", "MSAL/IdentityCore/IdentityCore/src/**/ios/*", "MSAL/src/native_auth/**/*"
+    ext.requires_arc = true
   end
 
 end

From 55bfcd17b4b0df6ae61fb4db1ee0270081c1cf3d Mon Sep 17 00:00:00 2001
From: Swasti Gupta 
Date: Wed, 21 Feb 2024 15:41:34 -0800
Subject: [PATCH 62/84] Calculating prtId based on accountId and deviceId

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index eb123dcba8..97f2c911ef 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit eb123dcba81f7d391cef1a15cdd59ab01215292f
+Subproject commit 97f2c911efe6d6a6d274922ea58d47ff81d1e90b

From b9a8a2b200249357a17da0a0b70e52f4f0031e78 Mon Sep 17 00:00:00 2001
From: Danilo Raspa <105228698+nilo-ms@users.noreply.github.com>
Date: Thu, 22 Feb 2024 17:03:33 +0000
Subject: [PATCH 63/84] update IdentityCore reference to match main branch
 (#2034)

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index eb123dcba8..237ce0cded 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit eb123dcba81f7d391cef1a15cdd59ab01215292f
+Subproject commit 237ce0cded0ef8e2e19c59a2e59dde7dfdc92b65

From 5acf55203147e2a5b3b43c9157a74f84dbeb1de8 Mon Sep 17 00:00:00 2001
From: Danilo Raspa <105228698+nilo-ms@users.noreply.github.com>
Date: Thu, 22 Feb 2024 18:21:51 +0000
Subject: [PATCH 64/84] Merge MSAL main(hotfix/1.2.22) back to dev (#2033)

* Added privacy manifest

* Added phone number

* cherry picking from msal

* resolving unit test failure

* updating version numbers

* updating changelog

* updating xcode version

* adding updated common core submodule

* Updating MSAL framework checksum & url for 1.2.22 [skip ci]

---------

Co-authored-by: Olga Dalton 
Co-authored-by: Fidelia Nawar 
Co-authored-by: Hieu Nguyen <65981263+hieunguyenmsft@users.noreply.github.com>
Co-authored-by: Fidelia Nawar <89487029+fidelianawar@users.noreply.github.com>
---
 CHANGELOG.md                                      | 3 +++
 MSAL.podspec                                      | 2 +-
 MSAL/resources/ios/Info.plist                     | 2 +-
 MSAL/resources/mac/Info.plist                     | 2 +-
 MSAL/src/MSAL_Internal.h                          | 2 +-
 MSAL/test/unit/MSALPublicClientApplicationTests.m | 2 +-
 Package.swift                                     | 2 +-
 azure_pipelines/automation.yml                    | 6 ++++++
 8 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 190c1bb846..632c1f28dc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+## [1.2.22]
+* Add privacy manifest (#1984)
+
 ## [1.2.21]
 * Add additional error codes for PSSO KeyId mismatch (#1946)
 
diff --git a/MSAL.podspec b/MSAL.podspec
index 01021c433b..8eaa9eb2ac 100644
--- a/MSAL.podspec
+++ b/MSAL.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name         = "MSAL"
-  s.version      = "1.2.21"
+  s.version      = "1.2.22"
   s.summary      = "Microsoft Authentication Library (MSAL) for iOS"
   s.description  = <<-DESC
                    The MSAL library for iOS gives your app the ability to begin using the Microsoft Cloud by supporting Microsoft Azure Active Directory and Microsoft Accounts in a converged experience using industry standard OAuth2 and OpenID Connect. The library also supports Microsoft Azure B2C for those using our hosted identity management service.
diff --git a/MSAL/resources/ios/Info.plist b/MSAL/resources/ios/Info.plist
index fef34a9926..0f2c055230 100644
--- a/MSAL/resources/ios/Info.plist
+++ b/MSAL/resources/ios/Info.plist
@@ -15,7 +15,7 @@
 	CFBundlePackageType
 	FMWK
 	CFBundleShortVersionString
-	1.2.21
+	1.2.22
 	CFBundleVersion
 	$(CURRENT_PROJECT_VERSION)
 	NSPrincipalClass
diff --git a/MSAL/resources/mac/Info.plist b/MSAL/resources/mac/Info.plist
index 65e0bedfab..a5b75be25e 100644
--- a/MSAL/resources/mac/Info.plist
+++ b/MSAL/resources/mac/Info.plist
@@ -15,7 +15,7 @@
 	CFBundlePackageType
 	FMWK
 	CFBundleShortVersionString
-	1.2.21
+	1.2.22
 	CFBundleVersion
 	$(CURRENT_PROJECT_VERSION)
 	NSHumanReadableCopyright
diff --git a/MSAL/src/MSAL_Internal.h b/MSAL/src/MSAL_Internal.h
index 74922f80fe..c149e5b02c 100644
--- a/MSAL/src/MSAL_Internal.h
+++ b/MSAL/src/MSAL_Internal.h
@@ -27,7 +27,7 @@
 
 #define MSAL_VER_HIGH       1
 #define MSAL_VER_LOW        2
-#define MSAL_VER_PATCH      21
+#define MSAL_VER_PATCH      22
 
 #define STR_HELPER(x) #x
 #define STR(x) STR_HELPER(x)
diff --git a/MSAL/test/unit/MSALPublicClientApplicationTests.m b/MSAL/test/unit/MSALPublicClientApplicationTests.m
index 6b8980f8ab..b87d215a2e 100644
--- a/MSAL/test/unit/MSALPublicClientApplicationTests.m
+++ b/MSAL/test/unit/MSALPublicClientApplicationTests.m
@@ -2015,7 +2015,7 @@ - (void)testAcquireSilentScopesUserAuthorityForceRefreshCorrelationId_andCustomK
         
                 XCTAssertNil(result);
                 XCTAssertNotNil(error);
-    }];    
+    }];
 }
 #if TARGET_OS_OSX
 - (void)testGetDeviceInfo_whenBrokerEnabled_andFoundDeviceInfo_shouldReturnDeviceInfoWithPlatformSSOStatus API_AVAILABLE(ios(13.0), macos(10.15))
diff --git a/Package.swift b/Package.swift
index 2e9fc44599..df27d85043 100644
--- a/Package.swift
+++ b/Package.swift
@@ -13,6 +13,6 @@ let package = Package(
           targets: ["MSAL"]),
   ],
   targets: [
-      .binaryTarget(name: "MSAL", url: "https://github.com/AzureAD/microsoft-authentication-library-for-objc/releases/download/1.2.21/MSAL.zip", checksum: "c6329a0f9d793276fb45ab256600db277e29296897a3106126fa639facb15d19")
+      .binaryTarget(name: "MSAL", url: "https://github.com/AzureAD/microsoft-authentication-library-for-objc/releases/download/1.2.22/MSAL.zip", checksum: "c87a8f8de8395169ea5444676b83f0fca3a5889810dbeefe4c04b3f6e2455ae1")
   ]
 )
diff --git a/azure_pipelines/automation.yml b/azure_pipelines/automation.yml
index 864c74bace..df8fb00c87 100644
--- a/azure_pipelines/automation.yml
+++ b/azure_pipelines/automation.yml
@@ -43,6 +43,12 @@ jobs:
     fetchDepth: 1
     persistCredentials: true
     path: s
+    
+  - task: Bash@3
+    displayName: 'Select Xcode version'
+    inputs:
+      targetType: 'inline'
+      script: '/bin/bash -c "sudo xcode-select -s /Applications/Xcode_14.3.app"'
   
   - task: Bash@3
     displayName: Go to project folder

From 268e85982e0a879d8a5e2f8ce02eaa4d2f9997ce Mon Sep 17 00:00:00 2001
From: Swasti Gupta 
Date: Thu, 22 Feb 2024 12:51:58 -0800
Subject: [PATCH 65/84] update submodule

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 97f2c911ef..386c832b3b 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 97f2c911efe6d6a6d274922ea58d47ff81d1e90b
+Subproject commit 386c832b3b6c501d4e6ec3e21a9f64f744fbbfb4

From 4323107fde9bac70bfbd99e7926b1ba168347431 Mon Sep 17 00:00:00 2001
From: Olga Dalton 
Date: Fri, 23 Feb 2024 08:02:57 -0800
Subject: [PATCH 66/84] Minor automation stability tweaks

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 237ce0cded..81f5cd60f7 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 237ce0cded0ef8e2e19c59a2e59dde7dfdc92b65
+Subproject commit 81f5cd60f7383d3bbb1d0e30a36e03d5db3340f8

From 37edee4d694ba566d52c2e7a6d52f4e228b6023b Mon Sep 17 00:00:00 2001
From: Olga Dalton 
Date: Fri, 23 Feb 2024 18:15:17 -0800
Subject: [PATCH 67/84] Fix cookie clearing callback

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 81f5cd60f7..6f19eb19e3 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 81f5cd60f7383d3bbb1d0e30a36e03d5db3340f8
+Subproject commit 6f19eb19e32b6f72b11253d9084c229135d5efa2

From fe9c3b665511387308eeb05a3e7c0ce38b30edc5 Mon Sep 17 00:00:00 2001
From: Olga Dalton 
Date: Fri, 23 Feb 2024 18:58:05 -0800
Subject: [PATCH 68/84] Further reverted cookie changes

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 6f19eb19e3..e64ff34bf1 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 6f19eb19e32b6f72b11253d9084c229135d5efa2
+Subproject commit e64ff34bf1d1b302598a5b51e3a8ec6f260ae868

From 7786e372f054eed32edee5ae78f392bc76b96b8c Mon Sep 17 00:00:00 2001
From: Olga Dalton 
Date: Sat, 24 Feb 2024 14:47:04 -0800
Subject: [PATCH 69/84] Update IdentityCore

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index e64ff34bf1..3aabe930a1 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit e64ff34bf1d1b302598a5b51e3a8ec6f260ae868
+Subproject commit 3aabe930a12faf8babc41e420fe5a379303381cb

From 737c81437fe744ae7c89561a4836e0eb9318d6b1 Mon Sep 17 00:00:00 2001
From: Olga Dalton 
Date: Sat, 24 Feb 2024 15:45:25 -0800
Subject: [PATCH 70/84] Fixed compilation

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 3aabe930a1..7036009938 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 3aabe930a12faf8babc41e420fe5a379303381cb
+Subproject commit 7036009938a547408a87cbf96982bb23d6a5293c

From c0c0a914a218075a497570bf2e73d891967ccd40 Mon Sep 17 00:00:00 2001
From: Danilo Raspa <105228698+nilo-ms@users.noreply.github.com>
Date: Tue, 27 Feb 2024 09:16:21 +0000
Subject: [PATCH 71/84] Merge main to dev (#2060)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Added privacy manifest

* Added phone number

* cherry picking from msal

* resolving unit test failure

* updating version numbers

* updating changelog

* updating xcode version

* adding updated common core submodule

* Updating MSAL framework checksum & url for 1.2.22 [skip ci]

* use common core dev

* Release/1.3.0 (#2039)

* Update submodule

* Update submodule

* Get token operation for BrowserCore (#1862)

* Update core.

* Update msal.

* Update core.

* update core.

* Update core.

* Update core.

* Update core.

* Update core.

* Update core.

* Update core.

* Update submodule

* Updated submodule

* Updated submodule

* Update submodule

* update submodule for current key change

* New error message when device is not PSSO registered.

* Merge release 1220 into dev (#1934)

* Release MSAL 1.2.20 (#1930)

* Update submodule

* Update submodule

* Get token operation for BrowserCore (#1862)

* Update core.

* Update msal.

* Update core.

* update core.

* Update core.

* Update core.

* Update core.

* Update core.

* Update core.

* Update core.

* Update submodule

* Updated submodule

* Updated submodule

* Update submodule

* update submodule for current key change

* New error message when device is not PSSO registered.

* Release MSAL 1.2.20

* Align with latest main (#1933)

---------

Co-authored-by: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com>
Co-authored-by: Sergei Demchenko 
Co-authored-by: Swasti Gupta 
Co-authored-by: Swasti Gupta 
Co-authored-by: Juan Arias 
Co-authored-by: Kai 

* Updating MSAL framework checksum & url for 1.2.20 [skip ci]

* Update CommonCore to latest dev

---------

Co-authored-by: Veena Soman 
Co-authored-by: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com>
Co-authored-by: Sergei Demchenko 
Co-authored-by: Swasti Gupta 
Co-authored-by: Swasti Gupta 
Co-authored-by: Juan Arias 

* Native Auth features (#1911)

* check that codeLength is not nil

* Initial depth first doc comments for Sign In public interface

* Quick fixes to sign in docs

* Initial sign up doc comments

* Two small fixes

* Typos

* Just adding some fullstops

* Doc comments for getCurrentAccount and result

* Added SSPR doc comments

* Fixed doc comment for sign up

* Updated top level documentation

* Add doc comments for init methdos

* Merged PR 9103: Fix sign out e2e tests for mock API, skip for test tenant

## Proposed changes

Small PR to fix sign out e2e tests for mock API, skip for test tenant.

Now that we no longer go straight to the token endpoint when signing in with a password, we need to provide queue up the mock responses for the /initiate and /challenge endpoints too.

Also, as this flow isn't supported in the test tenant at the moment we need to skip running this if it is not a Mock API test configuration.

## Type of change

- [ ] Feature work
- [ ] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [X] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [X] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

Fix sign out e2e tests for mock API, skip for test tenant

* Initial depth first doc comments for Sign In public interface

* Quick fixes to sign in docs

* Initial sign up doc comments

* Two small fixes

* Typos

* Just adding some fullstops

* Doc comments for getCurrentAccount and result

* Added SSPR doc comments

* Fixed doc comment for sign up

* Updated top level documentation

* Add doc comments for init methdos

* PR Comments

* PR Comments

* PR Comments

* Removed not needed configuration parameter

* Added Notes about optional delegate parameters

* Used consistent parameter groups for documentation when more than 1 parameter

* Added note and corrected error

* Changed description of `newState` parameter in docc comments

* Removed mention of text message from docc comments

* Doc comment updates

* Added some missing doc comments

* Added optional label to optional parameters in doc comments

* Updated comment

* Updated initial text in markdown about Native Auth

* PR comment

* PR comment

* Updated PCA initialiser to take clientId, tenantName and challengeTypes as parameters

* Fixed bad commit

* - Added a slice config property to MSALNativeAuthConfiguration
- Changed MSALNativeAuthRequestable default implementation to inject the slice information in an url query
- All controllers that want to point to a specific test slice need to first set the sliceConfig property (in MSALNativeAuthClientApplicationConfig) before constructing an instance of MSALNativeAuthPublicClientApplication

* Fixed capitalisation

* Fixed reference to password error delegate in code comment

* Fixed typos in doc comments

* Updated error description in doc comments

* Updated delegate description in doc comments

* Updated doc comment for account result

* Added missing doc comments for some error types

* Merged PR 9102: Add default error descriptions for all MSALNativeAuthError subclasses

## Proposed changes

This PR adds default error descriptions for all `MSALNativeAuthError` subclasses. If an error already has a non-nil `errorDescription` then that is returned, otherwise we return a string based on the `type`.

## Type of change

- [X] Feature work
- [ ] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [X] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

Before:
![CleanShot 2023-07-14 at 07.11.10@2x.png](https://identitydivision.visualstudio.com/fac9d424-53d2-45c0-91b5-ef6ba7a6bf26/_apis/git/repositories/616da9d3-8336-4562-811a-581d9a5cbe9c/pullRequests/9102/attachments/CleanShot%202023-07-14%20at%2007.11.10%402x.png)

After:
![CleanShot 2023-07-14 at 07.10.36@2x.png](https://identitydivision.visualstudio.com/fac9d424-53d2-45c0-91b5-ef6ba7a6bf26/_apis/git/repositories/616da9d3-8336-4562-811a-581d9a5cbe9c/pullRequests/9102/attachments/CleanShot%202023-07-14%20at%2007.10.36%402x.png)

* - Added unit test for MSALNativeAuthRequestable default implementation

* - Using url components to construct endpoints

* Updated PCA initialiser to take clientId, tenantName and challengeTypes as parameters

* Fixed bad commit

* Removed debug code

* Fixed doc comment for new initialiser

* - Removed changes done in view controllers, since Sample App is going to use a different initialiser

* Added back redirectUri parameter

* - Fixing url component to resolve against base url

* - Added new unit test for when test slice is not used

* - Fixing merge issues

* - Fixing more merge issues

* Changing parameter from NULL to nil when constructing MSALNativeAuthPublicClientApplication in objc view controller

* make account accessible from external dev, update unit tests

* remove accountClaims and fix swift lint warnings

* update signUp integration tests

* make account a constant and remove private(set)

* call SDK signOut method when pressing signOut button

* submodule update

* Update readme

* Merged PR 9199: Update MSAL podspec to enable installation of Native Auth with Cocoapods

## Proposed changes

- Added updates to MSAL.podspec needed to compile the Swift files that were added to the project:
-- Disabled MACos build as it's outside the private preview scope
-- Added the 'HEADER_SEARCH_PATHS' => __dir__  to the pod_target_xcconfig to allow for the Pod Project to compile the modulemap
-- Added the Swift extension to the list of source files for both iOS and MacOS (app.source_files / ext.source_files)
-- Added the new MSAL Native Auth public headers to both subspecs and both platforms - "MSAL/src/native_auth/public/*.h"
- The swift files removed were still present in the folders even though they were not use inside the xcodeproj, but because Cocoapods was picking them up as Swift files, they needed to be removed.

## Type of change

- [x] Feature work
- [ ] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [x] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

To test:
- Create a new App
- Install Cocoapods
- Go to the folder of the app in terminal and execute "pod init"
- Edit the Podfile and set your pulled branch as the local path to the folder:
`pod 'MSAL' , :path => '/Users//Desktop/Projects/MSAL'` (or wherever your project is)
- Go to the folder of the app in terminal and execute "pod install"
- Import MSAL, make sure you can access the MSALNativeAuthPublicClientApplication class
- To build be sure to be on the iOS framework, not the MACos one

Related work items: #2621133

* Merged PR 9342: Fix Build for Azure Pipelines

## Proposed changes

Fix project so pipeline builds successfully
Following fixes were applied:
-Because of this [issue](https://github.com/actions/runner-images/issues/8023) where the latest MacOS 13 image uses XCode 15 with the iOS 17 beta simulator, the "latest" iPhone 14 simulator is now 17. Due to this, the build is very slow which makes multiple tests fail due to timeouts
-The iOS simulator that is now launched is the iOS 16.4 one instead of the 17 one
-The GUID used for code coverage is the one of the iOS 16.4 simulator to allow the code coverage to work properly
-Swiftlint appears to be running on all the code now, so fixed swiftlint issues on the Native Auth Sample app

## Type of change

- [ ] Feature work
- [ ] Bug fix
- [ ] Documentation
- [x] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [X] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

Related work items: #2655681

* Merged PR 9259: ResetPassword-start. Not all invalidRequest are related to "UserDoesNotHaveAPassword" error

## Proposed changes

Highlights:
- Created new custom validated error enum for resetPassword start
- update unit tests

## Type of change

- [ ] Feature work
- [X] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information
We don't need to log the unexpected error codes

Related work items: #2640267

* Merged PR 9426: Include errorDescription, when available, on log message

## Proposed changes

- Whenever an error gets logged it's errorDescription should be logged rather than the description of the Object. `error.errorDescription` vs 'error.description'
- The change to the `MSALNativeAuthPublicClientApplication.swift` is due to an Swiftlint issue that doesn't get picked up by the git difference.
- The cases where an errorType or error as part of a do/try was logged didn't need change.
## Type of change

- [ ] Feature work
- [ ] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [x] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information
This can be tested by replacing this function in AppDelegate.swift on the NativeAuthSampleApp and then calling an API
```
func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        MSALGlobalConfig.loggerConfig.setLogCallback {
            (level: MSALLogLevel, message: String?, containsPII: Bool) in
            // If PiiLoggingEnabled is set YES, this block will potentially contain sensitive information (Personally Identifiable Information), but not all messages will contain it.
            // containsPII == YES indicates if a particular message contains PII.
            // You might want to capture PII only in debug builds, or only if you take necessary actions to handle PII properly according to legal requirements of the region
            if let displayableMessage = message {
                if (!containsPII) {
#if DEBUG
                    // NB! This sample uses print just for testing purposes
                    // You should only ever log to NSLog in debug mode to prevent leaking potentially sensitive information
                    print(displayableMessage)
#endif
                }
            }
        }
        return true
    }
```

Related work items: #2641240

* points to latests commit on IdentityCore/ciam-master

* increase timeout cause the mac agent uses beta version simulator

* - Added two new delegates to sign up, to be triggered instead of returning errors: `onSignUpAttributesRequired` and `onSignUpAttributesInvalid`
- Parsing error responses from sign up /start and /continue endpoints
- Adjusted spies and tests accordingly

* add new otp error codes, parse error code for invalid request, add new unit tests

* Merged PR 9568: - Fix re-encoding of attributes in MSALNativeAuthSignUpRequestProvider

## Proposed changes

Describe what this PR is trying to do.

## Type of change

- [ ] Feature work
- [X] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [X] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

- Fix re-encoding of attributes in MSALNativeAuthSignUpRequestProvider

Related work items: #2670284

* Merged PR 9542: iOS - Use error description from API when available

## Proposed changes

Whenever API sends error descriptions, they should be returned to the developer integrating the SDK to better debug the issues they are facing
-Changed how errors are returned
-Changed unit tests to use the new functionality
-Added unit tests for the Enums and new functions

## Type of change

- [x] Feature work
- [ ] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [x] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

Related work items: #2610913

* - Removed unnecessary statement in MSALNativeAuthErrorRequiredAttributes string description

* - Fixed unit testes for MSALNativeAuthErrorRequiredAttributes

* - Removed public access tp MSALNativeAuthErrorRequiredAttributes initialiser

* i Improved methods description in SignUpAttributesRequiredDelegate

* - Methods description fix

* - Removed error assertion

* - Made property "regex" of RequiredAttributeOptions access public as well

* - Moved MSALNativeAuthErrorBasicAttributes and RequiredAttributeOptions to separate files

* - Fixed file headers
- Fixed SwiftLint warnings
- Changed MSALNativeAuthSignUpContinueResponseError to use MSALNativeAuthErrorBasicAttributes instead of dictionary in unverifiedAttributes

* handle new otp error codes for signIn token endpoint result

* handle invalid request for otp error codes in signUp

* send invalid user input result instead of generic error

* - Created RequiredAttributesError to separate MSALNativeAuthErrorRequiredAttributes from the SDK's external interface

* test all error cases for invalid grant

* add new tests for invalid request-otp error codes in signUp validator class

* return invalidRequest instead of general error when invalidRequest is received

* - Added list of attributes required to SignUpVerifyCodeDelegate and SignUpPasswordRequiredDelegate

* no message

* Rename file

* Fixed white space

* Fixed attributeValidationFailed case on submitCode and submitPassword

* Grouped cases together

* Merged PR 9618: Provide username for signin with slt via SignUpController

## Proposed changes

Now we keep the username in memory between calls. I'm carrying over every call in order to avoid having state in the Controller.

I've added an integration test at the end of `MSALNativeAuthSignUpControllerTests` because although we have the E2E test for signUp, the mock api is not updated and I'm not sure if the parameter is mandatory at the moment.

Apart from the test in code, I've retested the following tests of the [Native Auth Private Preview test cases](https://microsofteur.sharepoint.com/:x:/t/DevExDublin/ESLT-SpZO7dEpuN4aLIiB9MBMPeJ94oJWIy8vFEa4Jsimg?e=enJcyV) sheet:

- Test 1 (also tried re-sending the oob code and continuing from there)
- Test 3
- Test 13
- Test 17

## Type of change

- [ ] Feature work
- [x] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

Related work items: #2670401

* remove swiftlint warinings, copy all error fields, add new unit tests related to the changes

* Add new eSTS error for sign-up flow. However, this will need to be refactored since we shouldn't be creating API Models on our own (IMO). API Models should reflect API. I'm making this change now to avoid creating another "middle" model for the sign-up errors, which would lead to a few changes in tests. Options to solve this problem in the future would be:

1) Create a new validated error enum in the SignUpValidator
2) Perform some conversion logic from the eSTS error to our error inside the error API models via a method or computed property.

* Fix test

* Add integration test to mock api

* remove invalid and required attributes error

* update and add unit tests

* remove newState from attributesRequiredError callback. update unit and integration tests

* Add new case to handle invalidUsername error in MSALNativeAuthSignUpStartValidatedResponse

* remove invalid attributes for signUpStart error enums, use optional delegate methods

* update sample app

* remove swiftlint warnings

* update unit tests

* add new unit tests

* update log message for invalid attributes

* Merged PR 9669: Change API error invalid_client to unauthorized_client

## Proposed changes

-For SignUp Start/Challenge/Continue and SignIn Initiate/Challenge the error code for invalid_client should be changed to unauthorized_client
-For Token unauthorized_client should be added to the possible list of error codes

## Type of change

- [ ] Feature work
- [ ] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [x] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information
-Integration tests don't work anymore as the Mock API is not updated so they were disabled

Related work items: #2654063

* Update submodules

* Merged PR 9687: Change auth_not_supported to unsupported_auth_method

## Proposed changes

Changed auth_not_supported to unsupported_auth_method

## Type of change

- [ ] Feature work
- [ ] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

Related work items: #2673106

* update configuration file

* do not show cached user username. log accountId instead of username

* use sample placeholders as specified in the document

* rename tenantName to tenantSubdomain

* remove client id

* add default value for redirectUri and bypass redirect URI validation when needed

* Merged PR 9738: Update IdentityCore submodule

## Proposed changes

Update submodules in the project to include our [latest changes](https://identitydivision.visualstudio.com/Engineering/_git/devexdub-microsoft-authentication-library-common-for-objc/pullrequest/9737) from IdentityCore.

## Type of change

- [ ] Feature work
- [ ] Bug fix
- [ ] Documentation
- [x] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

Update submodules

Related work items: #2643139

* add new unit test, remove unwanted characters

* Remove old sample app and rename proper sample app folder

* remove raw tenant from MSIDCIAMAuthotiry initialisation

* remove doc folder

* remove old sample app from build script and rename folder

* update build script, remove simple word from

* remove blank lines to make swiftlint happy

* Merged PR 9759: Treat InvalidClientId correctly

## Proposed changes

Because both invalid client id and invalid username API errors generate a invalidRequest error with an error code of 90100, we have to check the error_description to see why it happens
-Invalid username is now mapped to public error invalidUsername
-Invalid client id is now mapped to public error generalError but we log the client id error
## Type of change

- [ ] Feature work
- [x] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

Related work items: #2685134

* set correct name for attributes required method name

* remove optional methods from sample app

* Merged PR 9768: Update MSALNativeAuthServerTelemetry to include optional errors

## Proposed changes

We need to merge !9767 before merging this one.

## Type of change

- [ ] Feature work
- [ ] Bug fix
- [ ] Documentation
- [x] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

Update MSALNativeAuthServerTelemetry to include optional errors

Related work items: #2643139

* remove empty implementation of optional methods

* update readme doc

* update readme file, add new images

* address comments

* modifications to let xcode 13.4.1 works

* update SDK version for private preview

* skip test for private preview versioning

* Merged PR 9361: Refactor controllers to enable new public interfaces

## Proposed changes

- Refactor the controllers to return a response to the public interface (and the public interface will return to the developer). This makes the task of creating public interfaces (such as async/await, combine, etc.) easier because the controller is not tightly coupled to the interface.
- Unit tests updated.

## Type of change

- [x] Feature work
- [ ] Bug fix
- [ ] Documentation
- [x] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [x] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

Related work items: #2635763

* Merged PR 9843: Changes to NativeAuthSampleApp for Xcode 13.4 compatibility

## Proposed changes

Changes that remove Swift features specific to Xcode 14 to allow building NativeAuthSampleApp on Xcode 13.4.
The 2 Swift changes needed to build on Xcode 13.4 are
1. Providing initializers in if/guard statements when unwrapping optionals
2. Explicit use of "self"

The project format has been changed to "Xcode 13.0-compatible"

## Type of change

- [ ] Feature work
- [ ] Bug fix
- [ ] Documentation
- [x] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

* Fix for account claims

* Made the initialiser easier to use

* Merged PR 9900: Fix Cocoapods to work with Git installations

## Proposed changes

- Fixed Cocoapods so that when users use
`pod 'MSAL', :git => "https://github.com/AzureAD/msal-objc-native-auth-preview"`
in their pod file it works as intended
- This change means the local install with path doesn't work as both relative and absolute paths can't work at the same time (there could be a configuration that we are unaware of which might make both work but the git one is more important)
-To test from ADO set
`pod 'MSAL', :git => "https://identitydivision.visualstudio.com/DefaultCollection/Engineering/_git/devexdub-microsoft-authentication-library-for-objc", :branch => "spetrescu/cocoapods-git-fix", :submodules => true
`
## Type of change

- [ ] Feature work
- [ ] Bug fix
- [ ] Documentation
- [x] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [x] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information
- Changed modulemap to use Relative Path instead of Absolute
- Added modulemap file to source files so it gets downloaded as we use a private module map rather than a normal one (where all files are public)
- Split modulemap file into two modules for files that are not added to the target
- Modified unit tests to load needed modules based on requirements

Related work items: #2697240

* - Added Native Auth base classes that interact with MSAL

* - Added Native Auth network classes that interact with MSAL

* - Added unit tests

* - Added unit tests

* -Fixed unit tests
-PR Comments

* - Added Native Auth Sign Up files

* - Added Native Auth Sign In

* - Added Native Auth Password Reset files

* Merged PR 9949: [iOS SDK] Make the SDK build for Release and Profiling

## Proposed changes

Fix the build error around the `performTokenRequest` function in `MSALNativeAuthTokenController`
The linker, when optimizing for speed or size, doesn't process the function
`private func performTokenRequest(_ request: MSIDHttpRequest, context: MSIDRequestContext) async -> Result {` properly.
The only workaround found so far was to move all private functions into an extension in the same file

## Type of change

- [ ] Feature work
- [x] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

Created extension to circumvent undefined symbol error

Related work items: #2694846

* - Clearing cache in setup and teardown methods only (MSALNativeAuthCacheAccessorTests)
- Added full SLT naming

* Merged PR 10009: Fix imports for new MSAL private module in integration tests

## Proposed changes

Quick fix to two places in the integration tests that required the MSAL_Unit_Test_Private instead of MSAL_Private

## Type of change

- [ ] Feature work
- [ ] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [X] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [X] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

Fix imports for new MSAL private module in integration tests

* Merged PR 9998: [iOS SDK] Make changes to project and Cocoapods to allow building the MAC Framework

## Proposed changes

-There were no changes needed to the project as they were already done previously and MacOS MSAL framework builds properly
-The Podspec file has been changed to build properly

## Type of change

- [x] Feature work
- [ ] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information
To test properly, create a XCode Project with a Mac target which uses Cocoapods
Set the Podfile as follows:
```
target 'TestAppMac' do
   pod 'MSAL', :git => "https://identitydivision.visualstudio.com/Engineering/_git/devexdub-microsoft-authentication-library-for-objc", :branch => "spetrescu/msal-mac-cocoapods", :submodules => true
end
```

Related work items: #2652866

* Merged PR 10087: [iOS SDK] Fix Sample App pipeline build

## Proposed changes

Swiftlint added a rule to check if functions that `override` only call the super, which in the end indeed does nothing.
For example:
```
override func viewDidLoad() {
        super.viewDidLoad()
    }
```
Because the sample app had 3 such functions the PR validation failed
Furthermore our PR validation script runs Swiftlint on the Native Sample App but we didn't have that so the script was added

## Type of change

- [ ] Feature work
- [x] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information
-Added swiftlint to Sample App
-Disabled warnings for Sample App

* Merged PR 10086: [IOS SDK] Remove unused getAccount function from Cache Interface

## Proposed changes

Because the function getAccount was unused as we don't have multiple accounts yet we need to remove it from the Accessor, Protocol and unit tests

## Type of change

- [x] Feature work
- [ ] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

Related work items: #2644201

* Merged PR 10133: Update position of "delegate" parameter in public interfaces for consistency

## Proposed changes

This pull request is about changing the position of the `delegate` parameter in public interface method calls, for consistency.
Modified interfaces:
- MSALNativeAuthUserAccountResult
- SignUpStates
- SignInStates
- ResetPasswordStates

## Type of change

- [ ] Feature work
- [ ] Bug fix
- [ ] Documentation
- [X] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [X] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

- Changed public interface to be consistent and always have the delegate as the last parameter of method calls
- Changed sample app to reflect the changes

Related work items: #2690285

* Merged PR 10194: Fix inline documentation in public delegates

## Proposed changes

Add missing inline documentation for parameters in ResetPasswordDelegates, SignInDelegates and SignUpDelegates that were found while working [this ticket](https://identitydivision.visualstudio.com/Engineering/_workitems/edit/2711520/).

## Type of change

- [ ] Feature work
- [ ] Bug fix
- [x] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

----
#### AI-Generated Description
This pull request modifies three files related to the native authentication state machine delegates in MSAL. The main changes are:

- Adding parameters to some delegate methods to provide more information about the new state of the flow and the required attributes.
- Changing the error parameter type in some delegate methods to include the new state of the flow as an optional value.
- Adding some optional methods to some delegate protocols to handle different scenarios that may require a code or a password from the user.

Related work items: #2711520

* - Refactor of MSALNativeAuthResponseErrorHandler to remove duplicated code with IdetityCore

* - Added MSIDAADRequestErrorHandler to module map

* - Changed method name from "handleAPIError" to "handleCustomError" to be more concise with IdentityCore implementation.

* - Added NativeAuthCustomErrorSerializer to deal with Native Auth custom errors serialization
- Refactor of MSALNativeAuthResponseErrorHandler

* - Removed unused property

* - Changed class name to add "MSAL" prefix

* - Added a comment explaining the "throw" command in MSALNativeAuthCustomErrorSerializer method

* Merged PR 10303: Ciam Master updated to MSAL 1.2.18

## Proposed changes

Update with MSAL 1.2.18 from GitHub

## Type of change

- [ ] Feature work
- [ ] Bug fix
- [ ] Documentation
- [X] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [X] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [ ] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

----
#### AI-Generated Description
This pull request updates the MSAL library for iOS and Mac to version 1.2.18. The main changes are:

- Fixed duplicate values for error JIT codes (#1893)
- Added ccs request id header (#1844)
- Added separate error code for OneAuth telemetry purpose (common core #1292)
- Exposed APIs for manually setting time_Interval for request and session resource (#1288)
- Updated the iOS simulator device and OS version for testing
- Updated the Package.swift and MSAL.podspec files with the new version number
- Fixed some linting and code coverage issues

Related work items: #2726861

* Merged PR 10343: [iOS SDK] SignUp error API responses are parsed to general SDK error

## Proposed changes

Problem:
MSALNativeAuthResponseErrorHandler was changed during merging to use the responseSerializer passed into the handleError function resulting in the incorrect serializer parsing API response errors.

Solution:
Always use MSALNativeAuthCustomErrorSerializer as the responseSerializer to ensure API errors are parsed as expected.

## Type of change

- [ ] Feature work
- [x] Bug fix
- [ ] Documentation
- [ ] Engineering change
- [ ] Test
- [ ] Logging/Telemetry

## Risk

- [ ] High – Errors could cause MAJOR regression of many scenarios. (Example: new large features or high level infrastructure changes)
- [ ] Medium – Errors could cause regression of 1 or more scenarios. (Example: somewhat complex bug fixes, small new features)
- [x] Small – No issues are expected. (Example: Very small bug fixes, string changes, or configuration settings changes)

## Additional information

----
#### AI-Generated Description
This pull request adds a new unit test case for the MSALNativeAuthResponseErrorHandler class, which handles errors from native auth requests. The test case checks that the error handler uses the correct response serializer when the status code is 400 and the error is verification_required. The pull request also modifies the error handler to always use the MSALNativeAuthCustomErrorSerializer instead of the response serializer passed as an argument.

Related work items: #2727783

* PR comments

* Files changed/removed during private preview
Removed documentation for NativeAuth
Removed NativeAuthSampleApp

* - Restored changes based on code review

* - Removed extra space

* - Restored original README.md

* Spacing on Pr-Validation.yml

* Changed Mock API url

* Switched to Environment variable

* - Created cgmanifest.json file to add SwiftLint to component governance verification

* - Updated CODEOWNERS file to give AppleCIAMTeam onwnership over Native Auth code.

* - Updated description

* - Changed CIAM team

* - Fixed text description

* Removed MSALNativeAuthInternalChallengeType.swift from being added twice to the Project

---------

Co-authored-by: Danilo Raspa 
Co-authored-by: Silviu Petrescu 
Co-authored-by: Rodhan Hickey 
Co-authored-by: Swasti Gupta 
Co-authored-by: Swasti Gupta 
Co-authored-by: Ameya <>
Co-authored-by: Ameya Patil 
Co-authored-by: Diego Jerez Barroso 
Co-authored-by: Dualtagh Murray 
Co-authored-by: Danilo Raspa <105228698+nilo-ms@users.noreply.github.com>

* Add co-ownership of MSAL project file

* Check if attributes are parsable to JSON before to parse

* - Added correlationId to MSALNativeAuthBaseState (#1915)

- Removed correlationId from state actions
- Adjusted tests accordingly

- Removed correlation id from `SignInAfterSignUpState` action method
- Fixed SwiftLint warnings
- Tidy up

Unit tests for correlation ids

Renamed MSALNativeAuthControllerFactoryRequestProviderMock to MSALNativeAuthControllerRequestProviderFactoryMock

PR comments

Made prepareMockRequest more flexible

Renamed MSALNativeAuthControllerRequestProviderFactoryMock to MSALNativeAuthControllerProtocolFactoryMock

PR Comments

Clarified where parameters are checked internally

PR comment about signInRequestProviderMock.expectedContext = contextMock

Updated end to end tests to not use correlation id's

Update submodule

Update submodule

Update submodule

New error message when device is not PSSO registered.

Hotfix 1.2.19 (#1909)

* Update release config

* point to latest main from cc

---------

Co-authored-by: Yong Zeng 

Updating MSAL framework checksum & url for 1.2.19 [skip ci]

Merge release 1220 into dev (#1934)

* Release MSAL 1.2.20 (#1930)

* Update submodule

* Update submodule

* Get token operation for BrowserCore (#1862)

* Update core.

* Update msal.

* Update core.

* update core.

* Update core.

* Update core.

* Update core.

* Update core.

* Update core.

* Update core.

* Update submodule

* Updated submodule

* Updated submodule

* Update submodule

* update submodule for current key change

* New error message when device is not PSSO registered.

* Release MSAL 1.2.20

* Align with latest main (#1933)

---------

Co-authored-by: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com>
Co-authored-by: Sergei Demchenko 
Co-authored-by: Swasti Gupta 
Co-authored-by: Swasti Gupta 
Co-authored-by: Juan Arias 
Co-authored-by: Kai 

* Updating MSAL framework checksum & url for 1.2.20 [skip ci]

* Update CommonCore to latest dev

---------

Co-authored-by: Veena Soman 
Co-authored-by: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com>
Co-authored-by: Sergei Demchenko 
Co-authored-by: Swasti Gupta 
Co-authored-by: Swasti Gupta 
Co-authored-by: Juan Arias 

- Changed submodule

* Removed all Native Auth files from iOS Static Library target (#1916)

Removed MSALLogMask.h & MSALLogMask.m from Static Libary

* Add optional delegates everywhere (keep delegates that return errors as mandatory). (#1914)

Add DelegateDispatchers to handle optional delegate methods

Add newState parameter to onSignUpResendCodeError

Add comments to clarify why the telemetry event always fails

Remove comments because this class will remain internal

Rename error methods in SignUpPasswordStartDelegate, SignUpStartDelegate, SignInPasswordStartDelegate, SignInStartDelegate and ResetPasswordStartDelegate.

Fix inline doc

Updated end to end tests to not use correlation id's

Updated End To End tests to use latest delegates

* Make errors extensible (#1923)

Fix broken tests. Add tests for public errors

PR code review

Change the `identifier` variable from String to Int. This allows us to enable the public ErrorType enums for objc developers.

Rename SignInPasswordStartError's invalidPassword to invalidCredentials

Fix failing test. Update inline documentation for isBrowserRequired error

Remove error.identifier from public interface.

Update inline doc to use "username" instead of "email".

Fixed integration tests

Renamed MockAPIURL env variable to authorityURL to work with the test case

* Don't send empty attribute list in SignUp/start (#1940)

* do not create an empty list of attributes when no attributes are available

* check that request parameter is not nil

* fix unit tests after dev merge

* Add SignInAfterResetPassword (#1932)

* - Added correlationId to MSALNativeAuthBaseState
- Removed correlationId from state actions
- Adjusted tests accordingly

- Removed correlation id from `SignInAfterSignUpState` action method
- Fixed SwiftLint warnings
- Tidy up

Unit tests for correlation ids

Renamed MSALNativeAuthControllerFactoryRequestProviderMock to MSALNativeAuthControllerRequestProviderFactoryMock

PR comments

Made prepareMockRequest more flexible

Renamed MSALNativeAuthControllerRequestProviderFactoryMock to MSALNativeAuthControllerProtocolFactoryMock

PR Comments

Clarified where parameters are checked internally

PR comment about signInRequestProviderMock.expectedContext = contextMock

Updated end to end tests to not use correlation id's

Update submodule

Update submodule

Update submodule

New error message when device is not PSSO registered.

Hotfix 1.2.19 (#1909)

* Update release config

* point to latest main from cc

---------

Co-authored-by: Yong Zeng 

Updating MSAL framework checksum & url for 1.2.19 [skip ci]

Merge release 1220 into dev (#1934)

* Release MSAL 1.2.20 (#1930)

* Update submodule

* Update submodule

* Get token operation for BrowserCore (#1862)

* Update core.

* Update msal.

* Update core.

* update core.

* Update core.

* Update core.

* Update core.

* Update core.

* Update core.

* Update core.

* Update submodule

* Updated submodule

* Updated submodule

* Update submodule

* update submodule for current key change

* New error message when device is not PSSO registered.

* Release MSAL 1.2.20

* Align with latest main (#1933)

---------

Co-authored-by: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com>
Co-authored-by: Sergei Demchenko 
Co-authored-by: Swasti Gupta 
Co-authored-by: Swasti Gupta 
Co-authored-by: Juan Arias 
Co-authored-by: Kai 

* Updating MSAL framework checksum & url for 1.2.20 [skip ci]

* Update CommonCore to latest dev

---------

Co-authored-by: Veena Soman 
Co-authored-by: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com>
Co-authored-by: Sergei Demchenko 
Co-authored-by: Swasti Gupta 
Co-authored-by: Swasti Gupta 
Co-authored-by: Juan Arias 

- Changed submodule

* Add optional delegates everywhere (keep delegates that return errors as mandatory).
Add DelegateDispatchers to handle optional delegate methods

PR code review

Add newState parameter to onSignUpResendCodeError

Add comments to clarify why the telemetry event always fails

Remove comments because this class will remain internal

PR comments

Rename error methods in SignUpPasswordStartDelegate, SignUpStartDelegate, SignInPasswordStartDelegate, SignInStartDelegate and ResetPasswordStartDelegate.

Fix inline doc

Updated end to end tests to not use correlation id's

Updated End To End tests to use latest delegates

* Make errors extensible

Fix broken tests. Add tests for public errors

PR code review

Change the `identifier` variable from String to Int. This allows us to enable the public ErrorType enums for objc developers.

Rename SignInPasswordStartError's invalidPassword to invalidCredentials

Fix failing test. Update inline documentation for isBrowserRequired error

Remove error.identifier from public interface.

Update inline doc to use "username" instead of "email".

Fixed integration tests

Renamed MockAPIURL env variable to authorityURL to work with the test case

* Add SignInAfterResetPassword

rename slt to continuation token for reset password poll complete, fix swiftlint warning

update submodules

---------

Co-authored-by: Marcos Borges 
Co-authored-by: Danilo Raspa 

* Update MacOS readme webviewparameters

* Added optional password parameter to signUp/signIn methods (#1942)

* - Added optional password parameter to signUp/signIn methods
- Removed SignUpUsingPassword method from public interface
- Removed SignInUsingPassword method from public interface
- Unified SignUpPasswordStartError and SignUpStartError
- Unified SignUpPasswordStartError and SignUpStartError
- Unified SignInStartDelegate and SignInPasswordStartDelegate
- Unified SignUpStartDelegate and SignUpPasswordStartDelegate
- Unified SignInPasswordStartResult and SignInStartResult
- Unified SignUpPasswordStartResult and SignUpStartResult
- Unified SignUpPasswordStartDelegateDispatcher and SignUpStartDelegateDispatcher
- Unified SignInPasswordStartDelegateDispatcher and SignInStartDelegateDispatcher

* - Fixed unit test.

* - Fixed unit test.

* address comments, remove duplicated code, update unit tests

* delete unused public parameter classes

* unify signIn with code and password controller methods, update unit tests

* fix warnings

* unify signUp methods, update unit tests

* fix swiflint warnings

* remove unused method

* Update SignUpStartErrorTests.swift

* Update SignUpStartErrorTests.swift

---------

Co-authored-by: Danilo Raspa 
Co-authored-by: Sergei Demchenko 

* Capitalised logs, added context where missing, clarified them

* PR comments

* Rename all tokens to continuation token (#1963)

* rename various tokens to continuation token

* rename some other tokens to continuation token

* fix integration test

* rename some more vars to continuation token

* remove not needed coding keys and rename tokens

* rename internal variable to avoid shadowing

* Update api errors (#1943)

* Update api errors

* PR comments. Remove invalid_grant error handling from signin/initiate

* Updated common core submodule

* Reuse MSAL initialised cache for Native Auth flows (#1958)

* Reuse MSAL initialised cache for Native Auth flows

* Added test for cacheAccessor to public client application test (and related changes)

* Reuse existing MSALNativeAuthCacheAccessorMock in tests

* Add documentation needed for NativeAuth (#1968)

* - Added documentation for all public classes, methods, enums and properties
- Renamed MSALNativeAuthRequiredAttributes to MSALNativeAuthRequiredAttribute as it's a singular object rather than multiple ones

* PR comments

* PR  comments

* PR comments

* Changed MSALNativeAuthErrorBasicAttributes to MSALNativeAuthErrorBasicAttribute

* Reverted changes to MSALNativeAuthErrorBasicAttributes and MSALNativeAuthRequiredAttributes

* Reverted more things

* Revert project.pbxproj

* Reverted MSALNativeAuthRequiredAttributesOptions to MSALNativeAuthRequiredAttributeOptions

* Reverted MSALNativeAuthRequiredAttributesOptions

* PR comments

* Renamed MSALNativeAuthErrorBasicAttributes to MSALNativeAuthErrorBasicAttribute (#1971)

Renamed MSALNativeAuthRequiredAttributes to MSALNativeAuthRequiredAttribute
Renamed MSALNativeAuthRequiredAttributesInternal to MSALNativeAuthRequiredAttributeInternal

* Print warning on console if URL scheme is not configured (#1970)

* Updated public initializers of MSALNativeAuthPublicClientApplication to output a message when redirectUri is not set

* Use MSALLogger instead of print to display warning about redirectUri not set

* Rename invalid client to unauthorized client (#1972)

* Renamed invalidClient to unauthorizedClient

* Added back the skipping of the test

* Renamed all internal invalidClient references to unauthorizedClient except for the /token endpoint

* Added unauthorizedClient to responses from MockAPI

* Skipping unauthorizedClient as the response is not yet implemented

* Support dual headed acount hint in broker

* Updated variable name

* Fixed indent

* When SDK receives an unexpected Error type, the error description is returned to the developer (#1974)

* -Allowed decoding of errors even if the type is cannot be decoded
-Made the API message to be sent back all the way to the developer

Fixed failing unit tests

PR Comments

PR comments

changed invalidServerResponse to unexpectedError

* Add errorDescription check to SignInDelegateSpy for passwordError

* PR comments

* PR comments

---------

Co-authored-by: Diego Jerez 

* Update CommonCore submodule to latest (#1983)

* Update CommonCore submodule to latest

* dummy chang to trigger pipelines

* Added SSO ext property

* Renamed dual headed param

* Added privacy manifest

* mark MSAL-ObjC-CIAM team as owner of the modulemap file (#1987)

* Latest version of build_docs.sh (#1973)

* Read correlationId from server on 2xx and 4xx responses. Add correlationId and errorCodes to public errors. (#1981)

* Read correlationId from server on 2xx and 4xx responses. Add correlationId and errorCodes to sign-up flow.

* Add check for correlationId in every test of the `toPublic...` methods.

* Use correlationId instead of MSIDRequestContext. Update tests. PR comments

* Add handling of correlationId for 2xx and 4xx responses that can't be deserialized

* Return correlationId from the controllers

* Skipping Account Validation based on request parameters

* update submodule after fixing unit tests

* Added phone number

* Fix unknown cases in Oauth2ErrorCode and SubErrorCode enums (#1994)

* Add UnknownCaseProtocol

* Remove CaseIterable from errors. Make tests more domain specific

* Make `error` property non-optional.

* Updated common core for ADBNTLMHandler PR

* updated common core after merging PR

* updated to latest dev of common core

* update submodule

* Update core. (#1975)

* Update core.

* Update core.

* Update iOS version to test on

* Update xctestrun file name

* Fix static framework - Add dedicated pod subspec for native auth code (#2019)

* Testing cocoapod

* nww file

* New podfile

* remove swift files from extension, add OBJC native auth files to all subspecs

* remove native auth header files for osx

* no need to specify native auth objC files because already included in the first include

* remove trailing spaces

---------

Co-authored-by: Silviu Petrescu 

* update IdentityCore reference to match main branch (#2034)

* Merge MSAL main(hotfix/1.2.22) back to dev (#2033)

* Added privacy manifest

* Added phone number

* cherry picking from msal

* resolving unit test failure

* updating version numbers

* updating changelog

* updating xcode version

* adding updated common core submodule

* Updating MSAL framework checksum & url for 1.2.22 [skip ci]

---------

Co-authored-by: Olga Dalton 
Co-authored-by: Fidelia Nawar 
Co-authored-by: Hieu Nguyen <65981263+hieunguyenmsft@users.noreply.github.com>
Co-authored-by: Fidelia Nawar <89487029+fidelianawar@users.noreply.github.com>

* Update version to 1.3.0

* Fix automation yml

---------

Co-authored-by: Veena Soman 
Co-authored-by: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com>
Co-authored-by: Sergei Demchenko 
Co-authored-by: Swasti Gupta 
Co-authored-by: Swasti Gupta 
Co-authored-by: Juan Arias 
Co-authored-by: Kai 
Co-authored-by: Marcos Borges <116104275+borgesmb@users.noreply.github.com>
Co-authored-by: Silviu Petrescu 
Co-authored-by: Rodhan Hickey 
Co-authored-by: Ameya Patil 
Co-authored-by: Diego Jerez Barroso 
Co-authored-by: Dualtagh Murray 
Co-authored-by: Silviu Petrescu <111577419+spetrescu84@users.noreply.github.com>
Co-authored-by: Diego Jerez Barroso <109726904+diegojerezba@users.noreply.github.com>
Co-authored-by: Marcos Borges 
Co-authored-by: Olga Dalton 
Co-authored-by: Chase Hawthorne 
Co-authored-by: Rodhán Hickey <110929942+rodhan-ms@users.noreply.github.com>
Co-authored-by: mipetriu 
Co-authored-by: mipetriu <62564090+mipetriu@users.noreply.github.com>
Co-authored-by: Ameya Patil 
Co-authored-by: Fidelia Nawar 
Co-authored-by: Hieu Nguyen <65981263+hieunguyenmsft@users.noreply.github.com>
Co-authored-by: Fidelia Nawar <89487029+fidelianawar@users.noreply.github.com>

* Updating MSAL framework checksum & url for 1.3.0 [skip ci]

---------

Co-authored-by: Olga Dalton 
Co-authored-by: Fidelia Nawar 
Co-authored-by: Hieu Nguyen <65981263+hieunguyenmsft@users.noreply.github.com>
Co-authored-by: Fidelia Nawar <89487029+fidelianawar@users.noreply.github.com>
Co-authored-by: Hieu Nguyen 
Co-authored-by: Veena Soman 
Co-authored-by: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com>
Co-authored-by: Sergei Demchenko 
Co-authored-by: Swasti Gupta 
Co-authored-by: Swasti Gupta 
Co-authored-by: Juan Arias 
Co-authored-by: Kai 
Co-authored-by: Marcos Borges <116104275+borgesmb@users.noreply.github.com>
Co-authored-by: Silviu Petrescu 
Co-authored-by: Rodhan Hickey 
Co-authored-by: Ameya Patil 
Co-authored-by: Diego Jerez Barroso 
Co-authored-by: Dualtagh Murray 
Co-authored-by: Silviu Petrescu <111577419+spetrescu84@users.noreply.github.com>
Co-authored-by: Diego Jerez Barroso <109726904+diegojerezba@users.noreply.github.com>
Co-authored-by: Marcos Borges 
Co-authored-by: Chase Hawthorne 
Co-authored-by: Rodhán Hickey <110929942+rodhan-ms@users.noreply.github.com>
Co-authored-by: mipetriu 
Co-authored-by: mipetriu <62564090+mipetriu@users.noreply.github.com>
Co-authored-by: Ameya Patil 
---
 CHANGELOG.md                   | 2 ++
 MSAL.podspec                   | 2 +-
 MSAL/resources/ios/Info.plist  | 2 +-
 MSAL/resources/mac/Info.plist  | 2 +-
 MSAL/src/MSAL_Internal.h       | 4 ++--
 Package.swift                  | 2 +-
 azure_pipelines/automation.yml | 2 +-
 7 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 632c1f28dc..cd0c5c49b6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,5 @@
+## [1.3.0]
+
 ## [1.2.22]
 * Add privacy manifest (#1984)
 
diff --git a/MSAL.podspec b/MSAL.podspec
index 8eaa9eb2ac..94f14b6787 100644
--- a/MSAL.podspec
+++ b/MSAL.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name         = "MSAL"
-  s.version      = "1.2.22"
+  s.version      = "1.3.0"
   s.summary      = "Microsoft Authentication Library (MSAL) for iOS"
   s.description  = <<-DESC
                    The MSAL library for iOS gives your app the ability to begin using the Microsoft Cloud by supporting Microsoft Azure Active Directory and Microsoft Accounts in a converged experience using industry standard OAuth2 and OpenID Connect. The library also supports Microsoft Azure B2C for those using our hosted identity management service.
diff --git a/MSAL/resources/ios/Info.plist b/MSAL/resources/ios/Info.plist
index 0f2c055230..18065b543d 100644
--- a/MSAL/resources/ios/Info.plist
+++ b/MSAL/resources/ios/Info.plist
@@ -15,7 +15,7 @@
 	CFBundlePackageType
 	FMWK
 	CFBundleShortVersionString
-	1.2.22
+	1.3.0
 	CFBundleVersion
 	$(CURRENT_PROJECT_VERSION)
 	NSPrincipalClass
diff --git a/MSAL/resources/mac/Info.plist b/MSAL/resources/mac/Info.plist
index a5b75be25e..423560ac00 100644
--- a/MSAL/resources/mac/Info.plist
+++ b/MSAL/resources/mac/Info.plist
@@ -15,7 +15,7 @@
 	CFBundlePackageType
 	FMWK
 	CFBundleShortVersionString
-	1.2.22
+	1.3.0
 	CFBundleVersion
 	$(CURRENT_PROJECT_VERSION)
 	NSHumanReadableCopyright
diff --git a/MSAL/src/MSAL_Internal.h b/MSAL/src/MSAL_Internal.h
index c149e5b02c..69cd760878 100644
--- a/MSAL/src/MSAL_Internal.h
+++ b/MSAL/src/MSAL_Internal.h
@@ -26,8 +26,8 @@
 //------------------------------------------------------------------------------
 
 #define MSAL_VER_HIGH       1
-#define MSAL_VER_LOW        2
-#define MSAL_VER_PATCH      22
+#define MSAL_VER_LOW        3
+#define MSAL_VER_PATCH      0
 
 #define STR_HELPER(x) #x
 #define STR(x) STR_HELPER(x)
diff --git a/Package.swift b/Package.swift
index df27d85043..d297f207d0 100644
--- a/Package.swift
+++ b/Package.swift
@@ -13,6 +13,6 @@ let package = Package(
           targets: ["MSAL"]),
   ],
   targets: [
-      .binaryTarget(name: "MSAL", url: "https://github.com/AzureAD/microsoft-authentication-library-for-objc/releases/download/1.2.22/MSAL.zip", checksum: "c87a8f8de8395169ea5444676b83f0fca3a5889810dbeefe4c04b3f6e2455ae1")
+      .binaryTarget(name: "MSAL", url: "https://github.com/AzureAD/microsoft-authentication-library-for-objc/releases/download/1.3.0/MSAL.zip", checksum: "7498c009990c6f7e65902f754d242074c1afbc7064b8304a486f20edbef97e47")
   ]
 )
diff --git a/azure_pipelines/automation.yml b/azure_pipelines/automation.yml
index df8fb00c87..b9fb5a9090 100644
--- a/azure_pipelines/automation.yml
+++ b/azure_pipelines/automation.yml
@@ -138,4 +138,4 @@ jobs:
         issue_title = "Automation tests failure"
         issue_body = '''@AzureAD/appleidentity \nAutomation failed for [$(repositoryName)]({0}) ran against commit : {1} \n Pipeline URL : [{2}]({2})'''.format('$(Build.Repository.Uri)', git_commit, pipeline_uri) 
         github.create_issue(github_org, repo, issue_title, issue_body, labels=['automation failure'])
-  
+  
\ No newline at end of file

From e912fe7dc3382733f6a6be1f87469fa9e9e5566e Mon Sep 17 00:00:00 2001
From: mipetriu 
Date: Wed, 28 Feb 2024 17:47:24 -0800
Subject: [PATCH 72/84] Updated common core

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 3e0d4a27b8..39aa995fea 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 3e0d4a27b82d0f04c43da5c90005368cb3b56eea
+Subproject commit 39aa995feaa04d07a98b6d3d9c06666caf7eec22

From e94aea75196774de0a57e90ac54622967fa4b38d Mon Sep 17 00:00:00 2001
From: mipetriu 
Date: Wed, 28 Feb 2024 17:56:32 -0800
Subject: [PATCH 73/84] Added camera permission for MSAL Test App

---
 MSAL/test/app/ios/resources/Info.plist | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MSAL/test/app/ios/resources/Info.plist b/MSAL/test/app/ios/resources/Info.plist
index dc7d25d958..71949684c4 100644
--- a/MSAL/test/app/ios/resources/Info.plist
+++ b/MSAL/test/app/ios/resources/Info.plist
@@ -2,6 +2,8 @@
 
 
 
+	NSCameraUsageDescription
+	This app may need to scan QR codes.
 	CFBundleDevelopmentRegion
 	en
 	CFBundleExecutable

From d5c752cc9a16697ab65f11e30af538fe285d2849 Mon Sep 17 00:00:00 2001
From: Silviu Petrescu <111577419+spetrescu84@users.noreply.github.com>
Date: Mon, 4 Mar 2024 13:09:31 +0200
Subject: [PATCH 74/84] Fix Build Docs script build (#2066)

* -Added fix for simulator for automation script
-Changed MacOS for release script from 11 to 13
-Modified build_docs.sh so it works on CI

* Changed folder destination

* -Reverted yml
-Changed destination for jazzy to docs.temp/docs
---
 azure_pipelines/automation.yml    | 6 +++---
 azure_pipelines/spm-framework.yml | 8 +++++++-
 build_docs.sh                     | 4 ++--
 3 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/azure_pipelines/automation.yml b/azure_pipelines/automation.yml
index b9fb5a9090..860d181a88 100644
--- a/azure_pipelines/automation.yml
+++ b/azure_pipelines/automation.yml
@@ -72,7 +72,7 @@ jobs:
           -workspace MSAL.xcworkspace \
           -scheme "MSAL Test Automation (iOS)" \
           -sdk iphonesimulator \
-          -destination 'platform=iOS Simulator,name=iPhone 14,OS=17.2' \
+          -destination 'platform=iOS Simulator,name=iPhone 14,OS=16.4' \
           -derivedDataPath 'build' \
           | tee xcodebuild.log \
           | xcpretty -c
@@ -84,8 +84,8 @@ jobs:
       script: |
         ls build/Build/Products/
         xcodebuild test-without-building \
-            -xctestrun 'build/Build/Products/MSAL Test Automation (iOS)_iphonesimulator17.0-x86_64.xctestrun' \
-            -destination 'platform=iOS Simulator,name=iPhone 14,OS=17.2' \
+            -xctestrun 'build/Build/Products/MSAL Test Automation (iOS)_iphonesimulator16.4-x86_64.xctestrun' \
+            -destination 'platform=iOS Simulator,name=iPhone 14,OS=16.4' \
             -retry-tests-on-failure \
             -parallel-testing-enabled NO \
             -resultBundlePath '$(Agent.BuildDirectory)/s/test_output/report.xcresult'       
diff --git a/azure_pipelines/spm-framework.yml b/azure_pipelines/spm-framework.yml
index 3bd9ecc91e..e07a136f3c 100644
--- a/azure_pipelines/spm-framework.yml
+++ b/azure_pipelines/spm-framework.yml
@@ -36,7 +36,7 @@ jobs:
 - job: BuildXcFrameworks
   displayName: Build MSAL framework and release
   pool:
-    vmImage: 'macOS-11'
+    vmImage: 'macOS-13'
     timeOutInMinutes: 20
 
   steps:
@@ -357,6 +357,12 @@ jobs:
       workingDirectory: '$(Build.SourcesDirectory)'
     env:
       COCOAPODS_TRUNK_TOKEN: $(COCOAPODS_TRUNK_TOKEN)
+  - task: Bash@3
+    displayName: Install Sourcekitten
+    inputs:
+      targetType: 'inline'
+      script: |
+        brew install sourcekitten
   - task: Bash@3
     displayName: Build MSAL docs via Jazzy
     inputs:
diff --git a/build_docs.sh b/build_docs.sh
index 0dba505886..f7f7c10c84 100755
--- a/build_docs.sh
+++ b/build_docs.sh
@@ -13,7 +13,7 @@ cp README.md docs.temp/
 
 echo -e "Generating MSAL documentation"
 # Generate Swift SourceKitten output
-sourcekitten doc -- -workspace MSAL.xcworkspace -scheme "MSAL (iOS Framework)" -configuration Debug RUN_CLANG_STATIC_ANALYZER=NO -sdk iphonesimulator CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -destination 'platform=iOS Simulator' > docs.temp/swiftDoc.json
+sourcekitten doc -- -workspace MSAL.xcworkspace -scheme "MSAL (iOS Framework)" -configuration Debug RUN_CLANG_STATIC_ANALYZER=NO -sdk iphonesimulator CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -destination 'platform=iOS Simulator,name=iPhone 14,OS=16.4' > docs.temp/swiftDoc.json
 
 # Generate Objective-C SourceKitten output
 cd docs.temp
@@ -21,4 +21,4 @@ sourcekitten doc --objc $(pwd)/MSAL/MSAL.h -- -x objective-c  -isysroot $(xcrun
 cd ..
 
 # Feed both outputs to Jazzy as a comma-separated list
-jazzy --module MSAL --sourcekitten-sourcefile docs.temp/swiftDoc.json,docs.temp/objcDoc.json --author Microsoft\ Corporation --author_url https://aka.ms/azuread --github_url https://github.com/AzureAD/microsoft-authentication-library-for-objc --theme fullwidth
\ No newline at end of file
+jazzy --module MSAL --sourcekitten-sourcefile docs.temp/swiftDoc.json,docs.temp/objcDoc.json --author Microsoft\ Corporation --author_url https://aka.ms/azuread --github_url https://github.com/AzureAD/microsoft-authentication-library-for-objc --theme fullwidth --output docs.temp/docs

From beb131cccd78cad4809a37745887eb30ea1738e4 Mon Sep 17 00:00:00 2001
From: Swasti Gupta 
Date: Mon, 4 Mar 2024 21:29:14 -0800
Subject: [PATCH 75/84] Update submodule

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 386c832b3b..0e657a0271 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 386c832b3b6c501d4e6ec3e21a9f64f744fbbfb4
+Subproject commit 0e657a0271bc6849c703d51ed2557e005213d11d

From d41b8fae2dd97215617617356b7ffc0623122729 Mon Sep 17 00:00:00 2001
From: Danilo Raspa <105228698+nilo-ms@users.noreply.github.com>
Date: Thu, 7 Mar 2024 18:06:30 +0000
Subject: [PATCH 76/84] remove --use-libraries option from pod trunk push
 command (#2067)

---
 azure_pipelines/spm-framework.yml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/azure_pipelines/spm-framework.yml b/azure_pipelines/spm-framework.yml
index e07a136f3c..b1f10f531f 100644
--- a/azure_pipelines/spm-framework.yml
+++ b/azure_pipelines/spm-framework.yml
@@ -352,7 +352,8 @@ jobs:
       targetType: 'inline'
       script: |
         # Release to CocoaPods
-        pod trunk push --use-libraries --allow-warnings MSAL.podspec
+        # Do not use "--use-libraries" option because native auth code doesn't support static library yet
+        pod trunk push --allow-warnings MSAL.podspec
         #pod trunk me
       workingDirectory: '$(Build.SourcesDirectory)'
     env:

From a52825e88fc77a59ad213600986ab9a5ace41e62 Mon Sep 17 00:00:00 2001
From: mipetriu 
Date: Thu, 7 Mar 2024 14:33:51 -0800
Subject: [PATCH 77/84] Removed public enum value for QR+PIN

---
 MSAL/IdentityCore                      | 2 +-
 MSAL/src/MSALDeviceInformation.m       | 2 +-
 MSAL/src/MSALPublicClientApplication.m | 3 ++-
 MSAL/src/public/MSALDefinitions.h      | 7 +------
 4 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 39aa995fea..2b2f34dded 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 39aa995feaa04d07a98b6d3d9c06666caf7eec22
+Subproject commit 2b2f34ddeda0b07970b31358040f29d52d057b10
diff --git a/MSAL/src/MSALDeviceInformation.m b/MSAL/src/MSALDeviceInformation.m
index f949c7bff3..3594fd14fe 100644
--- a/MSAL/src/MSALDeviceInformation.m
+++ b/MSAL/src/MSALDeviceInformation.m
@@ -140,7 +140,7 @@ - (MSALPreferredAuthMethod)msalPreferredAuthMethodFromMSIDPreferredAuthMethod:(M
 {
     switch (msidPreferredAuthConfig) {
         case MSIDPreferredAuthMethodQRPIN:
-            return MSALPreferredAuthMethodQRPIN;
+            return 1; // Private enum value for QR+PIN
             
         default:
             return MSALPreferredAuthMethodNone;
diff --git a/MSAL/src/MSALPublicClientApplication.m b/MSAL/src/MSALPublicClientApplication.m
index e3d9b5399f..b3e3a7e0f9 100644
--- a/MSAL/src/MSALPublicClientApplication.m
+++ b/MSAL/src/MSALPublicClientApplication.m
@@ -1183,7 +1183,8 @@ - (void)acquireTokenWithParameters:(MSALInteractiveTokenParameters *)parameters
     // Extra parameters to be added to the /authorize endpoint.
     msidParams.extraAuthorizeURLQueryParameters = self.internalConfig.extraQueryParameters.extraAuthorizeURLQueryParameters;
     
-    if (parameters.preferredAuthMethod == MSALPreferredAuthMethodQRPIN)
+    // Private enum value for QR+PIN
+    if (parameters.preferredAuthMethod == 1)
     {
         NSMutableDictionary *extraAuthorizeURLQueryParameters = [msidParams.extraAuthorizeURLQueryParameters mutableCopy];;
         [extraAuthorizeURLQueryParameters setObject:MSID_PREFERRED_AUTH_METHOD_QR_PIN forKey:MSID_PREFERRED_AUTH_METHOD_KEY];
diff --git a/MSAL/src/public/MSALDefinitions.h b/MSAL/src/public/MSALDefinitions.h
index 88623b0d2d..3c9efc5b85 100644
--- a/MSAL/src/public/MSALDefinitions.h
+++ b/MSAL/src/public/MSALDefinitions.h
@@ -187,12 +187,7 @@ typedef NS_ENUM(NSUInteger, MSALPreferredAuthMethod)
     /*
         No preferred auth method passed with the request to the authetication server.
     */
-    MSALPreferredAuthMethodNone,
-    
-    /*
-        QR+PIN preferred as the auth method.
-    */
-    MSALPreferredAuthMethodQRPIN
+    MSALPreferredAuthMethodNone
 };
 
 /**

From 679e3b0b22d6a336c8c4883ccaf22ecf87d40f28 Mon Sep 17 00:00:00 2001
From: mipetriu 
Date: Thu, 7 Mar 2024 14:47:55 -0800
Subject: [PATCH 78/84] Updated changelog and common core commit

---
 CHANGELOG.md      | 3 +++
 MSAL/IdentityCore | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index cd0c5c49b6..d5b5243a01 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+## [1.3.1]
+* Add support for QR+PIN (#1929)
+
 ## [1.3.0]
 
 ## [1.2.22]
diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 2b2f34dded..cc64d069cd 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 2b2f34ddeda0b07970b31358040f29d52d057b10
+Subproject commit cc64d069cd1d318972b2b53657a580488b1efa9f

From 96b78e9b530f957c80a226c1cc90ede0b7db05f1 Mon Sep 17 00:00:00 2001
From: Jason Zeng 
Date: Thu, 7 Mar 2024 15:42:18 -0800
Subject: [PATCH 79/84] Update common core

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index da2e70c7e6..5871430c84 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit da2e70c7e6c99da6a827c9d966777e86f887f2de
+Subproject commit 5871430c84d66d5ffdd56b64d7488d6aa6aded7b

From 57e60e5700a30defaef7c9720c1b5814a94c3e19 Mon Sep 17 00:00:00 2001
From: Silviu Petrescu <111577419+spetrescu84@users.noreply.github.com>
Date: Fri, 8 Mar 2024 14:21:52 +0200
Subject: [PATCH 80/84] Move access token info inside MSALNativeAuthTokenResult
 (#2081)

* Move access token info from account result to access toke result

* access token should not be nil, rename result

* -Moved credentials SPY to check scopes, access token and expiration date
-Fixed unit tests

* Fixed all unit tests, disabled one

* Removed .tokenNotFound as it was not used anymore along with test

* Fixed unit tests
Removed not needed message

* Pr comments

* renamed accessToken to accessTokenResult

* Spacing

---------

Co-authored-by: Danilo Raspa 
---
 MSAL/MSAL.xcodeproj/project.pbxproj           |  4 ++
 .../cache/MSALNativeAuthTokens.swift          |  4 +-
 .../MSALNativeAuthCredentialsController.swift | 11 ++--
 ...MSALNativeAuthCredentialsControlling.swift |  3 +-
 .../errors/MSALNativeAuthErrorMessage.swift   |  1 -
 .../public/MSALNativeAuthTokenResult.swift    | 53 +++++++++++++++++++
 ...NativeAuthUserAccountResult+Internal.swift | 15 ++----
 .../MSALNativeAuthUserAccountResult.swift     | 14 +----
 .../delegate/CredentialsDelegates.swift       |  4 +-
 .../CredentialsDelegateDispatcher.swift       |  4 +-
 .../error/RetrieveAccessTokenError.swift      |  8 ---
 .../state_machine/state/SignUpStates.swift    |  1 -
 .../MSALNativeAuthCacheAccessorTest.swift     | 12 ++---
 ...NativeAuthCredentialsControllerTests.swift |  9 ++--
 .../MSALNativeAuthResultFactoryTests.swift    |  4 --
 .../mock/CredentialsDelegateSpies.swift       | 22 +++++---
 .../mock/SignInDelegatesSpies.swift           |  5 --
 ...ativeAuthTokenResponseValidatorTests.swift | 15 +++---
 ...ativeAuthPublicClientApplicationTest.swift | 20 ++-----
 ...MSALNativeAuthUserAccountResultTests.swift | 21 ++------
 ...tchAccessTokenRetrieveCompletedTests.swift | 32 ++++++++---
 .../error/RetrieveAccessTokenErrorTests.swift | 13 +----
 22 files changed, 151 insertions(+), 124 deletions(-)
 create mode 100644 MSAL/src/native_auth/public/MSALNativeAuthTokenResult.swift

diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj
index f13ebc146f..9166bfd047 100644
--- a/MSAL/MSAL.xcodeproj/project.pbxproj
+++ b/MSAL/MSAL.xcodeproj/project.pbxproj
@@ -241,6 +241,7 @@
 		23FB5C1E22542B99002BF1EB /* MSALJsonDeserializable.h in Headers */ = {isa = PBXBuildFile; fileRef = 23FB5C1C22542B99002BF1EB /* MSALJsonDeserializable.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		2826932A2A0974750037B93A /* MSALNativeAuthTokenRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282693272A0974740037B93A /* MSALNativeAuthTokenRequestParameters.swift */; };
 		2826933B2A0B98750037B93A /* MSALNativeAuthSignInParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2826933A2A0B98750037B93A /* MSALNativeAuthSignInParameters.swift */; };
+		285D0D692B99C14F002A1D4A /* MSALNativeAuthTokenResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 285D0D682B99C14F002A1D4A /* MSALNativeAuthTokenResult.swift */; };
 		285F36082A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 285F36072A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift */; };
 		2877081F2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2877081E2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift */; };
 		287708222A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287708212A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift */; };
@@ -1540,6 +1541,7 @@
 		23FB5C1C22542B99002BF1EB /* MSALJsonDeserializable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALJsonDeserializable.h; sourceTree = ""; };
 		282693272A0974740037B93A /* MSALNativeAuthTokenRequestParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenRequestParameters.swift; sourceTree = ""; };
 		2826933A2A0B98750037B93A /* MSALNativeAuthSignInParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInParameters.swift; sourceTree = ""; };
+		285D0D682B99C14F002A1D4A /* MSALNativeAuthTokenResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenResult.swift; sourceTree = ""; };
 		285F36072A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInControlling.swift; sourceTree = ""; };
 		2877081E2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInChallengeValidatedResponse.swift; sourceTree = ""; };
 		287708212A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthInternalChannelType.swift; sourceTree = ""; };
@@ -3941,6 +3943,7 @@
 				9BD78D7A2A126A1500AA7E12 /* MSALNativeAuthChallengeTypes.h */,
 				DE8BE7DB2A1F6BD2009642A5 /* MSALNativeAuthUserAccountResult.swift */,
 				E2D3BC4E2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift */,
+				285D0D682B99C14F002A1D4A /* MSALNativeAuthTokenResult.swift */,
 			);
 			path = public;
 			sourceTree = "";
@@ -5791,6 +5794,7 @@
 				E2F626A72A780F3D00C4A303 /* SignUpStates+Internal.swift in Sources */,
 				2826932A2A0974750037B93A /* MSALNativeAuthTokenRequestParameters.swift in Sources */,
 				28EDF93E29E6D43900A99F2A /* SignUpStartError.swift in Sources */,
+				285D0D692B99C14F002A1D4A /* MSALNativeAuthTokenResult.swift in Sources */,
 				DE94C9F029F2AF5E00C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParameters.swift in Sources */,
 				D61BD2B31EBD09F90007E484 /* MSALPromptType.m in Sources */,
 				DEC1E425298BE18A00948BED /* MSALNativeAuthServerTelemetry.swift in Sources */,
diff --git a/MSAL/src/native_auth/cache/MSALNativeAuthTokens.swift b/MSAL/src/native_auth/cache/MSALNativeAuthTokens.swift
index 13105e414f..ebc8099f20 100644
--- a/MSAL/src/native_auth/cache/MSALNativeAuthTokens.swift
+++ b/MSAL/src/native_auth/cache/MSALNativeAuthTokens.swift
@@ -25,11 +25,11 @@
 @_implementationOnly import MSAL_Private
 
 class MSALNativeAuthTokens {
-    let accessToken: MSIDAccessToken?
+    let accessToken: MSIDAccessToken
     let refreshToken: MSIDRefreshToken?
     let rawIdToken: String?
 
-    init(accessToken: MSIDAccessToken?, refreshToken: MSIDRefreshToken?, rawIdToken: String?) {
+    init(accessToken: MSIDAccessToken, refreshToken: MSIDRefreshToken?, rawIdToken: String?) {
         self.accessToken = accessToken
         self.refreshToken = refreshToken
         self.rawIdToken = rawIdToken
diff --git a/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift
index b882989d8b..82261faedd 100644
--- a/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift
+++ b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsController.swift
@@ -86,7 +86,7 @@ final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController,
     func refreshToken(context: MSALNativeAuthRequestContext, authTokens: MSALNativeAuthTokens) async -> RefreshTokenCredentialControllerResponse {
         MSALLogger.log(level: .verbose, context: context, format: "Refresh started")
         let telemetryEvent = makeAndStartTelemetryEvent(id: .telemetryApiIdRefreshToken, context: context)
-        let scopes = authTokens.accessToken?.scopes.array as? [String] ?? []
+        let scopes = authTokens.accessToken.scopes.array as? [String] ?? []
         guard let request = createRefreshTokenRequest(
             scopes: scopes,
             refreshToken: authTokens.refreshToken?.refreshToken,
@@ -94,7 +94,7 @@ final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController,
         ) else {
             stopTelemetryEvent(telemetryEvent, context: context, error: MSALNativeAuthInternalError.invalidRequest)
             return .init(
-                .failure(RetrieveAccessTokenError(type: .generalError, correlationId: context.correlationId())), 
+                .failure(RetrieveAccessTokenError(type: .generalError, correlationId: context.correlationId())),
                 correlationId: context.correlationId()
             )
         }
@@ -181,8 +181,13 @@ final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController,
                 level: .verbose,
                 context: context,
                 format: "Refresh Token completed successfully")
+            // TODO: Handle tokenResult.refreshToken as? MSIDRefreshToken in a safer way
             return .init(
-                .success(tokenResult.accessToken.accessToken),
+                .success(MSALNativeAuthTokenResult(authTokens: MSALNativeAuthTokens(
+                    accessToken: tokenResult.accessToken,
+                    refreshToken: tokenResult.refreshToken as? MSIDRefreshToken,
+                    rawIdToken: tokenResult.rawIdToken
+                ))),
                 correlationId: context.correlationId(),
                 telemetryUpdate: { [weak self] result in
                 telemetryEvent?.setUserInformation(tokenResult.account)
diff --git a/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsControlling.swift b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsControlling.swift
index 0e85fa4531..2b8882032e 100644
--- a/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsControlling.swift
+++ b/MSAL/src/native_auth/controllers/credentials/MSALNativeAuthCredentialsControlling.swift
@@ -25,7 +25,8 @@
 import Foundation
 
 protocol MSALNativeAuthCredentialsControlling {
-    typealias RefreshTokenCredentialControllerResponse = MSALNativeAuthControllerTelemetryWrapper>
+    typealias RefreshTokenCredentialControllerResponse =
+    MSALNativeAuthControllerTelemetryWrapper>
 
     func retrieveUserAccountResult(context: MSALNativeAuthRequestContext) -> MSALNativeAuthUserAccountResult?
     func refreshToken(context: MSALNativeAuthRequestContext, authTokens: MSALNativeAuthTokens) async -> RefreshTokenCredentialControllerResponse
diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift
index a814deb147..1462d82862 100644
--- a/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift
+++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift
@@ -41,7 +41,6 @@ enum MSALNativeAuthErrorMessage {
     static let generalError = "General error"
     static let invalidCode = "Invalid code"
     static let refreshTokenExpired = "Refresh token is expired"
-    static let tokenNotFound = "Token not found"
     static let redirectUriNotSetWarning = "WARNING ⚠️: redirectUri not set during MSAL Native Auth initialization. Production apps must correctly configure a redirect URI and call acquireToken in response to all browserRequired errors. See https://learn.microsoft.com/entra/identity-platform/redirect-uris-ios"
     static let unexpectedResponseBody = "Unexpected response body received"
     static let unexpectedChallengeType = "Unexpected challenge type"
diff --git a/MSAL/src/native_auth/public/MSALNativeAuthTokenResult.swift b/MSAL/src/native_auth/public/MSALNativeAuthTokenResult.swift
new file mode 100644
index 0000000000..ff65e624d9
--- /dev/null
+++ b/MSAL/src/native_auth/public/MSALNativeAuthTokenResult.swift
@@ -0,0 +1,53 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.  
+
+import Foundation
+
+public class MSALNativeAuthTokenResult: NSObject {
+
+    let authTokens: MSALNativeAuthTokens
+
+    init(authTokens: MSALNativeAuthTokens) {
+        self.authTokens = authTokens
+    }
+
+    /**
+     The Access Token requested.
+     Note that if access token is not returned in token response, this property will be returned as an empty string.
+     */
+    @objc public var accessToken: String {
+        authTokens.accessToken.accessToken
+    }
+
+    /// Get the list of permissions for the access token for the account.
+    @objc public var scopes: [String] {
+        authTokens.accessToken.scopes.array as? [String] ?? []
+    }
+
+    /// Get the expiration date for the access token for the account.
+    /// This value is calculated based on current UTC time measured locally and the value expiresIn returned from the service
+    @objc public var expiresOn: Date? {
+        authTokens.accessToken.expiresOn
+    }
+}
diff --git a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift
index b2afa7a7bf..12972ea676 100644
--- a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift
+++ b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult+Internal.swift
@@ -34,17 +34,12 @@ extension MSALNativeAuthUserAccountResult {
         let context = MSALNativeAuthRequestContext(correlationId: correlationId)
         let correlationId = context.correlationId()
 
-        if let accessToken = self.authTokens.accessToken {
-            if forceRefresh || accessToken.isExpired() {
-                let controllerFactory = MSALNativeAuthControllerFactory(config: configuration)
-                let credentialsController = controllerFactory.makeCredentialsController(cacheAccessor: cacheAccessor)
-                return await credentialsController.refreshToken(context: context, authTokens: authTokens)
-            } else {
-                return .init(.success(accessToken.accessToken), correlationId: correlationId)
-            }
+        if forceRefresh || self.authTokens.accessToken.isExpired() {
+            let controllerFactory = MSALNativeAuthControllerFactory(config: configuration)
+            let credentialsController = controllerFactory.makeCredentialsController(cacheAccessor: cacheAccessor)
+            return await credentialsController.refreshToken(context: context, authTokens: authTokens)
         } else {
-            MSALLogger.log(level: .error, context: context, format: "Retrieve Access Token: Existing token not found")
-            return .init(.failure(RetrieveAccessTokenError(type: .tokenNotFound, correlationId: correlationId)), correlationId: correlationId)
+            return .init(.success(MSALNativeAuthTokenResult(authTokens: authTokens)), correlationId: correlationId)
         }
     }
 }
diff --git a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift
index 90ce3efecb..960a4f5c1f 100644
--- a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift
+++ b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift
@@ -38,16 +38,6 @@ import Foundation
         authTokens.rawIdToken
     }
 
-    /// Get the list of permissions for the access token for the account if present.
-    @objc public var scopes: [String] {
-        authTokens.accessToken?.scopes.array as? [String] ?? []
-    }
-
-    /// Get the expiration date for the access token for the account if present.
-    @objc public var expiresOn: Date? {
-        authTokens.accessToken?.expiresOn
-    }
-
     init(
         account: MSALAccount,
         authTokens: MSALNativeAuthTokens,
@@ -96,9 +86,9 @@ import Foundation
             let delegateDispatcher = CredentialsDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate)
 
             switch controllerResponse.result {
-            case .success(let accessToken):
+            case .success(let accessTokenResult):
                 await delegateDispatcher.dispatchAccessTokenRetrieveCompleted(
-                    accessToken: accessToken,
+                    result: accessTokenResult,
                     correlationId: controllerResponse.correlationId
                 )
             case .failure(let error):
diff --git a/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift b/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift
index 1d20fc6013..d946abc1b8 100644
--- a/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift
+++ b/MSAL/src/native_auth/public/state_machine/delegate/CredentialsDelegates.swift
@@ -33,6 +33,6 @@ public protocol CredentialsDelegate {
 
     /// Notifies the delegate that the operation completed successfully.
     /// - Note: If a flow requires this optional method and it is not implemented, then ``onAccessTokenRetrieveError(error:)`` will be called.
-    /// - Parameter accessToken: The access token string.
-    @MainActor @objc optional func onAccessTokenRetrieveCompleted(accessToken: String)
+    /// - Parameter result: The access token result.
+    @MainActor @objc optional func onAccessTokenRetrieveCompleted(result: MSALNativeAuthTokenResult)
 }
diff --git a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/CredentialsDelegateDispatcher.swift b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/CredentialsDelegateDispatcher.swift
index a587579ea1..f95d6d35d1 100644
--- a/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/CredentialsDelegateDispatcher.swift
+++ b/MSAL/src/native_auth/public/state_machine/delegate_dispatcher/CredentialsDelegateDispatcher.swift
@@ -26,10 +26,10 @@ import Foundation
 
 final class CredentialsDelegateDispatcher: DelegateDispatcher {
 
-    func dispatchAccessTokenRetrieveCompleted(accessToken: String, correlationId: UUID) async {
+    func dispatchAccessTokenRetrieveCompleted(result: MSALNativeAuthTokenResult, correlationId: UUID) async {
         if let onAccessTokenRetrieveCompleted = delegate.onAccessTokenRetrieveCompleted {
             telemetryUpdate?(.success(()))
-            await onAccessTokenRetrieveCompleted(accessToken)
+            await onAccessTokenRetrieveCompleted(result)
         } else {
             let error = RetrieveAccessTokenError(
                 type: .generalError,
diff --git a/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift b/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift
index 4407609508..32c44f30c8 100644
--- a/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift
+++ b/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift
@@ -30,7 +30,6 @@ public class RetrieveAccessTokenError: MSALNativeAuthError {
     enum ErrorType: CaseIterable {
         case browserRequired
         case refreshTokenExpired
-        case tokenNotFound
         case generalError
     }
 
@@ -52,8 +51,6 @@ public class RetrieveAccessTokenError: MSALNativeAuthError {
             return MSALNativeAuthErrorMessage.browserRequired
         case .refreshTokenExpired:
             return MSALNativeAuthErrorMessage.refreshTokenExpired
-        case .tokenNotFound:
-            return MSALNativeAuthErrorMessage.tokenNotFound
         case .generalError:
             return MSALNativeAuthErrorMessage.generalError
         }
@@ -68,9 +65,4 @@ public class RetrieveAccessTokenError: MSALNativeAuthError {
     public var isRefreshTokenExpired: Bool {
         return type == .refreshTokenExpired
     }
-
-    /// Returns `true` if the existing token cannot be found.
-    public var isTokenNotFound: Bool {
-        return type == .tokenNotFound
-    }
 }
diff --git a/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift b/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift
index b421718cb8..ff7772343a 100644
--- a/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift
+++ b/MSAL/src/native_auth/public/state_machine/state/SignUpStates.swift
@@ -77,7 +77,6 @@ public class SignUpBaseState: MSALNativeAuthBaseState {
     public func submitCode(code: String, delegate: SignUpVerifyCodeDelegate) {
         Task {
             let controllerResponse = await submitCodeInternal(code: code)
-            
             let delegateDispatcher = SignUpVerifyCodeDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate)
 
             switch controllerResponse.result {
diff --git a/MSAL/test/unit/native_auth/cache/MSALNativeAuthCacheAccessorTest.swift b/MSAL/test/unit/native_auth/cache/MSALNativeAuthCacheAccessorTest.swift
index ad14e9d6ca..bc38d8ba2e 100644
--- a/MSAL/test/unit/native_auth/cache/MSALNativeAuthCacheAccessorTest.swift
+++ b/MSAL/test/unit/native_auth/cache/MSALNativeAuthCacheAccessorTest.swift
@@ -56,7 +56,7 @@ final class MSALNativeAuthCacheAccessorTest: XCTestCase {
         var tokens: MSALNativeAuthTokens? = nil
         
         XCTAssertNoThrow(tokens = try cacheAccessor.getTokens(account: parameters.account, configuration: parameters.msidConfiguration, context: contextStub))
-        XCTAssertEqual(tokens?.accessToken?.accessToken, tokenResponse.accessToken)
+        XCTAssertEqual(tokens?.accessToken.accessToken, tokenResponse.accessToken)
         XCTAssertEqual(tokens?.refreshToken?.refreshToken, tokenResponse.refreshToken)
         XCTAssertEqual(tokens?.rawIdToken, tokenResponse.idToken)
     }
@@ -67,7 +67,7 @@ final class MSALNativeAuthCacheAccessorTest: XCTestCase {
         var tokens: MSALNativeAuthTokens? = nil
         
         XCTAssertNoThrow(tokens = try cacheAccessor.getTokens(account: parameters.account, configuration: parameters.msidConfiguration, context: contextStub))
-        XCTAssertEqual(tokens?.accessToken?.accessToken, tokenResponse.accessToken)
+        XCTAssertEqual(tokens?.accessToken.accessToken, tokenResponse.accessToken)
         XCTAssertEqual(tokens?.refreshToken?.refreshToken, tokenResponse.refreshToken)
         XCTAssertEqual(tokens?.rawIdToken, tokenResponse.idToken)
         
@@ -80,7 +80,7 @@ final class MSALNativeAuthCacheAccessorTest: XCTestCase {
         XCTAssertNoThrow(try cacheAccessor.validateAndSaveTokensAndAccount(tokenResponse: tokenResponse, configuration: parameters.msidConfiguration, context: contextStub))
 
         XCTAssertNoThrow(tokens = try cacheAccessor.getTokens(account: parameters.account, configuration: parameters.msidConfiguration, context: contextStub))
-        XCTAssertEqual(tokens?.accessToken?.accessToken, newAccessToken)
+        XCTAssertEqual(tokens?.accessToken.accessToken, newAccessToken)
         XCTAssertEqual(tokens?.refreshToken?.refreshToken, newRefreshToken)
         XCTAssertEqual(tokens?.rawIdToken, newIdToken)
     }
@@ -97,7 +97,7 @@ final class MSALNativeAuthCacheAccessorTest: XCTestCase {
         XCTAssertEqual(account?.environment, "contoso.com")
         XCTAssertNil(account?.accountClaims)
         XCTAssertNoThrow(tokens = try cacheAccessor.getTokens(account: account!, configuration: parameters.msidConfiguration, context: contextStub))
-        XCTAssertEqual(tokens?.accessToken?.accessToken, tokenResponse.accessToken)
+        XCTAssertEqual(tokens?.accessToken.accessToken, tokenResponse.accessToken)
         XCTAssertEqual(tokens?.refreshToken?.refreshToken, tokenResponse.refreshToken)
         XCTAssertEqual(tokens?.rawIdToken, tokenResponse.idToken)
     }
@@ -115,7 +115,7 @@ final class MSALNativeAuthCacheAccessorTest: XCTestCase {
         XCTAssertNil(account?.accountClaims)
         parameters.msidConfiguration = getMSIDConfiguration(host: "https://contoso.com/tfp/tenantName")
         XCTAssertNoThrow(tokens = try cacheAccessor.getTokens(account: account!, configuration: parameters.msidConfiguration, context: contextStub))
-        XCTAssertEqual(tokens?.accessToken?.accessToken, tokenResponse.accessToken)
+        XCTAssertEqual(tokens?.accessToken.accessToken, tokenResponse.accessToken)
         XCTAssertEqual(tokens?.refreshToken?.refreshToken, tokenResponse.refreshToken)
         XCTAssertEqual(tokens?.rawIdToken, tokenResponse.idToken)
     }
@@ -140,7 +140,7 @@ final class MSALNativeAuthCacheAccessorTest: XCTestCase {
         XCTAssertEqual(account?.environment, "contoso.com")
         XCTAssertNil(account?.accountClaims)
         XCTAssertNoThrow(tokens = try cacheAccessor.getTokens(account: account!, configuration: parameters.msidConfiguration, context: contextStub))
-        XCTAssertEqual(tokens?.accessToken?.accessToken, newAccessToken)
+        XCTAssertEqual(tokens?.accessToken.accessToken, newAccessToken)
         XCTAssertEqual(tokens?.refreshToken?.refreshToken, newRefreshToken)
         XCTAssertEqual(tokens?.rawIdToken, newIdToken)
     }
diff --git a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift
index 1fd52887c5..b7098bc616 100644
--- a/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift
+++ b/MSAL/test/unit/native_auth/controllers/MSALNativeAuthCredentialsControllerTests.swift
@@ -113,8 +113,6 @@ final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase {
         let accountResult = sut.retrieveUserAccountResult(context: expectedContext)
         XCTAssertEqual(accountResult?.account.username, account.username)
         XCTAssertEqual(accountResult?.idToken, authTokens.rawIdToken)
-        XCTAssertEqual(accountResult?.scopes, authTokens.accessToken?.scopes.array as? [String])
-        XCTAssertEqual(accountResult?.expiresOn, authTokens.accessToken?.expiresOn)
         XCTAssertTrue(NSDictionary(dictionary: accountResult?.account.accountClaims ?? [:]).isEqual(to: account.accountClaims ?? [:]))
     }
 
@@ -150,7 +148,10 @@ final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase {
         requestProviderMock.mockRequestRefreshTokenFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
 
         let expectedAccessToken = "accessToken"
-        let helper = CredentialsTestValidatorHelper(expectation: expectation, expectedAccessToken: expectedAccessToken)
+        let helper = CredentialsTestValidatorHelper(expectation: expectation, expectedResult: MSALNativeAuthTokenResult(authTokens: authTokens))
+        helper.expectedAccessToken = authTokens.accessToken.accessToken
+        helper.expectedExpiresOn = authTokens.accessToken.expiresOn
+        helper.expectedScopes = authTokens.accessToken.scopes.array as? [String] ?? []
 
         factory.mockMakeUserAccountResult(userAccountResult)
         tokenResult.accessToken = MSIDAccessToken()
@@ -163,7 +164,7 @@ final class MSALNativeAuthCredentialsControllerTests: MSALNativeAuthTestCase {
         helper.onAccessTokenRetrieveCompleted(result)
 
         await fulfillment(of: [expectation], timeout: 1)
-        XCTAssertEqual(expectedAccessToken, authTokens.accessToken?.accessToken)
+        XCTAssertEqual(expectedAccessToken, authTokens.accessToken.accessToken)
     }
 
     func test_whenErrorIsReturnedFromValidator_itIsCorrectlyTranslatedToDelegateError() async  {
diff --git a/MSAL/test/unit/native_auth/controllers/factories/MSALNativeAuthResultFactoryTests.swift b/MSAL/test/unit/native_auth/controllers/factories/MSALNativeAuthResultFactoryTests.swift
index 2138c7221c..1752c6d7eb 100644
--- a/MSAL/test/unit/native_auth/controllers/factories/MSALNativeAuthResultFactoryTests.swift
+++ b/MSAL/test/unit/native_auth/controllers/factories/MSALNativeAuthResultFactoryTests.swift
@@ -80,8 +80,6 @@ final class MSALNativeAuthResultFactoryTests: XCTestCase {
         }
         XCTAssertEqual(accountResult.account.username, username)
         XCTAssertEqual(accountResult.idToken, idToken)
-        XCTAssertEqual(accountResult.expiresOn, expiresOn)
-        XCTAssertEqual(accountResult.scopes, scopes)
         XCTAssertNotNil(accountResult.account.accountClaims)
         XCTAssertEqual(accountResult.account.accountClaims?.count, 21)
     }
@@ -112,8 +110,6 @@ final class MSALNativeAuthResultFactoryTests: XCTestCase {
         }
         XCTAssertEqual(accountResult.account.username, username)
         XCTAssertEqual(accountResult.idToken, idToken)
-        XCTAssertEqual(accountResult.expiresOn, expiresOn)
-        XCTAssertEqual(accountResult.scopes, scopes)
         XCTAssertNil(accountResult.account.accountClaims)
     }
 }
diff --git a/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift b/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift
index 51568ecaf7..cf42834e27 100644
--- a/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift
+++ b/MSAL/test/unit/native_auth/mock/CredentialsDelegateSpies.swift
@@ -29,18 +29,24 @@ open class CredentialsDelegateSpy: CredentialsDelegate {
 
     private let expectation: XCTestExpectation
     var expectedError: RetrieveAccessTokenError?
+    var expectedResult: MSALNativeAuthTokenResult?
     var expectedAccessToken: String?
-    
-    init(expectation: XCTestExpectation, expectedError: RetrieveAccessTokenError? = nil, expectedAccessToken: String? = nil) {
+    var expectedScopes: [String]?
+    var expectedExpiresOn: Date?
+
+    init(expectation: XCTestExpectation, expectedError: RetrieveAccessTokenError? = nil, expectedResult: MSALNativeAuthTokenResult? = nil) {
         self.expectation = expectation
         self.expectedError = expectedError
-        self.expectedAccessToken = expectedAccessToken
+        self.expectedResult = expectedResult
     }
 
-    public func onAccessTokenRetrieveCompleted(accessToken: String) {
-        if let expectedAccessToken = expectedAccessToken {
+    public func onAccessTokenRetrieveCompleted(result: MSALNativeAuthTokenResult) {
+        if let expectedResult = expectedResult {
             XCTAssertTrue(Thread.isMainThread)
-            XCTAssertEqual(expectedAccessToken, accessToken)
+            XCTAssertEqual(expectedResult, expectedResult)
+            XCTAssertEqual(expectedResult.accessToken, expectedAccessToken)
+            XCTAssertEqual(expectedResult.scopes, expectedScopes)
+            XCTAssertEqual(expectedResult.expiresOn, expectedExpiresOn)
         } else {
             XCTFail("This method should not be called")
         }
@@ -84,11 +90,11 @@ final class CredentialsDelegateOptionalMethodsNotImplemented: CredentialsDelegat
 class CredentialsTestValidatorHelper: CredentialsDelegateSpy {
 
     func onAccessTokenRetrieveCompleted(_ response: MSALNativeAuthCredentialsController.RefreshTokenCredentialControllerResponse) {
-        guard case let .success(token) = response.result else {
+        guard case let .success(result) = response.result else {
             return XCTFail("wrong result")
         }
 
-        Task { await self.onAccessTokenRetrieveCompleted(accessToken: token) }
+        Task { await self.onAccessTokenRetrieveCompleted(result: result) }
     }
 
     func onAccessTokenRetrieveError(_ response: MSALNativeAuthCredentialsController.RefreshTokenCredentialControllerResponse) {
diff --git a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift
index d754bc56d7..72e0c9bf2c 100644
--- a/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift
+++ b/MSAL/test/unit/native_auth/mock/SignInDelegatesSpies.swift
@@ -65,7 +65,6 @@ open class SignInPasswordStartDelegateSpy: SignInStartDelegate {
         if let expectedUserAccountResult = expectedUserAccountResult {
             XCTAssertTrue(Thread.isMainThread)
             XCTAssertEqual(expectedUserAccountResult.idToken, result.idToken)
-            XCTAssertEqual(expectedUserAccountResult.scopes, result.scopes)
         } else {
             XCTFail("This method should not be called")
         }
@@ -106,7 +105,6 @@ class SignInPasswordRequiredDelegateSpy: SignInPasswordRequiredDelegate {
         XCTAssertTrue(Thread.isMainThread)
         if let expectedUserAccountResult = expectedUserAccountResult {
             XCTAssertEqual(expectedUserAccountResult.idToken, result.idToken)
-            XCTAssertEqual(expectedUserAccountResult.scopes, result.scopes)
         } else {
             XCTFail("This method should not be called")
         }
@@ -278,7 +276,6 @@ open class SignInVerifyCodeDelegateSpy: SignInVerifyCodeDelegate {
             return
         }
         XCTAssertEqual(expectedUserAccountResult.idToken, result.idToken)
-        XCTAssertEqual(expectedUserAccountResult.scopes, result.scopes)
         XCTAssertTrue(Thread.isMainThread)
         expectation.fulfill()
     }
@@ -329,7 +326,6 @@ open class SignInAfterSignUpDelegateSpy: SignInAfterSignUpDelegate {
             return
         }
         XCTAssertEqual(expectedUserAccountResult.idToken, result.idToken)
-        XCTAssertEqual(expectedUserAccountResult.scopes, result.scopes)
         XCTAssertTrue(Thread.isMainThread)
         expectation.fulfill()
     }
@@ -361,7 +357,6 @@ class SignInAfterResetPasswordDelegateSpy: SignInAfterResetPasswordDelegate {
             return
         }
         XCTAssertEqual(expectedUserAccountResult.idToken, result.idToken)
-        XCTAssertEqual(expectedUserAccountResult.scopes, result.scopes)
         XCTAssertTrue(Thread.isMainThread)
         expectation.fulfill()
     }
diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift
index d983c185fd..8bacca8be0 100644
--- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift
+++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift
@@ -56,16 +56,19 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase {
 
     func test_whenValidTokenResponse_validationIsSuccessful() {
         let context = MSALNativeAuthRequestContext(correlationId: defaultUUID)
+        let accessToken = MSIDAccessToken()
+        accessToken.accessToken = nil
+        let refreshToken = MSIDRefreshToken()
+        refreshToken.refreshToken = nil
+        let rawIdToken = "rawIdToken"
+        let authTokens = MSALNativeAuthTokens(accessToken: accessToken,
+                                              refreshToken: refreshToken,
+                                              rawIdToken: rawIdToken)
         let userAccountResult = MSALNativeAuthUserAccountResult(account:
                                                                     MSALNativeAuthUserAccountResultStub.account,
-                                                                authTokens: MSALNativeAuthTokens(accessToken: nil,
-                                                                                                 refreshToken: nil,
-                                                                                                 rawIdToken: nil),
+                                                                authTokens:authTokens,
                                                                 configuration: MSALNativeAuthConfigStubs.configuration,
                                                                 cacheAccessor: MSALNativeAuthCacheAccessorMock())
-        let refreshToken = MSIDRefreshToken()
-        refreshToken.familyId = "familyId"
-        refreshToken.refreshToken = "refreshToken"
         let tokenResponse = MSIDCIAMTokenResponse()
         factory.mockMakeUserAccountResult(userAccountResult)
         let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .success(tokenResponse))
diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift
index 196ffc0c1a..147fdd6434 100644
--- a/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift
+++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthPublicClientApplicationTest.swift
@@ -585,9 +585,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         
         let authResultFactoryMock = MSALNativeAuthResultFactoryMock()
         let userAccountResult = MSALNativeAuthUserAccountResult(account: MSALNativeAuthUserAccountResultStub.account,
-                                                                authTokens: MSALNativeAuthTokens(accessToken: nil,
-                                                                                                 refreshToken: nil,
-                                                                                                 rawIdToken: nil),
+                                                                authTokens: MSALNativeAuthUserAccountResultStub.authTokens,
                                                                 configuration: MSALNativeAuthConfigStubs.configuration,
                                                                 cacheAccessor: MSALNativeAuthCacheAccessorMock())
         authResultFactoryMock.mockMakeUserAccountResult(userAccountResult)
@@ -687,9 +685,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         
         let authResultFactoryMock = MSALNativeAuthResultFactoryMock()
         let userAccountResult = MSALNativeAuthUserAccountResult(account: MSALNativeAuthUserAccountResultStub.account,
-                                                                authTokens: MSALNativeAuthTokens(accessToken: nil,
-                                                                                                 refreshToken: nil,
-                                                                                                 rawIdToken: nil),
+                                                                authTokens: MSALNativeAuthUserAccountResultStub.authTokens,
                                                                 configuration: MSALNativeAuthConfigStubs.configuration,
                                                                 cacheAccessor: MSALNativeAuthCacheAccessorMock())
         authResultFactoryMock.mockMakeUserAccountResult(userAccountResult)
@@ -784,9 +780,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         
         let authResultFactoryMock = MSALNativeAuthResultFactoryMock()
         let userAccountResult = MSALNativeAuthUserAccountResult(account: MSALNativeAuthUserAccountResultStub.account,
-                                                                authTokens: MSALNativeAuthTokens(accessToken: nil,
-                                                                                                 refreshToken: nil,
-                                                                                                 rawIdToken: nil),
+                                                                authTokens: MSALNativeAuthUserAccountResultStub.authTokens,
                                                                 configuration: MSALNativeAuthConfigStubs.configuration,
                                                                 cacheAccessor: MSALNativeAuthCacheAccessorMock())
         authResultFactoryMock.mockMakeUserAccountResult(userAccountResult)
@@ -874,9 +868,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
         
         let authResultFactoryMock = MSALNativeAuthResultFactoryMock()
         let userAccountResult = MSALNativeAuthUserAccountResult(account: MSALNativeAuthUserAccountResultStub.account,
-                                                                authTokens: MSALNativeAuthTokens(accessToken: nil,
-                                                                                                 refreshToken: nil,
-                                                                                                 rawIdToken: nil),
+                                                                authTokens: MSALNativeAuthUserAccountResultStub.authTokens,
                                                                 configuration: MSALNativeAuthConfigStubs.configuration,
                                                                 cacheAccessor: MSALNativeAuthCacheAccessorMock())
         authResultFactoryMock.mockMakeUserAccountResult(userAccountResult)
@@ -974,9 +966,7 @@ final class MSALNativeAuthPublicClientApplicationTest: XCTestCase {
 
         let authResultFactoryMock = MSALNativeAuthResultFactoryMock()
         let userAccountResult = MSALNativeAuthUserAccountResult(account: MSALNativeAuthUserAccountResultStub.account,
-                                                                authTokens: MSALNativeAuthTokens(accessToken: nil,
-                                                                                                 refreshToken: nil,
-                                                                                                 rawIdToken: nil),
+                                                                authTokens: MSALNativeAuthUserAccountResultStub.authTokens,
                                                                 configuration: MSALNativeAuthConfigStubs.configuration,
                                                                 cacheAccessor: MSALNativeAuthCacheAccessorMock())
         authResultFactoryMock.mockMakeUserAccountResult(userAccountResult)
diff --git a/MSAL/test/unit/native_auth/public/MSALNativeAuthUserAccountResultTests.swift b/MSAL/test/unit/native_auth/public/MSALNativeAuthUserAccountResultTests.swift
index 73ec596553..3755ad4b75 100644
--- a/MSAL/test/unit/native_auth/public/MSALNativeAuthUserAccountResultTests.swift
+++ b/MSAL/test/unit/native_auth/public/MSALNativeAuthUserAccountResultTests.swift
@@ -57,26 +57,15 @@ class MSALNativeAuthUserAccountResultTests: XCTestCase {
 
     func test_whenAccountAndTokenExist_itReturnsCorrectData() {
         let expectation = expectation(description: "CredentialsController")
-
-        let mockDelegate = CredentialsDelegateSpy(expectation: expectation, expectedAccessToken: "accessToken")
+        let authTokens = MSALNativeAuthUserAccountResultStub.authTokens
+        let mockDelegate = CredentialsDelegateSpy(expectation: expectation, expectedResult: MSALNativeAuthTokenResult(authTokens: authTokens))
+        mockDelegate.expectedAccessToken = authTokens.accessToken.accessToken
+        mockDelegate.expectedExpiresOn = authTokens.accessToken.expiresOn
+        mockDelegate.expectedScopes = authTokens.accessToken.scopes.array as? [String] ?? []
         sut.getAccessToken(delegate: mockDelegate)
         wait(for: [expectation], timeout: 1)
     }
 
-    func test_whenNoAccessToken_itReturnsCorrectError() {
-        let expectation = expectation(description: "CredentialsController")
-        sut = MSALNativeAuthUserAccountResult(
-            account: account!,
-            authTokens: MSALNativeAuthTokens(accessToken: nil, refreshToken: nil, rawIdToken: nil),
-            configuration: MSALNativeAuthConfigStubs.configuration,
-            cacheAccessor: MSALNativeAuthCacheAccessorMock()
-        )
-        let correlationId = UUID()
-        let mockDelegate = CredentialsDelegateSpy(expectation: expectation, expectedError: RetrieveAccessTokenError(type: .tokenNotFound, correlationId: correlationId, errorCodes: []))
-        sut.getAccessToken(correlationId: correlationId, delegate: mockDelegate)
-        wait(for: [expectation], timeout: 1)
-    }
-
     // MARK: - sign-out tests
 
     func test_signOut_successfullyCallsCacheAccessor() {
diff --git a/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift b/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift
index a45f69a76a..634c680819 100644
--- a/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift
+++ b/MSAL/test/unit/native_auth/public/delegate/DispatchAccessTokenRetrieveCompletedTests.swift
@@ -22,6 +22,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+@_implementationOnly import MSAL_Private
 @testable import MSAL
 import XCTest
 
@@ -39,9 +40,19 @@ final class DispatchAccessTokenRetrieveCompletedTests: XCTestCase {
     }
 
     func test_dispatchAccessTokenRetrieveCompleted_whenDelegateMethodsAreImplemented() async {
-        let expectedToken = "token"
-        let delegate = CredentialsDelegateSpy(expectation: delegateExp, expectedAccessToken: expectedToken)
-
+        let accessToken = MSIDAccessToken()
+        accessToken.accessToken = "accessToken"
+        accessToken.scopes = ["scope1", "scope2"]
+        let refreshToken = MSIDRefreshToken()
+        refreshToken.refreshToken = "refreshToken"
+        let rawIdToken = "rawIdToken"
+        let authTokens = MSALNativeAuthTokens(accessToken: accessToken,
+                                              refreshToken: refreshToken,
+                                              rawIdToken: rawIdToken)
+        let expectedResult = MSALNativeAuthTokenResult(authTokens: authTokens)
+        let delegate = CredentialsDelegateSpy(expectation: delegateExp, expectedResult: expectedResult)
+        delegate.expectedAccessToken = accessToken.accessToken
+        delegate.expectedScopes = accessToken.scopes.array as? [String] ?? []
         sut = .init(delegate: delegate, telemetryUpdate: { result in
             guard case .success = result else {
                 return XCTFail("wrong result")
@@ -49,11 +60,11 @@ final class DispatchAccessTokenRetrieveCompletedTests: XCTestCase {
             self.telemetryExp.fulfill()
         })
 
-        await sut.dispatchAccessTokenRetrieveCompleted(accessToken: expectedToken, correlationId: correlationId)
+        await sut.dispatchAccessTokenRetrieveCompleted(result: expectedResult, correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
 
-        XCTAssertEqual(delegate.expectedAccessToken, expectedToken)
+        XCTAssertEqual(delegate.expectedResult, expectedResult)
     }
 
     func test_dispatchAccessTokenRetrieveCompleted_whenDelegateOptionalMethodsNotImplemented() async {
@@ -69,7 +80,16 @@ final class DispatchAccessTokenRetrieveCompletedTests: XCTestCase {
             self.telemetryExp.fulfill()
         })
 
-        await sut.dispatchAccessTokenRetrieveCompleted(accessToken: "token", correlationId: correlationId)
+        let accessToken = MSIDAccessToken()
+        accessToken.accessToken = "accessToken"
+        let refreshToken = MSIDRefreshToken()
+        refreshToken.refreshToken = "refreshToken"
+        let rawIdToken = "rawIdToken"
+        let authTokens = MSALNativeAuthTokens(accessToken: accessToken,
+                                              refreshToken: refreshToken,
+                                              rawIdToken: rawIdToken)
+
+        await sut.dispatchAccessTokenRetrieveCompleted(result: MSALNativeAuthTokenResult(authTokens: authTokens), correlationId: correlationId)
 
         await fulfillment(of: [telemetryExp, delegateExp])
         checkError(delegate.expectedError)
diff --git a/MSAL/test/unit/native_auth/public/error/RetrieveAccessTokenErrorTests.swift b/MSAL/test/unit/native_auth/public/error/RetrieveAccessTokenErrorTests.swift
index 26040a55b8..6ff8fa7ec6 100644
--- a/MSAL/test/unit/native_auth/public/error/RetrieveAccessTokenErrorTests.swift
+++ b/MSAL/test/unit/native_auth/public/error/RetrieveAccessTokenErrorTests.swift
@@ -30,7 +30,7 @@ final class RetrieveAccessTokenErrorTests: XCTestCase {
     private var sut: RetrieveAccessTokenError!
 
     func test_totalCases() {
-        XCTAssertEqual(RetrieveAccessTokenError.ErrorType.allCases.count, 4)
+        XCTAssertEqual(RetrieveAccessTokenError.ErrorType.allCases.count, 3)
     }
 
     func test_customErrorDescription() {
@@ -43,14 +43,12 @@ final class RetrieveAccessTokenErrorTests: XCTestCase {
         let sut: [RetrieveAccessTokenError] = [
             .init(type: .browserRequired, correlationId: .init()),
             .init(type: .refreshTokenExpired, correlationId: .init()),
-            .init(type: .tokenNotFound, correlationId: .init()),
             .init(type: .generalError, correlationId: .init())
         ]
 
         let expectedIdentifiers = [
             MSALNativeAuthErrorMessage.browserRequired,
             MSALNativeAuthErrorMessage.refreshTokenExpired,
-            MSALNativeAuthErrorMessage.tokenNotFound,
             MSALNativeAuthErrorMessage.generalError
         ]
 
@@ -65,20 +63,11 @@ final class RetrieveAccessTokenErrorTests: XCTestCase {
         sut = .init(type: .browserRequired, correlationId: .init())
         XCTAssertTrue(sut.isBrowserRequired)
         XCTAssertFalse(sut.isRefreshTokenExpired)
-        XCTAssertFalse(sut.isTokenNotFound)
     }
 
     func test_isRefreshTokenExpired() {
         sut = .init(type: .refreshTokenExpired, correlationId: .init())
         XCTAssertTrue(sut.isRefreshTokenExpired)
         XCTAssertFalse(sut.isBrowserRequired)
-        XCTAssertFalse(sut.isTokenNotFound)
-    }
-
-    func test_isTokenNotFound() {
-        sut = .init(type: .tokenNotFound, correlationId: .init())
-        XCTAssertTrue(sut.isTokenNotFound)
-        XCTAssertFalse(sut.isBrowserRequired)
-        XCTAssertFalse(sut.isRefreshTokenExpired)
     }
 }

From 2103fd4190bfa93fcafcf54b51f5e9d34c7b370f Mon Sep 17 00:00:00 2001
From: mipetriu 
Date: Sat, 9 Mar 2024 12:18:37 -0800
Subject: [PATCH 81/84] Updated changelog, common core to dev

---
 CHANGELOG.md                           | 2 +-
 MSAL/IdentityCore                      | 2 +-
 MSAL/src/MSALPublicClientApplication.m | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d5b5243a01..80dca51454 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,5 @@
 ## [1.3.1]
-* Add support for QR+PIN (#1929)
+* Preferred auth method added to device information, returned from broker
 
 ## [1.3.0]
 
diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 51f4013c49..9dd0ce8d4f 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 51f4013c498dbdd913bce184ce0960526fc35225
+Subproject commit 9dd0ce8d4fd03fb1a5aab319b25d3f4d5af4879d
diff --git a/MSAL/src/MSALPublicClientApplication.m b/MSAL/src/MSALPublicClientApplication.m
index a6292565dc..0371cf430d 100644
--- a/MSAL/src/MSALPublicClientApplication.m
+++ b/MSAL/src/MSALPublicClientApplication.m
@@ -1186,7 +1186,7 @@ - (void)acquireTokenWithParameters:(MSALInteractiveTokenParameters *)parameters
     // Private enum value for QR+PIN
     if (parameters.preferredAuthMethod == 1)
     {
-        NSMutableDictionary *extraAuthorizeURLQueryParameters = [msidParams.extraAuthorizeURLQueryParameters mutableCopy];;
+        NSMutableDictionary *extraAuthorizeURLQueryParameters = [msidParams.extraAuthorizeURLQueryParameters mutableCopy];
         [extraAuthorizeURLQueryParameters setObject:MSID_PREFERRED_AUTH_METHOD_QR_PIN forKey:MSID_PREFERRED_AUTH_METHOD_KEY];
         msidParams.extraAuthorizeURLQueryParameters = extraAuthorizeURLQueryParameters;
     }

From 8dfe40dbb81c975f88e6e53fc545eb381c981c3b Mon Sep 17 00:00:00 2001
From: mipetriu 
Date: Mon, 11 Mar 2024 09:29:06 -0700
Subject: [PATCH 82/84] Updated common core to release branch and update
 versions

---
 MSAL.podspec                  | 2 +-
 MSAL/IdentityCore             | 2 +-
 MSAL/resources/ios/Info.plist | 2 +-
 MSAL/resources/mac/Info.plist | 2 +-
 MSAL/src/MSAL_Internal.h      | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/MSAL.podspec b/MSAL.podspec
index 94f14b6787..2fe8cb9ec1 100644
--- a/MSAL.podspec
+++ b/MSAL.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name         = "MSAL"
-  s.version      = "1.3.0"
+  s.version      = "1.3.1"
   s.summary      = "Microsoft Authentication Library (MSAL) for iOS"
   s.description  = <<-DESC
                    The MSAL library for iOS gives your app the ability to begin using the Microsoft Cloud by supporting Microsoft Azure Active Directory and Microsoft Accounts in a converged experience using industry standard OAuth2 and OpenID Connect. The library also supports Microsoft Azure B2C for those using our hosted identity management service.
diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index 9dd0ce8d4f..e2f6965553 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit 9dd0ce8d4fd03fb1a5aab319b25d3f4d5af4879d
+Subproject commit e2f6965553a5cf645d5f1cc4eaa2b5cba256433b
diff --git a/MSAL/resources/ios/Info.plist b/MSAL/resources/ios/Info.plist
index 18065b543d..9f9016aec0 100644
--- a/MSAL/resources/ios/Info.plist
+++ b/MSAL/resources/ios/Info.plist
@@ -15,7 +15,7 @@
 	CFBundlePackageType
 	FMWK
 	CFBundleShortVersionString
-	1.3.0
+	1.3.1
 	CFBundleVersion
 	$(CURRENT_PROJECT_VERSION)
 	NSPrincipalClass
diff --git a/MSAL/resources/mac/Info.plist b/MSAL/resources/mac/Info.plist
index 423560ac00..48e80a7a11 100644
--- a/MSAL/resources/mac/Info.plist
+++ b/MSAL/resources/mac/Info.plist
@@ -15,7 +15,7 @@
 	CFBundlePackageType
 	FMWK
 	CFBundleShortVersionString
-	1.3.0
+	1.3.1
 	CFBundleVersion
 	$(CURRENT_PROJECT_VERSION)
 	NSHumanReadableCopyright
diff --git a/MSAL/src/MSAL_Internal.h b/MSAL/src/MSAL_Internal.h
index 69cd760878..1fbddfd9eb 100644
--- a/MSAL/src/MSAL_Internal.h
+++ b/MSAL/src/MSAL_Internal.h
@@ -27,7 +27,7 @@
 
 #define MSAL_VER_HIGH       1
 #define MSAL_VER_LOW        3
-#define MSAL_VER_PATCH      0
+#define MSAL_VER_PATCH      1
 
 #define STR_HELPER(x) #x
 #define STR(x) STR_HELPER(x)

From 220bdfabca8e5823a55d77cc5b1e14ceee155cd7 Mon Sep 17 00:00:00 2001
From: mipetriu 
Date: Wed, 13 Mar 2024 14:02:42 -0700
Subject: [PATCH 83/84] Update common core to main

---
 MSAL/IdentityCore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore
index e2f6965553..8b5a08a636 160000
--- a/MSAL/IdentityCore
+++ b/MSAL/IdentityCore
@@ -1 +1 @@
-Subproject commit e2f6965553a5cf645d5f1cc4eaa2b5cba256433b
+Subproject commit 8b5a08a636490e96f3e57ce10b8e35d8a28c7aab

From 26efb029d3ebc418d6f165461b304d767ae0ec6a Mon Sep 17 00:00:00 2001
From: mipetriu 
Date: Wed, 13 Mar 2024 14:36:45 -0700
Subject: [PATCH 84/84] Missed 2 merge conflict files, fixed

---
 .../public/MSALNativeAuthUserAccountResult.swift    |  6 ------
 .../error/RetrieveAccessTokenError.swift            | 13 -------------
 2 files changed, 19 deletions(-)

diff --git a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift
index 73bdb90cd7..960a4f5c1f 100644
--- a/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift
+++ b/MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift
@@ -86,15 +86,9 @@ import Foundation
             let delegateDispatcher = CredentialsDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate)
 
             switch controllerResponse.result {
-<<<<<<< HEAD
             case .success(let accessTokenResult):
                 await delegateDispatcher.dispatchAccessTokenRetrieveCompleted(
                     result: accessTokenResult,
-=======
-            case .success(let accessToken):
-                await delegateDispatcher.dispatchAccessTokenRetrieveCompleted(
-                    accessToken: accessToken,
->>>>>>> main
                     correlationId: controllerResponse.correlationId
                 )
             case .failure(let error):
diff --git a/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift b/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift
index f224a9e2ed..32c44f30c8 100644
--- a/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift
+++ b/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift
@@ -51,11 +51,6 @@ public class RetrieveAccessTokenError: MSALNativeAuthError {
             return MSALNativeAuthErrorMessage.browserRequired
         case .refreshTokenExpired:
             return MSALNativeAuthErrorMessage.refreshTokenExpired
-<<<<<<< HEAD
-=======
-        case .tokenNotFound:
-            return MSALNativeAuthErrorMessage.tokenNotFound
->>>>>>> main
         case .generalError:
             return MSALNativeAuthErrorMessage.generalError
         }
@@ -70,12 +65,4 @@ public class RetrieveAccessTokenError: MSALNativeAuthError {
     public var isRefreshTokenExpired: Bool {
         return type == .refreshTokenExpired
     }
-<<<<<<< HEAD
-=======
-
-    /// Returns `true` if the existing token cannot be found.
-    public var isTokenNotFound: Bool {
-        return type == .tokenNotFound
-    }
->>>>>>> main
 }