diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index a327a541dd..227cbe0115 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -308,7 +308,7 @@ 28B28B832C6F46E50030D5C5 /* MFAStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B28B822C6F46E50030D5C5 /* MFAStates.swift */; }; 28B28B8C2C6F4B570030D5C5 /* MFADelegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B28B8B2C6F4B570030D5C5 /* MFADelegates.swift */; }; 28B28B922C6F611F0030D5C5 /* MSALAuthMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B28B912C6F611F0030D5C5 /* MSALAuthMethod.swift */; }; - 28B6494D2A0959EB00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B6494A2A0959DC00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTest.swift */; }; + 28B6494D2A0959EB00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B6494A2A0959DC00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTests.swift */; }; 28BBB7CE2C80C5740055AF64 /* MSALNativeAuthLogMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28BBB7CD2C80C5740055AF64 /* MSALNativeAuthLogMessage.swift */; }; 28CA6F5D29689F34004DB11D /* MSALNativeAuthCacheAccessorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28CA6F5429689F26004DB11D /* MSALNativeAuthCacheAccessorTest.swift */; }; 28D1D57029BF62E900CE75F4 /* MSAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D65A6F431E3FD30A00C69FBA /* MSAL.framework */; }; @@ -1097,6 +1097,42 @@ DE6BF32D2C419325000BB2D9 /* libIdentityAutomationTestLib Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B21FA9BE2204DC5700806B68 /* libIdentityAutomationTestLib Mac.a */; }; DE729ECD2A1793A100A761D9 /* MSALNativeAuthChannelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE729ECC2A1793A100A761D9 /* MSALNativeAuthChannelType.swift */; }; DE87DE6A2A39E80B0032BF9E /* MSALNativeAuthUserAccountResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE87DE692A39E80B0032BF9E /* MSALNativeAuthUserAccountResultTests.swift */; }; + DE8973E62DA523BD00C67203 /* MSALNativeAuthJITIntrospectRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8973E52DA523B000C67203 /* MSALNativeAuthJITIntrospectRequestParameters.swift */; }; + DE8973E72DA523BD00C67203 /* MSALNativeAuthJITIntrospectRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8973E52DA523B000C67203 /* MSALNativeAuthJITIntrospectRequestParameters.swift */; }; + DE8973EE2DA5251400C67203 /* MSALNativeAuthJITContinueRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8973ED2DA5251400C67203 /* MSALNativeAuthJITContinueRequestParameters.swift */; }; + DE8973EF2DA5251400C67203 /* MSALNativeAuthJITChallengeRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8973EC2DA5251400C67203 /* MSALNativeAuthJITChallengeRequestParameters.swift */; }; + DE8973F02DA5251400C67203 /* MSALNativeAuthJITContinueRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8973ED2DA5251400C67203 /* MSALNativeAuthJITContinueRequestParameters.swift */; }; + DE8973F12DA5251400C67203 /* MSALNativeAuthJITChallengeRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8973EC2DA5251400C67203 /* MSALNativeAuthJITChallengeRequestParameters.swift */; }; + DE8973F32DA5256000C67203 /* MSALNativeAuthJITRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8973F22DA5256000C67203 /* MSALNativeAuthJITRequestProvider.swift */; }; + DE8973F42DA5256000C67203 /* MSALNativeAuthJITRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8973F22DA5256000C67203 /* MSALNativeAuthJITRequestProvider.swift */; }; + DE8973FA2DA5274000C67203 /* MSALNativeAuthJITIntrospectResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8973F82DA5274000C67203 /* MSALNativeAuthJITIntrospectResponse.swift */; }; + DE8973FB2DA5274000C67203 /* MSALNativeAuthJITContinueResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8973F72DA5274000C67203 /* MSALNativeAuthJITContinueResponse.swift */; }; + DE8973FD2DA5274000C67203 /* MSALNativeAuthJITChallengeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8973F62DA5274000C67203 /* MSALNativeAuthJITChallengeResponse.swift */; }; + DE8973FE2DA5274000C67203 /* MSALNativeAuthJITIntrospectResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8973F82DA5274000C67203 /* MSALNativeAuthJITIntrospectResponse.swift */; }; + DE8973FF2DA5274000C67203 /* MSALNativeAuthJITContinueResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8973F72DA5274000C67203 /* MSALNativeAuthJITContinueResponse.swift */; }; + DE8974012DA5274000C67203 /* MSALNativeAuthJITChallengeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8973F62DA5274000C67203 /* MSALNativeAuthJITChallengeResponse.swift */; }; + DE8974092DA52BE800C67203 /* MSALNativeAuthJITIntrospectOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974062DA52BE800C67203 /* MSALNativeAuthJITIntrospectOauth2ErrorCode.swift */; }; + DE89740A2DA52BE800C67203 /* MSALNativeAuthJITContinueOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974042DA52BE800C67203 /* MSALNativeAuthJITContinueOauth2ErrorCode.swift */; }; + DE89740B2DA52BE800C67203 /* MSALNativeAuthJITChallengeResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974032DA52BE800C67203 /* MSALNativeAuthJITChallengeResponseError.swift */; }; + DE89740C2DA52BE800C67203 /* MSALNativeAuthJITIntrospectResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974072DA52BE800C67203 /* MSALNativeAuthJITIntrospectResponseError.swift */; }; + DE89740D2DA52BE800C67203 /* MSALNativeAuthJITChallengeOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974022DA52BE800C67203 /* MSALNativeAuthJITChallengeOauth2ErrorCode.swift */; }; + DE89740E2DA52BE800C67203 /* MSALNativeAuthJITContinueResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974052DA52BE800C67203 /* MSALNativeAuthJITContinueResponseError.swift */; }; + DE89740F2DA52BE800C67203 /* MSALNativeAuthJITIntrospectOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974062DA52BE800C67203 /* MSALNativeAuthJITIntrospectOauth2ErrorCode.swift */; }; + DE8974102DA52BE800C67203 /* MSALNativeAuthJITContinueOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974042DA52BE800C67203 /* MSALNativeAuthJITContinueOauth2ErrorCode.swift */; }; + DE8974112DA52BE800C67203 /* MSALNativeAuthJITChallengeResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974032DA52BE800C67203 /* MSALNativeAuthJITChallengeResponseError.swift */; }; + DE8974122DA52BE800C67203 /* MSALNativeAuthJITIntrospectResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974072DA52BE800C67203 /* MSALNativeAuthJITIntrospectResponseError.swift */; }; + DE8974132DA52BE800C67203 /* MSALNativeAuthJITChallengeOauth2ErrorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974022DA52BE800C67203 /* MSALNativeAuthJITChallengeOauth2ErrorCode.swift */; }; + DE8974142DA52BE800C67203 /* MSALNativeAuthJITContinueResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974052DA52BE800C67203 /* MSALNativeAuthJITContinueResponseError.swift */; }; + DE8974282DA56FEF00C67203 /* MSALNativeAuthJITIntrospectValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974242DA56FEF00C67203 /* MSALNativeAuthJITIntrospectValidatedResponse.swift */; }; + DE8974292DA56FEF00C67203 /* MSALNativeAuthJITChallengeValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974222DA56FEF00C67203 /* MSALNativeAuthJITChallengeValidatedResponse.swift */; }; + DE89742A2DA56FEF00C67203 /* MSALNativeAuthJITContinueValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974232DA56FEF00C67203 /* MSALNativeAuthJITContinueValidatedResponse.swift */; }; + DE89742B2DA56FEF00C67203 /* MSALNativeAuthJITResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974262DA56FEF00C67203 /* MSALNativeAuthJITResponseValidator.swift */; }; + DE89742C2DA56FEF00C67203 /* MSALNativeAuthJITIntrospectValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974242DA56FEF00C67203 /* MSALNativeAuthJITIntrospectValidatedResponse.swift */; }; + DE89742D2DA56FEF00C67203 /* MSALNativeAuthJITChallengeValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974222DA56FEF00C67203 /* MSALNativeAuthJITChallengeValidatedResponse.swift */; }; + DE89742E2DA56FEF00C67203 /* MSALNativeAuthJITContinueValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974232DA56FEF00C67203 /* MSALNativeAuthJITContinueValidatedResponse.swift */; }; + DE89742F2DA56FEF00C67203 /* MSALNativeAuthJITResponseValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974262DA56FEF00C67203 /* MSALNativeAuthJITResponseValidator.swift */; }; + DE8974922DA6DE4400C67203 /* MSALNativeAuthJITResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974912DA6DE2600C67203 /* MSALNativeAuthJITResponseValidatorTests.swift */; }; + DE8974932DA6DE4400C67203 /* MSALNativeAuthJITResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8974912DA6DE2600C67203 /* MSALNativeAuthJITResponseValidatorTests.swift */; }; DE8BE7DC2A1F6BD2009642A5 /* MSALNativeAuthUserAccountResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8BE7DB2A1F6BD2009642A5 /* MSALNativeAuthUserAccountResult.swift */; }; DE8DC4512C66218900534E8F /* MSALNativeAuthInternalError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E206FC5E296D65DE00AF4400 /* MSALNativeAuthInternalError.swift */; }; DE8DC4592C66218C00534E8F /* MSALNativeAuthCacheAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289E156C2948EB8A006104D9 /* MSALNativeAuthCacheAccessor.swift */; }; @@ -1335,7 +1371,7 @@ DE8DC5512C66221000534E8F /* MSALNativeAuthTokenResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE54B59C2A44521E00460B34 /* MSALNativeAuthTokenResponseValidatorTests.swift */; }; DE8DC5522C66221000534E8F /* MSALNativeAuthResetPasswordResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B6EECEE2A3146ED008ABA50 /* MSALNativeAuthResetPasswordResponseValidatorTests.swift */; }; DE8DC5532C66221000534E8F /* MSALNativeAuthSignUpResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22952672A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift */; }; - DE8DC5542C66221000534E8F /* MSALNativeAuthSignInResponseValidatorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B6494A2A0959DC00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTest.swift */; }; + DE8DC5542C66221000534E8F /* MSALNativeAuthSignInResponseValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B6494A2A0959DC00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTests.swift */; }; DE8DC5552C66221000534E8F /* MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2BBA2D2A3292400075F702 /* MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift */; }; DE8DC5562C66221300534E8F /* MSALNativeAuthSignUpContinueRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BC029B29D766CB00041DBC /* MSALNativeAuthSignUpContinueRequestParametersTest.swift */; }; DE8DC5572C66221300534E8F /* MSALNativeAuthSignUpChallengeRequestParametersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BC029729D766A800041DBC /* MSALNativeAuthSignUpChallengeRequestParametersTest.swift */; }; @@ -1447,6 +1483,12 @@ DEE34F8DD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F8BD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponseError.swift */; }; DEE34F96D170B71C00BC302A /* MSALNativeAuthRequiredAttributeInternal.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34F95D170B71C00BC302A /* MSALNativeAuthRequiredAttributeInternal.swift */; }; DEE34FA1D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE34FA0D170B71C00BC302A /* MSALNativeAuthResetPasswordRequestProvider.swift */; }; + DEEFCE852DB106F300237F5A /* MSALNativeAuthJITChallengeIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEEFCE842DB106F300237F5A /* MSALNativeAuthJITChallengeIntegrationTests.swift */; }; + DEEFCE862DB106F300237F5A /* MSALNativeAuthJITChallengeIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEEFCE842DB106F300237F5A /* MSALNativeAuthJITChallengeIntegrationTests.swift */; }; + DEEFCF192DB15B1400237F5A /* MSALNativeAuthJITContinueIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEEFCF182DB15B1400237F5A /* MSALNativeAuthJITContinueIntegrationTests.swift */; }; + DEEFCF1A2DB15B1400237F5A /* MSALNativeAuthJITIntrospectIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEEFCF172DB15B1400237F5A /* MSALNativeAuthJITIntrospectIntegrationTests.swift */; }; + DEEFCF1B2DB15B1400237F5A /* MSALNativeAuthJITContinueIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEEFCF182DB15B1400237F5A /* MSALNativeAuthJITContinueIntegrationTests.swift */; }; + DEEFCF1C2DB15B1400237F5A /* MSALNativeAuthJITIntrospectIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEEFCF172DB15B1400237F5A /* MSALNativeAuthJITIntrospectIntegrationTests.swift */; }; DEF1DD322AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF1DD312AA9CBC300D22194 /* MSALNativeAuthESTSApiErrorDescriptions.swift */; }; DEF1DD3C2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF1DD3B2AA9D07000D22194 /* MSALNativeAuthESTSApiErrorDescriptionsTests.swift */; }; DEF9D989296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF9D988296EC26A006CB384 /* MSALNativeAuthCurrentRequestTelemetry.swift */; }; @@ -2082,7 +2124,7 @@ 28B28B822C6F46E50030D5C5 /* MFAStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFAStates.swift; sourceTree = ""; }; 28B28B8B2C6F4B570030D5C5 /* MFADelegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFADelegates.swift; sourceTree = ""; }; 28B28B912C6F611F0030D5C5 /* MSALAuthMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALAuthMethod.swift; sourceTree = ""; }; - 28B6494A2A0959DC00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInResponseValidatorTest.swift; sourceTree = ""; }; + 28B6494A2A0959DC00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInResponseValidatorTests.swift; sourceTree = ""; }; 28BBB7CD2C80C5740055AF64 /* MSALNativeAuthLogMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthLogMessage.swift; sourceTree = ""; }; 28CA6F5429689F26004DB11D /* MSALNativeAuthCacheAccessorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCacheAccessorTest.swift; sourceTree = ""; }; 28CED2E82C21E0F9004320D1 /* MSAL iOS Native Auth E2E Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "MSAL iOS Native Auth E2E Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2530,6 +2572,24 @@ DE729ECC2A1793A100A761D9 /* MSALNativeAuthChannelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthChannelType.swift; sourceTree = ""; }; DE869DCD2C4179FA000EF487 /* NativeAuthEndToEndTestPlan Mac.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "NativeAuthEndToEndTestPlan Mac.xctestplan"; sourceTree = ""; }; DE87DE692A39E80B0032BF9E /* MSALNativeAuthUserAccountResultTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthUserAccountResultTests.swift; sourceTree = ""; }; + DE8973E52DA523B000C67203 /* MSALNativeAuthJITIntrospectRequestParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITIntrospectRequestParameters.swift; sourceTree = ""; }; + DE8973EC2DA5251400C67203 /* MSALNativeAuthJITChallengeRequestParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITChallengeRequestParameters.swift; sourceTree = ""; }; + DE8973ED2DA5251400C67203 /* MSALNativeAuthJITContinueRequestParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITContinueRequestParameters.swift; sourceTree = ""; }; + DE8973F22DA5256000C67203 /* MSALNativeAuthJITRequestProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITRequestProvider.swift; sourceTree = ""; }; + DE8973F62DA5274000C67203 /* MSALNativeAuthJITChallengeResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITChallengeResponse.swift; sourceTree = ""; }; + DE8973F72DA5274000C67203 /* MSALNativeAuthJITContinueResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITContinueResponse.swift; sourceTree = ""; }; + DE8973F82DA5274000C67203 /* MSALNativeAuthJITIntrospectResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITIntrospectResponse.swift; sourceTree = ""; }; + DE8974022DA52BE800C67203 /* MSALNativeAuthJITChallengeOauth2ErrorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITChallengeOauth2ErrorCode.swift; sourceTree = ""; }; + DE8974032DA52BE800C67203 /* MSALNativeAuthJITChallengeResponseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITChallengeResponseError.swift; sourceTree = ""; }; + DE8974042DA52BE800C67203 /* MSALNativeAuthJITContinueOauth2ErrorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITContinueOauth2ErrorCode.swift; sourceTree = ""; }; + DE8974052DA52BE800C67203 /* MSALNativeAuthJITContinueResponseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITContinueResponseError.swift; sourceTree = ""; }; + DE8974062DA52BE800C67203 /* MSALNativeAuthJITIntrospectOauth2ErrorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITIntrospectOauth2ErrorCode.swift; sourceTree = ""; }; + DE8974072DA52BE800C67203 /* MSALNativeAuthJITIntrospectResponseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITIntrospectResponseError.swift; sourceTree = ""; }; + DE8974222DA56FEF00C67203 /* MSALNativeAuthJITChallengeValidatedResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITChallengeValidatedResponse.swift; sourceTree = ""; }; + DE8974232DA56FEF00C67203 /* MSALNativeAuthJITContinueValidatedResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITContinueValidatedResponse.swift; sourceTree = ""; }; + DE8974242DA56FEF00C67203 /* MSALNativeAuthJITIntrospectValidatedResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITIntrospectValidatedResponse.swift; sourceTree = ""; }; + DE8974262DA56FEF00C67203 /* MSALNativeAuthJITResponseValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITResponseValidator.swift; sourceTree = ""; }; + DE8974912DA6DE2600C67203 /* MSALNativeAuthJITResponseValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITResponseValidatorTests.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 = ""; }; @@ -2586,6 +2646,9 @@ DEE34F8BD170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordPollCompletionResponseError.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 = ""; }; + DEEFCE842DB106F300237F5A /* MSALNativeAuthJITChallengeIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITChallengeIntegrationTests.swift; sourceTree = ""; }; + DEEFCF172DB15B1400237F5A /* MSALNativeAuthJITIntrospectIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITIntrospectIntegrationTests.swift; sourceTree = ""; }; + DEEFCF182DB15B1400237F5A /* MSALNativeAuthJITContinueIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthJITContinueIntegrationTests.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 = ""; }; @@ -3121,10 +3184,11 @@ 28B649492A0959B800EF3DB7 /* validator */ = { isa = PBXGroup; children = ( + DE8974912DA6DE2600C67203 /* MSALNativeAuthJITResponseValidatorTests.swift */, DE5738B32A8E74DC00D9120D /* MSALNativeAuthSignInInitiateValidatedErrorTypeTests.swift */, DE5738B52A8E790100D9120D /* MSALNativeAuthTokenValidatedErrorTypeTests.swift */, 9B2BBA2D2A3292400075F702 /* MSALNativeAuthResetPasswordStartValidatedErrorTypeTests.swift */, - 28B6494A2A0959DC00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTest.swift */, + 28B6494A2A0959DC00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTests.swift */, E22952672A1A4FCB00EDD58C /* MSALNativeAuthSignUpResponseValidatorTests.swift */, 9B6EECEE2A3146ED008ABA50 /* MSALNativeAuthResetPasswordResponseValidatorTests.swift */, DE54B59C2A44521E00460B34 /* MSALNativeAuthTokenResponseValidatorTests.swift */, @@ -3245,6 +3309,7 @@ isa = PBXGroup; children = ( 28F19BE12A2F4A0100575581 /* sign_in */, + DE8974272DA56FEF00C67203 /* jit */, E2B8532D2A153287007A4776 /* sign_up */, 9B6EECE62A31467E008ABA50 /* reset_password */, DE54B5972A44431C00460B34 /* token */, @@ -4252,6 +4317,7 @@ DE0D65C429D344AC005798B1 /* requests */ = { isa = PBXGroup; children = ( + DEEFCE832DB106A700237F5A /* jit */, E243F6AC29D4424D00DAC60F /* sign_up */, DEDB29AE29DDC04A008DA85B /* sign_in */, DE8EC8762A026C2E003FA561 /* reset_password */, @@ -4265,6 +4331,7 @@ children = ( 28DE70CD29FAC14500EB75AA /* validator */, DEDB29A029DDA18F008DA85B /* sign_in */, + DE8973F92DA5274000C67203 /* jit */, E243F69229D1973900DAC60F /* sign_up */, DEE34F51D170B71C00BC302A /* reset_password */, DE0FECAA2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift */, @@ -4336,6 +4403,66 @@ path = token; sourceTree = ""; }; + DE8973E42DA5237D00C67203 /* jit */ = { + isa = PBXGroup; + children = ( + DE8973E52DA523B000C67203 /* MSALNativeAuthJITIntrospectRequestParameters.swift */, + DE8973EC2DA5251400C67203 /* MSALNativeAuthJITChallengeRequestParameters.swift */, + DE8973ED2DA5251400C67203 /* MSALNativeAuthJITContinueRequestParameters.swift */, + ); + path = jit; + sourceTree = ""; + }; + DE8973EB2DA5245F00C67203 /* jit */ = { + isa = PBXGroup; + children = ( + DE8973F22DA5256000C67203 /* MSALNativeAuthJITRequestProvider.swift */, + ); + path = jit; + sourceTree = ""; + }; + DE8973F92DA5274000C67203 /* jit */ = { + isa = PBXGroup; + children = ( + DE8973F82DA5274000C67203 /* MSALNativeAuthJITIntrospectResponse.swift */, + DE8973F62DA5274000C67203 /* MSALNativeAuthJITChallengeResponse.swift */, + DE8973F72DA5274000C67203 /* MSALNativeAuthJITContinueResponse.swift */, + ); + path = jit; + sourceTree = ""; + }; + DE8974082DA52BE800C67203 /* jit */ = { + isa = PBXGroup; + children = ( + DE8974062DA52BE800C67203 /* MSALNativeAuthJITIntrospectOauth2ErrorCode.swift */, + DE8974072DA52BE800C67203 /* MSALNativeAuthJITIntrospectResponseError.swift */, + DE8974022DA52BE800C67203 /* MSALNativeAuthJITChallengeOauth2ErrorCode.swift */, + DE8974032DA52BE800C67203 /* MSALNativeAuthJITChallengeResponseError.swift */, + DE8974042DA52BE800C67203 /* MSALNativeAuthJITContinueOauth2ErrorCode.swift */, + DE8974052DA52BE800C67203 /* MSALNativeAuthJITContinueResponseError.swift */, + ); + path = jit; + sourceTree = ""; + }; + DE8974252DA56FEF00C67203 /* validated_response */ = { + isa = PBXGroup; + children = ( + DE8974242DA56FEF00C67203 /* MSALNativeAuthJITIntrospectValidatedResponse.swift */, + DE8974222DA56FEF00C67203 /* MSALNativeAuthJITChallengeValidatedResponse.swift */, + DE8974232DA56FEF00C67203 /* MSALNativeAuthJITContinueValidatedResponse.swift */, + ); + path = validated_response; + sourceTree = ""; + }; + DE8974272DA56FEF00C67203 /* jit */ = { + isa = PBXGroup; + children = ( + DE8974252DA56FEF00C67203 /* validated_response */, + DE8974262DA56FEF00C67203 /* MSALNativeAuthJITResponseValidator.swift */, + ); + path = jit; + sourceTree = ""; + }; DE8EC86B2A026BA0003FA561 /* sign_in */ = { isa = PBXGroup; children = ( @@ -4445,6 +4572,7 @@ E2025CC82B2A182200E32871 /* MSALNativeAuthSubErrorCode.swift */, E2C61FD829DECE8900F15203 /* sign_up */, DEDB29A329DDA99C008DA85B /* sign_in */, + DE8974082DA52BE800C67203 /* jit */, DEE34F5DD170B71C00BC302A /* reset_password */, DE54B5A02A44601500460B34 /* token */, ); @@ -4458,8 +4586,8 @@ DEDB29A429DDA9DC008DA85B /* MSALNativeAuthSignInInitiateResponseError.swift */, DEDB29A629DDAEB3008DA85B /* MSALNativeAuthSignInChallengeOauth2ErrorCode.swift */, DEDB29AA29DDAF52008DA85B /* MSALNativeAuthSignInChallengeResponseError.swift */, - 285F58602C5BC1EC00F4EFA4 /* MSALNativeAuthSignInIntrospectResponseError.swift */, 285F58622C5BC67900F4EFA4 /* MSALNativeAuthSignInIntrospectOauth2ErrorCode.swift */, + 285F58602C5BC1EC00F4EFA4 /* MSALNativeAuthSignInIntrospectResponseError.swift */, ); path = sign_in; sourceTree = ""; @@ -4535,6 +4663,16 @@ path = reset_password; sourceTree = ""; }; + DEEFCE832DB106A700237F5A /* jit */ = { + isa = PBXGroup; + children = ( + DEEFCF172DB15B1400237F5A /* MSALNativeAuthJITIntrospectIntegrationTests.swift */, + DEEFCE842DB106F300237F5A /* MSALNativeAuthJITChallengeIntegrationTests.swift */, + DEEFCF182DB15B1400237F5A /* MSALNativeAuthJITContinueIntegrationTests.swift */, + ); + path = jit; + sourceTree = ""; + }; DEFB46E12A52B9B800DBC006 /* reset_password */ = { isa = PBXGroup; children = ( @@ -4897,6 +5035,7 @@ children = ( E243F6A829D42F7800DAC60F /* sign_up */, DE8EC86B2A026BA0003FA561 /* sign_in */, + DE8973EB2DA5245F00C67203 /* jit */, DEE34F9FD170B71C00BC302A /* reset_password */, DE0347952A3B20B2003CB3B6 /* token */, E2ACA47A29520C2200E98964 /* MSALNativeAuthEndpoint.swift */, @@ -4922,6 +5061,7 @@ children = ( E235612F29C9CE81000E01CA /* sign_up */, E2C6201E29E038DB00F15203 /* sign_in */, + DE8973E42DA5237D00C67203 /* jit */, DEE34F10D170B71C00BC302A /* reset_password */, E2C872C2294CDEE800C4F580 /* MSALNativeAuthRequestable.swift */, E2ACA48A2952302B00E98964 /* MSALNativeAuthRequestContext.swift */, @@ -6472,8 +6612,11 @@ 28D1D58029BF883D00CE75F4 /* MSALNativeAuthIntegrationBaseTests.swift in Sources */, DE8EC8A92A026FE7003FA561 /* MSALNativeAuthResetPasswordPollCompletionIntegrationTests.swift in Sources */, DE8EC8AA2A026FEA003FA561 /* MSALNativeAuthResetPasswordStartIntegrationTests.swift in Sources */, + DEEFCE852DB106F300237F5A /* MSALNativeAuthJITChallengeIntegrationTests.swift in Sources */, DE8EC8AB2A026FEC003FA561 /* MSALNativeAuthResetPasswordContinueIntegrationTests.swift in Sources */, DE0D65CD29D5CE56005798B1 /* MSALNativeAuthSignInChallengeIntegrationTests.swift in Sources */, + DEEFCF1B2DB15B1400237F5A /* MSALNativeAuthJITContinueIntegrationTests.swift in Sources */, + DEEFCF1C2DB15B1400237F5A /* MSALNativeAuthJITIntrospectIntegrationTests.swift in Sources */, E243F6AF29D446FC00DAC60F /* MSALNativeAuthSignUpStartIntegrationTests.swift in Sources */, E2BC027529D6E0C600041DBC /* MSALNativeAuthSignUpContinueIntegrationTests.swift in Sources */, E23E955F29D4B9F7001DC59C /* MSALNativeAuthSignUpChallengeIntegrationTests.swift in Sources */, @@ -6665,6 +6808,10 @@ DEE34F7BD170B71C00BC302A /* MSALNativeAuthResetPasswordContinueOauth2ErrorCode.swift in Sources */, DEE34F7FD170B71C00BC302A /* MSALNativeAuthResetPasswordSubmitResponse.swift in Sources */, E284F5D929F28B4200DBED7D /* MSALNativeAuthSignUpController.swift in Sources */, + DE89742C2DA56FEF00C67203 /* MSALNativeAuthJITIntrospectValidatedResponse.swift in Sources */, + DE89742D2DA56FEF00C67203 /* MSALNativeAuthJITChallengeValidatedResponse.swift in Sources */, + DE89742E2DA56FEF00C67203 /* MSALNativeAuthJITContinueValidatedResponse.swift in Sources */, + DE89742F2DA56FEF00C67203 /* MSALNativeAuthJITResponseValidator.swift in Sources */, E2CD2E8D2A015C54009F8FFA /* MSALNativeAuthSignUpResponseValidator.swift in Sources */, 28DCD0A229D7272300C4601E /* SignInDelegates.swift in Sources */, 1EE776C0246C98D300F7EBFC /* MSALAuthenticationSchemeBearer.m in Sources */, @@ -6677,6 +6824,7 @@ E284F5E429F2F28A00DBED7D /* MSALNativeAuthSignUpControlling.swift in Sources */, DE0FECAC2993AD3700B139A8 /* MSALNativeAuthResendCodeRequestResponse.swift in Sources */, 23A68A7C20F538B90071E435 /* MSALB2CAuthority.m in Sources */, + DE8973E62DA523BD00C67203 /* MSALNativeAuthJITIntrospectRequestParameters.swift in Sources */, DEE34F48D170B71C00BC302A /* MSALNativeAuthResultFactory.swift in Sources */, 6077D4A922498D87001798A2 /* MSALTenantProfile.m in Sources */, 9B9D05E82B4FFBEC00024E6E /* MSALNativeAuthCacheAccessorFactory.swift in Sources */, @@ -6767,6 +6915,7 @@ DEE34F73D170B71C00BC302A /* MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift in Sources */, DEDB29A829DDAEB3008DA85B /* MSALNativeAuthSignInChallengeOauth2ErrorCode.swift in Sources */, DE03478A2A39ED6A003CB3B6 /* MSALCIAMOauth2Provider.m in Sources */, + DE8973F32DA5256000C67203 /* MSALNativeAuthJITRequestProvider.swift in Sources */, E205D62E29B783FF003887BC /* MSALNativeAuthConfiguration.swift in Sources */, D61BD2B21EBD09F90007E484 /* MSALAccount.m in Sources */, DE0D65B629CC6BBA005798B1 /* MSALNativeAuthSignInChallengeResponse.swift in Sources */, @@ -6775,6 +6924,9 @@ E2EFAD092A69A34300D6C3DE /* CodeRequiredGenericResult.swift in Sources */, E2EFAD0C2A69B45100D6C3DE /* SignUpResults.swift in Sources */, 289E44B62C9D7B0900F6B9D7 /* MFAGetAuthMethodsError.swift in Sources */, + DE8973FA2DA5274000C67203 /* MSALNativeAuthJITIntrospectResponse.swift in Sources */, + DE8973FB2DA5274000C67203 /* MSALNativeAuthJITContinueResponse.swift in Sources */, + DE8973FD2DA5274000C67203 /* MSALNativeAuthJITChallengeResponse.swift in Sources */, DE0D65AC29CC6A5A005798B1 /* MSALNativeAuthSignInInitiateResponse.swift in Sources */, B266391C22B4B84600FEB673 /* NSString+MSALAccountIdenfiers.m in Sources */, DEE34F87D170B71C00BC302A /* MSALNativeAuthResetPasswordPollCompletionResponse.swift in Sources */, @@ -6815,6 +6967,8 @@ D61BD2B31EBD09F90007E484 /* MSALPromptType.m in Sources */, 28F8D2942D8C5EBF005084FA /* MSALNativeAuthChallengeAuthMethodParameters.swift in Sources */, DEC1E425298BE18A00948BED /* MSALNativeAuthServerTelemetry.swift in Sources */, + DE8973F02DA5251400C67203 /* MSALNativeAuthJITContinueRequestParameters.swift in Sources */, + DE8973F12DA5251400C67203 /* MSALNativeAuthJITChallengeRequestParameters.swift in Sources */, E224F74D2B18FC9C000A7B2E /* SignInAfterPreviousFlowBaseState.swift in Sources */, 9B4EE9D82A1687AE00F243C1 /* MSALNativeAuthResetPasswordResponseValidator.swift in Sources */, 28D811EB2C7602A1002BE1AA /* MFAResults.swift in Sources */, @@ -6847,6 +7001,12 @@ DE43150A2D3E551F009A7FA2 /* MSALNativeAuthGetAccessTokenParameters.swift in Sources */, DE43150B2D3E551F009A7FA2 /* MSALNativeAuthSignInParameters.swift in Sources */, DE43150C2D3E551F009A7FA2 /* MSALNativeAuthSignUpParameters.swift in Sources */, + DE89740F2DA52BE800C67203 /* MSALNativeAuthJITIntrospectOauth2ErrorCode.swift in Sources */, + DE8974102DA52BE800C67203 /* MSALNativeAuthJITContinueOauth2ErrorCode.swift in Sources */, + DE8974112DA52BE800C67203 /* MSALNativeAuthJITChallengeResponseError.swift in Sources */, + DE8974122DA52BE800C67203 /* MSALNativeAuthJITIntrospectResponseError.swift in Sources */, + DE8974132DA52BE800C67203 /* MSALNativeAuthJITChallengeOauth2ErrorCode.swift in Sources */, + DE8974142DA52BE800C67203 /* MSALNativeAuthJITContinueResponseError.swift in Sources */, DE43150D2D3E551F009A7FA2 /* MSALNativeAuthSignInAfterSignUpParameters.swift in Sources */, DE43150E2D3E551F009A7FA2 /* MSALNativeAuthResetPasswordParameters.swift in Sources */, DE43150F2D3E551F009A7FA2 /* MSALNativeAuthSignInAfterResetPasswordParameters .swift in Sources */, @@ -6959,6 +7119,7 @@ DE8DC4C42C6621C500534E8F /* MSALNativeAuthSignInInitiateResponse.swift in Sources */, 28EE65122C8B0E3600015F90 /* MSALNativeAuthSignInIntrospectResponse.swift in Sources */, DE8DC4BD2C6621C100534E8F /* MSALNativeAuthSignUpResponseValidator.swift in Sources */, + DE8973E72DA523BD00C67203 /* MSALNativeAuthJITIntrospectRequestParameters.swift in Sources */, DE8DC48F2C6621A600534E8F /* SignUpDelegates.swift in Sources */, DE8DC4E92C6621D000534E8F /* MSALNativeAuthResetPasswordChallengeOauth2ErrorCode.swift in Sources */, DE8DC48A2C6621A300534E8F /* SignUpStates.swift in Sources */, @@ -7036,8 +7197,15 @@ 28F8D2922D8C5C7E005084FA /* JITStates.swift in Sources */, DE8DC4CF2C6621C900534E8F /* MSALNativeAuthESTSApiErrorDescriptions.swift in Sources */, 96B5E6D12256D152002232F9 /* MSALCacheConfig.m in Sources */, + DE8973FE2DA5274000C67203 /* MSALNativeAuthJITIntrospectResponse.swift in Sources */, + DE8973FF2DA5274000C67203 /* MSALNativeAuthJITContinueResponse.swift in Sources */, + DE8974012DA5274000C67203 /* MSALNativeAuthJITChallengeResponse.swift in Sources */, DE8DC45D2C66219600534E8F /* MSALNativeAuthResetPasswordController.swift in Sources */, DE8DC4DD2C6621CE00534E8F /* MSALNativeAuthSignInInitiateOauth2ErrorCode.swift in Sources */, + DE8974282DA56FEF00C67203 /* MSALNativeAuthJITIntrospectValidatedResponse.swift in Sources */, + DE8974292DA56FEF00C67203 /* MSALNativeAuthJITChallengeValidatedResponse.swift in Sources */, + DE89742A2DA56FEF00C67203 /* MSALNativeAuthJITContinueValidatedResponse.swift in Sources */, + DE89742B2DA56FEF00C67203 /* MSALNativeAuthJITResponseValidator.swift in Sources */, DE8DC4872C6621A300534E8F /* SignInAfterSignUpState.swift in Sources */, DE8DC4DA2C6621CC00534E8F /* MSALNativeAuthSignUpContinueResponseError.swift in Sources */, 232D68DF223DBA0700594BBD /* MSALInteractiveTokenParameters.m in Sources */, @@ -7053,9 +7221,16 @@ 289E44B72C9D7B0900F6B9D7 /* MFAGetAuthMethodsError.swift in Sources */, DE8DC4DB2C6621CC00534E8F /* MSALNativeAuthSignUpStartResponseError.swift in Sources */, DE8DC4E52C6621D000534E8F /* MSALNativeAuthResetPasswordContinueResponseError.swift in Sources */, + DE8974092DA52BE800C67203 /* MSALNativeAuthJITIntrospectOauth2ErrorCode.swift in Sources */, + DE89740A2DA52BE800C67203 /* MSALNativeAuthJITContinueOauth2ErrorCode.swift in Sources */, + DE89740B2DA52BE800C67203 /* MSALNativeAuthJITChallengeResponseError.swift in Sources */, + DE89740C2DA52BE800C67203 /* MSALNativeAuthJITIntrospectResponseError.swift in Sources */, + DE89740D2DA52BE800C67203 /* MSALNativeAuthJITChallengeOauth2ErrorCode.swift in Sources */, + DE89740E2DA52BE800C67203 /* MSALNativeAuthJITContinueResponseError.swift in Sources */, DE8DC4B12C6621B800534E8F /* MSALNativeAuthResetPasswordContinueRequestParameters.swift in Sources */, DE8DC45E2C66219600534E8F /* MSALNativeAuthCredentialsControlling.swift in Sources */, B26756C722921C42000F01D7 /* MSALAADOauth2Provider.m in Sources */, + DE8973F42DA5256000C67203 /* MSALNativeAuthJITRequestProvider.swift in Sources */, DE8DC4772C66219E00534E8F /* SignUpDelegateDispatchers.swift in Sources */, DE8DC4CB2C6621C700534E8F /* MSALNativeAuthResetPasswordContinueResponse.swift in Sources */, 04D32CAF1FD615B3000B123E /* MSALErrorConverter.m in Sources */, @@ -7069,6 +7244,8 @@ B28BBD362211DC7D00F51723 /* MSALPublicClientStatusNotifications.m in Sources */, DE8DC47D2C6621A100534E8F /* PasswordRequiredError.swift in Sources */, D673F0931E4CE6D70018BA91 /* MSALResult.m in Sources */, + DE8973EE2DA5251400C67203 /* MSALNativeAuthJITContinueRequestParameters.swift in Sources */, + DE8973EF2DA5251400C67203 /* MSALNativeAuthJITChallengeRequestParameters.swift in Sources */, 28F8D29B2D8C6615005084FA /* RegisterStrongAuthChallengeError.swift in Sources */, DE8DC4F22C6621D600534E8F /* MSALNativeAuthCurrentRequestTelemetry.swift in Sources */, DE8DC4BA2C6621BD00534E8F /* MSALNativeAuthSignInResponseValidator.swift in Sources */, @@ -7196,7 +7373,7 @@ DE5738C02A8F7C2000D9120D /* MSALNativeAuthSignUpStartResponseErrorTests.swift in Sources */, 233E970B226571AB007FCE2A /* MSALTelemetryAggregatedTests.m in Sources */, B2725ECA22C04661009B454A /* MSALLegacySharedAccountTests.m in Sources */, - 28B6494D2A0959EB00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTest.swift in Sources */, + 28B6494D2A0959EB00EF3DB7 /* MSALNativeAuthSignInResponseValidatorTests.swift in Sources */, DE1560E42CAE8F3F00C85E51 /* MSALNativeAuthSilentTokenProviderFactoryConfigTester.swift in Sources */, B253153B23DD717900432133 /* MSALDeviceInfoProviderTests.m in Sources */, 9B61C91C2A27E57C00CE9E3A /* MSALNativeAuthResetPasswordResponseValidatorMock.swift in Sources */, @@ -7228,6 +7405,7 @@ E20C217E2A7A61CC00E31598 /* ResetPasswordDelegateSpies.swift in Sources */, E2C190752B20DE1100095534 /* SignInAfterResetPasswordDelegateDispatcherTests.swift in Sources */, E22427F82B066F750006C55E /* SignInResendCodeDelegateDispatcherTests.swift in Sources */, + DE8974922DA6DE4400C67203 /* MSALNativeAuthJITResponseValidatorTests.swift in Sources */, E2CE911C2B0BA48D0009AEDD /* RetrieveAccessTokenErrorTests.swift in Sources */, E248917A2A1CFA6B001ECBE2 /* MSALNativeAuthConfigStubs.swift in Sources */, E22427E62B065D0D0006C55E /* SignUpStartDelegateDispatcherTests.swift in Sources */, @@ -7418,6 +7596,7 @@ D69ADB381E516F9B00952049 /* MSALTestCase.m in Sources */, DE8DC5112C6621EA00534E8F /* MSALNativeAuthSignUpResponseValidatorMock.swift in Sources */, DE8DC52E2C6621F800534E8F /* ResendCodeErrorTests.swift in Sources */, + DE8974932DA6DE4400C67203 /* MSALNativeAuthJITResponseValidatorTests.swift in Sources */, 28EE65222C8B109300015F90 /* MFASubmitChallengeErrorTests.swift in Sources */, 04D32CD11FD8AFF3000B123E /* MSALErrorConverterTests.m in Sources */, DE8DC5382C66220000534E8F /* MSALNativeAuthUserAccountResultTests.swift in Sources */, @@ -7425,7 +7604,7 @@ DE8DC4F62C6621E200534E8F /* MSALNativeAuthTelemetryTestDispatcher.swift in Sources */, DE8DC5662C66221A00534E8F /* MSALNativeAuthResponseSerializerTests.swift in Sources */, DE8DC5252C6621F500534E8F /* DispatchAccessTokenRetrieveCompletedTests.swift in Sources */, - DE8DC5542C66221000534E8F /* MSALNativeAuthSignInResponseValidatorTest.swift in Sources */, + DE8DC5542C66221000534E8F /* MSALNativeAuthSignInResponseValidatorTests.swift in Sources */, DE8DC5032C6621EA00534E8F /* SignUpTestsValidatorHelpers.swift in Sources */, 232D6193224C53E500260C42 /* MSALClaimsRequestTests.m in Sources */, DE8DC5622C66221A00534E8F /* MSALNativeAuthRequestErrorHandlerTests.swift in Sources */, @@ -7502,8 +7681,11 @@ DE1BD0E22C3C27C500B0888E /* MSALNativeAuthSignUpContinueIntegrationTests.swift in Sources */, DE1BD0EE2C3C27E200B0888E /* MockAPIHandlerTest.swift in Sources */, DE1BD0E32C3C27C700B0888E /* MSALNativeAuthSignInInitiateIntegrationTests.swift in Sources */, + DEEFCE862DB106F300237F5A /* MSALNativeAuthJITChallengeIntegrationTests.swift in Sources */, DE1BD0EA2C3C27D400B0888E /* MSALNativeAuthTokenIntegrationTests.swift in Sources */, DE1BD0E12C3C27C300B0888E /* MSALNativeAuthSignUpChallengeIntegrationTests.swift in Sources */, + DEEFCF192DB15B1400237F5A /* MSALNativeAuthJITContinueIntegrationTests.swift in Sources */, + DEEFCF1A2DB15B1400237F5A /* MSALNativeAuthJITIntrospectIntegrationTests.swift in Sources */, DE1BD0E72C3C27CF00B0888E /* MSALNativeAuthResetPasswordContinueIntegrationTests.swift in Sources */, DE1BD0E02C3C27C100B0888E /* MSALNativeAuthSignUpStartIntegrationTests.swift in Sources */, DE1BD0E62C3C27CD00B0888E /* MSALNativeAuthResetPasswordChallengeIntegrationTests.swift in Sources */, diff --git a/MSAL/src/native_auth/controllers/responses/SignInResults.swift b/MSAL/src/native_auth/controllers/responses/SignInResults.swift index 50e6ba05ca..0530d6cf74 100644 --- a/MSAL/src/native_auth/controllers/responses/SignInResults.swift +++ b/MSAL/src/native_auth/controllers/responses/SignInResults.swift @@ -29,6 +29,7 @@ enum SignInStartResult { case codeRequired(newState: SignInCodeRequiredState, sentTo: String, channelTargetType: MSALNativeAuthChannelType, codeLength: Int) case passwordRequired(newState: SignInPasswordRequiredState) case awaitingMFA(newState: AwaitingMFAState) + case jitRequired(authMethods: [MSALAuthMethod], newState: RegisterStrongAuthState) case error(SignInStartError) } @@ -37,6 +38,7 @@ typealias SignInResendCodeResult = CodeRequiredGenericResult Void, onAwaitingMFA: @escaping (AwaitingMFAState) -> Void, + onJITRequired: @escaping ([MSALAuthMethod], RegisterStrongAuthState) -> Void, onError: @escaping (SignInStartError) -> Void ) { let config = factory.makeMSIDConfiguration(scopes: scopes) @@ -744,6 +771,15 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN ) MSALLogger.log(level: .info, context: telemetryInfo.context, format: "Multi factor authentication required") onAwaitingMFA(state) + case .jitRequired(let continuationToken): + // TODO: A call will be done here to /register/introspect to retrieve the AuthMethods + let authMethods = [MSALAuthMethod]() + let state = RegisterStrongAuthState( + continuationToken: continuationToken, + correlationId: telemetryInfo.context.correlationId() + ) + MSALLogger.log(level: .info, context: telemetryInfo.context, format: "JIT required") + onJITRequired(authMethods, state) } } @@ -826,6 +862,15 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN self?.stopTelemetryEvent(telemetryInfo.event, context: telemetryInfo.context, delegateDispatcherResult: result) }) ) + }, onJITRequired: { authMethods, jitRequiredState in + continuation.resume( + returning: SignInControllerResponse( + .jitRequired(authMethods: authMethods, newState: jitRequiredState), + 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), correlationId: telemetryInfo.context.correlationId())) diff --git a/MSAL/src/native_auth/network/MSALNativeAuthEndpoint.swift b/MSAL/src/native_auth/network/MSALNativeAuthEndpoint.swift index 8fd91247ea..0a04994e0b 100644 --- a/MSAL/src/native_auth/network/MSALNativeAuthEndpoint.swift +++ b/MSAL/src/native_auth/network/MSALNativeAuthEndpoint.swift @@ -29,6 +29,9 @@ enum MSALNativeAuthEndpoint: String, CaseIterable { case signInInitiate = "/oauth2/v2.0/initiate" case signInChallenge = "/oauth2/v2.0/challenge" case signInIntrospect = "/oauth2/v2.0/introspect" + case jitIntrospect = "/register/v1.0/introspect" + case jitChallenge = "/register/v1.0/challenge" + case jitContinue = "/register/v1.0/continue" case token = "/oauth2/v2.0/token" case resetPasswordStart = "/resetpassword/v1.0/start" case resetPasswordChallenge = "/resetpassword/v1.0/challenge" diff --git a/MSAL/src/native_auth/network/MSALNativeAuthRequestConfigurator.swift b/MSAL/src/native_auth/network/MSALNativeAuthRequestConfigurator.swift index 2ae8528bd9..1d7820689d 100644 --- a/MSAL/src/native_auth/network/MSALNativeAuthRequestConfigurator.swift +++ b/MSAL/src/native_auth/network/MSALNativeAuthRequestConfigurator.swift @@ -39,6 +39,12 @@ enum MSALNativeAuthRequestConfiguratorType { case introspect(MSALNativeAuthSignInIntrospectRequestParameters) } + enum JIT { + case introspect(MSALNativeAuthJITIntrospectRequestParameters) + case challenge(MSALNativeAuthJITChallengeRequestParameters) + case `continue`(MSALNativeAuthJITContinueRequestParameters) + } + enum ResetPassword { case start(MSALNativeAuthResetPasswordStartRequestParameters) case challenge(MSALNativeAuthResetPasswordChallengeRequestParameters) @@ -54,6 +60,7 @@ enum MSALNativeAuthRequestConfiguratorType { case signUp(SignUp) case signIn(SignIn) + case jit(JIT) case resetPassword(ResetPassword) case token(Token) } @@ -73,6 +80,8 @@ class MSALNativeAuthRequestConfigurator: MSIDAADRequestConfigurator { try signUpConfigure(subType, request, telemetryProvider) case .signIn(let subType): try signInConfigure(subType, request, telemetryProvider) + case .jit(let subType): + try jitConfigure(subType, request, telemetryProvider) case .resetPassword(let subType): try resetPasswordConfigure(subType, request, telemetryProvider) case .token(let subType): @@ -148,6 +157,41 @@ class MSALNativeAuthRequestConfigurator: MSIDAADRequestConfigurator { } } + private func jitConfigure(_ subType: MSALNativeAuthRequestConfiguratorType.JIT, + _ request: MSIDHttpRequest, + _ telemetryProvider: MSALNativeAuthTelemetryProviding) throws { + switch subType { + case .introspect(let parameters): + let responseSerializer = MSALNativeAuthResponseSerializer() + let telemetry = telemetryProvider.telemetryForRegister(type: .jitIntrospect) + 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.telemetryForRegister(type: .jitChallenge) + 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.telemetryForRegister(type: .jitContinue) + 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 { diff --git a/MSAL/src/native_auth/network/MSALNativeAuthRequestParametersKey.swift b/MSAL/src/native_auth/network/MSALNativeAuthRequestParametersKey.swift index be0c7eb0f4..355e6aba2f 100644 --- a/MSAL/src/native_auth/network/MSALNativeAuthRequestParametersKey.swift +++ b/MSAL/src/native_auth/network/MSALNativeAuthRequestParametersKey.swift @@ -27,6 +27,8 @@ import Foundation enum MSALNativeAuthRequestParametersKey: String { case clientId = "client_id" case challengeType = "challenge_type" + case challengeTarget = "challenge_target" + case challengeChannel = "challenge_channel" case grantType = "grant_type" case id = "id" case username diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorCodes.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorCodes.swift index ca88c8de10..9433c509b6 100644 --- a/MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorCodes.swift +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthESTSApiErrorCodes.swift @@ -29,4 +29,5 @@ enum MSALNativeAuthESTSApiErrorCodes: Int { case userNotHaveAPassword = 500222 case invalidRequestParameter = 90100 case resetPasswordRequired = 50142 + case invalidVerificationContact = 901001 } diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthSubErrorCode.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthSubErrorCode.swift index fcefc08c4d..b1e330c91e 100644 --- a/MSAL/src/native_auth/network/errors/MSALNativeAuthSubErrorCode.swift +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthSubErrorCode.swift @@ -35,6 +35,7 @@ enum MSALNativeAuthSubErrorCode: String, Decodable, Equatable, MSALNativeAuthUnk case invalidOOBValue = "invalid_oob_value" case introspectRequired = "introspect_required" case mfaRequired = "mfa_required" + case jitRequired = "registration_required" case unknown var isAnyPasswordError: Bool { @@ -50,6 +51,7 @@ enum MSALNativeAuthSubErrorCode: String, Decodable, Equatable, MSALNativeAuthUnk .invalidOOBValue, .introspectRequired, .mfaRequired, + .jitRequired, .unknown: return false } diff --git a/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITChallengeOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITChallengeOauth2ErrorCode.swift new file mode 100644 index 0000000000..1c1119945a --- /dev/null +++ b/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITChallengeOauth2ErrorCode.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 + +enum MSALNativeAuthJITChallengeOauth2ErrorCode: String, Decodable, MSALNativeAuthUnknownCaseProtocol { + case invalidRequest = "invalid_request" + case unknown +} diff --git a/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITChallengeResponseError.swift b/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITChallengeResponseError.swift new file mode 100644 index 0000000000..a326fefe15 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITChallengeResponseError.swift @@ -0,0 +1,60 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION 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 MSALNativeAuthJITChallengeResponseError: MSALNativeAuthResponseError { + + let error: MSALNativeAuthJITChallengeOauth2ErrorCode + let errorDescription: String? + let errorCodes: [Int]? + let errorURI: String? + let innerErrors: [MSALNativeAuthInnerError]? + var correlationId: UUID? + + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + case errorCodes = "error_codes" + case errorURI = "error_uri" + case innerErrors = "inner_errors" + case correlationId + } + + init( + error: MSALNativeAuthJITChallengeOauth2ErrorCode = .unknown, + 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/jit/MSALNativeAuthJITContinueOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITContinueOauth2ErrorCode.swift new file mode 100644 index 0000000000..b062b93ca3 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITContinueOauth2ErrorCode.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 + +enum MSALNativeAuthJITContinueOauth2ErrorCode: String, Decodable, MSALNativeAuthUnknownCaseProtocol { + case invalidGrant = "invalid_grant" + case unknown +} diff --git a/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITContinueResponseError.swift b/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITContinueResponseError.swift new file mode 100644 index 0000000000..6b94f6514e --- /dev/null +++ b/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITContinueResponseError.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 + +struct MSALNativeAuthJITContinueResponseError: MSALNativeAuthResponseError { + + let error: MSALNativeAuthJITContinueOauth2ErrorCode + let errorDescription: String? + let errorCodes: [Int]? + let errorURI: String? + let innerErrors: [MSALNativeAuthInnerError]? + let subError: MSALNativeAuthSubErrorCode? + var correlationId: UUID? + + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + case errorCodes = "error_codes" + case errorURI = "error_uri" + case innerErrors = "inner_errors" + case subError = "suberror" + case correlationId + } + + init( + error: MSALNativeAuthJITContinueOauth2ErrorCode = .unknown, + errorDescription: String? = nil, + errorCodes: [Int]? = nil, + errorURI: String? = nil, + innerErrors: [MSALNativeAuthInnerError]? = nil, + subError: MSALNativeAuthSubErrorCode? = nil, + correlationId: UUID? = nil + ) { + self.error = error + self.errorDescription = errorDescription + self.errorCodes = errorCodes + self.errorURI = errorURI + self.innerErrors = innerErrors + self.subError = subError + self.correlationId = correlationId + } +} diff --git a/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITIntrospectOauth2ErrorCode.swift b/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITIntrospectOauth2ErrorCode.swift new file mode 100644 index 0000000000..28766c8c05 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITIntrospectOauth2ErrorCode.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 + +enum MSALNativeAuthJITIntrospectOauth2ErrorCode: String, Decodable, MSALNativeAuthUnknownCaseProtocol { + case unknown +} diff --git a/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITIntrospectResponseError.swift b/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITIntrospectResponseError.swift new file mode 100644 index 0000000000..f43744b8f8 --- /dev/null +++ b/MSAL/src/native_auth/network/errors/jit/MSALNativeAuthJITIntrospectResponseError.swift @@ -0,0 +1,60 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION 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 MSALNativeAuthJITIntrospectResponseError: MSALNativeAuthResponseError { + + let error: MSALNativeAuthJITIntrospectOauth2ErrorCode + let errorDescription: String? + let errorCodes: [Int]? + let errorURI: String? + let innerErrors: [MSALNativeAuthInnerError]? + var correlationId: UUID? + + enum CodingKeys: String, CodingKey { + case error + case errorDescription = "error_description" + case errorCodes = "error_codes" + case errorURI = "error_uri" + case innerErrors = "inner_errors" + case correlationId + } + + init( + error: MSALNativeAuthJITIntrospectOauth2ErrorCode = .unknown, + 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/jit/MSALNativeAuthJITRequestProvider.swift b/MSAL/src/native_auth/network/jit/MSALNativeAuthJITRequestProvider.swift new file mode 100644 index 0000000000..a4971779b9 --- /dev/null +++ b/MSAL/src/native_auth/network/jit/MSALNativeAuthJITRequestProvider.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. + +@_implementationOnly import MSAL_Private + +protocol MSALNativeAuthJITRequestProviding { + func introspect( + parameters: MSALNativeAuthJITIntrospectRequestParameters, + context: MSIDRequestContext + ) throws -> MSIDHttpRequest + + func challenge( + parameters: MSALNativeAuthJITChallengeRequestParameters, + context: MSIDRequestContext + ) throws -> MSIDHttpRequest + + func `continue`( + parameters: MSALNativeAuthJITContinueRequestParameters, + context: MSIDRequestContext + ) throws -> MSIDHttpRequest +} + +final class MSALNativeAuthJITRequestProvider: MSALNativeAuthJITRequestProviding { + + // 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: - Register Introspect + + func introspect( + parameters: MSALNativeAuthJITIntrospectRequestParameters, + context: any MSIDRequestContext + ) throws -> MSIDHttpRequest { + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .jit(.introspect(parameters)), + request: request, + telemetryProvider: telemetryProvider) + return request + } + + // MARK: - Register Challenge + + func challenge( + parameters: MSALNativeAuthJITChallengeRequestParameters, + context: any MSIDRequestContext + ) throws -> MSIDHttpRequest { + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .jit(.challenge(parameters)), + request: request, + telemetryProvider: telemetryProvider) + return request + } + + // MARK: - Register Continue + + func `continue`( + parameters: MSALNativeAuthJITContinueRequestParameters, + context: MSIDRequestContext + ) throws -> MSIDHttpRequest { + + let request = MSIDHttpRequest() + try requestConfigurator.configure(configuratorType: .jit(.continue(parameters)), + request: request, + telemetryProvider: telemetryProvider) + return request + } +} diff --git a/MSAL/src/native_auth/network/parameters/jit/MSALNativeAuthJITChallengeRequestParameters.swift b/MSAL/src/native_auth/network/parameters/jit/MSALNativeAuthJITChallengeRequestParameters.swift new file mode 100644 index 0000000000..9e69991711 --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/jit/MSALNativeAuthJITChallengeRequestParameters.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 MSALNativeAuthJITChallengeRequestParameters: MSALNativeAuthRequestable { + let endpoint: MSALNativeAuthEndpoint = .jitChallenge + let context: MSALNativeAuthRequestContext + let continuationToken: String + let authMethod: MSALAuthMethod + let verificationContact: String + + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { + typealias Key = MSALNativeAuthRequestParametersKey + + return [ + Key.clientId.rawValue: config.clientId, + Key.continuationToken.rawValue: continuationToken, + Key.challengeType.rawValue: authMethod.challengeType, + Key.challengeTarget.rawValue: verificationContact, + Key.challengeChannel.rawValue: authMethod.channelTargetType.value + ].compactMapValues { $0 } + } +} diff --git a/MSAL/src/native_auth/network/parameters/jit/MSALNativeAuthJITContinueRequestParameters.swift b/MSAL/src/native_auth/network/parameters/jit/MSALNativeAuthJITContinueRequestParameters.swift new file mode 100644 index 0000000000..dffe658dc6 --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/jit/MSALNativeAuthJITContinueRequestParameters.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 MSALNativeAuthJITContinueRequestParameters: MSALNativeAuthRequestable { + let endpoint: MSALNativeAuthEndpoint = .jitContinue + let context: MSALNativeAuthRequestContext + let grantType: MSALNativeAuthGrantType + let continuationToken: String + let oobCode: String? + + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { + typealias Key = MSALNativeAuthRequestParametersKey + + return [ + Key.clientId.rawValue: config.clientId, + Key.grantType.rawValue: grantType.rawValue, + Key.continuationToken.rawValue: continuationToken, + Key.oobCode.rawValue: oobCode + ].compactMapValues { $0 } + } +} diff --git a/MSAL/src/native_auth/network/parameters/jit/MSALNativeAuthJITIntrospectRequestParameters.swift b/MSAL/src/native_auth/network/parameters/jit/MSALNativeAuthJITIntrospectRequestParameters.swift new file mode 100644 index 0000000000..25201c7cbc --- /dev/null +++ b/MSAL/src/native_auth/network/parameters/jit/MSALNativeAuthJITIntrospectRequestParameters.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 MSALNativeAuthJITIntrospectRequestParameters: MSALNativeAuthRequestable { + let endpoint: MSALNativeAuthEndpoint = .jitIntrospect + let context: MSALNativeAuthRequestContext + let continuationToken: String + + func makeRequestBody(config: MSALNativeAuthConfiguration) -> [String: String] { + typealias Key = MSALNativeAuthRequestParametersKey + + return [ + Key.clientId.rawValue: config.clientId, + Key.continuationToken.rawValue: continuationToken + ].compactMapValues { $0 } + } +} diff --git a/MSAL/src/native_auth/network/responses/jit/MSALNativeAuthJITChallengeResponse.swift b/MSAL/src/native_auth/network/responses/jit/MSALNativeAuthJITChallengeResponse.swift new file mode 100644 index 0000000000..72cc620097 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/jit/MSALNativeAuthJITChallengeResponse.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 + +struct MSALNativeAuthJITChallengeResponse: Decodable, MSALNativeAuthResponseCorrelatable { + + // MARK: - Variables + let continuationToken: String? + let challengeType: String + let bindingMethod: String? + let challengeTarget: String? + let challengeChannel: String? + let codeLength: Int? + let interval: Int? + var correlationId: UUID? +} diff --git a/MSAL/src/native_auth/network/responses/jit/MSALNativeAuthJITContinueResponse.swift b/MSAL/src/native_auth/network/responses/jit/MSALNativeAuthJITContinueResponse.swift new file mode 100644 index 0000000000..022dc2e107 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/jit/MSALNativeAuthJITContinueResponse.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 MSALNativeAuthJITContinueResponse: Decodable, MSALNativeAuthResponseCorrelatable { + + // MARK: - Variables + let continuationToken: String? + var correlationId: UUID? +} diff --git a/MSAL/src/native_auth/network/responses/jit/MSALNativeAuthJITIntrospectResponse.swift b/MSAL/src/native_auth/network/responses/jit/MSALNativeAuthJITIntrospectResponse.swift new file mode 100644 index 0000000000..f443ff0bbe --- /dev/null +++ b/MSAL/src/native_auth/network/responses/jit/MSALNativeAuthJITIntrospectResponse.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 MSALNativeAuthJITIntrospectResponse: Decodable, MSALNativeAuthResponseCorrelatable { + + // MARK: - Variables + let continuationToken: String? + let methods: [MSALNativeAuthInternalAuthenticationMethod]? + var correlationId: UUID? +} diff --git a/MSAL/src/native_auth/network/responses/validator/jit/MSALNativeAuthJITResponseValidator.swift b/MSAL/src/native_auth/network/responses/validator/jit/MSALNativeAuthJITResponseValidator.swift new file mode 100644 index 0000000000..8e4765682f --- /dev/null +++ b/MSAL/src/native_auth/network/responses/validator/jit/MSALNativeAuthJITResponseValidator.swift @@ -0,0 +1,180 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION 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 MSALNativeAuthJITResponseValidating { + func validateIntrospect( + context: MSIDRequestContext, + result: Result + ) -> MSALNativeAuthJITIntrospectValidatedResponse + + func validateChallenge( + context: MSIDRequestContext, + result: Result + ) -> MSALNativeAuthJITChallengeValidatedResponse + + func validateContinue( + context: MSIDRequestContext, + result: Result + ) -> MSALNativeAuthJITContinueValidatedResponse + +} + +final class MSALNativeAuthJITResponseValidator: MSALNativeAuthJITResponseValidating { + + func validateIntrospect( + context: any MSIDRequestContext, + result: Result + ) -> MSALNativeAuthJITIntrospectValidatedResponse { + switch result { + case .success(let introspectResponse): + guard let continuationToken = introspectResponse.continuationToken, + let methods = introspectResponse.methods, + !methods.isEmpty else { + MSALLogger.logPII( + level: .error, + context: context, + format: "register/introspect: Invalid response, content: \(MSALLogMask.maskPII(introspectResponse))") + return .error(.unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))) + } + return .authMethodsRetrieved(continuationToken: continuationToken, authMethods: methods) + case .failure(let introspectResponseError): + guard let introspectResponseError = + introspectResponseError as? MSALNativeAuthJITIntrospectResponseError else { + MSALLogger.logPII( + level: .error, + context: context, + format: "register/introspect: Unable to decode error response: \(MSALLogMask.maskPII(introspectResponseError))") + return .error(.unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))) + } + switch introspectResponseError.error { + case .unknown: + return .error(.unexpectedError(introspectResponseError)) + } + } + } + + func validateChallenge( + context: any MSIDRequestContext, + result: Result + ) -> MSALNativeAuthJITChallengeValidatedResponse { + switch result { + case .success(let challengeResponse): + return handleSuccessfulJITChallengeResult(context, response: challengeResponse) + case .failure(let JITChallengeResponseError): + guard let JITChallengeResponseError = + JITChallengeResponseError as? MSALNativeAuthJITChallengeResponseError else { + MSALLogger.logPII( + level: .error, + context: context, + format: "register/challenge: Unable to decode error response: \(MSALLogMask.maskPII(JITChallengeResponseError))") + return .error(.unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))) + } + return handleFailedJITChallengeResult(error: JITChallengeResponseError) + } + } + + func validateContinue( + context: MSIDRequestContext, + result: Result + ) -> MSALNativeAuthJITContinueValidatedResponse { + switch result { + case .success(let initiateResponse): + if let continuationToken = initiateResponse.continuationToken { + return .success(continuationToken: continuationToken) + } + MSALLogger.log(level: .error, context: context, format: "register/continue: challengeType and continuation token empty") + return .error(.unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))) + case .failure(let responseError): + guard let initiateResponseError = responseError as? MSALNativeAuthJITContinueResponseError else { + MSALLogger.logPII( + level: .error, + context: context, + format: "register/continue: Unable to decode error response: \(MSALLogMask.maskPII(responseError))") + return .error(.unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))) + } + return handleFailedJITContinueResult(error: initiateResponseError) + } + } + + // MARK: private methods + + private func handleSuccessfulJITChallengeResult( + _ context: MSIDRequestContext, + response: MSALNativeAuthJITChallengeResponse) -> MSALNativeAuthJITChallengeValidatedResponse { + switch response.challengeType { + case "oob": + guard let continuationToken = response.continuationToken, + let targetLabel = response.challengeTarget, + let codeLength = response.codeLength, + let channelType = response.challengeChannel else { + MSALLogger.logPII( + level: .error, + context: context, + format: "register/challenge: Invalid response with challenge type oob, response: \(MSALLogMask.maskPII(response))") + return .error(.unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody))) + } + return .codeRequired( + continuationToken: continuationToken, + sentTo: targetLabel, + channelType: MSALNativeAuthChannelType(value: channelType), + codeLength: codeLength) + case "redirect": + return .error(.redirect) + default: + MSALLogger.log( + level: .error, + context: context, + format: "register/challenge: Received unexpected challenge type: \(response.challengeType)") + return .error(.unexpectedError(.init(errorDescription: MSALNativeAuthErrorMessage.unexpectedChallengeType))) + } + } + + private func handleFailedJITChallengeResult( + error: MSALNativeAuthJITChallengeResponseError) -> MSALNativeAuthJITChallengeValidatedResponse { + switch error.error { + case .invalidRequest: + guard let errorCode = error.errorCodes?.first, + let knownErrorCode = MSALNativeAuthESTSApiErrorCodes(rawValue: errorCode), + knownErrorCode == .invalidVerificationContact else { + return .error(.unexpectedError(error)) + } + return .error(.invalidVerificationContact(error)) + case .unknown: + return .error(.unexpectedError(error)) + } + } + + private func handleFailedJITContinueResult(error: MSALNativeAuthJITContinueResponseError) -> MSALNativeAuthJITContinueValidatedResponse { + switch error.error { + case .invalidGrant where error.subError == .invalidOOBValue: + return .error(.invalidOOBCode(error)) + case .unknown: + return .error(.unexpectedError(error)) + default: + return .error(.unexpectedError(error)) + } + } +} diff --git a/MSAL/src/native_auth/network/responses/validator/jit/validated_response/MSALNativeAuthJITChallengeValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/jit/validated_response/MSALNativeAuthJITChallengeValidatedResponse.swift new file mode 100644 index 0000000000..1ca20065d7 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/validator/jit/validated_response/MSALNativeAuthJITChallengeValidatedResponse.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 MSALNativeAuthJITChallengeValidatedResponse { + case codeRequired(continuationToken: String, sentTo: String, channelType: MSALNativeAuthChannelType, codeLength: Int) + case error(MSALNativeAuthJITChallengeValidatedErrorType) +} + +enum MSALNativeAuthJITChallengeValidatedErrorType: Error { + case redirect + case invalidVerificationContact(MSALNativeAuthJITChallengeResponseError) + case unexpectedError(MSALNativeAuthJITChallengeResponseError?) +} diff --git a/MSAL/src/native_auth/network/responses/validator/jit/validated_response/MSALNativeAuthJITContinueValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/jit/validated_response/MSALNativeAuthJITContinueValidatedResponse.swift new file mode 100644 index 0000000000..b6a9b694e4 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/validator/jit/validated_response/MSALNativeAuthJITContinueValidatedResponse.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 MSALNativeAuthJITContinueValidatedResponse { + case success(continuationToken: String) + case error(MSALNativeAuthJITContinueValidatedErrorType) +} + +enum MSALNativeAuthJITContinueValidatedErrorType: Error { + case redirect + case invalidOOBCode(MSALNativeAuthJITContinueResponseError) + case unexpectedError(MSALNativeAuthJITContinueResponseError?) +} diff --git a/MSAL/src/native_auth/network/responses/validator/jit/validated_response/MSALNativeAuthJITIntrospectValidatedResponse.swift b/MSAL/src/native_auth/network/responses/validator/jit/validated_response/MSALNativeAuthJITIntrospectValidatedResponse.swift new file mode 100644 index 0000000000..6b5b70aee9 --- /dev/null +++ b/MSAL/src/native_auth/network/responses/validator/jit/validated_response/MSALNativeAuthJITIntrospectValidatedResponse.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 + +enum MSALNativeAuthJITIntrospectValidatedResponse { + case authMethodsRetrieved(continuationToken: String, authMethods: [MSALNativeAuthInternalAuthenticationMethod]) + case error(MSALNativeAuthJITIntrospectValidatedErrorType) +} + +enum MSALNativeAuthJITIntrospectValidatedErrorType: Error { + case redirect + case unexpectedError(MSALNativeAuthJITIntrospectResponseError?) +} 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 791c5fc7b0..ff0520144b 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 @@ -257,7 +257,8 @@ final class MSALNativeAuthSignUpResponseValidator: MSALNativeAuthSignUpResponseV } case .unknown, .introspectRequired, - .mfaRequired: + .mfaRequired, + .jitRequired: 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 169ae17fb4..171b9a2bc4 100644 --- a/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift +++ b/MSAL/src/native_auth/network/responses/validator/token/MSALNativeAuthTokenResponseValidator.swift @@ -89,7 +89,7 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal return validAccount } - // swiftlint:disable:next cyclomatic_complexity + // swiftlint:disable:next cyclomatic_complexity function_body_length private func handleFailedTokenResult( _ context: MSIDRequestContext, _ responseError: MSALNativeAuthTokenResponseError) -> MSALNativeAuthTokenValidatedResponse { @@ -113,6 +113,17 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal )) } return .strongAuthRequired(continuationToken: continuationToken) + } else if responseError.subError == .jitRequired { + guard let continuationToken = responseError.continuationToken else { + MSALLogger.log( + level: .error, + context: context, + format: "Token: JIT required response, expected continuation token not empty") + return .error(.generalError( + MSALNativeAuthTokenResponseError(errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody) + )) + } + return .jitRequired(continuationToken: continuationToken) } else { return handleInvalidGrantErrorCodes(apiError: responseError, context: context) } @@ -220,7 +231,8 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal return .invalidPassword(apiError) case .userNotHaveAPassword, .invalidRequestParameter, - .resetPasswordRequired: + .resetPasswordRequired, + .invalidVerificationContact: return .generalError(apiError) } } @@ -234,7 +246,8 @@ final class MSALNativeAuthTokenResponseValidator: MSALNativeAuthTokenResponseVal .invalidCredentials, .userNotHaveAPassword, .invalidRequestParameter, - .resetPasswordRequired: + .resetPasswordRequired, + .invalidVerificationContact: 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 1a50ebffdf..31dc19b5d6 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 @@ -27,6 +27,7 @@ enum MSALNativeAuthTokenValidatedResponse { case success(MSIDTokenResponse) case strongAuthRequired(continuationToken: String) + case jitRequired(continuationToken: String) case error(MSALNativeAuthTokenValidatedErrorType) } diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift index 4a0d47c521..48c4212d89 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift @@ -248,6 +248,10 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic await delegate.onSignInStartError(error: error) case .awaitingMFA(let newState): await delegateDispatcher.dispatchAwaitingMFA(newState: newState, correlationId: controllerResponse.correlationId) + case .jitRequired(let authMethods, let newState): + await delegateDispatcher.dispatchJITRequired(authMethods: authMethods, + newState: newState, + correlationId: controllerResponse.correlationId) } } } 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 9acb02a2ff..d6bbddf8ea 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 @@ -77,6 +77,21 @@ final class SignInStartDelegateDispatcher: DelegateDispatcher { diff --git a/MSAL/src/native_auth/public/state_machine/error/RegisterStrongAuthChallengeError.swift b/MSAL/src/native_auth/public/state_machine/error/RegisterStrongAuthChallengeError.swift index 6ac9486b03..0efc0a9c93 100644 --- a/MSAL/src/native_auth/public/state_machine/error/RegisterStrongAuthChallengeError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/RegisterStrongAuthChallengeError.swift @@ -27,6 +27,7 @@ import Foundation @objcMembers public class RegisterStrongAuthChallengeError: MSALNativeAuthError { enum ErrorType: CaseIterable { + case browserRequired case invalidInput case generalError } @@ -45,6 +46,8 @@ public class RegisterStrongAuthChallengeError: MSALNativeAuthError { } switch type { + case .browserRequired: + return MSALNativeAuthErrorMessage.browserRequired case .invalidInput: return MSALNativeAuthErrorMessage.invalidInput case .generalError: diff --git a/MSAL/src/native_auth/public/state_machine/error/RegisterStrongAuthSubmitChallengeError.swift b/MSAL/src/native_auth/public/state_machine/error/RegisterStrongAuthSubmitChallengeError.swift index 6b57141ef3..a08592ca83 100644 --- a/MSAL/src/native_auth/public/state_machine/error/RegisterStrongAuthSubmitChallengeError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/RegisterStrongAuthSubmitChallengeError.swift @@ -27,6 +27,7 @@ import Foundation @objcMembers public class RegisterStrongAuthSubmitChallengeError: MSALNativeAuthError { enum ErrorType: CaseIterable { + case browserRequired case invalidChallenge case generalError } @@ -45,6 +46,8 @@ public class RegisterStrongAuthSubmitChallengeError: MSALNativeAuthError { } switch type { + case .browserRequired: + return MSALNativeAuthErrorMessage.browserRequired case .invalidChallenge: return MSALNativeAuthErrorMessage.invalidChallenge case .generalError: 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 7c7169f116..88daf2652f 100644 --- a/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift +++ b/MSAL/src/native_auth/public/state_machine/state/SignInStates.swift @@ -147,6 +147,10 @@ import Foundation await delegate.onSignInPasswordRequiredError(error: error, newState: newState) case .awaitingMFA(let newState): await delegateDispatcher.dispatchAwaitingMFA(newState: newState, correlationId: controllerResponse.correlationId) + case .jitrequired(let authMethods, let newState): + await delegateDispatcher.dispatchJITRequired(authMethods: authMethods, + newState: newState, + correlationId: controllerResponse.correlationId) } } } diff --git a/MSAL/src/native_auth/telemetry/MSALNativeAuthOperationTypes.swift b/MSAL/src/native_auth/telemetry/MSALNativeAuthOperationTypes.swift index 25a6fd93ae..7126d1c478 100644 --- a/MSAL/src/native_auth/telemetry/MSALNativeAuthOperationTypes.swift +++ b/MSAL/src/native_auth/telemetry/MSALNativeAuthOperationTypes.swift @@ -44,6 +44,12 @@ enum MSALNativeAuthSignInType: MSALNativeAuthOperationType { case signInIntrospect = 4 } +enum MSALNativeAuthJITType: MSALNativeAuthOperationType { + case jitIntrospect = 0 + case jitChallenge = 1 + case jitContinue = 2 +} + enum MSALNativeAuthTokenType: MSALNativeAuthOperationType { case signInWithPassword = 0 case refreshToken = 1 diff --git a/MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryApiId.swift b/MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryApiId.swift index 7672ad8e08..650a01355a 100644 --- a/MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryApiId.swift +++ b/MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryApiId.swift @@ -57,4 +57,7 @@ enum MSALNativeAuthTelemetryApiId: Int { case telemetryApiIdMFARequestChallenge = 75016 case telemetryApiIdMFAGetAuthMethods = 75017 case telemetryApiIdMFASubmitChallenge = 75018 + case telemetryApiIdJITIntrospect = 75029 + case telemetryApiIdJITChallenge = 75030 + case telemetryApiIdJITContinue = 75031 } diff --git a/MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryProvider.swift b/MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryProvider.swift index e24929bf46..13e1fb961b 100644 --- a/MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryProvider.swift +++ b/MSAL/src/native_auth/telemetry/MSALNativeAuthTelemetryProvider.swift @@ -28,6 +28,8 @@ protocol MSALNativeAuthTelemetryProviding { type: MSALNativeAuthSignUpType) -> MSALNativeAuthCurrentRequestTelemetry func telemetryForSignIn( type: MSALNativeAuthSignInType) -> MSALNativeAuthCurrentRequestTelemetry + func telemetryForRegister( + type: MSALNativeAuthJITType) -> MSALNativeAuthCurrentRequestTelemetry func telemetryForToken( type: MSALNativeAuthTokenType) -> MSALNativeAuthCurrentRequestTelemetry func telemetryForResetPassword( @@ -59,6 +61,14 @@ class MSALNativeAuthTelemetryProvider: MSALNativeAuthTelemetryProviding { platformFields: nil) } + func telemetryForRegister( + type: MSALNativeAuthJITType) -> MSALNativeAuthCurrentRequestTelemetry { + return MSALNativeAuthCurrentRequestTelemetry( + apiId: .telemetryApiIdJITIntrospect, + operationType: type.rawValue, + platformFields: nil) + } + func telemetryForToken( type: MSALNativeAuthTokenType) -> MSALNativeAuthCurrentRequestTelemetry { return MSALNativeAuthCurrentRequestTelemetry( diff --git a/MSAL/test/integration/native_auth/common/Model.swift b/MSAL/test/integration/native_auth/common/Model.swift index f769e2d3e1..2a82d78adc 100644 --- a/MSAL/test/integration/native_auth/common/Model.swift +++ b/MSAL/test/integration/native_auth/common/Model.swift @@ -43,6 +43,9 @@ enum MockAPIEndpoint: String { case resetPasswordContinue = "SSPRContinue" case resetPasswordSubmit = "SSPRSubmit" case resetPasswordPollCompletion = "SSPRPoll" + case jitIntrospect = "JITIntrospect" + case jitChallenge = "JITChallenge" + case jitContinue = "JITContinue" } enum MockAPIResponse: String { @@ -90,6 +93,15 @@ enum MockAPIResponse: String { case ssprPollNotStarted = "SSPRPollNotStarted" case signUpContinueSuccess = "SignUpContinueSuccess" case invalidUsername = "InvalidUsername" + case registrationRequired = "RegistrationRequired" + // Typo below on Registraion is expected, on par with Mock API + case registrationIntrospectSuccess = "RegistraionIntrospectSuccess" + case registrationChallengeSuccess = "RegistraionChallengeSuccess" + case registrationContinueSuccess = "RegistrationContinueSuccess" + case registrationInvalidOOBValue = "RegistrationInvalidOOBValue" + case registraionInvalidChallengeTarget = "RegistraionInvalidChallengeTarget" + case serverError = "ServerError" + case accessDenied = "AccessDenied" } // MARK: request body diff --git a/MSAL/test/integration/native_auth/requests/jit/MSALNativeAuthJITChallengeIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/jit/MSALNativeAuthJITChallengeIntegrationTests.swift new file mode 100644 index 0000000000..7d955f1976 --- /dev/null +++ b/MSAL/test/integration/native_auth/requests/jit/MSALNativeAuthJITChallengeIntegrationTests.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 +@_implementationOnly import MSAL_Private + +class MSALNativeAuthJITChallengeIntegrationTests: MSALNativeAuthIntegrationBaseTests { + private typealias Error = MSALNativeAuthJITChallengeResponseError + private var provider: MSALNativeAuthJITRequestProvider! + + override func setUpWithError() throws { + try super.setUpWithError() + + provider = MSALNativeAuthJITRequestProvider(requestConfigurator: MSALNativeAuthRequestConfigurator(config: config)) + + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + sut = try provider.challenge( + parameters: .init(context: context, + continuationToken: "Test Credential Token", + authMethod: MSALAuthMethod(id: "1", + challengeType: "oob", + loginHint: "not-used-test@contoso.com", + channelTargetType: MSALNativeAuthChannelType(value: "email")), + verificationContact: "test@contoso.com"), + context: context + ) + } + + func test_succeedRequest_challengeSuccess() async throws { + try await mockResponse(.registrationChallengeSuccess, endpoint: .jitChallenge) + let response: MSALNativeAuthJITChallengeResponse? = try await performTestSucceed() + + XCTAssertTrue(response?.challengeType == "oob") + XCTAssertTrue(response?.bindingMethod == "prompt") + XCTAssertTrue(response?.challengeTarget == "bar@contoso.com") + XCTAssertTrue(response?.challengeChannel == "email") + XCTAssertTrue(response?.codeLength == 8) + XCTAssertNotNil(response?.continuationToken) + } + + func test_failRequest_InvalidChallengeTarget() async throws { + try await perform_testFail( + endpoint: .jitChallenge, + response: .registraionInvalidChallengeTarget, + expectedError: Error(error: .invalidRequest, errorDescription: nil, errorCodes: [901001], errorURI: nil, innerErrors: nil) + ) + } + + func test_failRequest_expiredToken() async throws { + try await perform_testFail( + endpoint: .jitChallenge, + response: .expiredToken, + expectedError: Error(error: .unknown, errorDescription: nil, errorCodes: [55112], errorURI: nil, innerErrors: nil) + ) + } + + func test_failRequest_invalidRequest() async throws { + try await perform_testFail( + endpoint: .jitChallenge, + response: .invalidRequest, + expectedError: Error(error: .invalidRequest, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) + ) + } +} diff --git a/MSAL/test/integration/native_auth/requests/jit/MSALNativeAuthJITContinueIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/jit/MSALNativeAuthJITContinueIntegrationTests.swift new file mode 100644 index 0000000000..6a651fc4b0 --- /dev/null +++ b/MSAL/test/integration/native_auth/requests/jit/MSALNativeAuthJITContinueIntegrationTests.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. + +import XCTest +@testable import MSAL +@_implementationOnly import MSAL_Private + +class MSALNativeAuthJITContinueIntegrationTests: MSALNativeAuthIntegrationBaseTests { + private typealias Error = MSALNativeAuthJITContinueResponseError + private var provider: MSALNativeAuthJITRequestProvider! + + override func setUpWithError() throws { + try super.setUpWithError() + + provider = MSALNativeAuthJITRequestProvider(requestConfigurator: MSALNativeAuthRequestConfigurator(config: config)) + + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + sut = try provider.continue( + parameters: .init(context: context, + grantType: .oobCode, + continuationToken: "Test Credential Token", + oobCode: "code"), + context: context + ) + } + + func test_succeedRequest_continueSuccess() async throws { + try await mockResponse(.registrationContinueSuccess, endpoint: .jitContinue) + let response: MSALNativeAuthJITContinueResponse? = try await performTestSucceed() + + XCTAssertNotNil(response?.continuationToken) + } + + func test_failRequest_InvalidChallengeTarget() async throws { + let result = try await perform_testFail( + endpoint: .jitContinue, + response: .registrationInvalidOOBValue, + expectedError: Error(error: .invalidGrant, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, subError: .invalidOOBValue) + ) + XCTAssertEqual(result.subError, .invalidOOBValue) + } + + func test_failRequest_expiredToken() async throws { + try await perform_testFail( + endpoint: .jitContinue, + response: .expiredToken, + expectedError: Error(error: .unknown, errorDescription: nil, errorCodes: [55112], errorURI: nil, innerErrors: nil) + ) + } + + func test_failRequest_invalidRequest() async throws { + try await perform_testFail( + endpoint: .jitContinue, + response: .invalidRequest, + expectedError: Error(error: .unknown, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) + ) + } + + func test_failRequest_invalidGrant() async throws { + try await perform_testFail( + endpoint: .jitContinue, + response: .invalidGrant, + expectedError: Error(error: .invalidGrant, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) + ) + } + + func test_failRequest_accessDenied() async throws { + try await perform_testFail( + endpoint: .jitContinue, + response: .accessDenied, + expectedError: Error(error: .unknown, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) + ) + } + + func test_failRequest_authorizationPending() async throws { + try await perform_testFail( + endpoint: .jitContinue, + response: .authorizationPending, + expectedError: Error(error: .unknown, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) + ) + } +} diff --git a/MSAL/test/integration/native_auth/requests/jit/MSALNativeAuthJITIntrospectIntegrationTests.swift b/MSAL/test/integration/native_auth/requests/jit/MSALNativeAuthJITIntrospectIntegrationTests.swift new file mode 100644 index 0000000000..9effcbecdb --- /dev/null +++ b/MSAL/test/integration/native_auth/requests/jit/MSALNativeAuthJITIntrospectIntegrationTests.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 +@_implementationOnly import MSAL_Private + +class MSALNativeAuthJITIntrospectIntegrationTests: MSALNativeAuthIntegrationBaseTests { + private typealias Error = MSALNativeAuthJITIntrospectResponseError + private var provider: MSALNativeAuthJITRequestProvider! + + override func setUpWithError() throws { + try super.setUpWithError() + + provider = MSALNativeAuthJITRequestProvider(requestConfigurator: MSALNativeAuthRequestConfigurator(config: config)) + + let context = MSALNativeAuthRequestContext(correlationId: correlationId) + + sut = try provider.introspect( + parameters: .init(context: context, + continuationToken: "Test Credential Token"), + context: context + ) + } + + func test_succeedRequest_introspectSuccess() async throws { + try await mockResponse(.registrationIntrospectSuccess, endpoint: .jitIntrospect) + let response: MSALNativeAuthJITIntrospectResponse? = try await performTestSucceed() + + XCTAssertNotNil(response?.continuationToken) + XCTAssertNotNil(response?.methods) + XCTAssertTrue(response!.methods!.count > 0) + } + + func test_failRequest_expiredToken() async throws { + try await perform_testFail( + endpoint: .jitIntrospect, + response: .expiredToken, + expectedError: Error(error: .unknown, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) + ) + } + + func test_failRequest_invalidRequest() async throws { + try await perform_testFail( + endpoint: .jitIntrospect, + response: .invalidRequest, + expectedError: Error(error: .unknown, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil) + ) + } +} diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthEndpointTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthEndpointTests.swift index 199bc8312e..b1a43f93ac 100644 --- a/MSAL/test/unit/native_auth/network/MSALNativeAuthEndpointTests.swift +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthEndpointTests.swift @@ -30,7 +30,7 @@ final class MSALNativeAuthEndpointTests: XCTestCase { private typealias sut = MSALNativeAuthEndpoint func test_allEndpoints_are_tested() { - XCTAssertEqual(sut.allCases.count, 13) + XCTAssertEqual(sut.allCases.count, 16) } func test_signUp_start() { @@ -57,6 +57,18 @@ final class MSALNativeAuthEndpointTests: XCTestCase { XCTAssertEqual(sut.signInIntrospect.rawValue, "/oauth2/v2.0/introspect") } + func test_jitIntrospect_endpoint() { + XCTAssertEqual(sut.jitIntrospect.rawValue, "/register/v1.0/introspect") + } + + func test_jitChallenge_endpoint() { + XCTAssertEqual(sut.jitChallenge.rawValue, "/register/v1.0/challenge") + } + + func test_jitContinue_endpoint() { + XCTAssertEqual(sut.jitContinue.rawValue, "/register/v1.0/continue") + } + func test_token_endpoint() { XCTAssertEqual(sut.token.rawValue, "/oauth2/v2.0/token") } diff --git a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift index 4ae171202e..9029383f09 100644 --- a/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift +++ b/MSAL/test/unit/native_auth/network/MSALNativeAuthRequestConfiguratorTests.swift @@ -159,6 +159,96 @@ final class MSALNativeAuthRequestConfiguratorTests: XCTestCase { checkTelemetry(request.serverTelemetry, telemetry) } + func test_jitIntrospect_getsConfiguredSuccessfully() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [], redirectUri: nil)) + let telemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetryProvider.telemetryForRegister(type: .jitIntrospect), + context: context + ) + + let request = MSIDHttpRequest() + let params = MSALNativeAuthJITIntrospectRequestParameters(context: context, + continuationToken: "Test Continuation Token") + let sut = MSALNativeAuthRequestConfigurator(config: config) + try sut.configure(configuratorType: .jit(.introspect(params)), + request: request, + telemetryProvider: telemetryProvider) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "continuation_token": "Test Continuation Token" + ] + + XCTAssertEqual(request.parameters, expectedBodyParams) + checkUrlRequest(request.urlRequest, endpoint: .jitIntrospect) + checkHeaders(request: request) + checkTelemetry(request.serverTelemetry, telemetry) + } + + func test_jitChallenge_getsConfiguredSuccessfully() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [], redirectUri: nil)) + let telemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetryProvider.telemetryForRegister(type: .jitChallenge), + context: context + ) + + let request = MSIDHttpRequest() + let params = MSALNativeAuthJITChallengeRequestParameters( + context: context, + continuationToken: "Test Continuation Token", + authMethod: MSALAuthMethod(id: "1", + challengeType: "otp", + loginHint: "test-not-used@example.com", channelTargetType: MSALNativeAuthChannelType(value: "email")), + verificationContact: "test@example.com") + let sut = MSALNativeAuthRequestConfigurator(config: config) + try sut.configure(configuratorType: .jit(.challenge(params)), + request: request, + telemetryProvider: telemetryProvider) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "continuation_token": "Test Continuation Token", + "challenge_type": "otp", + "challenge_target": "test@example.com", + "challenge_channel": "email" + ] + + XCTAssertEqual(request.parameters, expectedBodyParams) + checkUrlRequest(request.urlRequest, endpoint: .jitChallenge) + checkHeaders(request: request) + checkTelemetry(request.serverTelemetry, telemetry) + } + + func test_jitContinue_getsConfiguredSuccessfully() throws { + XCTAssertNoThrow(config = try .init(clientId: DEFAULT_TEST_CLIENT_ID, authority: MSALCIAMAuthority(url: baseUrl), challengeTypes: [], redirectUri: nil)) + let telemetry = MSALNativeAuthServerTelemetry( + currentRequestTelemetry: telemetryProvider.telemetryForRegister(type: .jitContinue), + context: context + ) + + let request = MSIDHttpRequest() + let params = MSALNativeAuthJITContinueRequestParameters(context: context, + grantType: .oobCode, + continuationToken: "Test Continuation Token", + oobCode: "0000") + let sut = MSALNativeAuthRequestConfigurator(config: config) + try sut.configure(configuratorType: .jit(.continue(params)), + request: request, + telemetryProvider: telemetryProvider) + + let expectedBodyParams = [ + "client_id": DEFAULT_TEST_CLIENT_ID, + "grant_type": "oob", + "continuation_token": "Test Continuation Token", + "oob": "0000" + ] + + XCTAssertEqual(request.parameters, expectedBodyParams) + checkUrlRequest(request.urlRequest, endpoint: .jitContinue) + 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], redirectUri: nil)) let telemetry = MSALNativeAuthServerTelemetry( diff --git a/MSAL/test/unit/native_auth/network/errors/MSALNativeAuthSubErrorCodeTests.swift b/MSAL/test/unit/native_auth/network/errors/MSALNativeAuthSubErrorCodeTests.swift index 40e2b3b75e..896cd53559 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, 11) + XCTAssertEqual(sut.allCases.count, 12) } func test_passwordTooWeak() { @@ -71,4 +71,8 @@ final class MSALNativeAuthSubErrorCodeTests: XCTestCase { func test_mfaRequiredValue() { XCTAssertEqual(sut.mfaRequired.rawValue, "mfa_required") } + + func test_jitRequiredValue() { + XCTAssertEqual(sut.jitRequired.rawValue, "registration_required") + } } diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthJITResponseValidatorTests.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthJITResponseValidatorTests.swift new file mode 100644 index 0000000000..99d4c477c3 --- /dev/null +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthJITResponseValidatorTests.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_Unit_Test_Private + +final class MSALNativeAuthJITResponseValidatorTests: XCTestCase { + + private var sut: MSALNativeAuthJITResponseValidator! + private var context: MSALNativeAuthRequestContext! + private var defaultUUID = UUID(uuidString: DEFAULT_TEST_UID)! + + override func setUpWithError() throws { + try super.setUpWithError() + sut = MSALNativeAuthJITResponseValidator() + context = MSALNativeAuthRequestContext(correlationId: UUID()) + } + + // MARK: introspect API tests + func test_whenIntrospectWithNilAuthMethod_validationShouldFail() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let continuationToken = "continuationToken" + let challengeResponse = MSALNativeAuthJITIntrospectResponse(continuationToken: continuationToken, methods: nil) + let result = sut.validateIntrospect(context: context, result: .success(challengeResponse)) + if case .error(.unexpectedError(MSALNativeAuthJITIntrospectResponseError(error: .unknown, errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody, errorCodes: nil, errorURI: nil, innerErrors: nil, correlationId: nil))) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenIntrospectWithEmptyAuthMethodList_validationShouldFail() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let continuationToken = "continuationToken" + let challengeResponse = MSALNativeAuthJITIntrospectResponse(continuationToken: continuationToken, methods: []) + let result = sut.validateIntrospect(context: context, result: .success(challengeResponse)) + if case .error(.unexpectedError(MSALNativeAuthJITIntrospectResponseError(error: .unknown, errorDescription: MSALNativeAuthErrorMessage.unexpectedResponseBody, errorCodes: nil, errorURI: nil, innerErrors: nil, correlationId: nil))) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenIntrospectReturnsValidResult_validationNotFail() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let continuationToken = "continuationToken" + let methods = [MSALNativeAuthInternalAuthenticationMethod(id: "1", challengeType: .oob, challengeChannel: "email", loginHint: "us******so.com")] + let challengeResponse = MSALNativeAuthJITIntrospectResponse(continuationToken: continuationToken, methods: methods) + let result = sut.validateIntrospect(context: context, result: .success(challengeResponse)) + if case .authMethodsRetrieved(continuationToken: continuationToken, authMethods: methods) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + // MARK: challenge API tests + + func test_whenChallengeTypeRedirect_validationShouldReturnRedirectError() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let challengeResponse = MSALNativeAuthJITChallengeResponse(continuationToken: nil, challengeType: "redirect", bindingMethod: nil, challengeTarget: nil, challengeChannel: nil, codeLength: nil, interval: nil) + let result = sut.validateChallenge(context: context, result: .success(challengeResponse)) + if case .error(.redirect) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenChallengeTypeInvalidRequest_validationShouldReturnInvalidVerificationContact() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let challengeErrorResponse = MSALNativeAuthJITChallengeResponseError(error: .invalidRequest, errorCodes: [901001]) + let result = sut.validateChallenge(context: context, result: .failure(challengeErrorResponse)) + if case .error(.invalidVerificationContact) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenChallengeTypePassword_validationShouldFail() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let continuationToken = "continuationToken" + let challengeResponse = MSALNativeAuthJITChallengeResponse(continuationToken: continuationToken, challengeType: "password", bindingMethod: nil, challengeTarget: nil, challengeChannel: nil, codeLength: nil, interval: nil) + let result = sut.validateChallenge(context: context, result: .success(challengeResponse)) + if case .error(.unexpectedError(.init(errorDescription: "Unexpected challenge type"))) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenChallengeTypeOOB_validationShouldReturnCodeRequired() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let continuationToken = "continuationToken" + let targetLabel = "targetLabel" + let codeLength = 4 + let channelTypeRawValue = "email" + let challengeResponse = MSALNativeAuthJITChallengeResponse(continuationToken: continuationToken, challengeType: "oob", bindingMethod: nil, challengeTarget: targetLabel, challengeChannel: channelTypeRawValue, codeLength: codeLength, interval: nil) + let result = sut.validateChallenge(context: context, result: .success(challengeResponse)) + if case .codeRequired(let validatedCT, let sentTo, let channelType, let validatedCodeLength) = result { + XCTAssertEqual(validatedCT, continuationToken) + XCTAssertEqual(sentTo, targetLabel) + XCTAssertTrue(channelType.isEmailType) + XCTAssertEqual(validatedCodeLength, codeLength) + } else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenChallengeTypeOOBButMissingAttributes_validationShouldFail() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let continuationToken = "continuationToken" + let targetLabel = "targetLabel" + let codeLength = 4 + let channelType = "email" + let missingCredentialToken = MSALNativeAuthJITChallengeResponse(continuationToken: nil, challengeType: "oob", bindingMethod: nil, challengeTarget: targetLabel, challengeChannel: channelType, codeLength: codeLength, interval: nil) + var result = sut.validateChallenge(context: context, result: .success(missingCredentialToken)) + if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else { + XCTFail("Unexpected result: \(result)") + } + let missingTargetLabel = MSALNativeAuthJITChallengeResponse(continuationToken: continuationToken, challengeType: "oob", bindingMethod: nil, challengeTarget: nil, challengeChannel: channelType, codeLength: codeLength, interval: nil) + result = sut.validateChallenge(context: context, result: .success(missingTargetLabel)) + if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else { + XCTFail("Unexpected result: \(result)") + } + let missingChannelType = MSALNativeAuthJITChallengeResponse(continuationToken: continuationToken, challengeType: "oob", bindingMethod: nil, challengeTarget: targetLabel, challengeChannel: nil, codeLength: codeLength, interval: nil) + result = sut.validateChallenge(context: context, result: .success(missingChannelType)) + if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else { + XCTFail("Unexpected result: \(result)") + } + let missingCodeLength = MSALNativeAuthJITChallengeResponse(continuationToken: continuationToken, challengeType: "oob", bindingMethod: nil, challengeTarget: targetLabel, challengeChannel: channelType, codeLength: nil, interval: nil) + result = sut.validateChallenge(context: context, result: .success(missingCodeLength)) + if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenChallengeTypeOTP_validationShouldFail() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let challengeResponse = MSALNativeAuthJITChallengeResponse(continuationToken: "something", challengeType: "otp", bindingMethod: nil, challengeTarget: "some", challengeChannel: "email", codeLength: 2, interval: nil) + let result = sut.validateChallenge(context: context, result: .success(challengeResponse)) + if case .error(.unexpectedError(.init(errorDescription: "Unexpected challenge type"))) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + // MARK: - continue API tests + + func test_whenContinueReturnsInvalidGrantWithoutCorrectSubError_validationShouldReturnUnexpectedError() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let continueErrorResponse = MSALNativeAuthJITContinueResponseError(error: .invalidGrant) + let result = sut.validateContinue(context: context, result: .failure(continueErrorResponse)) + if case .error(.unexpectedError(.init(error:.invalidGrant, errorDescription: nil))) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenContinueReturnsInvalidGrantWithoutCorrectSubError_validationShouldReturnCorrectError() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let continueErrorResponse = MSALNativeAuthJITContinueResponseError(error: .invalidGrant, subError: .invalidOOBValue) + let result = sut.validateContinue(context: context, result: .failure(continueErrorResponse)) + if case .error(.invalidOOBCode(continueErrorResponse)) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenJITContinueSuccessResponseMissingContinuationToken_validationShouldFail() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let continueResponse = MSALNativeAuthJITContinueResponse(continuationToken: nil, correlationId: context.correlationId()) + let result = sut.validateContinue(context: context, result: .success(continueResponse)) + if case .error(.unexpectedError(.init(errorDescription: "Unexpected response body received"))) = result {} else { + XCTFail("Unexpected result: \(result)") + } + } + + func test_whenJITContinueSuccessResponseContainsContinuationToken_validationShouldSucceed() { + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let continueResponse = MSALNativeAuthJITContinueResponse(continuationToken: "", correlationId: context.correlationId()) + let result = sut.validateContinue(context: context, result: .success(continueResponse)) + if case .success(continuationToken: "") = result {} else { + XCTFail("Unexpected result: \(result)") + } + } +} diff --git a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTests.swift similarity index 98% rename from MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift rename to MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTests.swift index b3341ff70f..c17192ef84 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTest.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthSignInResponseValidatorTests.swift @@ -26,18 +26,16 @@ import XCTest @testable import MSAL @_implementationOnly import MSAL_Unit_Test_Private -final class MSALNativeAuthSignInResponseValidatorTest: MSALNativeAuthTestCase { +final class MSALNativeAuthSignInResponseValidatorTests: 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() } 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 50585153df..c51a4402ee 100644 --- a/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift +++ b/MSAL/test/unit/native_auth/network/responses/validator/MSALNativeAuthTokenResponseValidatorTests.swift @@ -219,6 +219,34 @@ final class MSALNativeAuthTokenResponseValidatorTest: MSALNativeAuthTestCase { XCTAssertEqual(validatedError?.error, .unknown) } + func test_invalidGrantRegisterRequired_triggerJITRequiredResponse() { + let continuationTokenResponse = "ct" + let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, subError: .jitRequired, errorDescription: nil, errorCodes: nil, errorURI: nil, innerErrors: nil, continuationToken: continuationTokenResponse) + + let context = MSALNativeAuthRequestContext(correlationId: defaultUUID) + let result = sut.validate(context: context, msidConfiguration: MSALNativeAuthConfigStubs.msidConfiguration, result: .failure(error)) + + guard case .jitRequired(let continuationToken) = result else { + return XCTFail("Unexpected response") + } + XCTAssertEqual(continuationTokenResponse, continuationToken) + } + + func test_invalidGrantRegistrationRequiredNoContinuationToken_validationFails() { + let error = MSALNativeAuthTokenResponseError(error: .invalidGrant, subError: .jitRequired, 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)) + + guard case .error(let errorType) = result else { + return XCTFail("Unexpected response") + } + guard case .generalError(let validatedError) = errorType else { + return XCTFail("Unexpected Error") + } + XCTAssertEqual(validatedError?.error, .unknown) + } + func test_invalidGrantTokenResponse_withUnknownErrorCode_andKnownErrorCodes_isProperlyHandled() { let knownErrorCode = MSALNativeAuthESTSApiErrorCodes.userNotFound.rawValue let unknownErrorCode1 = Int.max