/// <summary> /// Generate the new session for the logged in user. Also, set the appropriate claims for the user in this session. /// The multi-factor authentication setting value can be obtained from external logins(in case of AADv2). /// </summary> /// <returns>Awaitable task</returns> public virtual async Task CreateSessionAsync(IOwinContext owinContext, AuthenticatedUser authenticatedUser, bool wasMultiFactorAuthenticated = false) { // Create a claims identity for the session ClaimsIdentity identity = CreateIdentity(authenticatedUser.User, AuthenticationTypes.LocalUser, await GetUserLoginClaims(authenticatedUser, wasMultiFactorAuthenticated)); // Issue the session token and clean up the external token if present owinContext.Authentication.SignIn(new AuthenticationProperties() { IsPersistent = true }, identity); owinContext.Authentication.SignOut(AuthenticationTypes.External); _telemetryService.TrackUserLogin(authenticatedUser.User, authenticatedUser.CredentialUsed, wasMultiFactorAuthenticated); // Write an audit record await Auditing.SaveAuditRecordAsync( new UserAuditRecord(authenticatedUser.User, AuditedUserAction.Login, authenticatedUser.CredentialUsed)); }
private async Task <Claim[]> GetUserLoginClaims(AuthenticatedUser user, bool wasMultiFactorAuthenticated) { await _contentObjectService.Refresh(); var claims = new List <Claim>(); if (_contentObjectService.LoginDiscontinuationConfiguration.IsLoginDiscontinued(user)) { ClaimsExtensions.AddBooleanClaim(claims, NuGetClaims.DiscontinuedLogin); } if (user.User.HasPasswordCredential()) { ClaimsExtensions.AddBooleanClaim(claims, NuGetClaims.PasswordLogin); } if (user.User.HasExternalCredential()) { ClaimsExtensions.AddBooleanClaim(claims, NuGetClaims.ExternalLogin); var externalIdentities = user.User .Credentials .Where(cred => cred.IsExternal()) .Select(cred => cred.Identity) .ToArray(); var identityList = string.Join(" or ", externalIdentities); ClaimsExtensions.AddExternalCredentialIdentityClaim(claims, identityList); } if (user.User.EnableMultiFactorAuthentication) { ClaimsExtensions.AddBooleanClaim(claims, NuGetClaims.EnabledMultiFactorAuthentication); } if (wasMultiFactorAuthenticated) { ClaimsExtensions.AddBooleanClaim(claims, NuGetClaims.WasMultiFactorAuthenticated); } ClaimsExtensions.AddExternalLoginCredentialTypeClaim(claims, user.CredentialUsed.Type); return(claims.ToArray()); }
private async Task <Claim[]> GetDiscontinuedLoginClaims(AuthenticatedUser user) { await _contentObjectService.Refresh(); var claims = new List <Claim>(); if (_contentObjectService.LoginDiscontinuationConfiguration.IsLoginDiscontinued(user)) { ClaimsExtensions.AddBooleanClaim(claims, NuGetClaims.DiscontinuedLogin); } if (user.User.HasPasswordCredential()) { ClaimsExtensions.AddBooleanClaim(claims, NuGetClaims.PasswordLogin); } if (user.User.HasExternalCredential()) { ClaimsExtensions.AddBooleanClaim(claims, NuGetClaims.ExternalLogin); } return(claims.ToArray()); }
public async Task GivenNoLinkButEmailMatchingLocalUser_ItDisplaysLogOnViewPresetForSignIn() { // Arrange var existingUser = new User("existingUser") { EmailAddress = "*****@*****.**" }; var cred = CredentialBuilder.CreateExternalCredential("MicrosoftAccount", "blorg", "Bloog"); var msAuther = new MicrosoftAccountAuthenticator(); var msaUI = msAuther.GetUI(); var authUser = new AuthenticatedUser( Fakes.CreateUser("test", cred), cred); GetMock<AuthenticationService>(); // Force a mock to be created GetMock<IUserService>() .Setup(u => u.FindByEmailAddress(existingUser.EmailAddress)) .Returns(existingUser); var controller = GetController<AuthenticationController>(); GetMock<AuthenticationService>() .Setup(x => x.AuthenticateExternalLogin(controller.OwinContext)) .CompletesWith(new AuthenticateExternalLoginResult() { ExternalIdentity = new ClaimsIdentity(new [] { new Claim(ClaimTypes.Email, existingUser.EmailAddress) }), Authenticator = msAuther }); // Act var result = await controller.LinkExternalAccount("theReturnUrl"); // Assert var model = ResultAssert.IsView<LogOnViewModel>(result, viewName: "LogOn"); Assert.Equal(msaUI.AccountNoun, model.External.ProviderAccountNoun); Assert.Null(model.External.AccountName); Assert.True(model.External.FoundExistingUser); Assert.Equal(existingUser.EmailAddress, model.SignIn.UserNameOrEmail); Assert.Equal(existingUser.EmailAddress, model.Register.EmailAddress); }
public async Task GivenAssociatedLocalAdminUser_ItChallengesWhenNotUsingRequiredExternalProvider(string providerUsedForLogin, bool shouldChallenge) { // Arrange var enforcedProvider = "AzureActiveDirectory"; var config = Get<ConfigurationService>(); config.Current = new AppConfiguration() { ConfirmEmailAddresses = false, EnforcedAuthProviderForAdmin = enforcedProvider }; GetMock<AuthenticationService>(); // Force a mock to be created var controller = GetController<AuthenticationController>(); var cred = CredentialBuilder.CreateExternalCredential(providerUsedForLogin, "blorg", "Bloog"); var authUser = new AuthenticatedUser( Fakes.CreateUser("test", cred), cred); authUser.User.Roles.Add(new Role { Name = Constants.AdminRoleName }); GetMock<AuthenticationService>() .Setup(x => x.AuthenticateExternalLogin(controller.OwinContext)) .CompletesWith(new AuthenticateExternalLoginResult() { ExternalIdentity = new ClaimsIdentity(), Authentication = authUser }); if (shouldChallenge) { GetMock<AuthenticationService>() .Setup(x => x.Challenge(enforcedProvider, It.IsAny<string>())) .Returns(new ChallengeResult(enforcedProvider, null)) .Verifiable(); } else { GetMock<AuthenticationService>() .Setup(x => x.CreateSession(controller.OwinContext, authUser.User)) .Verifiable(); } // Act var result = await controller.LinkExternalAccount("theReturnUrl"); // Assert if (shouldChallenge) { ResultAssert.IsChallengeResult(result, enforcedProvider); } else { ResultAssert.IsSafeRedirectTo(result, "theReturnUrl"); GetMock<AuthenticationService>().VerifyAll(); } }
public async Task GivenAssociatedLocalUser_ItCreatesASessionAndSafeRedirectsToReturnUrl() { // Arrange GetMock<AuthenticationService>(); // Force a mock to be created var controller = GetController<AuthenticationController>(); var cred = CredentialBuilder.CreateExternalCredential("MicrosoftAccount", "blorg", "Bloog"); var authUser = new AuthenticatedUser( Fakes.CreateUser("test", cred), cred); GetMock<AuthenticationService>() .Setup(x => x.AuthenticateExternalLogin(controller.OwinContext)) .CompletesWith(new AuthenticateExternalLoginResult() { ExternalIdentity = new ClaimsIdentity(), Authentication = authUser }); // Act var result = await controller.LinkExternalAccount("theReturnUrl"); // Assert ResultAssert.IsSafeRedirectTo(result, "theReturnUrl"); GetMock<AuthenticationService>() .Verify(x => x.CreateSession(controller.OwinContext, authUser.User)); }
public async Task GivenAdminLogsInWithExternalIdentity_ItChallengesWhenNotUsingRequiredExternalProvider(string providerUsedForLogin, bool shouldChallenge) { // Arrange var enforcedProvider = "AzureActiveDirectory"; var config = Get<ConfigurationService>(); config.Current = new AppConfiguration() { ConfirmEmailAddresses = false, EnforcedAuthProviderForAdmin = enforcedProvider }; var externalCred = CredentialBuilder.CreateExternalCredential(providerUsedForLogin, "blorg", "Bloog"); var authUser = new AuthenticatedUser( new User("theUsername") { UnconfirmedEmailAddress = "*****@*****.**", EmailConfirmationToken = "t0k3n", Roles = { new Role { Name = Constants.AdminRoleName } } }, externalCred); GetMock<AuthenticationService>() .Setup(x => x.Register("theUsername", "theEmailAddress", externalCred)) .CompletesWith(authUser); EnableAllAuthenticators(Get<AuthenticationService>()); var controller = GetController<AuthenticationController>(); if (shouldChallenge) { GetMock<AuthenticationService>() .Setup(x => x.Challenge(enforcedProvider, It.IsAny<string>())) .Returns(new ChallengeResult(enforcedProvider, null)) .Verifiable(); } else { GetMock<AuthenticationService>() .Setup(x => x.CreateSession(controller.OwinContext, authUser.User)) .Verifiable(); } GetMock<AuthenticationService>() .Setup(x => x.ReadExternalLoginCredential(controller.OwinContext)) .CompletesWith(new AuthenticateExternalLoginResult() { ExternalIdentity = new ClaimsIdentity(), Credential = externalCred }); // Act var result = await controller.Register( new LogOnViewModel() { Register = new RegisterViewModel { Username = "******", EmailAddress = "theEmailAddress", } }, "/theReturnUrl", linkingAccount: true); // Assert if (shouldChallenge) { ResultAssert.IsChallengeResult(result, enforcedProvider); } else { ResultAssert.IsSafeRedirectTo(result, "/theReturnUrl"); } GetMock<AuthenticationService>().VerifyAll(); }
public async Task WritesAnAuditRecord() { // Arrange var service = Get<AuthenticationService>(); var context = Fakes.CreateOwinContext(); var credential = Fakes.Admin.Credentials.SingleOrDefault( c => String.Equals(c.Type, CredentialTypes.Password.Pbkdf2, StringComparison.OrdinalIgnoreCase)); var authenticatedUser = new AuthenticatedUser(Fakes.Admin, credential); // Act await service.CreateSessionAsync(context, authenticatedUser); // Assert var authenticationService = Get<AuthenticationService>(); Assert.True(authenticationService.Auditing.WroteRecord<UserAuditRecord>(ar => ar.Action == AuditedUserAction.Login && ar.Username == Fakes.Admin.Username)); }
private async Task<AuthenticatedUser> AssociateCredential(AuthenticatedUser user) { var result = await _authService.ReadExternalLoginCredential(OwinContext); if (result.ExternalIdentity == null) { // User got here without an external login cookie (or an expired one) // Send them to the logon action return null; } await _authService.AddCredential(user.User, result.Credential); // Notify the user of the change _messageService.SendCredentialAddedNotice(user.User, result.Credential); return new AuthenticatedUser(user.User, result.Credential); }
public async Task WillCreateAndLogInTheUserWhenNotLinking() { // Arrange var authUser = new AuthenticatedUser( new User("theUsername") { UnconfirmedEmailAddress = "*****@*****.**", EmailConfirmationToken = "t0k3n" }, new Credential()); GetMock<AuthenticationService>() .Setup(x => x.Register("theUsername", "*****@*****.**", It.IsAny<Credential>())) .CompletesWith(authUser); var controller = GetController<AuthenticationController>(); GetMock<AuthenticationService>() .Setup(x => x.CreateSession(controller.OwinContext, authUser.User)) .Verifiable(); // Act var result = await controller.Register( new LogOnViewModel() { Register = new RegisterViewModel { Username = "******", Password = "******", EmailAddress = "*****@*****.**", } }, "/theReturnUrl", linkingAccount: false); // Assert GetMock<AuthenticationService>().VerifyAll(); var expectedAddress = new MailAddress(authUser.User.UnconfirmedEmailAddress, authUser.User.Username); GetMock<IMessageService>() .Verify(x => x.SendNewAccountEmail( expectedAddress, "https://nuget.local/account/confirm/theUsername/t0k3n")); ResultAssert.IsSafeRedirectTo(result, "/theReturnUrl"); }
public async Task GivenValidExternalAuth_ItLinksCredentialSendsEmailAndLogsIn() { // Arrange var authUser = new AuthenticatedUser( new User("theUsername") { EmailAddress = "*****@*****.**" }, new Credential() { Type = "Foo" }); var externalCred = CredentialBuilder.CreateExternalCredential("MicrosoftAccount", "blorg", "Bloog"); GetMock<AuthenticationService>() .Setup(x => x.Authenticate(authUser.User.Username, "thePassword")) .CompletesWith(authUser); GetMock<AuthenticationService>() .Setup(x => x.AddCredential(authUser.User, externalCred)) .Completes() .Verifiable(); GetMock<IMessageService>() .Setup(x => x.SendCredentialAddedNotice(authUser.User, externalCred)) .Verifiable(); var controller = GetController<AuthenticationController>(); GetMock<AuthenticationService>() .Setup(x => x.CreateSession(controller.OwinContext, authUser.User)) .Verifiable(); GetMock<AuthenticationService>() .Setup(x => x.ReadExternalLoginCredential(controller.OwinContext)) .CompletesWith(new AuthenticateExternalLoginResult() { ExternalIdentity = new ClaimsIdentity(), Credential = externalCred }); // Act var result = await controller.SignIn( new LogOnViewModel( new SignInViewModel( authUser.User.Username, "thePassword")), "theReturnUrl", linkingAccount: true); // Assert ResultAssert.IsSafeRedirectTo(result, "theReturnUrl"); GetMock<AuthenticationService>().VerifyAll(); GetMock<IMessageService>().VerifyAll(); }
public async Task GivenExpiredExternalAuth_ItRedirectsBackToLogOnWithExternalAuthExpiredMessage() { // Arrange var authUser = new AuthenticatedUser( new User("theUsername") { EmailAddress = "*****@*****.**" }, new Credential() { Type = "Foo" }); GetMock<AuthenticationService>() .Setup(x => x.Authenticate(authUser.User.Username, "thePassword")) .CompletesWith(authUser); var controller = GetController<AuthenticationController>(); GetMock<AuthenticationService>() .Setup(x => x.ReadExternalLoginCredential(controller.OwinContext)) .CompletesWith(new AuthenticateExternalLoginResult()); // Act var result = await controller.SignIn( new LogOnViewModel( new SignInViewModel( authUser.User.Username, "thePassword")), "theReturnUrl", linkingAccount: true); // Assert VerifyExternalLinkExpiredResult(controller, result); GetMock<AuthenticationService>() .Verify(x => x.CreateSession(It.IsAny<IOwinContext>(), It.IsAny<User>()), Times.Never()); }
public async Task WillLogTheUserOnWithUsernameEvenWithoutConfirmedEmailAddress() { // Arrange var authUser = new AuthenticatedUser( new User("theUsername") { UnconfirmedEmailAddress = "*****@*****.**" }, new Credential() { Type = "Foo" }); GetMock<AuthenticationService>() .Setup(x => x.Authenticate("*****@*****.**", "thePassword")) .CompletesWith(authUser); var controller = GetController<AuthenticationController>(); GetMock<AuthenticationService>() .Setup(a => a.CreateSession(controller.OwinContext, authUser.User)) .Verifiable(); // Act var result = await controller.SignIn( new LogOnViewModel( new SignInViewModel( "*****@*****.**", "thePassword")), "theReturnUrl", linkingAccount: false); // Assert ResultAssert.IsSafeRedirectTo(result, "theReturnUrl"); GetMock<AuthenticationService>().VerifyAll(); }
public async Task GivenAdminLogsInWithValidExternalAuth_ItChallengesWhenNotUsingRequiredExternalProvider(string providerUsedForLogin, bool shouldChallenge) { var enforcedProvider = "AzureActiveDirectory"; var mockConfig = GetMock<IGalleryConfigurationService>(); mockConfig.Setup(x => x.Current).Returns(new AppConfiguration { ConfirmEmailAddresses = false, EnforcedAuthProviderForAdmin = enforcedProvider }); var externalCred = new CredentialBuilder().CreateExternalCredential(providerUsedForLogin, "blorg", "Bloog"); var authUser = new AuthenticatedUser( new User("theUsername") { UnconfirmedEmailAddress = "*****@*****.**", Roles = { new Role { Name = Constants.AdminRoleName } } }, externalCred); GetMock<AuthenticationService>() .Setup(x => x.Authenticate(authUser.User.Username, "thePassword")) .CompletesWith(authUser); GetMock<AuthenticationService>() .Setup(x => x.AddCredential(authUser.User, externalCred)) .Completes() .Verifiable(); GetMock<IMessageService>() .Setup(x => x.SendCredentialAddedNotice(authUser.User, externalCred)) .Verifiable(); EnableAllAuthenticators(Get<AuthenticationService>()); var controller = GetController<AuthenticationController>(); if (shouldChallenge) { GetMock<AuthenticationService>() .Setup(x => x.Challenge(enforcedProvider, It.IsAny<string>())) .Returns(new ChallengeResult(enforcedProvider, null)) .Verifiable(); } else { GetMock<AuthenticationService>() .Setup(x => x.CreateSessionAsync(controller.OwinContext, It.IsAny<AuthenticatedUser>())) .Returns(Task.FromResult(0)) .Verifiable(); } GetMock<AuthenticationService>() .Setup(x => x.ReadExternalLoginCredential(controller.OwinContext)) .CompletesWith(new AuthenticateExternalLoginResult() { ExternalIdentity = new ClaimsIdentity(), Credential = externalCred }); // Act var result = await controller.SignIn( new LogOnViewModel( new SignInViewModel( authUser.User.Username, "thePassword")), "theReturnUrl", linkingAccount: true); // Assert if (shouldChallenge) { ResultAssert.IsChallengeResult(result, enforcedProvider); } else { ResultAssert.IsSafeRedirectTo(result, "theReturnUrl"); } GetMock<AuthenticationService>().VerifyAll(); GetMock<IMessageService>().VerifyAll(); }
public async Task CanLogTheUserOnWithUserName() { // Arrange var authUser = new AuthenticatedUser( new User("theUsername") { EmailAddress = "*****@*****.**" }, new Credential { Type = "Foo" }); var authResult = new PasswordAuthenticationResult(PasswordAuthenticationResult.AuthenticationResult.Success, authUser); GetMock<AuthenticationService>() .Setup(x => x.Authenticate(authUser.User.Username, "thePassword")) .CompletesWith(authResult); var controller = GetController<AuthenticationController>(); GetMock<AuthenticationService>() .Setup(a => a.CreateSessionAsync(controller.OwinContext, authUser)) .Returns(Task.FromResult(0)) .Verifiable(); // Act var result = await controller.SignIn( new LogOnViewModel( new SignInViewModel( authUser.User.Username, "thePassword")), "theReturnUrl", linkingAccount: false); // Assert ResultAssert.IsSafeRedirectTo(result, "theReturnUrl"); GetMock<AuthenticationService>().VerifyAll(); }
public void VerifyShouldChallenge(string providerUsedForLogin, bool shouldChallenge) { // Arrange var enforcedProvider = "AzureActiveDirectory"; EnableAllAuthenticators(Get<AuthenticationService>()); var controller = GetController<AuthenticationController>(); var authUser = new AuthenticatedUser( new User("theUsername") { EmailAddress = "*****@*****.**", Roles = { new Role { Name = Constants.AdminRoleName } } }, new Credential { Type = providerUsedForLogin }); // Act ActionResult challengeResult; var result = controller.ShouldChallengeEnforcedProvider(enforcedProvider, authUser, null, out challengeResult); // Assert Assert.Equal(shouldChallenge, result); if (shouldChallenge) { ResultAssert.IsChallengeResult(challengeResult, enforcedProvider); } }
internal bool ShouldChallengeEnforcedProvider(string enforcedProviders, AuthenticatedUser authenticatedUser, string returnUrl, out ActionResult challenge) { if (!string.IsNullOrEmpty(enforcedProviders) && authenticatedUser.CredentialUsed.Type != null && authenticatedUser.User.IsInRole(Constants.AdminRoleName)) { // Seems we *need* a specific authentication provider. Check if we logged in using one... var providers = enforcedProviders.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries); if (!providers.Any(p => string.Equals(p, authenticatedUser.CredentialUsed.Type, StringComparison.OrdinalIgnoreCase)) && !providers.Any(p => string.Equals(CredentialTypes.ExternalPrefix + p, authenticatedUser.CredentialUsed.Type, StringComparison.OrdinalIgnoreCase))) { // Challenge authentication using the first required authentication provider challenge = _authService.Challenge( providers.First(), Url.Action("LinkExternalAccount", "Authentication", new { ReturnUrl = returnUrl })); return true; } } challenge = null; return false; }
public async Task WillNotSendConfirmationEmailWhenConfirmEmailAddressesIsOff() { // Arrange var authUser = new AuthenticatedUser( new User("theUsername") { UnconfirmedEmailAddress = "*****@*****.**", EmailConfirmationToken = "t0k3n" }, new Credential()); var config = Get<ConfigurationService>(); config.Current = new AppConfiguration() { ConfirmEmailAddresses = false }; GetMock<AuthenticationService>() .Setup(x => x.Register("theUsername", "*****@*****.**", It.IsAny<Credential>())) .CompletesWith(authUser); var controller = GetController<AuthenticationController>(); GetMock<AuthenticationService>() .Setup(x => x.CreateSession(controller.OwinContext, authUser.User)) .Verifiable(); // Act var result = await controller.Register( new LogOnViewModel() { Register = new RegisterViewModel { Username = "******", Password = "******", EmailAddress = "*****@*****.**", } }, "/theReturnUrl", linkingAccount: false); // Assert GetMock<IMessageService>() .Verify(x => x.SendNewAccountEmail( It.IsAny<MailAddress>(), It.IsAny<string>()), Times.Never()); }
public async Task GivenAUser_ItCreatesAnOwinAuthenticationTicketForTheUser() { // Arrange var service = Get<AuthenticationService>(); var context = Fakes.CreateOwinContext(); var passwordCred = Fakes.Admin.Credentials.SingleOrDefault( c => String.Equals(c.Type, CredentialTypes.Password.Pbkdf2, StringComparison.OrdinalIgnoreCase)); var authUser = new AuthenticatedUser(Fakes.Admin, passwordCred); // Act await service.CreateSessionAsync(context, authUser); // Assert var principal = context.Authentication.AuthenticationResponseGrant.Principal; var id = principal.Identity; Assert.NotNull(principal); Assert.NotNull(id); Assert.Equal(Fakes.Admin.Username, id.Name); Assert.Equal(Fakes.Admin.Username, principal.GetClaimOrDefault(ClaimTypes.NameIdentifier)); Assert.Equal(AuthenticationTypes.LocalUser, id.AuthenticationType); Assert.True(principal.IsInRole(Constants.AdminRoleName)); }
public async Task GivenExpiredExternalAuth_ItRedirectsBackToLogOnWithExternalAuthExpiredMessage() { // Arrange var authUser = new AuthenticatedUser(new User("theUsername"), new Credential()); GetMock<AuthenticationService>(); // Force AuthenticationService to be mocked even though it's concrete var controller = GetController<AuthenticationController>(); GetMock<AuthenticationService>() .Setup(x => x.CreateSession(controller.OwinContext, authUser.User)) .Verifiable(); GetMock<AuthenticationService>() .Setup(x => x.ReadExternalLoginCredential(controller.OwinContext)) .CompletesWith(new AuthenticateExternalLoginResult()); // Act var result = await controller.Register( new LogOnViewModel() { Register = new RegisterViewModel { Username = "******", EmailAddress = "theEmailAddress", } }, "/theReturnUrl", linkingAccount: true); // Assert VerifyExternalLinkExpiredResult(controller, result); GetMock<AuthenticationService>() .Verify(x => x.CreateSession(It.IsAny<IOwinContext>(), It.IsAny<User>()), Times.Never()); GetMock<AuthenticationService>() .Verify(x => x.Register("theUsername", "theEmailAddress", It.IsAny<Credential>()), Times.Never()); }
public virtual async Task CreateSessionAsync(IOwinContext owinContext, AuthenticatedUser user) { // Create a claims identity for the session ClaimsIdentity identity = CreateIdentity(user.User, AuthenticationTypes.LocalUser); // Issue the session token and clean up the external token if present owinContext.Authentication.SignIn(identity); owinContext.Authentication.SignOut(AuthenticationTypes.External); // Write an audit record await Auditing.SaveAuditRecord( new UserAuditRecord(user.User, AuditedUserAction.Login, user.CredentialUsed)); }
public async Task GivenValidExternalAuth_ItCreatesAccountAndLinksCredential() { // Arrange var authUser = new AuthenticatedUser( new User("theUsername") { UnconfirmedEmailAddress = "*****@*****.**", EmailConfirmationToken = "t0k3n" }, new Credential()); var externalCred = CredentialBuilder.CreateExternalCredential("MicrosoftAccount", "blorg", "Bloog"); GetMock<AuthenticationService>() .Setup(x => x.Register("theUsername", "theEmailAddress", externalCred)) .CompletesWith(authUser); var controller = GetController<AuthenticationController>(); GetMock<AuthenticationService>() .Setup(x => x.CreateSession(controller.OwinContext, authUser.User)) .Verifiable(); GetMock<AuthenticationService>() .Setup(x => x.ReadExternalLoginCredential(controller.OwinContext)) .CompletesWith(new AuthenticateExternalLoginResult() { ExternalIdentity = new ClaimsIdentity(), Credential = externalCred }); // Simulate the model state error that will be added when doing an external account registration (since password is not present) controller.ModelState.AddModelError("Register.Password", "Password is required"); // Act var result = await controller.Register( new LogOnViewModel() { Register = new RegisterViewModel { Username = "******", EmailAddress = "theEmailAddress", } }, "/theReturnUrl", linkingAccount: true); // Assert GetMock<AuthenticationService>().VerifyAll(); var expectedAddress = new MailAddress(authUser.User.UnconfirmedEmailAddress, authUser.User.Username); GetMock<IMessageService>() .Verify(x => x.SendNewAccountEmail( expectedAddress, "https://nuget.local/account/confirm/theUsername/t0k3n")); ResultAssert.IsSafeRedirectTo(result, "/theReturnUrl"); }