diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index 1633bfd437..9d3dfce677 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -7,7 +7,33 @@ objects = { /* Begin PBXBuildFile section */ + 01462653AC546A8B95A0D912 /* MSALNativeAuthMFARequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FE5D3DE054DBA691A401E3D /* MSALNativeAuthMFARequiredState.swift */; }; 022239DBCF2EF4AD83359DD3 /* MailTMConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B4CF9C872C00B3E5FD2C40 /* MailTMConstants.swift */; }; + 06AAD69B63B7A013959ECEF7 /* MSALNativeAuthFlowScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88219AB3EAB46203CD9729B9 /* MSALNativeAuthFlowScenario.swift */; }; + 1FFBE815F16A5C07BCAEEA7A /* MSALNativeAuthCodeRequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FB0FFEFC459978DDDDE9212 /* MSALNativeAuthCodeRequiredState.swift */; }; + 32EB647A08781A29C344ACC6 /* MSALNativeAuthStrongAuthRegistrationRequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509588E9A2AE1A919D2AF029 /* MSALNativeAuthStrongAuthRegistrationRequiredState.swift */; }; + 3661378FB7B5DA5CCB37D76E /* MSALNativeAuthPasswordRequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4EA08303731BCACB308104F /* MSALNativeAuthPasswordRequiredState.swift */; }; + 42E1FE910A9592561A2F44DC /* MSALNativeAuthStrongAuthVerificationRequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAEA06244B0DACD04D94193D /* MSALNativeAuthStrongAuthVerificationRequiredState.swift */; }; + 4F6C95BC33A85725CB3F2185 /* MSALNativeAuthStrongAuthRegistrationRequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509588E9A2AE1A919D2AF029 /* MSALNativeAuthStrongAuthRegistrationRequiredState.swift */; }; + 5A7906E804836B39F0D61EE5 /* MSALNativeAuthFlowScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88219AB3EAB46203CD9729B9 /* MSALNativeAuthFlowScenario.swift */; }; + 5DA9B72FCAECBF4718161CE1 /* MSALNativeAuthAttributesInvalidState.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFEF89FFAE159B6EE80EDFC7 /* MSALNativeAuthAttributesInvalidState.swift */; }; + 6534A6BDFED26846E71370A9 /* MSALNativeAuthAttributesRequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A315CA10DE2299B7370E11BE /* MSALNativeAuthAttributesRequiredState.swift */; }; + 6A130FEA55D11486D2F4FA55 /* MSALNativeAuthCodeRequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FB0FFEFC459978DDDDE9212 /* MSALNativeAuthCodeRequiredState.swift */; }; + 6B4459C145930D5EC63EA477 /* MSALNativeAuthMFAVerificationRequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6439500470AC3BBD79E7D046 /* MSALNativeAuthMFAVerificationRequiredState.swift */; }; + 6FF4FECB6AE1581341C3AF5E /* MSALNativeAuthFlowError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87AA69B6347AED83F0C677E4 /* MSALNativeAuthFlowError.swift */; }; + 79B0D18719E266EBFAA96F9D /* MSALNativeAuthStrongAuthVerificationRequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAEA06244B0DACD04D94193D /* MSALNativeAuthStrongAuthVerificationRequiredState.swift */; }; + 969B85F56D10B314FEE5E165 /* MSALNativeAuthState.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF41A7FB39DDF09BF8D97B35 /* MSALNativeAuthState.swift */; }; + 9959BEB45FADB738C8BFE331 /* MSALNativeAuthAttributesRequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A315CA10DE2299B7370E11BE /* MSALNativeAuthAttributesRequiredState.swift */; }; + B311DA009515BDDE5FDF3679 /* MSALNativeAuthMFARequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FE5D3DE054DBA691A401E3D /* MSALNativeAuthMFARequiredState.swift */; }; + B3E12C5ECC553A95521CFEFA /* MSALNativeAuthNewPasswordRequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8273A2EAA82AE303691B976F /* MSALNativeAuthNewPasswordRequiredState.swift */; }; + BCC3280FFD148F8A55084523 /* MSALNativeAuthFlowDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7081D4EEFA60AF1D7938C1C /* MSALNativeAuthFlowDelegate.swift */; }; + BE5CFDC45CA2EB0EC61A9A85 /* MSALNativeAuthFlowError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87AA69B6347AED83F0C677E4 /* MSALNativeAuthFlowError.swift */; }; + C4675E1CCC8208251CE74818 /* MSALNativeAuthPasswordRequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4EA08303731BCACB308104F /* MSALNativeAuthPasswordRequiredState.swift */; }; + DE5CDB156AF38066359E4B66 /* MSALNativeAuthState.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF41A7FB39DDF09BF8D97B35 /* MSALNativeAuthState.swift */; }; + E03A45C678944B4F5D572922 /* MSALNativeAuthNewPasswordRequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8273A2EAA82AE303691B976F /* MSALNativeAuthNewPasswordRequiredState.swift */; }; + E952116ECFF2C75D77A896AB /* MSALNativeAuthFlowDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7081D4EEFA60AF1D7938C1C /* MSALNativeAuthFlowDelegate.swift */; }; + F05FC2CFEF1AE5462086AD0C /* MSALNativeAuthMFAVerificationRequiredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6439500470AC3BBD79E7D046 /* MSALNativeAuthMFAVerificationRequiredState.swift */; }; + F68F10EB13E4A78906E6C12E /* MSALNativeAuthAttributesInvalidState.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFEF89FFAE159B6EE80EDFC7 /* MSALNativeAuthAttributesInvalidState.swift */; }; 04A6B5AE226936F30035C7C2 /* MSALFramework.m in Sources */ = {isa = PBXBuildFile; fileRef = D61F5BC91E59359900912CB8 /* MSALFramework.m */; }; 04A6B5AF226936F40035C7C2 /* MSALFramework.m in Sources */ = {isa = PBXBuildFile; fileRef = D61F5BC91E59359900912CB8 /* MSALFramework.m */; }; 04A6B5B0226936FE0035C7C2 /* MSIDVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = B2C17B091FC8DB2E0070A514 /* MSIDVersion.m */; }; @@ -1102,14 +1128,18 @@ DE43150A2D3E551F009A7FA2 /* MSALNativeAuthGetAccessTokenParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4315032D3E551E009A7FA2 /* MSALNativeAuthGetAccessTokenParameters.swift */; }; DE43150B2D3E551F009A7FA2 /* MSALNativeAuthSignInParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4315072D3E551E009A7FA2 /* MSALNativeAuthSignInParameters.swift */; }; DE43150C2D3E551F009A7FA2 /* MSALNativeAuthSignUpParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4315082D3E551E009A7FA2 /* MSALNativeAuthSignUpParameters.swift */; }; + FE0A0B00000000000000A002 /* MSALNativeAuthSignUpParametersV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE0A0B00000000000000F002 /* MSALNativeAuthSignUpParametersV2.swift */; }; DE43150D2D3E551F009A7FA2 /* MSALNativeAuthSignInAfterSignUpParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4315062D3E551E009A7FA2 /* MSALNativeAuthSignInAfterSignUpParameters.swift */; }; DE43150E2D3E551F009A7FA2 /* MSALNativeAuthResetPasswordParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4315042D3E551E009A7FA2 /* MSALNativeAuthResetPasswordParameters.swift */; }; + FE0A0B00000000000000A001 /* MSALNativeAuthResetPasswordParametersV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE0A0B00000000000000F001 /* MSALNativeAuthResetPasswordParametersV2.swift */; }; DE43150F2D3E551F009A7FA2 /* MSALNativeAuthSignInAfterResetPasswordParameters .swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4315052D3E551E009A7FA2 /* MSALNativeAuthSignInAfterResetPasswordParameters .swift */; }; DE4315102D3E551F009A7FA2 /* MSALNativeAuthGetAccessTokenParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4315032D3E551E009A7FA2 /* MSALNativeAuthGetAccessTokenParameters.swift */; }; DE4315112D3E551F009A7FA2 /* MSALNativeAuthSignInParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4315072D3E551E009A7FA2 /* MSALNativeAuthSignInParameters.swift */; }; DE4315122D3E551F009A7FA2 /* MSALNativeAuthSignUpParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4315082D3E551E009A7FA2 /* MSALNativeAuthSignUpParameters.swift */; }; + FE0A0B00000000000000B002 /* MSALNativeAuthSignUpParametersV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE0A0B00000000000000F002 /* MSALNativeAuthSignUpParametersV2.swift */; }; DE4315132D3E551F009A7FA2 /* MSALNativeAuthSignInAfterSignUpParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4315062D3E551E009A7FA2 /* MSALNativeAuthSignInAfterSignUpParameters.swift */; }; DE4315142D3E551F009A7FA2 /* MSALNativeAuthResetPasswordParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4315042D3E551E009A7FA2 /* MSALNativeAuthResetPasswordParameters.swift */; }; + FE0A0B00000000000000B001 /* MSALNativeAuthResetPasswordParametersV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE0A0B00000000000000F001 /* MSALNativeAuthResetPasswordParametersV2.swift */; }; DE4315152D3E551F009A7FA2 /* MSALNativeAuthSignInAfterResetPasswordParameters .swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4315052D3E551E009A7FA2 /* MSALNativeAuthSignInAfterResetPasswordParameters .swift */; }; DE4F0F3129D6F1AA00D561FD /* MSALNativeAuthTokenIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4F0F2929D6F1AA00D561FD /* MSALNativeAuthTokenIntegrationTests.swift */; }; DE54B5912A434B9B00460B34 /* MSALNativeAuthTokenController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE54B5902A434B9B00460B34 /* MSALNativeAuthTokenController.swift */; }; @@ -2216,6 +2246,19 @@ 28FDC4AB2A38D7D200E38BE1 /* MSALNativeAuthSignInControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInControllerMock.swift; sourceTree = ""; }; 475F1413DA1D76D5EF31F4EC /* MailTMHTTPClient.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MailTMHTTPClient.swift; sourceTree = ""; }; 49AAD919E560052DA700D2DA /* RetryExecutor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RetryExecutor.swift; sourceTree = ""; }; + 509588E9A2AE1A919D2AF029 /* MSALNativeAuthStrongAuthRegistrationRequiredState.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthStrongAuthRegistrationRequiredState.swift; sourceTree = ""; }; + 6439500470AC3BBD79E7D046 /* MSALNativeAuthMFAVerificationRequiredState.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthMFAVerificationRequiredState.swift; sourceTree = ""; }; + 8273A2EAA82AE303691B976F /* MSALNativeAuthNewPasswordRequiredState.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthNewPasswordRequiredState.swift; sourceTree = ""; }; + 87AA69B6347AED83F0C677E4 /* MSALNativeAuthFlowError.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthFlowError.swift; sourceTree = ""; }; + 88219AB3EAB46203CD9729B9 /* MSALNativeAuthFlowScenario.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthFlowScenario.swift; sourceTree = ""; }; + 8FB0FFEFC459978DDDDE9212 /* MSALNativeAuthCodeRequiredState.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthCodeRequiredState.swift; sourceTree = ""; }; + 8FE5D3DE054DBA691A401E3D /* MSALNativeAuthMFARequiredState.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthMFARequiredState.swift; sourceTree = ""; }; + A315CA10DE2299B7370E11BE /* MSALNativeAuthAttributesRequiredState.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthAttributesRequiredState.swift; sourceTree = ""; }; + B4EA08303731BCACB308104F /* MSALNativeAuthPasswordRequiredState.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthPasswordRequiredState.swift; sourceTree = ""; }; + B7081D4EEFA60AF1D7938C1C /* MSALNativeAuthFlowDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthFlowDelegate.swift; sourceTree = ""; }; + BFEF89FFAE159B6EE80EDFC7 /* MSALNativeAuthAttributesInvalidState.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthAttributesInvalidState.swift; sourceTree = ""; }; + FAEA06244B0DACD04D94193D /* MSALNativeAuthStrongAuthVerificationRequiredState.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthStrongAuthVerificationRequiredState.swift; sourceTree = ""; }; + FF41A7FB39DDF09BF8D97B35 /* MSALNativeAuthState.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthState.swift; sourceTree = ""; }; 583BFD1524DDF9B10035B901 /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; 58B81F6524AC59A000E8799E /* MSALTestCacheTokenResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALTestCacheTokenResponse.h; sourceTree = ""; }; 58B81F6E24AC59C600E8799E /* MSALTestCacheTokenResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALTestCacheTokenResponse.m; sourceTree = ""; }; @@ -2610,10 +2653,12 @@ DE40A4D22A8F80C100928CEE /* MSALNativeAuthSignUpContinueResponseErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpContinueResponseErrorTests.swift; sourceTree = ""; }; DE4315032D3E551E009A7FA2 /* MSALNativeAuthGetAccessTokenParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthGetAccessTokenParameters.swift; sourceTree = ""; }; DE4315042D3E551E009A7FA2 /* MSALNativeAuthResetPasswordParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordParameters.swift; sourceTree = ""; }; + FE0A0B00000000000000F001 /* MSALNativeAuthResetPasswordParametersV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthResetPasswordParametersV2.swift; sourceTree = ""; }; DE4315052D3E551E009A7FA2 /* MSALNativeAuthSignInAfterResetPasswordParameters .swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MSALNativeAuthSignInAfterResetPasswordParameters .swift"; sourceTree = ""; }; DE4315062D3E551E009A7FA2 /* MSALNativeAuthSignInAfterSignUpParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInAfterSignUpParameters.swift; sourceTree = ""; }; DE4315072D3E551E009A7FA2 /* MSALNativeAuthSignInParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInParameters.swift; sourceTree = ""; }; DE4315082D3E551E009A7FA2 /* MSALNativeAuthSignUpParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpParameters.swift; sourceTree = ""; }; + FE0A0B00000000000000F002 /* MSALNativeAuthSignUpParametersV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignUpParametersV2.swift; sourceTree = ""; }; DE4F0F2929D6F1AA00D561FD /* MSALNativeAuthTokenIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenIntegrationTests.swift; sourceTree = ""; }; DE53C7D4293F9F5A00E5B2BB /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; DE54B5902A434B9B00460B34 /* MSALNativeAuthTokenController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenController.swift; sourceTree = ""; }; @@ -3336,6 +3381,7 @@ 28DCD09529D7170F00C4601E /* state */, 28DCD09029D7165700C4601E /* delegate */, 28F8D29C2D8C6B1C005084FA /* result */, + F58967D39C050697CB65B47C /* v2 */, ); path = state_machine; sourceTree = ""; @@ -3449,6 +3495,34 @@ path = result; sourceTree = ""; }; + 58F36BCB7532CC3D9D60EE3A /* state */ = { + isa = PBXGroup; + children = ( + FF41A7FB39DDF09BF8D97B35 /* MSALNativeAuthState.swift */, + 8FB0FFEFC459978DDDDE9212 /* MSALNativeAuthCodeRequiredState.swift */, + B4EA08303731BCACB308104F /* MSALNativeAuthPasswordRequiredState.swift */, + 8273A2EAA82AE303691B976F /* MSALNativeAuthNewPasswordRequiredState.swift */, + A315CA10DE2299B7370E11BE /* MSALNativeAuthAttributesRequiredState.swift */, + BFEF89FFAE159B6EE80EDFC7 /* MSALNativeAuthAttributesInvalidState.swift */, + 8FE5D3DE054DBA691A401E3D /* MSALNativeAuthMFARequiredState.swift */, + 6439500470AC3BBD79E7D046 /* MSALNativeAuthMFAVerificationRequiredState.swift */, + 509588E9A2AE1A919D2AF029 /* MSALNativeAuthStrongAuthRegistrationRequiredState.swift */, + FAEA06244B0DACD04D94193D /* MSALNativeAuthStrongAuthVerificationRequiredState.swift */, + ); + path = state; + sourceTree = ""; + }; + F58967D39C050697CB65B47C /* v2 */ = { + isa = PBXGroup; + children = ( + 87AA69B6347AED83F0C677E4 /* MSALNativeAuthFlowError.swift */, + B7081D4EEFA60AF1D7938C1C /* MSALNativeAuthFlowDelegate.swift */, + 88219AB3EAB46203CD9729B9 /* MSALNativeAuthFlowScenario.swift */, + 58F36BCB7532CC3D9D60EE3A /* state */, + ); + path = v2; + sourceTree = ""; + }; 91AA245E2BDF6441005037EA /* Preview Content */ = { isa = PBXGroup; children = ( @@ -4469,10 +4543,12 @@ children = ( DE4315032D3E551E009A7FA2 /* MSALNativeAuthGetAccessTokenParameters.swift */, DE4315042D3E551E009A7FA2 /* MSALNativeAuthResetPasswordParameters.swift */, + FE0A0B00000000000000F001 /* MSALNativeAuthResetPasswordParametersV2.swift */, DE4315052D3E551E009A7FA2 /* MSALNativeAuthSignInAfterResetPasswordParameters .swift */, DE4315062D3E551E009A7FA2 /* MSALNativeAuthSignInAfterSignUpParameters.swift */, DE4315072D3E551E009A7FA2 /* MSALNativeAuthSignInParameters.swift */, DE4315082D3E551E009A7FA2 /* MSALNativeAuthSignUpParameters.swift */, + FE0A0B00000000000000F002 /* MSALNativeAuthSignUpParametersV2.swift */, 28F8D2932D8C5EBC005084FA /* MSALNativeAuthChallengeAuthMethodParameters.swift */, ); path = parameters; @@ -6968,6 +7044,19 @@ 28DCD0B229D7392400C4601E /* ResetPasswordStates.swift in Sources */, 23A68A7620F5386A0071E435 /* MSALAADAuthority.m in Sources */, 28DCD09A29D7192F00C4601E /* MSALNativeAuthError.swift in Sources */, + BE5CFDC45CA2EB0EC61A9A85 /* MSALNativeAuthFlowError.swift in Sources */, + BCC3280FFD148F8A55084523 /* MSALNativeAuthFlowDelegate.swift in Sources */, + 06AAD69B63B7A013959ECEF7 /* MSALNativeAuthFlowScenario.swift in Sources */, + DE5CDB156AF38066359E4B66 /* MSALNativeAuthState.swift in Sources */, + 6A130FEA55D11486D2F4FA55 /* MSALNativeAuthCodeRequiredState.swift in Sources */, + 3661378FB7B5DA5CCB37D76E /* MSALNativeAuthPasswordRequiredState.swift in Sources */, + B3E12C5ECC553A95521CFEFA /* MSALNativeAuthNewPasswordRequiredState.swift in Sources */, + 6534A6BDFED26846E71370A9 /* MSALNativeAuthAttributesRequiredState.swift in Sources */, + F68F10EB13E4A78906E6C12E /* MSALNativeAuthAttributesInvalidState.swift in Sources */, + B311DA009515BDDE5FDF3679 /* MSALNativeAuthMFARequiredState.swift in Sources */, + 6B4459C145930D5EC63EA477 /* MSALNativeAuthMFAVerificationRequiredState.swift in Sources */, + 32EB647A08781A29C344ACC6 /* MSALNativeAuthStrongAuthRegistrationRequiredState.swift in Sources */, + 42E1FE910A9592561A2F44DC /* MSALNativeAuthStrongAuthVerificationRequiredState.swift in Sources */, 28FDC4A92A38C0D100E38BE1 /* SignInAfterSignUpError.swift in Sources */, 233E96FD22653EFC007FCE2A /* MSALTelemetryEventsObservingProxy.m in Sources */, DE0D65C229D30C38005798B1 /* MSALNativeAuthSignInInitiateOauth2ErrorCode.swift in Sources */, @@ -7160,6 +7249,7 @@ DE43150A2D3E551F009A7FA2 /* MSALNativeAuthGetAccessTokenParameters.swift in Sources */, DE43150B2D3E551F009A7FA2 /* MSALNativeAuthSignInParameters.swift in Sources */, DE43150C2D3E551F009A7FA2 /* MSALNativeAuthSignUpParameters.swift in Sources */, + FE0A0B00000000000000A002 /* MSALNativeAuthSignUpParametersV2.swift in Sources */, DE89740F2DA52BE800C67203 /* MSALNativeAuthJITIntrospectOauth2ErrorCode.swift in Sources */, DE8974102DA52BE800C67203 /* MSALNativeAuthJITContinueOauth2ErrorCode.swift in Sources */, DE8974112DA52BE800C67203 /* MSALNativeAuthJITChallengeResponseError.swift in Sources */, @@ -7168,6 +7258,7 @@ DE8974142DA52BE800C67203 /* MSALNativeAuthJITContinueResponseError.swift in Sources */, DE43150D2D3E551F009A7FA2 /* MSALNativeAuthSignInAfterSignUpParameters.swift in Sources */, DE43150E2D3E551F009A7FA2 /* MSALNativeAuthResetPasswordParameters.swift in Sources */, + FE0A0B00000000000000A001 /* MSALNativeAuthResetPasswordParametersV2.swift in Sources */, DE43150F2D3E551F009A7FA2 /* MSALNativeAuthSignInAfterResetPasswordParameters .swift in Sources */, 232D68D8223DB8C200594BBD /* MSALSilentTokenParameters.m in Sources */, DE729ECD2A1793A100A761D9 /* MSALNativeAuthChannelType.swift in Sources */, @@ -7310,6 +7401,19 @@ DE8DC48E2C6621A300534E8F /* SignUpStates+Internal.swift in Sources */, DE8DC4C62C6621C500534E8F /* MSALNativeAuthSignInChallengeResponse.swift in Sources */, DE8DC47F2C6621A100534E8F /* MSALNativeAuthError.swift in Sources */, + 6FF4FECB6AE1581341C3AF5E /* MSALNativeAuthFlowError.swift in Sources */, + E952116ECFF2C75D77A896AB /* MSALNativeAuthFlowDelegate.swift in Sources */, + 5A7906E804836B39F0D61EE5 /* MSALNativeAuthFlowScenario.swift in Sources */, + 969B85F56D10B314FEE5E165 /* MSALNativeAuthState.swift in Sources */, + 1FFBE815F16A5C07BCAEEA7A /* MSALNativeAuthCodeRequiredState.swift in Sources */, + C4675E1CCC8208251CE74818 /* MSALNativeAuthPasswordRequiredState.swift in Sources */, + E03A45C678944B4F5D572922 /* MSALNativeAuthNewPasswordRequiredState.swift in Sources */, + 9959BEB45FADB738C8BFE331 /* MSALNativeAuthAttributesRequiredState.swift in Sources */, + 5DA9B72FCAECBF4718161CE1 /* MSALNativeAuthAttributesInvalidState.swift in Sources */, + 01462653AC546A8B95A0D912 /* MSALNativeAuthMFARequiredState.swift in Sources */, + F05FC2CFEF1AE5462086AD0C /* MSALNativeAuthMFAVerificationRequiredState.swift in Sources */, + 4F6C95BC33A85725CB3F2185 /* MSALNativeAuthStrongAuthRegistrationRequiredState.swift in Sources */, + 79B0D18719E266EBFAA96F9D /* MSALNativeAuthStrongAuthVerificationRequiredState.swift in Sources */, DE8DC4A82C6621B100534E8F /* MSALNativeAuthUrlRequestSerializer.swift in Sources */, 232D616522485BA700260C42 /* MSALIndividualClaimRequestAdditionalInfo.m in Sources */, DE8DC4CD2C6621C700534E8F /* MSALNativeAuthResendCodeRequestResponse.swift in Sources */, @@ -7443,8 +7547,10 @@ DEEFCE552DB0FA4800237F5A /* MSALNativeAuthLogger.swift in Sources */, DE4315112D3E551F009A7FA2 /* MSALNativeAuthSignInParameters.swift in Sources */, DE4315122D3E551F009A7FA2 /* MSALNativeAuthSignUpParameters.swift in Sources */, + FE0A0B00000000000000B002 /* MSALNativeAuthSignUpParametersV2.swift in Sources */, DE4315132D3E551F009A7FA2 /* MSALNativeAuthSignInAfterSignUpParameters.swift in Sources */, DE4315142D3E551F009A7FA2 /* MSALNativeAuthResetPasswordParameters.swift in Sources */, + FE0A0B00000000000000B001 /* MSALNativeAuthResetPasswordParametersV2.swift in Sources */, DE4315152D3E551F009A7FA2 /* MSALNativeAuthSignInAfterResetPasswordParameters .swift in Sources */, DE8DC4852C6621A300534E8F /* SignInAfterPreviousFlowBaseState+Internal.swift in Sources */, DE8DC49E2C6621AE00534E8F /* MSALNativeAuthResetPasswordRequestProvider.swift in Sources */, diff --git a/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift b/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift index 1efa01d2a9..ceb577e229 100644 --- a/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift +++ b/MSAL/src/native_auth/network/errors/MSALNativeAuthErrorMessage.swift @@ -39,6 +39,8 @@ enum MSALNativeAuthErrorMessage { static let invalidUsername = "Invalid username" static let generalError = "General error" static let invalidCode = "Invalid code" + static let delegateNotImplementedV2 = "Delegate %@ is not implemented" + static let invalidContinuationToken = "Invalid continuation token" static let invalidChallenge = "Invalid challenge" static let invalidInput = "Invalid input" static let refreshTokenExpired = "Refresh token is expired" diff --git a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift index 27dbf4e7d7..50a70c381a 100644 --- a/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift +++ b/MSAL/src/native_auth/public/MSALNativeAuthPublicClientApplication.swift @@ -230,7 +230,7 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic } } - /// Reset the password using parameters + /// Reset the password using parameters. /// - Parameters: /// - parameters: Parameters used for the Reset Password flow. /// - delegate: Delegate that receives callbacks for the Reset Password flow. @@ -259,6 +259,62 @@ public final class MSALNativeAuthPublicClientApplication: MSALPublicClientApplic } } + // MARK: - Native Auth V2 (server-driven) + + /// Sign up a user using the server-driven (V2) flow. + /// + /// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. + /// - Parameters: + /// - parameters: Parameters used for the Sign Up flow. + /// - delegate: Unified delegate that receives callbacks for the flow. + public func signUpV2( + parameters: MSALNativeAuthSignUpParametersV2, + delegate: MSALNativeAuthFlowDelegate + ) { + Task { @MainActor in + delegate.onFlowError( + error: MSALNativeAuthFlowError(type: .notImplemented, correlationId: parameters.correlationId ?? UUID()), + scenario: .signUp + ) + } + } + + /// Sign in a user using the server-driven (V2) flow. + /// + /// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. + /// - Parameters: + /// - parameters: Parameters used for the Sign In flow. + /// - delegate: Unified delegate that receives callbacks for the flow. + public func signInV2( + parameters: MSALNativeAuthSignInParameters, + delegate: MSALNativeAuthFlowDelegate + ) { + Task { @MainActor in + delegate.onFlowError( + error: MSALNativeAuthFlowError(type: .notImplemented, correlationId: parameters.correlationId ?? UUID()), + scenario: .signIn + ) + } + } + + /// Reset the password using the server-driven (V2) flow. + /// + /// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. + /// - Parameters: + /// - parameters: Parameters used for the Reset Password flow. + /// - delegate: Unified delegate that receives callbacks for the flow. + public func resetPasswordV2( + parameters: MSALNativeAuthResetPasswordParametersV2, + delegate: MSALNativeAuthFlowDelegate + ) { + Task { @MainActor in + delegate.onFlowError( + error: MSALNativeAuthFlowError(type: .notImplemented, correlationId: parameters.correlationId ?? UUID()), + scenario: .passwordReset + ) + } + } + /// Retrieve the current signed in account from the cache. /// - Parameter correlationId: Optional. UUID to correlate this request with the server for debugging. /// - Returns: An object representing the account information if present in the local cache. diff --git a/MSAL/src/native_auth/public/parameters/MSALNativeAuthResetPasswordParametersV2.swift b/MSAL/src/native_auth/public/parameters/MSALNativeAuthResetPasswordParametersV2.swift new file mode 100644 index 0000000000..45ee43a9b2 --- /dev/null +++ b/MSAL/src/native_auth/public/parameters/MSALNativeAuthResetPasswordParametersV2.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/// Encapsulates the parameters passed to the resetPasswordV2 method of MSALNativeAuthPublicClientApplication. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objcMembers +public class MSALNativeAuthResetPasswordParametersV2: MSALNativeAuthResetPasswordParameters { + + /// Permissions you want included in the access token received once the account is signed in + /// at the end of the reset password flow. + /// Not all scopes are guaranteed to be included in the access token returned. + public var scopes: [String]? + + public override init(username: String) { + super.init(username: username) + } +} diff --git a/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignUpParametersV2.swift b/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignUpParametersV2.swift new file mode 100644 index 0000000000..e856ad01fb --- /dev/null +++ b/MSAL/src/native_auth/public/parameters/MSALNativeAuthSignUpParametersV2.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/// Encapsulates the parameters passed to the signUpV2 method of MSALNativeAuthPublicClientApplication. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objcMembers +public class MSALNativeAuthSignUpParametersV2: MSALNativeAuthSignUpParameters { + + /// Permissions you want included in the access token received once the account is signed in + /// at the end of the sign up flow. + /// Not all scopes are guaranteed to be included in the access token returned. + public var scopes: [String]? + + public override init(username: String) { + super.init(username: username) + } +} diff --git a/MSAL/src/native_auth/public/state_machine/error/MFARequestChallengeError.swift b/MSAL/src/native_auth/public/state_machine/error/MFARequestChallengeError.swift index ffe4c2cec9..3c4a5c3bc6 100644 --- a/MSAL/src/native_auth/public/state_machine/error/MFARequestChallengeError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/MFARequestChallengeError.swift @@ -37,7 +37,14 @@ public class MFARequestChallengeError: MSALNativeAuthError { init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) { self.type = type - super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri) + super.init( + message: message, + correlationId: correlationId, + errorCodes: errorCodes, + errorUri: errorUri, + isBrowserRequired: type == .browserRequired, + isGeneralError: type == .generalError + ) } /// Describes why an error occurred and provides more information about the error. @@ -60,9 +67,4 @@ public class MFARequestChallengeError: MSALNativeAuthError { public var isAuthMethodBlocked: Bool { return type == .authMethodBlocked } - - /// Returns `true` if a browser is required to continue the operation. - public var isBrowserRequired: Bool { - return type == .browserRequired - } } diff --git a/MSAL/src/native_auth/public/state_machine/error/MFASubmitChallengeError.swift b/MSAL/src/native_auth/public/state_machine/error/MFASubmitChallengeError.swift index 9de15bf7df..0aba4566b3 100644 --- a/MSAL/src/native_auth/public/state_machine/error/MFASubmitChallengeError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/MFASubmitChallengeError.swift @@ -37,7 +37,14 @@ public class MFASubmitChallengeError: MSALNativeAuthError { init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) { self.type = type - super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri) + super.init( + message: message, + correlationId: correlationId, + errorCodes: errorCodes, + errorUri: errorUri, + isBrowserRequired: type == .browserRequired, + isGeneralError: type == .generalError + ) } init(error: VerifyCodeError) { @@ -53,7 +60,9 @@ public class MFASubmitChallengeError: MSALNativeAuthError { message: error.errorDescription, correlationId: error.correlationId, errorCodes: error.errorCodes, - errorUri: error.errorUri + errorUri: error.errorUri, + isBrowserRequired: self.type == .browserRequired, + isGeneralError: self.type == .generalError ) } @@ -77,9 +86,4 @@ public class MFASubmitChallengeError: MSALNativeAuthError { public var isInvalidChallenge: Bool { return type == .invalidChallenge } - - /// Returns `true` if a browser is required to continue the operation. - public var isBrowserRequired: Bool { - return type == .browserRequired - } } diff --git a/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift b/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift index 72a3d56edb..3c53c26a05 100644 --- a/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthError.swift @@ -39,12 +39,27 @@ public class MSALNativeAuthError: NSObject, LocalizedError { /// Error uri that can be followed to get more information about the error returned by the server public let errorUri: String? + /// Indicates whether the error can only be resolved by falling back to the browser-based interactive flow. + public let isBrowserRequired: Bool + + /// Indicates whether the error is an unclassified or unexpected error with no more specific handling. + public let isGeneralError: Bool + private let message: String? - init(message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) { + init( + message: String? = nil, + correlationId: UUID, + errorCodes: [Int] = [], + errorUri: String? = nil, + isBrowserRequired: Bool = false, + isGeneralError: Bool = false + ) { self.message = message self.correlationId = correlationId self.errorCodes = errorCodes self.errorUri = errorUri + self.isBrowserRequired = isBrowserRequired + self.isGeneralError = isGeneralError } } diff --git a/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthGenericError.swift b/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthGenericError.swift index a44366e0f4..7e6d705bef 100644 --- a/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthGenericError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/MSALNativeAuthGenericError.swift @@ -36,7 +36,14 @@ public class MSALNativeAuthGenericError: MSALNativeAuthError { init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) { self.type = type - super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri) + super.init( + message: message, + correlationId: correlationId, + errorCodes: errorCodes, + errorUri: errorUri, + isBrowserRequired: type == .browserRequired, + isGeneralError: type == .generalError + ) } /// Describes why an error occurred and provides more information about the error. @@ -53,9 +60,4 @@ public class MSALNativeAuthGenericError: MSALNativeAuthError { } } - /// Returns `true` if a browser is required to continue the operation. - public var isBrowserRequired: Bool { - return type == .browserRequired - } - } diff --git a/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift b/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift index 9e4dc75d48..9a3638e56a 100644 --- a/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/PasswordRequiredError.swift @@ -37,7 +37,14 @@ public class PasswordRequiredError: MSALNativeAuthError { init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) { self.type = type - super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri) + super.init( + message: message, + correlationId: correlationId, + errorCodes: errorCodes, + errorUri: errorUri, + isBrowserRequired: type == .browserRequired, + isGeneralError: type == .generalError + ) } init(signInStartError: SignInStartError) { @@ -58,7 +65,9 @@ public class PasswordRequiredError: MSALNativeAuthError { message: errorDescription, correlationId: signInStartError.correlationId, errorCodes: signInStartError.errorCodes, - errorUri: signInStartError.errorUri + errorUri: signInStartError.errorUri, + isBrowserRequired: self.type == .browserRequired, + isGeneralError: self.type == .generalError ) } @@ -78,11 +87,6 @@ public class PasswordRequiredError: MSALNativeAuthError { } } - /// Returns `true` if a browser is required to continue the operation. - public var isBrowserRequired: Bool { - return type == .browserRequired - } - /// Returns `true` when the password is not valid. public var isInvalidPassword: Bool { return type == .invalidPassword diff --git a/MSAL/src/native_auth/public/state_machine/error/RegisterStrongAuthChallengeError.swift b/MSAL/src/native_auth/public/state_machine/error/RegisterStrongAuthChallengeError.swift index ad64890182..f459591eb1 100644 --- a/MSAL/src/native_auth/public/state_machine/error/RegisterStrongAuthChallengeError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/RegisterStrongAuthChallengeError.swift @@ -37,7 +37,14 @@ public class RegisterStrongAuthChallengeError: MSALNativeAuthError { init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) { self.type = type - super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri) + super.init( + message: message, + correlationId: correlationId, + errorCodes: errorCodes, + errorUri: errorUri, + isBrowserRequired: type == .browserRequired, + isGeneralError: type == .generalError + ) } /// Describes why an error occurred and provides more information about the error. @@ -63,11 +70,6 @@ public class RegisterStrongAuthChallengeError: MSALNativeAuthError { return type == .invalidInput } - /// Returns `true` if a browser is required to continue the operation. - public var isBrowserRequired: Bool { - return type == .browserRequired - } - /// Returns `true` when the verification contact provided has been blocked. Try using another email or phone number, or select an alternative authentication method. public var isVerificationContactBlocked: Bool { return type == .verificationContactBlocked 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 f3821827c8..a1ba1a7c90 100644 --- a/MSAL/src/native_auth/public/state_machine/error/RegisterStrongAuthSubmitChallengeError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/RegisterStrongAuthSubmitChallengeError.swift @@ -36,7 +36,14 @@ public class RegisterStrongAuthSubmitChallengeError: MSALNativeAuthError { init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) { self.type = type - super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri) + super.init( + message: message, + correlationId: correlationId, + errorCodes: errorCodes, + errorUri: errorUri, + isBrowserRequired: type == .browserRequired, + isGeneralError: type == .generalError + ) } /// Describes why an error occurred and provides more information about the error. @@ -59,9 +66,4 @@ public class RegisterStrongAuthSubmitChallengeError: MSALNativeAuthError { public var isInvalidChallenge: Bool { return type == .invalidChallenge } - - /// Returns `true` if a browser is required to continue the operation. - public var isBrowserRequired: Bool { - return type == .browserRequired - } } diff --git a/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift b/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift index d47464aa76..6ab465d68b 100644 --- a/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/ResetPasswordStartError.swift @@ -39,7 +39,14 @@ public class ResetPasswordStartError: MSALNativeAuthError { init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) { self.type = type - super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri) + super.init( + message: message, + correlationId: correlationId, + errorCodes: errorCodes, + errorUri: errorUri, + isBrowserRequired: type == .browserRequired, + isGeneralError: type == .generalError + ) } /// Describes why an error occurred and provides more information about the error. @@ -62,11 +69,6 @@ public class ResetPasswordStartError: MSALNativeAuthError { } } - /// Returns `true` if a browser is required to continue the operation. - public var isBrowserRequired: Bool { - return type == .browserRequired - } - /// Returns `true` if the user does not have a password. public var isUserDoesNotHavePassword: Bool { return type == .userDoesNotHavePassword diff --git a/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift b/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift index 70ed9eebf1..c42a7ed056 100644 --- a/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/RetrieveAccessTokenError.swift @@ -38,7 +38,14 @@ public class RetrieveAccessTokenError: MSALNativeAuthError { init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) { self.type = type - super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri) + super.init( + message: message, + correlationId: correlationId, + errorCodes: errorCodes, + errorUri: errorUri, + isBrowserRequired: type == .browserRequired, + isGeneralError: type == .generalError + ) } /// Describes why an error occurred and provides more information about the error. @@ -59,11 +66,6 @@ public class RetrieveAccessTokenError: MSALNativeAuthError { } } - /// Returns `true` if a browser is required to continue the operation. - public var isBrowserRequired: Bool { - return type == .browserRequired - } - /// Returns `true` if the refresh token has expired. public var isRefreshTokenExpired: Bool { return type == .refreshTokenExpired diff --git a/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift index cfec543b91..47e5eac48c 100644 --- a/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/SignInStartError.swift @@ -39,7 +39,14 @@ public class SignInStartError: MSALNativeAuthError { init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) { self.type = type - super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri) + super.init( + message: message, + correlationId: correlationId, + errorCodes: errorCodes, + errorUri: errorUri, + isBrowserRequired: type == .browserRequired, + isGeneralError: type == .generalError + ) } /// Describes why an error occurred and provides more information about the error. @@ -62,11 +69,6 @@ public class SignInStartError: MSALNativeAuthError { } } - /// Returns `true` if a browser is required to continue the operation. - public var isBrowserRequired: Bool { - return type == .browserRequired - } - /// Returns `true` if the user that is trying to sign in cannot be found. public var isUserNotFound: Bool { return type == .userNotFound diff --git a/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift b/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift index 0ef525d2dc..d3b7107d67 100644 --- a/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/SignUpStartError.swift @@ -39,7 +39,14 @@ public class SignUpStartError: MSALNativeAuthError { init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) { self.type = type - super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri) + super.init( + message: message, + correlationId: correlationId, + errorCodes: errorCodes, + errorUri: errorUri, + isBrowserRequired: type == .browserRequired, + isGeneralError: type == .generalError + ) } /// Describes why an error occurred and provides more information about the error. @@ -62,11 +69,6 @@ public class SignUpStartError: MSALNativeAuthError { } } - /// Returns `true` if a browser is required to continue the operation. - public var isBrowserRequired: Bool { - return type == .browserRequired - } - /// Returns `true` when the user is trying to register an existing username. public var isUserAlreadyExists: Bool { return type == .userAlreadyExists diff --git a/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift b/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift index 9bbbf34ccd..d2d661f940 100644 --- a/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift +++ b/MSAL/src/native_auth/public/state_machine/error/VerifyCodeError.swift @@ -37,7 +37,14 @@ public class VerifyCodeError: MSALNativeAuthError { init(type: ErrorType, message: String? = nil, correlationId: UUID, errorCodes: [Int] = [], errorUri: String? = nil) { self.type = type - super.init(message: message, correlationId: correlationId, errorCodes: errorCodes, errorUri: errorUri) + super.init( + message: message, + correlationId: correlationId, + errorCodes: errorCodes, + errorUri: errorUri, + isBrowserRequired: type == .browserRequired, + isGeneralError: type == .generalError + ) } /// Describes why an error occurred and provides more information about the error. @@ -56,11 +63,6 @@ public class VerifyCodeError: MSALNativeAuthError { } } - /// Returns `true` if a browser is required to continue the operation. - public var isBrowserRequired: Bool { - return type == .browserRequired - } - /// Returns `true` when the code introduced is not valid. public var isInvalidCode: Bool { return type == .invalidCode diff --git a/MSAL/src/native_auth/public/state_machine/v2/MSALNativeAuthFlowDelegate.swift b/MSAL/src/native_auth/public/state_machine/v2/MSALNativeAuthFlowDelegate.swift new file mode 100644 index 0000000000..7f8c6c9a88 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/v2/MSALNativeAuthFlowDelegate.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 + +/// Shared base delegate for all Native Auth V2 (server-driven) flows. +/// +/// Unlike V1 — which exposes a different delegate protocol per step — V2 uses one +/// family of delegates for sign up, sign in and reset password. The SDK drives the flow and +/// reports back through these callbacks; the app reacts and continues the flow by +/// calling methods directly on the ``MSALNativeAuthState`` it is handed. +/// +/// This base protocol declares only the two terminal callbacks (``onFlowCompleted(result:scenario:)`` +/// and ``onFlowError(error:scenario:)``) that every flow reports. Each server-driven state is +/// delivered through its own per-state delegate protocol (e.g. ``MSALNativeAuthCodeRequiredDelegate``) +/// that extends this base and adds a single strongly-typed, required callback. The app conforms to +/// the per-state protocols for the states it wants to handle; if it does not conform to a state's +/// protocol, ``onFlowError(error:scenario:)`` is called with error type `notImplemented`. +/// +/// All callbacks are invoked on the main actor. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objc +public protocol MSALNativeAuthFlowDelegate { + + /// The flow completed successfully and the user now has tokens. + /// - Parameters: + /// - result: The authenticated user account result. + /// - scenario: The flow that produced this callback. + @MainActor func onFlowCompleted(result: MSALNativeAuthUserAccountResult, scenario: MSALNativeAuthFlowScenario) + + /// The flow encountered an error. + /// - Parameters: + /// - error: The error that occurred. The app decides whether it can retry by + /// inspecting the error (e.g. `error.isInvalidCode` / `error.isInvalidPassword`) and calling + /// the appropriate method again on the state it is currently handling. + /// - scenario: The flow that produced this callback. + @MainActor func onFlowError(error: MSALNativeAuthFlowError, scenario: MSALNativeAuthFlowScenario) +} diff --git a/MSAL/src/native_auth/public/state_machine/v2/MSALNativeAuthFlowError.swift b/MSAL/src/native_auth/public/state_machine/v2/MSALNativeAuthFlowError.swift new file mode 100644 index 0000000000..7ca07c8fd4 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/v2/MSALNativeAuthFlowError.swift @@ -0,0 +1,196 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// Unified error type surfaced by the Native Auth V2 (server-driven) flows. +/// +/// A single error type is used across all V2 flows so that an app's +/// ``MSALNativeAuthFlowDelegate`` has only one error shape to inspect, mirroring +/// the unified delegate contract described in the V2 interface. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objcMembers +public class MSALNativeAuthFlowError: MSALNativeAuthError { + + /// High level classification of the V2 flow error. + enum ErrorType: CaseIterable { + /// The delegate is not implemented. + case notImplemented + /// The provided username was not accepted by the server. + case userNotFound + /// The submitted one-time code was invalid or expired. + case invalidCode + /// The continuation token was rejected by the server. + case invalidContinuationToken + /// The submitted password did not meet the server's requirements. + case invalidPassword + /// The username and/or password supplied at sign in were not accepted by the server. + case invalidCredentials + /// The username supplied to the SDK failed local validation. + case invalidUsername + /// The account does not have a password associated with it. + case userDoesNotHavePassword + /// An account already exists for the supplied username during sign up. + case userAlreadyExists + /// The submitted authentication challenge was rejected by the server. + case invalidChallenge + /// The server blocked the requested strong authentication method. + case authMethodBlocked + /// The server blocked the verification contact provided for strong authentication. + case verificationContactBlocked + /// The input supplied for a strong authentication registration step was invalid. + case invalidInput + /// The flow must continue in a web browser. + case browserRequired + /// A generic / unexpected error occurred. + case generalError + } + + let type: ErrorType + + init( + type: ErrorType, + errorDescription: String? = nil, + errorCodes: [Int] = [], + correlationId: UUID, + errorUri: String? = nil + ) { + self.type = type + super.init( + message: errorDescription, + correlationId: correlationId, + errorCodes: errorCodes, + errorUri: errorUri, + isBrowserRequired: type == .browserRequired, + isGeneralError: type == .generalError + ) + } + + /// Describes why an error occurred and provides more information about the error. + public override var errorDescription: String? { + if let description = super.errorDescription { + return description + } + + switch type { + case .notImplemented: + return MSALNativeAuthErrorMessage.delegateNotImplementedV2 + case .userNotFound: + return MSALNativeAuthErrorMessage.userNotFound + case .invalidCode: + return MSALNativeAuthErrorMessage.invalidCode + case .invalidContinuationToken: + return MSALNativeAuthErrorMessage.invalidContinuationToken + case .invalidPassword: + return MSALNativeAuthErrorMessage.invalidPassword + case .invalidCredentials: + return MSALNativeAuthErrorMessage.invalidCredentials + case .invalidUsername: + return MSALNativeAuthErrorMessage.invalidUsername + case .userDoesNotHavePassword: + return MSALNativeAuthErrorMessage.userDoesNotHavePassword + case .userAlreadyExists: + return MSALNativeAuthErrorMessage.userAlreadyExists + case .invalidChallenge: + return MSALNativeAuthErrorMessage.invalidChallenge + case .authMethodBlocked: + return MSALNativeAuthErrorMessage.authMethodBlocked + case .verificationContactBlocked: + return MSALNativeAuthErrorMessage.verificationContactBlocked + case .invalidInput: + return MSALNativeAuthErrorMessage.invalidInput + case .browserRequired: + return MSALNativeAuthErrorMessage.browserRequired + case .generalError: + return MSALNativeAuthErrorMessage.generalError + } + } + + /// Whether the delegate that produced this error is not implemented yet. + public var isNotImplemented: Bool { + return type == .notImplemented + } + + /// Whether the username was not found in the directory. + public var isUserNotFound: Bool { + return type == .userNotFound + } + + /// Whether the submitted one-time code was invalid. + public var isInvalidCode: Bool { + return type == .invalidCode + } + + /// Whether the continuation token was rejected by the server. + public var isInvalidContinuationToken: Bool { + return type == .invalidContinuationToken + } + + /// Whether the submitted password was rejected because it did not satisfy the server's + /// policy during sign up. + public var isInvalidPassword: Bool { + return type == .invalidPassword + } + + /// Whether the username and/or password supplied at sign in were not accepted by the server. + public var isInvalidCredentials: Bool { + return type == .invalidCredentials + } + + /// Whether the username supplied to the SDK failed local validation. + public var isInvalidUsername: Bool { + return type == .invalidUsername + } + + /// Whether the account does not have a password associated with it. + public var isUserDoesNotHavePassword: Bool { + return type == .userDoesNotHavePassword + } + + /// Whether an account already exists for the supplied username during sign up. + public var isUserAlreadyExists: Bool { + return type == .userAlreadyExists + } + + /// Whether the submitted authentication challenge was rejected by the server. + public var isInvalidChallenge: Bool { + return type == .invalidChallenge + } + + /// Whether the server blocked the requested strong authentication method. + public var isAuthMethodBlocked: Bool { + return type == .authMethodBlocked + } + + /// Whether the server blocked the verification contact provided for strong authentication. + public var isVerificationContactBlocked: Bool { + return type == .verificationContactBlocked + } + + /// Whether the input supplied for a strong authentication registration step was invalid. + public var isInvalidInput: Bool { + return type == .invalidInput + } +} diff --git a/MSAL/src/native_auth/public/state_machine/v2/MSALNativeAuthFlowScenario.swift b/MSAL/src/native_auth/public/state_machine/v2/MSALNativeAuthFlowScenario.swift new file mode 100644 index 0000000000..b292eb85e4 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/v2/MSALNativeAuthFlowScenario.swift @@ -0,0 +1,50 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// Identifies which Native Auth V2 (server-driven) flow a ``MSALNativeAuthFlowDelegate`` callback +/// belongs to. +/// +/// Because V2 uses a single unified delegate for sign in, sign up and password reset, every delegate +/// callback also reports the `scenario` that triggered it so the app can react appropriately without +/// tracking the originating flow itself. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objc +public enum MSALNativeAuthFlowScenario: Int { + + /// The scenario could not be determined. This is the default value and should not normally be + /// reported to the app; it acts as a safe placeholder until a concrete flow scenario is resolved. + case unknown + + /// The callback originated from a sign up flow. + case signUp + + /// The callback originated from a sign in flow. + case signIn + + /// The callback originated from a password reset flow. + case passwordReset +} diff --git a/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthAttributesInvalidState.swift b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthAttributesInvalidState.swift new file mode 100644 index 0000000000..124502a0fc --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthAttributesInvalidState.swift @@ -0,0 +1,75 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// The server reports that some attributes were invalid and must be corrected. +/// Continue with ``submitAttributes(_:delegate:)``. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objcMembers +public class MSALNativeAuthAttributesInvalidState: MSALNativeAuthState { + + /// The names of the attributes that were invalid. + public let attributeNames: [String] + + public init(attributeNames: [String]) { + self.attributeNames = attributeNames + super.init() + } + + /// Resubmit the corrected user attributes. + public func submitAttributes(_ attributes: [String: Any], delegate: MSALNativeAuthFlowDelegate) { + Task { @MainActor in + delegate.onFlowError( + error: MSALNativeAuthFlowError(type: .notImplemented, correlationId: UUID()), + scenario: self.scenario + ) + } + } + + public override var description: String { + return "attributesInvalid (\(attributeNames.joined(separator: ", ")))" + } +} + +/// Per-state delegate for the ``MSALNativeAuthAttributesInvalidState`` step of a Native Auth V2 flow. +/// +/// Conform to this protocol (in addition to the terminal callbacks inherited from +/// ``MSALNativeAuthFlowDelegate``) to handle this state. Conforming is opt-in per state, but the +/// callback is required once you conform. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objc +public protocol MSALNativeAuthAttributesInvalidDelegate: MSALNativeAuthFlowDelegate { + + /// The server reports that some attributes were invalid and must be corrected. + /// Continue with ``MSALNativeAuthAttributesInvalidState/submitAttributes(_:delegate:)``. + /// - Parameters: + /// - state: The invalid-attributes state. + /// - scenario: The flow that produced this callback. + /// - Note: If the app's delegate does not conform to this protocol, then + /// ``MSALNativeAuthFlowDelegate/onFlowError(error:scenario:)`` is called with error type `notImplemented`. + @MainActor func onAttributesInvalid(state: MSALNativeAuthAttributesInvalidState, scenario: MSALNativeAuthFlowScenario) +} diff --git a/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthAttributesRequiredState.swift b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthAttributesRequiredState.swift new file mode 100644 index 0000000000..4cf2c8f774 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthAttributesRequiredState.swift @@ -0,0 +1,75 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// The server requires additional user attributes. +/// Continue with ``submitAttributes(_:delegate:)``. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objcMembers +public class MSALNativeAuthAttributesRequiredState: MSALNativeAuthState { + + /// The attributes the server requires. + public let attributes: [MSALNativeAuthRequiredAttribute] + + public init(attributes: [MSALNativeAuthRequiredAttribute]) { + self.attributes = attributes + super.init() + } + + /// Submit user attributes. + public func submitAttributes(_ attributes: [String: Any], delegate: MSALNativeAuthFlowDelegate) { + Task { @MainActor in + delegate.onFlowError( + error: MSALNativeAuthFlowError(type: .notImplemented, correlationId: UUID()), + scenario: self.scenario + ) + } + } + + public override var description: String { + return "attributesRequired (\(attributes.map { $0.name }.joined(separator: ", ")))" + } +} + +/// Per-state delegate for the ``MSALNativeAuthAttributesRequiredState`` step of a Native Auth V2 flow. +/// +/// Conform to this protocol (in addition to the terminal callbacks inherited from +/// ``MSALNativeAuthFlowDelegate``) to handle this state. Conforming is opt-in per state, but the +/// callback is required once you conform. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objc +public protocol MSALNativeAuthAttributesRequiredDelegate: MSALNativeAuthFlowDelegate { + + /// The server requires additional user attributes. + /// Continue with ``MSALNativeAuthAttributesRequiredState/submitAttributes(_:delegate:)``. + /// - Parameters: + /// - state: The required-attributes state. + /// - scenario: The flow that produced this callback. + /// - Note: If the app's delegate does not conform to this protocol, then + /// ``MSALNativeAuthFlowDelegate/onFlowError(error:scenario:)`` is called with error type `notImplemented`. + @MainActor func onAttributesRequired(state: MSALNativeAuthAttributesRequiredState, scenario: MSALNativeAuthFlowScenario) +} diff --git a/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthCodeRequiredState.swift b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthCodeRequiredState.swift new file mode 100644 index 0000000000..2d2b4886fe --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthCodeRequiredState.swift @@ -0,0 +1,95 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// The server requires the user to verify a one-time code. +/// Continue with ``submitCode(_:delegate:)`` or request a new code with ``resendCode(delegate:)``. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objcMembers +public class MSALNativeAuthCodeRequiredState: MSALNativeAuthState { + + /// A masked destination the code was sent to (e.g. a partially obfuscated email). + public let sentTo: String + + /// The channel the code was sent through. + public let channel: MSALNativeAuthChannelType + + /// The expected length of the code. + public let codeLength: Int + + public init(sentTo: String, channel: MSALNativeAuthChannelType, codeLength: Int) { + self.sentTo = sentTo + self.channel = channel + self.codeLength = codeLength + super.init() + } + + /// Submit a one-time verification code. + public func submitCode(_ code: String, delegate: MSALNativeAuthFlowDelegate) { + Task { @MainActor in + delegate.onFlowError( + error: MSALNativeAuthFlowError(type: .notImplemented, correlationId: UUID()), + scenario: self.scenario + ) + } + } + + /// Request the server to resend the one-time code. + public func resendCode(delegate: MSALNativeAuthFlowDelegate) { + Task { @MainActor in + delegate.onFlowError( + error: MSALNativeAuthFlowError(type: .notImplemented, correlationId: UUID()), + scenario: self.scenario + ) + } + } + + public override var description: String { + return "codeRequired (sentTo: \(sentTo), length: \(codeLength))" + } +} + +/// Per-state delegate for the ``MSALNativeAuthCodeRequiredState`` step of a Native Auth V2 flow. +/// +/// Conform to this protocol (in addition to the terminal callbacks inherited from +/// ``MSALNativeAuthFlowDelegate``) to handle this state. Conforming is opt-in per state, but the +/// callback is required once you conform. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objc +public protocol MSALNativeAuthCodeRequiredDelegate: MSALNativeAuthFlowDelegate { + + /// The server requires the user to verify a one-time code. + /// Continue with ``MSALNativeAuthCodeRequiredState/submitCode(_:delegate:)`` (or request a new + /// code with ``MSALNativeAuthCodeRequiredState/resendCode(delegate:)``). + /// - Parameters: + /// - state: The code-required state (destination, channel, expected length) that + /// also exposes the continuation methods. + /// - scenario: The flow that produced this callback. + /// - Note: If the app's delegate does not conform to this protocol, then + /// ``MSALNativeAuthFlowDelegate/onFlowError(error:scenario:)`` is called with error type `notImplemented`. + @MainActor func onCodeRequired(state: MSALNativeAuthCodeRequiredState, scenario: MSALNativeAuthFlowScenario) +} diff --git a/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthMFARequiredState.swift b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthMFARequiredState.swift new file mode 100644 index 0000000000..e754d088cf --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthMFARequiredState.swift @@ -0,0 +1,84 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// The server requires multi-factor authentication; the user must select an auth method. +/// Continue with ``selectAuthMethod(_:verificationContact:delegate:)``. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objcMembers +public class MSALNativeAuthMFARequiredState: MSALNativeAuthState { + + /// The authentication methods available for selection. + public let authMethods: [MSALAuthMethod] + + public init(authMethods: [MSALAuthMethod]) { + self.authMethods = authMethods + super.init() + } + + /// Select an authentication method for MFA. + public func selectAuthMethod( + _ method: MSALAuthMethod, + verificationContact: String?, + delegate: MSALNativeAuthFlowDelegate + ) { + Task { @MainActor in + delegate.onFlowError( + error: MSALNativeAuthFlowError(type: .notImplemented, correlationId: UUID()), + scenario: self.scenario + ) + } + } + + /// Select an authentication method for MFA, without an explicit verification contact. + public func selectAuthMethod(_ method: MSALAuthMethod, delegate: MSALNativeAuthFlowDelegate) { + selectAuthMethod(method, verificationContact: nil, delegate: delegate) + } + + public override var description: String { + return "mfaRequired" + } +} + +/// Per-state delegate for the ``MSALNativeAuthMFARequiredState`` step of a Native Auth V2 flow. +/// +/// Conform to this protocol (in addition to the terminal callbacks inherited from +/// ``MSALNativeAuthFlowDelegate``) to handle this state. Conforming is opt-in per state, but the +/// callback is required once you conform. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objc +public protocol MSALNativeAuthMFARequiredDelegate: MSALNativeAuthFlowDelegate { + + /// The server requires multi-factor authentication; the user must select an auth method. + /// Continue with ``MSALNativeAuthMFARequiredState/selectAuthMethod(_:verificationContact:delegate:)``. + /// - Parameters: + /// - state: The MFA-required state (available auth methods). + /// - scenario: The flow that produced this callback. + /// - Note: If the app's delegate does not conform to this protocol, then + /// ``MSALNativeAuthFlowDelegate/onFlowError(error:scenario:)`` is called with error type `notImplemented`. + @MainActor func onMFARequired(state: MSALNativeAuthMFARequiredState, scenario: MSALNativeAuthFlowScenario) +} diff --git a/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthMFAVerificationRequiredState.swift b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthMFAVerificationRequiredState.swift new file mode 100644 index 0000000000..210152322e --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthMFAVerificationRequiredState.swift @@ -0,0 +1,83 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// The server sent an MFA challenge; the user must enter the verification code. +/// Continue with ``submitChallenge(_:delegate:)``. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objcMembers +public class MSALNativeAuthMFAVerificationRequiredState: MSALNativeAuthState { + + /// A masked destination the code was sent to (e.g. a partially obfuscated email). + public let sentTo: String + + /// The channel the code was sent through. + public let channel: MSALNativeAuthChannelType + + /// The expected length of the code. + public let codeLength: Int + + public init(sentTo: String, channel: MSALNativeAuthChannelType, codeLength: Int) { + self.sentTo = sentTo + self.channel = channel + self.codeLength = codeLength + super.init() + } + + /// Submit the MFA challenge response. + public func submitChallenge(_ challenge: String, delegate: MSALNativeAuthFlowDelegate) { + Task { @MainActor in + delegate.onFlowError( + error: MSALNativeAuthFlowError(type: .notImplemented, correlationId: UUID()), + scenario: self.scenario + ) + } + } + + public override var description: String { + return "mfaVerificationRequired (sentTo: \(sentTo), length: \(codeLength))" + } +} + +/// Per-state delegate for the ``MSALNativeAuthMFAVerificationRequiredState`` step of a Native Auth V2 flow. +/// +/// Conform to this protocol (in addition to the terminal callbacks inherited from +/// ``MSALNativeAuthFlowDelegate``) to handle this state. Conforming is opt-in per state, but the +/// callback is required once you conform. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objc +public protocol MSALNativeAuthMFAVerificationRequiredDelegate: MSALNativeAuthFlowDelegate { + + /// The server sent an MFA challenge; the user must enter the verification code. + /// Continue with ``MSALNativeAuthMFAVerificationRequiredState/submitChallenge(_:delegate:)``. + /// - Parameters: + /// - state: The MFA verification state (destination, channel, expected length). + /// - scenario: The flow that produced this callback. + /// - Note: If the app's delegate does not conform to this protocol, then + /// ``MSALNativeAuthFlowDelegate/onFlowError(error:scenario:)`` is called with error type `notImplemented`. + @MainActor func onMFAVerificationRequired(state: MSALNativeAuthMFAVerificationRequiredState, scenario: MSALNativeAuthFlowScenario) +} diff --git a/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthNewPasswordRequiredState.swift b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthNewPasswordRequiredState.swift new file mode 100644 index 0000000000..c714faea72 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthNewPasswordRequiredState.swift @@ -0,0 +1,67 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// The server requires the user to enter a new password (self-service password reset). +/// Continue with ``submitNewPassword(_:delegate:)``. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objcMembers +public class MSALNativeAuthNewPasswordRequiredState: MSALNativeAuthState { + + /// Submit a new password (self-service password reset). + public func submitNewPassword(_ password: String, delegate: MSALNativeAuthFlowDelegate) { + Task { @MainActor in + delegate.onFlowError( + error: MSALNativeAuthFlowError(type: .notImplemented, correlationId: UUID()), + scenario: self.scenario + ) + } + } + + public override var description: String { + return "newPasswordRequired" + } +} + +/// Per-state delegate for the ``MSALNativeAuthNewPasswordRequiredState`` step of a Native Auth V2 flow. +/// +/// Conform to this protocol (in addition to the terminal callbacks inherited from +/// ``MSALNativeAuthFlowDelegate``) to handle this state. Conforming is opt-in per state, but the +/// callback is required once you conform. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objc +public protocol MSALNativeAuthNewPasswordRequiredDelegate: MSALNativeAuthFlowDelegate { + + /// The server requires the user to enter a new password (self-service password reset). + /// Continue with ``MSALNativeAuthNewPasswordRequiredState/submitNewPassword(_:delegate:)``. + /// - Parameters: + /// - state: The new-password-required state. + /// - scenario: The flow that produced this callback. + /// - Note: If the app's delegate does not conform to this protocol, then + /// ``MSALNativeAuthFlowDelegate/onFlowError(error:scenario:)`` is called with error type `notImplemented`. + @MainActor func onNewPasswordRequired(state: MSALNativeAuthNewPasswordRequiredState, scenario: MSALNativeAuthFlowScenario) +} diff --git a/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthPasswordRequiredState.swift b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthPasswordRequiredState.swift new file mode 100644 index 0000000000..d1e8260b04 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthPasswordRequiredState.swift @@ -0,0 +1,67 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// The server requires the user to enter their password. +/// Continue with ``submitPassword(_:delegate:)``. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objcMembers +public class MSALNativeAuthPasswordRequiredState: MSALNativeAuthState { + + /// Submit a password. + public func submitPassword(_ password: String, delegate: MSALNativeAuthFlowDelegate) { + Task { @MainActor in + delegate.onFlowError( + error: MSALNativeAuthFlowError(type: .notImplemented, correlationId: UUID()), + scenario: self.scenario + ) + } + } + + public override var description: String { + return "passwordRequired" + } +} + +/// Per-state delegate for the ``MSALNativeAuthPasswordRequiredState`` step of a Native Auth V2 flow. +/// +/// Conform to this protocol (in addition to the terminal callbacks inherited from +/// ``MSALNativeAuthFlowDelegate``) to handle this state. Conforming is opt-in per state, but the +/// callback is required once you conform. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objc +public protocol MSALNativeAuthPasswordRequiredDelegate: MSALNativeAuthFlowDelegate { + + /// The server requires the user to enter their password. + /// Continue with ``MSALNativeAuthPasswordRequiredState/submitPassword(_:delegate:)``. + /// - Parameters: + /// - state: The password-required state. + /// - scenario: The flow that produced this callback. + /// - Note: If the app's delegate does not conform to this protocol, then + /// ``MSALNativeAuthFlowDelegate/onFlowError(error:scenario:)`` is called with error type `notImplemented`. + @MainActor func onPasswordRequired(state: MSALNativeAuthPasswordRequiredState, scenario: MSALNativeAuthFlowScenario) +} diff --git a/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthState.swift b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthState.swift new file mode 100644 index 0000000000..39982b2040 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthState.swift @@ -0,0 +1,46 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// Base type for states the server can request during a Native Auth V2 (server-driven) flow. +/// +/// In V2 the server drives the flow: at each step the SDK reports a concrete +/// ``MSALNativeAuthState`` subclass through its dedicated ``MSALNativeAuthFlowDelegate`` callback +/// (e.g. ``MSALNativeAuthFlowDelegate/onCodeRequired(state:)``). The app then continues the flow by +/// calling the method(s) exposed on that concrete state — each state exposes only the +/// continuations valid for its step, so invalid calls are impossible. +/// +/// This is an abstract base class — the SDK always hands back one of its concrete subclasses to the +/// matching state-specific delegate callback, so apps never need to downcast the state. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objcMembers +public class MSALNativeAuthState: NSObject { + + /// The originating flow scenario for this state, set by the SDK when the state is created. + /// Reported alongside this state's delegate callbacks so the app can tell which flow produced + /// it. Internal detail — not part of the public API surface. + var scenario: MSALNativeAuthFlowScenario = .unknown +} diff --git a/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthStrongAuthRegistrationRequiredState.swift b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthStrongAuthRegistrationRequiredState.swift new file mode 100644 index 0000000000..36c238cce5 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthStrongAuthRegistrationRequiredState.swift @@ -0,0 +1,85 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// The server requires strong authentication registration (JIT); the user must select an auth method. +/// Continue with ``selectAuthMethod(_:verificationContact:delegate:)``. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objcMembers +public class MSALNativeAuthStrongAuthRegistrationRequiredState: MSALNativeAuthState { + + /// The authentication methods available for registration. + public let authMethods: [MSALAuthMethod] + + public init(authMethods: [MSALAuthMethod]) { + self.authMethods = authMethods + super.init() + } + + /// Select an authentication method for strong-auth registration. + public func selectAuthMethod( + _ method: MSALAuthMethod, + verificationContact: String?, + delegate: MSALNativeAuthFlowDelegate + ) { + Task { @MainActor in + delegate.onFlowError( + error: MSALNativeAuthFlowError(type: .notImplemented, correlationId: UUID()), + scenario: self.scenario + ) + } + } + + /// Select an authentication method for strong-auth registration, without an explicit + /// verification contact. + public func selectAuthMethod(_ method: MSALAuthMethod, delegate: MSALNativeAuthFlowDelegate) { + selectAuthMethod(method, verificationContact: nil, delegate: delegate) + } + + public override var description: String { + return "strongAuthRegistrationRequired" + } +} + +/// Per-state delegate for the ``MSALNativeAuthStrongAuthRegistrationRequiredState`` step of a Native Auth V2 flow. +/// +/// Conform to this protocol (in addition to the terminal callbacks inherited from +/// ``MSALNativeAuthFlowDelegate``) to handle this state. Conforming is opt-in per state, but the +/// callback is required once you conform. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objc +public protocol MSALNativeAuthStrongAuthRegistrationRequiredDelegate: MSALNativeAuthFlowDelegate { + + /// The server requires strong authentication registration (JIT); the user must select an auth method. + /// Continue with ``MSALNativeAuthStrongAuthRegistrationRequiredState/selectAuthMethod(_:verificationContact:delegate:)``. + /// - Parameters: + /// - state: The strong-auth registration state (available auth methods). + /// - scenario: The flow that produced this callback. + /// - Note: If the app's delegate does not conform to this protocol, then + /// ``MSALNativeAuthFlowDelegate/onFlowError(error:scenario:)`` is called with error type `notImplemented`. + @MainActor func onStrongAuthRegistrationRequired(state: MSALNativeAuthStrongAuthRegistrationRequiredState, scenario: MSALNativeAuthFlowScenario) +} diff --git a/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthStrongAuthVerificationRequiredState.swift b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthStrongAuthVerificationRequiredState.swift new file mode 100644 index 0000000000..9a38602281 --- /dev/null +++ b/MSAL/src/native_auth/public/state_machine/v2/state/MSALNativeAuthStrongAuthVerificationRequiredState.swift @@ -0,0 +1,83 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// The server sent a JIT challenge; the user must enter the verification code. +/// Continue with ``submitChallenge(_:delegate:)``. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objcMembers +public class MSALNativeAuthStrongAuthVerificationRequiredState: MSALNativeAuthState { + + /// A masked destination the code was sent to (e.g. a partially obfuscated email). + public let sentTo: String + + /// The channel the code was sent through. + public let channel: MSALNativeAuthChannelType + + /// The expected length of the code. + public let codeLength: Int + + public init(sentTo: String, channel: MSALNativeAuthChannelType, codeLength: Int) { + self.sentTo = sentTo + self.channel = channel + self.codeLength = codeLength + super.init() + } + + /// Submit the strong-auth (JIT) challenge response. + public func submitChallenge(_ challenge: String, delegate: MSALNativeAuthFlowDelegate) { + Task { @MainActor in + delegate.onFlowError( + error: MSALNativeAuthFlowError(type: .notImplemented, correlationId: UUID()), + scenario: self.scenario + ) + } + } + + public override var description: String { + return "strongAuthVerificationRequired (sentTo: \(sentTo), length: \(codeLength))" + } +} + +/// Per-state delegate for the ``MSALNativeAuthStrongAuthVerificationRequiredState`` step of a Native Auth V2 flow. +/// +/// Conform to this protocol (in addition to the terminal callbacks inherited from +/// ``MSALNativeAuthFlowDelegate``) to handle this state. Conforming is opt-in per state, but the +/// callback is required once you conform. +/// +/// - Warning: This API is experimental. It may be changed in the future without notice. Do not use in production applications. +@objc +public protocol MSALNativeAuthStrongAuthVerificationRequiredDelegate: MSALNativeAuthFlowDelegate { + + /// The server sent a JIT challenge; the user must enter the verification code. + /// Continue with ``MSALNativeAuthStrongAuthVerificationRequiredState/submitChallenge(_:delegate:)``. + /// - Parameters: + /// - state: The strong-auth verification state (destination, channel, expected length). + /// - scenario: The flow that produced this callback. + /// - Note: If the app's delegate does not conform to this protocol, then + /// ``MSALNativeAuthFlowDelegate/onFlowError(error:scenario:)`` is called with error type `notImplemented`. + @MainActor func onStrongAuthVerificationRequired(state: MSALNativeAuthStrongAuthVerificationRequiredState, scenario: MSALNativeAuthFlowScenario) +}