diff --git a/dotnet-authserver/src/TeacherIdentity.AuthServer/Pages/SignIn/TrnInUseChooseEmail.cshtml.cs b/dotnet-authserver/src/TeacherIdentity.AuthServer/Pages/SignIn/TrnInUseChooseEmail.cshtml.cs index 2aa37f5dc..4428a93b3 100644 --- a/dotnet-authserver/src/TeacherIdentity.AuthServer/Pages/SignIn/TrnInUseChooseEmail.cshtml.cs +++ b/dotnet-authserver/src/TeacherIdentity.AuthServer/Pages/SignIn/TrnInUseChooseEmail.cshtml.cs @@ -54,6 +54,11 @@ public async Task OnPost() } var authenticationState = _journey.AuthenticationState; + authenticationState.EnsureOAuthState(); + + var journeyTrnVerificationLevel = authenticationState.OAuthState.TrnMatchPolicy == TrnMatchPolicy.Strict ? + TrnVerificationLevel.Medium : + TrnVerificationLevel.Low; var lookupState = await _dbContext.JourneyTrnLookupStates .SingleOrDefaultAsync(s => s.JourneyId == authenticationState.JourneyId); @@ -61,23 +66,33 @@ public async Task OnPost() var user = await _dbContext.Users.SingleAsync(u => u.EmailAddress == authenticationState.TrnOwnerEmailAddress); var emailChanged = user.EmailAddress != Email; - user.EmailAddress = Email; + bool trnVerificationLevelChanged = false; + if (user.TrnVerificationLevel < journeyTrnVerificationLevel) + { + user.TrnVerificationLevel = journeyTrnVerificationLevel; + trnVerificationLevelChanged = true; + } + if (lookupState is not null) { lookupState.Locked = _clock.UtcNow; lookupState.UserId = user.UserId; } - if (emailChanged) + var changes = Events.UserUpdatedEventChanges.None | + (emailChanged ? Events.UserUpdatedEventChanges.EmailAddress : 0) | + (trnVerificationLevelChanged ? Events.UserUpdatedEventChanges.TrnVerificationLevel : 0); + + if (changes != Events.UserUpdatedEventChanges.None) { user.Updated = _clock.UtcNow; _dbContext.AddEvent(new Events.UserUpdatedEvent() { Source = Events.UserUpdatedEventSource.TrnMatchedToExistingUser, - Changes = Events.UserUpdatedEventChanges.EmailAddress, + Changes = changes, CreatedUtc = _clock.UtcNow, User = user, UpdatedByUserId = user.UserId, diff --git a/dotnet-authserver/tests/TeacherIdentity.AuthServer.Tests/EndpointTests/SignIn/TrnInUseChooseEmailTests.cs b/dotnet-authserver/tests/TeacherIdentity.AuthServer.Tests/EndpointTests/SignIn/TrnInUseChooseEmailTests.cs index bbb82424f..164bf75b3 100644 --- a/dotnet-authserver/tests/TeacherIdentity.AuthServer.Tests/EndpointTests/SignIn/TrnInUseChooseEmailTests.cs +++ b/dotnet-authserver/tests/TeacherIdentity.AuthServer.Tests/EndpointTests/SignIn/TrnInUseChooseEmailTests.cs @@ -301,19 +301,30 @@ public async Task Post_SubmittedEmailDoesNotMatchEnteredOrMatchedEmail_Rerenders } [Theory] - [InlineData(false)] - [InlineData(true)] - public async Task Post_ValidRequest_UpdatesUserAndRedirectsToNextPage(bool newEmailChosen) + [InlineData(false, TrnMatchPolicy.Default, TrnVerificationLevel.Low, TrnVerificationLevel.Low)] + [InlineData(false, TrnMatchPolicy.Default, TrnVerificationLevel.Medium, TrnVerificationLevel.Medium)] + [InlineData(false, TrnMatchPolicy.Strict, TrnVerificationLevel.Low, TrnVerificationLevel.Medium)] + [InlineData(false, TrnMatchPolicy.Strict, TrnVerificationLevel.Medium, TrnVerificationLevel.Medium)] + [InlineData(true, TrnMatchPolicy.Default, TrnVerificationLevel.Low, TrnVerificationLevel.Low)] + [InlineData(true, TrnMatchPolicy.Default, TrnVerificationLevel.Medium, TrnVerificationLevel.Medium)] + [InlineData(true, TrnMatchPolicy.Strict, TrnVerificationLevel.Low, TrnVerificationLevel.Medium)] + [InlineData(true, TrnMatchPolicy.Strict, TrnVerificationLevel.Medium, TrnVerificationLevel.Medium)] + public async Task Post_ValidRequest_UpdatesUserAndRedirectsToNextPage( + bool newEmailChosen, + TrnMatchPolicy trnMatchPolicy, + TrnVerificationLevel existingTrnVerificationLevel, + TrnVerificationLevel expectedNewTrnVerificationLevel) { // Arrange var email = Faker.Internet.Email(); - var existingTrnOwner = await TestData.CreateUser(hasTrn: true); + var existingTrnOwner = await TestData.CreateUser(hasTrn: true, trnVerificationLevel: existingTrnVerificationLevel); var chosenEmail = newEmailChosen ? email : existingTrnOwner.EmailAddress; var authStateHelper = await CreateAuthenticationStateHelper( c => c.TrnLookupCompletedForExistingTrnAndOwnerEmailVerified(existingTrnOwner, email), CustomScopes.Trn, - trnRequirementType: null); + trnRequirementType: null, + trnMatchPolicy: trnMatchPolicy); var request = new HttpRequestMessage(HttpMethod.Post, $"/sign-in/trn/choose-email?{authStateHelper.ToQueryParam()}") { @@ -340,12 +351,13 @@ public async Task Post_ValidRequest_UpdatesUserAndRedirectsToNextPage(bool newEm Assert.NotNull(user); Assert.Equal(chosenEmail, user.EmailAddress); + Assert.Equal(expectedNewTrnVerificationLevel, user.TrnVerificationLevel); return user.UserId; }); - // Should get a UserUpdatedEvent if the email address was changed - if (newEmailChosen) + // Should get a UserUpdatedEvent if the email address or TrnVerificationLevel was changed + if (newEmailChosen || existingTrnVerificationLevel != expectedNewTrnVerificationLevel) { EventObserver.AssertEventsSaved( e => @@ -354,6 +366,18 @@ public async Task Post_ValidRequest_UpdatesUserAndRedirectsToNextPage(bool newEm Assert.Equal(Clock.UtcNow, userUpdatedEvent.CreatedUtc); Assert.Equal(UserUpdatedEventSource.TrnMatchedToExistingUser, userUpdatedEvent.Source); Assert.Equal(userId, userUpdatedEvent.User.UserId); + + if (newEmailChosen) + { + Assert.Equal(chosenEmail, userUpdatedEvent.User.EmailAddress); + Assert.True(userUpdatedEvent.Changes.HasFlag(UserUpdatedEventChanges.EmailAddress)); + } + + if (existingTrnVerificationLevel != expectedNewTrnVerificationLevel) + { + Assert.Equal(expectedNewTrnVerificationLevel, userUpdatedEvent.User.TrnVerificationLevel); + Assert.True(userUpdatedEvent.Changes.HasFlag(UserUpdatedEventChanges.TrnVerificationLevel)); + } }); } else