Skip to content

Commit 5042032

Browse files
spetrescu84nilo-ms
andauthored
Updating JIT preverified flow (#2611)
* Updating JIT preverified flow * Update MSAL/src/native_auth/controllers/jit/MSALNativeAuthJITController.swift Co-authored-by: Danilo Raspa <[email protected]> --------- Co-authored-by: Danilo Raspa <[email protected]>
1 parent c005383 commit 5042032

15 files changed

+131
-53
lines changed

MSAL/src/native_auth/controllers/jit/MSALNativeAuthJITController.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,11 +277,19 @@ final class MSALNativeAuthJITController: MSALNativeAuthBaseController, MSALNativ
277277
telemetryId: .telemetryApiISignInAfterJIT,
278278
context: context)
279279
switch response.result {
280-
case .success(let account):
280+
case .completed(let account):
281281
return .init(.completed(account), correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in
282282
self?.stopTelemetryEvent(signInEvent, context: context, delegateDispatcherResult: result)
283283
})
284-
case .failure(let error):
284+
case .jitAuthMethodsSelectionRequired(_, _):
285+
return .init(.error(error: .init(type: .generalError,
286+
message: "Unexpected result received when trying to signIn: strong authentication method registration required.",
287+
correlationId: context.correlationId(),
288+
errorCodes: [],
289+
errorUri: nil),
290+
newState: nil),
291+
correlationId: context.correlationId())
292+
case .error(let error):
285293
return .init(.error(error: .init(type: .generalError,
286294
message: error.errorDescription,
287295
correlationId: error.correlationId,

MSAL/src/native_auth/controllers/responses/SignInResults.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,9 @@ enum SignInVerifyCodeResult {
4646
case completed(MSALNativeAuthUserAccountResult)
4747
case error(error: VerifyCodeError, newState: SignInCodeRequiredState?)
4848
}
49+
50+
enum SignInAfterPreviousFlowResult {
51+
case completed(MSALNativeAuthUserAccountResult)
52+
case jitAuthMethodsSelectionRequired(authMethods: [MSALAuthMethod], newState: RegisterStrongAuthState)
53+
case error(error: MSALNativeAuthError)
54+
}

MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInController.swift

Lines changed: 9 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN
128128
format: "SignIn after previous flow not available because continuationToken is nil")
129129
let error = SignInAfterSignUpError(message: MSALNativeAuthErrorMessage.signInNotAvailable, correlationId: context.correlationId())
130130
stopTelemetryEvent(telemetryInfo, error: error)
131-
return .init(.failure(error), correlationId: context.correlationId())
131+
return .init(.error(error: error), correlationId: context.correlationId())
132132
}
133133
let scopes = joinScopes(scopes)
134134
guard let request = createTokenRequest(
@@ -141,7 +141,7 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN
141141
) else {
142142
let error = SignInAfterSignUpError(correlationId: context.correlationId())
143143
stopTelemetryEvent(telemetryInfo, error: error)
144-
return .init(.failure(error), correlationId: context.correlationId())
144+
return .init(.error(error: error), correlationId: context.correlationId())
145145
}
146146
let response = await performAndValidateTokenRequest(request, context: context)
147147
let result = await handleTokenResponse(response,
@@ -150,56 +150,30 @@ final class MSALNativeAuthSignInController: MSALNativeAuthTokenController, MSALN
150150
telemetryInfo: telemetryInfo)
151151
switch result {
152152
case .success(let accountResult):
153-
return .init(.success(accountResult), correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in
153+
return .init(.completed(accountResult), correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in
154154
self?.stopTelemetryEvent(telemetryInfo.event, context: context, delegateDispatcherResult: result)
155155
})
156156
case .awaitingMFA(_):
157157
let error = SignInAfterSignUpError(correlationId: context.correlationId())
158158
MSALNativeAuthLogger.log(level: .error, context: context, format: "SignIn: received unexpected MFA required API result")
159159
self.stopTelemetryEvent(telemetryInfo.event, context: context, error: error)
160-
return .init(.failure(error), correlationId: context.correlationId())
160+
return .init(.error(error: error), correlationId: context.correlationId())
161161
case .jitAuthMethodsSelectionRequired(let authMethods, let jitRequiredState):
162162
MSALNativeAuthLogger.log(level: .info, context: context, format: "JIT required after sing in after previous flow")
163-
let jitController = createJITController()
164-
guard let authMethod = authMethods.first else {
165-
let error = SignInAfterSignUpError(correlationId: context.correlationId())
166-
MSALNativeAuthLogger.log(level: .error, context: context, format: "JIT required, did not receive any default methods")
167-
self.stopTelemetryEvent(telemetryInfo.event, context: context, error: error)
168-
return .init(.failure(error), correlationId: context.correlationId())
169-
}
170-
let jitChallengeResponse = await jitController.requestJITChallenge(
171-
continuationToken: jitRequiredState.continuationToken,
172-
authMethod: authMethod,
173-
verificationContact: nil,
174-
context: context)
175-
switch jitChallengeResponse.result {
176-
case .completed(let accountResult):
177-
return .init(.success(accountResult), correlationId: context.correlationId(), telemetryUpdate: { [weak self] result in
163+
return .init(
164+
.jitAuthMethodsSelectionRequired(authMethods: authMethods, newState: jitRequiredState),
165+
correlationId: context.correlationId(),
166+
telemetryUpdate: { [weak self] result in
178167
self?.stopTelemetryEvent(telemetryInfo.event, context: context, delegateDispatcherResult: result)
179168
})
180-
case .verificationRequired(_, _, _, _):
181-
let error = SignInAfterSignUpError(correlationId: context.correlationId())
182-
MSALNativeAuthLogger.log(level: .error,
183-
context: context,
184-
format: "Request JIT challenge, received verification required on SignInAfterPreviousFlow")
185-
self.stopTelemetryEvent(telemetryInfo.event, context: context, error: error)
186-
return .init(.failure(error), correlationId: context.correlationId())
187-
case .error(let apiError, _):
188-
let error = SignInAfterSignUpError(correlationId: context.correlationId())
189-
MSALNativeAuthLogger.logPII(level: .error,
190-
context: context,
191-
format: "Request JIT challenge, received invalid response \(MSALLogMask.maskPII(apiError.errorDescription))")
192-
self.stopTelemetryEvent(telemetryInfo.event, context: context, error: error)
193-
return .init(.failure(error), correlationId: context.correlationId())
194-
}
195169
case .error(let error):
196170
let error = SignInAfterSignUpError(
197171
message: error.errorDescription,
198172
correlationId: error.correlationId,
199173
errorCodes: error.errorCodes,
200174
errorUri: error.errorUri
201175
)
202-
return .init(.failure(error), correlationId: context.correlationId())
176+
return .init(.error(error: error), correlationId: context.correlationId())
203177
}
204178
}
205179

MSAL/src/native_auth/controllers/sign_in/MSALNativeAuthSignInControlling.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ protocol MSALNativeAuthSignInControlling {
2828

2929
typealias SignInControllerResponse = MSALNativeAuthControllerTelemetryWrapper<SignInStartResult>
3030
typealias SignInAfterPreviousFlowControllerResponse =
31-
MSALNativeAuthControllerTelemetryWrapper<Result<MSALNativeAuthUserAccountResult, MSALNativeAuthError>>
31+
MSALNativeAuthControllerTelemetryWrapper<SignInAfterPreviousFlowResult>
3232
typealias SignInSubmitCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper<SignInVerifyCodeResult>
3333
typealias SignInSubmitPasswordControllerResponse = MSALNativeAuthControllerTelemetryWrapper<SignInPasswordRequiredResult>
3434
typealias SignInResendCodeControllerResponse = MSALNativeAuthControllerTelemetryWrapper<SignInResendCodeResult>

MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterResetPasswordDelegateDispatcher.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,18 @@ final class SignInAfterResetPasswordDelegateDispatcher: DelegateDispatcher<SignI
3636
await delegate.onSignInAfterResetPasswordError(error: error)
3737
}
3838
}
39+
40+
func dispatchJITRequired(authMethods: [MSALAuthMethod], newState: RegisterStrongAuthState, correlationId: UUID) async {
41+
if let onSignInJITRequired = delegate.onSignInStrongAuthMethodRegistration {
42+
telemetryUpdate?(.success(()))
43+
await onSignInJITRequired(authMethods, newState)
44+
} else {
45+
let error = SignInAfterResetPasswordError(
46+
message: requiredErrorMessage(for: "onSignInStrongAuthMethodRegistration"),
47+
correlationId: correlationId
48+
)
49+
telemetryUpdate?(.failure(error))
50+
await delegate.onSignInAfterResetPasswordError(error: error)
51+
}
52+
}
3953
}

MSAL/src/native_auth/public/state_machine/delegate_dispatcher/SignInAfterSignUpDelegateDispatcher.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,18 @@ final class SignInAfterSignUpDelegateDispatcher: DelegateDispatcher<SignInAfterS
3636
await delegate.onSignInAfterSignUpError(error: error)
3737
}
3838
}
39+
40+
func dispatchJITRequired(authMethods: [MSALAuthMethod], newState: RegisterStrongAuthState, correlationId: UUID) async {
41+
if let onSignInJITRequired = delegate.onSignInStrongAuthMethodRegistration {
42+
telemetryUpdate?(.success(()))
43+
await onSignInJITRequired(authMethods, newState)
44+
} else {
45+
let error = SignInAfterSignUpError(
46+
message: requiredErrorMessage(for: "onSignInStrongAuthMethodRegistration"),
47+
correlationId: correlationId
48+
)
49+
telemetryUpdate?(.failure(error))
50+
await delegate.onSignInAfterSignUpError(error: error)
51+
}
52+
}
3953
}

MSAL/src/native_auth/public/state_machine/state/SignInAfterResetPasswordState.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,13 @@ import Foundation
4444
)
4545

4646
switch controllerResponse.result {
47-
case .success(let accountResult):
47+
case .completed(let accountResult):
4848
await delegateDispatcher.dispatchSignInCompleted(result: accountResult, correlationId: controllerResponse.correlationId)
49-
case .failure(let error):
49+
case .jitAuthMethodsSelectionRequired(authMethods: let authMethods, newState: let newState):
50+
await delegateDispatcher.dispatchJITRequired(authMethods: authMethods,
51+
newState: newState,
52+
correlationId: controllerResponse.correlationId)
53+
case .error(let error):
5054
let error = SignInAfterResetPasswordError(
5155
message: error.errorDescription,
5256
correlationId: error.correlationId,

MSAL/src/native_auth/public/state_machine/state/SignInAfterSignUpState.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,13 @@ import Foundation
4242
let delegateDispatcher = SignInAfterSignUpDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate)
4343

4444
switch controllerResponse.result {
45-
case .success(let accountResult):
45+
case .completed(let accountResult):
4646
await delegateDispatcher.dispatchSignInCompleted(result: accountResult, correlationId: controllerResponse.correlationId)
47-
case .failure(let error):
47+
case .jitAuthMethodsSelectionRequired(authMethods: let authMethods, newState: let newState):
48+
await delegateDispatcher.dispatchJITRequired(authMethods: authMethods,
49+
newState: newState,
50+
correlationId: controllerResponse.correlationId)
51+
case .error(let error):
4852
await delegate.onSignInAfterSignUpError(
4953
error: SignInAfterSignUpError(message: error.errorDescription, correlationId: error.correlationId, errorCodes: error.errorCodes)
5054
)

MSAL/test/unit/native_auth/controllers/MSALNativeAuthJITControllerTests.swift

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ class MSALNativeAuthJITControllerTests: MSALNativeAuthTestCase {
144144
codeLength: 8
145145
)
146146
let userAccountResult = MSALNativeAuthUserAccountResultStub.result
147-
signInControllerMock.continuationTokenResult = .init(.success(userAccountResult), correlationId: defaultUUID)
147+
signInControllerMock.continuationTokenResult = .init(.completed(userAccountResult), correlationId: defaultUUID)
148148
jitResponseValidatorMock.challengeValidatedResponse = .preverified(continuationToken: "continuationToken")
149149
jitResponseValidatorMock.continueValidatedResponse = .success(continuationToken: "continuationToken 2")
150150
let result = await sut.requestJITChallenge(continuationToken: expectedContinuationToken, authMethod: authMethod, verificationContact: verificationContact, context: expectedContext)
@@ -204,7 +204,7 @@ class MSALNativeAuthJITControllerTests: MSALNativeAuthTestCase {
204204
jitResponseValidatorMock.continueValidatedResponse = .success(continuationToken: expectedContinuationToken)
205205
let userAccountResult = MSALNativeAuthUserAccountResultStub.result
206206

207-
signInControllerMock.continuationTokenResult = .init(.success(userAccountResult), correlationId: defaultUUID)
207+
signInControllerMock.continuationTokenResult = .init(.completed(userAccountResult), correlationId: defaultUUID)
208208
jitResponseValidatorMock.continueValidatedResponse = .success(continuationToken: expectedContinuationToken)
209209
let result = await sut.submitJITChallenge(challenge: "123456", continuationToken: expectedContinuationToken, grantType: .oobCode, context: expectedContext)
210210
result.telemetryUpdate?(.success(()))
@@ -218,6 +218,34 @@ class MSALNativeAuthJITControllerTests: MSALNativeAuthTestCase {
218218
}
219219
}
220220

221+
func test_whenRequestJITContinueReturnsJITRequired_ErrorShouldBeReturned() async {
222+
let expectedContinuationToken = "continuationToken"
223+
let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID)
224+
let authMethod = MSALAuthMethod(id: "1", challengeType: "oob", loginHint: "hint", channelTargetType: MSALNativeAuthChannelType(value:"email"))
225+
let authMethods = [authMethod]
226+
let newState = RegisterStrongAuthState(
227+
controller: sut,
228+
continuationToken: expectedContinuationToken,
229+
correlationId: defaultUUID
230+
)
231+
232+
jitRequestProviderMock.mockContinueRequestFunc(MSALNativeAuthHTTPRequestMock.prepareMockRequest())
233+
jitResponseValidatorMock.continueValidatedResponse = .success(continuationToken: expectedContinuationToken)
234+
235+
signInControllerMock.continuationTokenResult = .init(.jitAuthMethodsSelectionRequired(authMethods: authMethods, newState: newState), correlationId: defaultUUID)
236+
jitResponseValidatorMock.continueValidatedResponse = .success(continuationToken: expectedContinuationToken)
237+
let result = await sut.submitJITChallenge(challenge: "123456", continuationToken: expectedContinuationToken, grantType: .oobCode, context: expectedContext)
238+
result.telemetryUpdate?(.success(()))
239+
240+
checkTelemetryEventResult(id: .telemetryApiIdJITContinue, isSuccessful: true)
241+
if case .error(let error, let newState) = result.result {
242+
XCTAssertEqual(error.type, .generalError)
243+
XCTAssertNil(newState)
244+
} else {
245+
XCTFail("Expected verificationRequired result")
246+
}
247+
}
248+
221249
func test_whenRequestJITContinueRequestFails_ErrorShouldBeReturned() async {
222250
let expectedContinuationToken = "continuationToken"
223251
let expectedContext = MSALNativeAuthRequestContext(correlationId: defaultUUID)

MSAL/test/unit/native_auth/controllers/MSALNativeAuthResetPasswordControllerTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -882,8 +882,8 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
882882

883883
let exp2 = expectation(description: "SignInAfterResetPassword expectation")
884884
signInControllerMock.expectation = exp2
885-
signInControllerMock.continuationTokenResult = .init(.failure(SignInAfterResetPasswordError(correlationId: correlationId)), correlationId: correlationId)
886-
885+
signInControllerMock.continuationTokenResult = .init(.error(error: SignInAfterResetPasswordError(correlationId: correlationId)), correlationId: correlationId)
886+
887887
let parameters = MSALNativeAuthSignInAfterResetPasswordParameters()
888888
helper.signInAfterResetPasswordState?.signIn(parameters: parameters, delegate: SignInAfterResetPasswordDelegateStub())
889889
await fulfillment(of: [exp2], timeout: 1)
@@ -934,7 +934,7 @@ final class MSALNativeAuthResetPasswordControllerTests: MSALNativeAuthTestCase {
934934

935935
let exp2 = expectation(description: "SignInAfterResetPassword expectation")
936936
signInControllerMock.expectation = exp2
937-
signInControllerMock.continuationTokenResult = .init(.failure(SignInAfterResetPasswordError(correlationId: correlationId)), correlationId: correlationId)
937+
signInControllerMock.continuationTokenResult = .init(.error(error: SignInAfterResetPasswordError(correlationId: correlationId)), correlationId: correlationId)
938938

939939
let parameters = MSALNativeAuthSignInAfterResetPasswordParameters()
940940
helper.signInAfterResetPasswordState?.signIn(parameters: parameters, delegate: SignInAfterResetPasswordDelegateStub())

0 commit comments

Comments
 (0)