From 7d4aed4e3b19da4af20d7e8097718b0f361687b6 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Thu, 7 Aug 2014 16:29:56 -0700 Subject: [PATCH] Clean up sign in manager - Add SignInOptions - Also fix SecurityStampValidator issue resolving against wrong service collection --- .../Controllers/ManageController.cs | 2 +- .../HttpAuthenticationManager.cs | 4 +- .../IdentityBuilderExtensions.cs | 3 +- .../SecurityStampValidator.cs | 4 +- .../IAuthenticationManager.cs | 4 +- .../IdentityOptions.cs | 4 + .../Microsoft.AspNet.Identity.kproj | 1 + .../SignInManager.cs | 107 +++++++++++------- .../SignInOptions.cs | 20 ++++ .../HttpSignInTest.cs | 65 ++++++++--- .../SecurityStampValidatorTest.cs | 44 ++++--- 11 files changed, 181 insertions(+), 77 deletions(-) create mode 100644 src/Microsoft.AspNet.Identity/SignInOptions.cs diff --git a/samples/IdentitySample.Mvc/Controllers/ManageController.cs b/samples/IdentitySample.Mvc/Controllers/ManageController.cs index 45f233a135..df0ccd613e 100644 --- a/samples/IdentitySample.Mvc/Controllers/ManageController.cs +++ b/samples/IdentitySample.Mvc/Controllers/ManageController.cs @@ -39,7 +39,7 @@ namespace IdentitySample PhoneNumber = await UserManager.GetPhoneNumberAsync(user), TwoFactor = await UserManager.GetTwoFactorEnabledAsync(user), Logins = await UserManager.GetLoginsAsync(user), - BrowserRemembered = await SignInManager.IsTwoFactorClientRemembered(user) + BrowserRemembered = await SignInManager.IsTwoFactorClientRememberedAsync(user) }; return View(model); } diff --git a/src/Microsoft.AspNet.Identity.Authentication/HttpAuthenticationManager.cs b/src/Microsoft.AspNet.Identity.Authentication/HttpAuthenticationManager.cs index d45d250f66..a0c742138c 100644 --- a/src/Microsoft.AspNet.Identity.Authentication/HttpAuthenticationManager.cs +++ b/src/Microsoft.AspNet.Identity.Authentication/HttpAuthenticationManager.cs @@ -2,11 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Security.Claims; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Security; using Microsoft.Framework.DependencyInjection; -using System; namespace Microsoft.AspNet.Identity.Authentication { @@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Identity.Authentication Context.Response.SignOut(TwoFactorRememberedAuthenticationType); } - public async Task IsClientRememeberedAsync(string userId) + public async Task IsClientRememeberedAsync(string userId, CancellationToken cancellationToken = default(CancellationToken)) { var result = await Context.AuthenticateAsync(TwoFactorRememberedAuthenticationType); diff --git a/src/Microsoft.AspNet.Identity.Authentication/IdentityBuilderExtensions.cs b/src/Microsoft.AspNet.Identity.Authentication/IdentityBuilderExtensions.cs index 2ca3a34adc..2233f32b90 100644 --- a/src/Microsoft.AspNet.Identity.Authentication/IdentityBuilderExtensions.cs +++ b/src/Microsoft.AspNet.Identity.Authentication/IdentityBuilderExtensions.cs @@ -12,8 +12,7 @@ namespace Microsoft.Framework.DependencyInjection where TUser : class where TRole : class { - // todo: review should this be scoped? - builder.Services.AddTransient(); + builder.Services.AddScoped(); return builder; } } diff --git a/src/Microsoft.AspNet.Identity.Authentication/SecurityStampValidator.cs b/src/Microsoft.AspNet.Identity.Authentication/SecurityStampValidator.cs index 6d760675ab..e52bfa6903 100644 --- a/src/Microsoft.AspNet.Identity.Authentication/SecurityStampValidator.cs +++ b/src/Microsoft.AspNet.Identity.Authentication/SecurityStampValidator.cs @@ -68,9 +68,9 @@ namespace Microsoft.AspNet.Identity.Authentication } if (validate) { - var manager = context.HttpContext.ApplicationServices.GetService>(); + var manager = context.HttpContext.RequestServices.GetService>(); var userId = getUserIdCallback(context.Identity); - var user = await manager.ValidateSecurityStamp(context.Identity, userId); + var user = await manager.ValidateSecurityStampAsync(context.Identity, userId); if (user != null) { bool isPersistent = false; diff --git a/src/Microsoft.AspNet.Identity/IAuthenticationManager.cs b/src/Microsoft.AspNet.Identity/IAuthenticationManager.cs index 6eba2566e8..c060d2b142 100644 --- a/src/Microsoft.AspNet.Identity/IAuthenticationManager.cs +++ b/src/Microsoft.AspNet.Identity/IAuthenticationManager.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Security.Claims; +using System.Threading; using System.Threading.Tasks; namespace Microsoft.AspNet.Identity @@ -14,7 +15,8 @@ namespace Microsoft.AspNet.Identity // remember browser for two factor void ForgetClient(); void RememberClient(string userId); - Task IsClientRememeberedAsync(string userId); + Task IsClientRememeberedAsync(string userId, + CancellationToken cancellationToken = default(CancellationToken)); // half cookie Task StoreUserId(string userId); diff --git a/src/Microsoft.AspNet.Identity/IdentityOptions.cs b/src/Microsoft.AspNet.Identity/IdentityOptions.cs index 18ca66c9c4..620ee13aa2 100644 --- a/src/Microsoft.AspNet.Identity/IdentityOptions.cs +++ b/src/Microsoft.AspNet.Identity/IdentityOptions.cs @@ -14,6 +14,7 @@ namespace Microsoft.AspNet.Identity User = new UserOptions(); Password = new PasswordOptions(); Lockout = new LockoutOptions(); + SignIn = new SignInOptions(); } public ClaimsIdentityOptions ClaimsIdentity { get; set; } @@ -23,5 +24,8 @@ namespace Microsoft.AspNet.Identity public PasswordOptions Password { get; set; } public LockoutOptions Lockout { get; set; } + + public SignInOptions SignIn { get; set; } + } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/Microsoft.AspNet.Identity.kproj b/src/Microsoft.AspNet.Identity/Microsoft.AspNet.Identity.kproj index 10083b8359..711c809802 100644 --- a/src/Microsoft.AspNet.Identity/Microsoft.AspNet.Identity.kproj +++ b/src/Microsoft.AspNet.Identity/Microsoft.AspNet.Identity.kproj @@ -77,6 +77,7 @@ + diff --git a/src/Microsoft.AspNet.Identity/SignInManager.cs b/src/Microsoft.AspNet.Identity/SignInManager.cs index 581f8edbfe..8048358c87 100644 --- a/src/Microsoft.AspNet.Identity/SignInManager.cs +++ b/src/Microsoft.AspNet.Identity/SignInManager.cs @@ -4,7 +4,9 @@ using System; using System.Security.Claims; using System.Security.Principal; +using System.Threading; using System.Threading.Tasks; +using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Identity { @@ -15,7 +17,7 @@ namespace Microsoft.AspNet.Identity public class SignInManager where TUser : class { public SignInManager(UserManager userManager, IAuthenticationManager authenticationManager, - IClaimsIdentityFactory claimsFactory) + IClaimsIdentityFactory claimsFactory, IOptionsAccessor optionsAccessor) { if (userManager == null) { @@ -29,23 +31,45 @@ namespace Microsoft.AspNet.Identity { throw new ArgumentNullException("claimsFactory"); } + if (optionsAccessor == null || optionsAccessor.Options == null) + { + throw new ArgumentNullException("optionsAccessor"); + } UserManager = userManager; AuthenticationManager = authenticationManager; ClaimsFactory = claimsFactory; + Options = optionsAccessor.Options; } public UserManager UserManager { get; private set; } public IAuthenticationManager AuthenticationManager { get; private set; } public IClaimsIdentityFactory ClaimsFactory { get; private set; } + public IdentityOptions Options { get; private set; } // Should this be a func? - public virtual async Task CreateUserIdentityAsync(TUser user) + public virtual async Task CreateUserIdentityAsync(TUser user, + CancellationToken cancellationToken = default(CancellationToken)) { // REVIEW: should sign in manager take options instead of using the user manager instance? - return await ClaimsFactory.CreateAsync(user, UserManager.Options.ClaimsIdentity); + return await ClaimsFactory.CreateAsync(user, Options.ClaimsIdentity); } - public virtual async Task SignInAsync(TUser user, bool isPersistent) + //public virtual async Task CanSignInAsync(TUser user, + // CancellationToken cancellationToken = default(CancellationToken)) + //{ + // if (Options.SignIn.RequireConfirmedEmail && !(await UserManager.IsEmailConfirmedAsync(user, cancellationToken))) + // { + // return false; + // } + // if (Options.SignIn.RequireConfirmedPhoneNumber && !(await UserManager.IsPhoneNumberConfirmedAsync(user, cancellationToken))) + // { + // return false; + // } + // return true; + //} + + public virtual async Task SignInAsync(TUser user, bool isPersistent, + CancellationToken cancellationToken = default(CancellationToken)) { var userIdentity = await CreateUserIdentityAsync(user); AuthenticationManager.SignIn(userIdentity, isPersistent); @@ -55,7 +79,7 @@ namespace Microsoft.AspNet.Identity public virtual void SignOut() { // REVIEW: need a new home for this option config? - AuthenticationManager.SignOut(UserManager.Options.ClaimsIdentity.AuthenticationType); + AuthenticationManager.SignOut(Options.ClaimsIdentity.AuthenticationType); } /// @@ -65,14 +89,15 @@ namespace Microsoft.AspNet.Identity /// /// /// - public virtual async Task ValidateSecurityStamp(ClaimsIdentity identity, string userId) + public virtual async Task ValidateSecurityStampAsync(ClaimsIdentity identity, string userId, + CancellationToken cancellationToken = default(CancellationToken)) { - var user = await UserManager.FindByIdAsync(userId); + var user = await UserManager.FindByIdAsync(userId, cancellationToken); if (user != null && UserManager.SupportsUserSecurityStamp) { var securityStamp = - identity.FindFirstValue(UserManager.Options.ClaimsIdentity.SecurityStampClaimType); - if (securityStamp == await UserManager.GetSecurityStampAsync(user)) + identity.FindFirstValue(Options.ClaimsIdentity.SecurityStampClaimType); + if (securityStamp == await UserManager.GetSecurityStampAsync(user, cancellationToken)) { return user; } @@ -81,26 +106,26 @@ namespace Microsoft.AspNet.Identity } public virtual async Task PasswordSignInAsync(string userName, string password, - bool isPersistent, bool shouldLockout) + bool isPersistent, bool shouldLockout, CancellationToken cancellationToken = default(CancellationToken)) { - var user = await UserManager.FindByNameAsync(userName); + var user = await UserManager.FindByNameAsync(userName, cancellationToken); if (user == null) { return SignInStatus.Failure; } - if (UserManager.SupportsUserLockout && await UserManager.IsLockedOutAsync(user)) + if (UserManager.SupportsUserLockout && await UserManager.IsLockedOutAsync(user, cancellationToken)) { return SignInStatus.LockedOut; } - if (await UserManager.CheckPasswordAsync(user, password)) + if (await UserManager.CheckPasswordAsync(user, password, cancellationToken)) { - return await SignInOrTwoFactor(user, isPersistent); + return await SignInOrTwoFactorAsync(user, isPersistent, cancellationToken); } if (UserManager.SupportsUserLockout && shouldLockout) { // If lockout is requested, increment access failed count which might lock out the user - await UserManager.AccessFailedAsync(user); - if (await UserManager.IsLockedOutAsync(user)) + await UserManager.AccessFailedAsync(user, cancellationToken); + if (await UserManager.IsLockedOutAsync(user, cancellationToken)) { return SignInStatus.LockedOut; } @@ -108,7 +133,8 @@ namespace Microsoft.AspNet.Identity return SignInStatus.Failure; } - public virtual async Task SendTwoFactorCode(string provider) + public virtual async Task SendTwoFactorCodeAsync(string provider, + CancellationToken cancellationToken = default(CancellationToken)) { var userId = await AuthenticationManager.RetrieveUserId(); if (userId == null) @@ -116,26 +142,28 @@ namespace Microsoft.AspNet.Identity return false; } - var user = await UserManager.FindByIdAsync(userId); + var user = await UserManager.FindByIdAsync(userId, cancellationToken); if (user == null) { return false; } - var token = await UserManager.GenerateTwoFactorTokenAsync(user, provider); + var token = await UserManager.GenerateTwoFactorTokenAsync(user, provider, cancellationToken); // See IdentityConfig.cs to plug in Email/SMS services to actually send the code - await UserManager.NotifyTwoFactorTokenAsync(user, provider, token); + await UserManager.NotifyTwoFactorTokenAsync(user, provider, token, cancellationToken); return true; } - public async Task IsTwoFactorClientRemembered(TUser user) + public async Task IsTwoFactorClientRememberedAsync(TUser user, + CancellationToken cancellationToken = default(CancellationToken)) { - var userId = await UserManager.GetUserIdAsync(user); - return await AuthenticationManager.IsClientRememeberedAsync(userId); + var userId = await UserManager.GetUserIdAsync(user, cancellationToken); + return await AuthenticationManager.IsClientRememeberedAsync(userId, cancellationToken); } - public virtual async Task RememberTwoFactorClient(TUser user) + public virtual async Task RememberTwoFactorClient(TUser user, + CancellationToken cancellationToken = default(CancellationToken)) { - var userId = await UserManager.GetUserIdAsync(user); + var userId = await UserManager.GetUserIdAsync(user, cancellationToken); AuthenticationManager.RememberClient(userId); } @@ -145,14 +173,15 @@ namespace Microsoft.AspNet.Identity return Task.FromResult(0); } - public virtual async Task TwoFactorSignInAsync(string provider, string code, bool isPersistent) + public virtual async Task TwoFactorSignInAsync(string provider, string code, bool isPersistent, + CancellationToken cancellationToken = default(CancellationToken)) { var userId = await AuthenticationManager.RetrieveUserId(); if (userId == null) { return SignInStatus.Failure; } - var user = await UserManager.FindByIdAsync(userId); + var user = await UserManager.FindByIdAsync(userId, cancellationToken); if (user == null) { return SignInStatus.Failure; @@ -161,45 +190,47 @@ namespace Microsoft.AspNet.Identity { return SignInStatus.LockedOut; } - if (await UserManager.VerifyTwoFactorTokenAsync(user, provider, code)) + if (await UserManager.VerifyTwoFactorTokenAsync(user, provider, code, cancellationToken)) { // When token is verified correctly, clear the access failed count used for lockout - await UserManager.ResetAccessFailedCountAsync(user); + await UserManager.ResetAccessFailedCountAsync(user, cancellationToken); await SignInAsync(user, isPersistent); return SignInStatus.Success; } // If the token is incorrect, record the failure which also may cause the user to be locked out - await UserManager.AccessFailedAsync(user); + await UserManager.AccessFailedAsync(user, cancellationToken); return SignInStatus.Failure; } - public async Task ExternalLoginSignInAsync(UserLoginInfo loginInfo, bool isPersistent) + public async Task ExternalLoginSignInAsync(UserLoginInfo loginInfo, bool isPersistent, + CancellationToken cancellationToken = default(CancellationToken)) { - var user = await UserManager.FindByLoginAsync(loginInfo); + var user = await UserManager.FindByLoginAsync(loginInfo, cancellationToken); if (user == null) { return SignInStatus.Failure; } - if (await UserManager.IsLockedOutAsync(user)) + if (await UserManager.IsLockedOutAsync(user, cancellationToken)) { return SignInStatus.LockedOut; } - return await SignInOrTwoFactor(user, isPersistent); + return await SignInOrTwoFactorAsync(user, isPersistent, cancellationToken); } - private async Task SignInOrTwoFactor(TUser user, bool isPersistent) + private async Task SignInOrTwoFactorAsync(TUser user, bool isPersistent, + CancellationToken cancellationToken) { if (UserManager.SupportsUserTwoFactor && await UserManager.GetTwoFactorEnabledAsync(user)) { - if (!await IsTwoFactorClientRemembered(user)) + if (!await IsTwoFactorClientRememberedAsync(user, cancellationToken)) { // Store the userId for use after two factor check - var userId = await UserManager.GetUserIdAsync(user); + var userId = await UserManager.GetUserIdAsync(user, cancellationToken); await AuthenticationManager.StoreUserId(userId); return SignInStatus.RequiresVerification; } } - await SignInAsync(user, isPersistent); + await SignInAsync(user, isPersistent, cancellationToken); return SignInStatus.Success; } } diff --git a/src/Microsoft.AspNet.Identity/SignInOptions.cs b/src/Microsoft.AspNet.Identity/SignInOptions.cs new file mode 100644 index 0000000000..6c20b64713 --- /dev/null +++ b/src/Microsoft.AspNet.Identity/SignInOptions.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNet.Identity +{ + public class SignInOptions + { + public SignInOptions() { } + + /// + /// If set, requires a confirmed email to sign in + /// + public bool RequireConfirmedEmail { get; set; } + + /// + /// If set, requires a confirmed phone number to sign in + /// + public bool RequireConfirmedPhoneNumber { get; set; } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Identity.Authentication.Test/HttpSignInTest.cs b/test/Microsoft.AspNet.Identity.Authentication.Test/HttpSignInTest.cs index 73e3c8e98f..e398887546 100644 --- a/test/Microsoft.AspNet.Identity.Authentication.Test/HttpSignInTest.cs +++ b/test/Microsoft.AspNet.Identity.Authentication.Test/HttpSignInTest.cs @@ -5,6 +5,7 @@ using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Security; using Microsoft.AspNet.Identity.Test; using Microsoft.Framework.DependencyInjection; +using Microsoft.Framework.OptionsModel; using Moq; using System; using System.Security.Claims; @@ -68,11 +69,13 @@ namespace Microsoft.AspNet.Identity.Authentication.Test [Fact] public void ConstructorNullChecks() { - Assert.Throws("userManager", () => new SignInManager(null, null, null)); + Assert.Throws("userManager", () => new SignInManager(null, null, null, null)); var userManager = MockHelpers.MockUserManager().Object; - Assert.Throws("authenticationManager", () => new SignInManager(userManager, null, null)); + Assert.Throws("authenticationManager", () => new SignInManager(userManager, null, null, null)); var authManager = new Mock().Object; - Assert.Throws("claimsFactory", () => new SignInManager(userManager, authManager, null)); + Assert.Throws("claimsFactory", () => new SignInManager(userManager, authManager, null, null)); + var claimsFactory = new Mock>().Object; + Assert.Throws("optionsAccessor", () => new SignInManager(userManager, authManager, claimsFactory, null)); } //TODO: Mock fails in K (this works fine in net45) @@ -119,7 +122,10 @@ namespace Microsoft.AspNet.Identity.Authentication.Test contextAccessor.Setup(a => a.Value).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); var claimsFactory = new Mock>(manager.Object, roleManager.Object); - var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory.Object); + var identityOptions = new IdentityOptions(); + var options = new Mock>(); + options.Setup(a => a.Options).Returns(identityOptions); + var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory.Object, options.Object); // Act var result = await helper.PasswordSignInAsync(user.UserName, "bogus", false, false); @@ -148,9 +154,12 @@ namespace Microsoft.AspNet.Identity.Authentication.Test var contextAccessor = new Mock>(); contextAccessor.Setup(a => a.Value).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); + var identityOptions = new IdentityOptions(); var claimsFactory = new Mock>(manager.Object, roleManager.Object); - claimsFactory.Setup(m => m.CreateAsync(user, manager.Object.Options.ClaimsIdentity, CancellationToken.None)).ReturnsAsync(new ClaimsIdentity("Microsoft.AspNet.Identity")).Verifiable(); - var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory.Object); + claimsFactory.Setup(m => m.CreateAsync(user, identityOptions.ClaimsIdentity, CancellationToken.None)).ReturnsAsync(new ClaimsIdentity("Microsoft.AspNet.Identity")).Verifiable(); + var options = new Mock>(); + options.Setup(a => a.Options).Returns(identityOptions); + var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory.Object, options.Object); // Act var result = await helper.PasswordSignInAsync(user.UserName, "password", isPersistent, false); @@ -182,7 +191,10 @@ namespace Microsoft.AspNet.Identity.Authentication.Test contextAccessor.Setup(a => a.Value).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); var claimsFactory = new Mock>(manager.Object, roleManager.Object); - var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory.Object); + var identityOptions = new IdentityOptions(); + var options = new Mock>(); + options.Setup(a => a.Options).Returns(identityOptions); + var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory.Object, options.Object); // Act var result = await helper.PasswordSignInAsync(user.UserName, "password", false, false); @@ -215,7 +227,10 @@ namespace Microsoft.AspNet.Identity.Authentication.Test var contextAccessor = new Mock>(); contextAccessor.Setup(a => a.Value).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); - var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), new ClaimsIdentityFactory(manager.Object, roleManager.Object)); + var identityOptions = new IdentityOptions(); + var options = new Mock>(); + options.Setup(a => a.Options).Returns(identityOptions); + var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), new ClaimsIdentityFactory(manager.Object, roleManager.Object), options.Object); // Act var result = await helper.PasswordSignInAsync(user.UserName, "password", false, false); @@ -255,7 +270,10 @@ namespace Microsoft.AspNet.Identity.Authentication.Test contextAccessor.Setup(a => a.Value).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); var claimsFactory = new ClaimsIdentityFactory(manager.Object, roleManager.Object); - var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory); + var identityOptions = new IdentityOptions(); + var options = new Mock>(); + options.Setup(a => a.Options).Returns(identityOptions); + var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory, options.Object); // Act var result = await helper.TwoFactorSignInAsync(provider, code, isPersistent); @@ -320,9 +338,12 @@ namespace Microsoft.AspNet.Identity.Authentication.Test contextAccessor.Setup(a => a.Value).Returns(context.Object); var signInService = new HttpAuthenticationManager(contextAccessor.Object); var roleManager = MockHelpers.MockRoleManager(); + var identityOptions = new IdentityOptions(); var claimsFactory = new Mock>(manager.Object, roleManager.Object); - claimsFactory.Setup(m => m.CreateAsync(user, manager.Object.Options.ClaimsIdentity, CancellationToken.None)).ReturnsAsync(new ClaimsIdentity(ClaimsIdentityOptions.DefaultAuthenticationType)).Verifiable(); - var helper = new SignInManager(manager.Object, signInService, claimsFactory.Object); + claimsFactory.Setup(m => m.CreateAsync(user, identityOptions.ClaimsIdentity, CancellationToken.None)).ReturnsAsync(new ClaimsIdentity(ClaimsIdentityOptions.DefaultAuthenticationType)).Verifiable(); + var options = new Mock>(); + options.Setup(a => a.Options).Returns(identityOptions); + var helper = new SignInManager(manager.Object, signInService, claimsFactory.Object, options.Object); // Act var result = await helper.PasswordSignInAsync(user.UserName, "password", isPersistent, false); @@ -351,8 +372,11 @@ namespace Microsoft.AspNet.Identity.Authentication.Test contextAccessor.Setup(a => a.Value).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); var claimsFactory = new Mock>(manager.Object, roleManager.Object); - manager.Object.Options.ClaimsIdentity.AuthenticationType = authenticationType; - var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory.Object); + var identityOptions = new IdentityOptions(); + var options = new Mock>(); + options.Setup(a => a.Options).Returns(identityOptions); + identityOptions.ClaimsIdentity.AuthenticationType = authenticationType; + var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory.Object, options.Object); // Act helper.SignOut(); @@ -377,7 +401,10 @@ namespace Microsoft.AspNet.Identity.Authentication.Test contextAccessor.Setup(a => a.Value).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); var claimsFactory = new Mock>(manager.Object, roleManager.Object); - var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory.Object); + var identityOptions = new IdentityOptions(); + var options = new Mock>(); + options.Setup(a => a.Options).Returns(identityOptions); + var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory.Object, options.Object); // Act var result = await helper.PasswordSignInAsync(user.UserName, "bogus", false, false); @@ -397,7 +424,10 @@ namespace Microsoft.AspNet.Identity.Authentication.Test contextAccessor.Setup(a => a.Value).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); var claimsFactory = new Mock>(manager.Object, roleManager.Object); - var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory.Object); + var identityOptions = new IdentityOptions(); + var options = new Mock>(); + options.Setup(a => a.Options).Returns(identityOptions); + var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory.Object, options.Object); // Act var result = await helper.PasswordSignInAsync("bogus", "bogus", false, false); @@ -428,7 +458,10 @@ namespace Microsoft.AspNet.Identity.Authentication.Test contextAccessor.Setup(a => a.Value).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); var claimsFactory = new Mock>(manager.Object, roleManager.Object); - var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory.Object); + var identityOptions = new IdentityOptions(); + var options = new Mock>(); + options.Setup(a => a.Options).Returns(identityOptions); + var helper = new SignInManager(manager.Object, new HttpAuthenticationManager(contextAccessor.Object), claimsFactory.Object, options.Object); // Act var result = await helper.PasswordSignInAsync(user.UserName, "bogus", false, true); diff --git a/test/Microsoft.AspNet.Identity.Authentication.Test/SecurityStampValidatorTest.cs b/test/Microsoft.AspNet.Identity.Authentication.Test/SecurityStampValidatorTest.cs index 74c9c88ca6..336e1461ba 100644 --- a/test/Microsoft.AspNet.Identity.Authentication.Test/SecurityStampValidatorTest.cs +++ b/test/Microsoft.AspNet.Identity.Authentication.Test/SecurityStampValidatorTest.cs @@ -3,6 +3,7 @@ using System; using System.Security.Claims; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Security; @@ -11,6 +12,7 @@ using Microsoft.AspNet.Security; using Microsoft.AspNet.Security.Cookies; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.DependencyInjection.Fallback; +using Microsoft.Framework.OptionsModel; using Moq; using Xunit; @@ -22,7 +24,7 @@ namespace Microsoft.AspNet.Identity.Authentication.Test public async Task OnValidateIdentityThrowsWithEmptyServiceCollection() { var httpContext = new Mock(); - httpContext.Setup(c => c.ApplicationServices).Returns(new ServiceCollection().BuildServiceProvider()); + httpContext.Setup(c => c.RequestServices).Returns(new ServiceCollection().BuildServiceProvider()); var id = new ClaimsIdentity(ClaimsIdentityOptions.DefaultAuthenticationType); var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }); var context = new CookieValidateIdentityContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); @@ -39,13 +41,16 @@ namespace Microsoft.AspNet.Identity.Authentication.Test var userManager = MockHelpers.MockUserManager(); var authManager = new Mock(); var claimsManager = new Mock>(); + var identityOptions = new IdentityOptions(); + var options = new Mock>(); + options.Setup(a => a.Options).Returns(identityOptions); var signInManager = new Mock>(userManager.Object, - authManager.Object, claimsManager.Object); - signInManager.Setup(s => s.ValidateSecurityStamp(It.IsAny(), user.Id)).ReturnsAsync(user).Verifiable(); - signInManager.Setup(s => s.SignInAsync(user, isPersistent)).Returns(Task.FromResult(0)).Verifiable(); + authManager.Object, claimsManager.Object, options.Object); + signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), user.Id, CancellationToken.None)).ReturnsAsync(user).Verifiable(); + signInManager.Setup(s => s.SignInAsync(user, isPersistent, CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable(); var services = new ServiceCollection(); services.AddInstance(signInManager.Object); - httpContext.Setup(c => c.ApplicationServices).Returns(services.BuildServiceProvider()); + httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); var id = new ClaimsIdentity(ClaimsIdentityOptions.DefaultAuthenticationType); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); @@ -68,12 +73,15 @@ namespace Microsoft.AspNet.Identity.Authentication.Test var userManager = MockHelpers.MockUserManager(); var authManager = new Mock(); var claimsManager = new Mock>(); + var identityOptions = new IdentityOptions(); + var options = new Mock>(); + options.Setup(a => a.Options).Returns(identityOptions); var signInManager = new Mock>(userManager.Object, - authManager.Object, claimsManager.Object); - signInManager.Setup(s => s.ValidateSecurityStamp(It.IsAny(), user.Id)).ReturnsAsync(null).Verifiable(); + authManager.Object, claimsManager.Object, options.Object); + signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), user.Id, CancellationToken.None)).ReturnsAsync(null).Verifiable(); var services = new ServiceCollection(); services.AddInstance(signInManager.Object); - httpContext.Setup(c => c.ApplicationServices).Returns(services.BuildServiceProvider()); + httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); var id = new ClaimsIdentity(ClaimsIdentityOptions.DefaultAuthenticationType); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); @@ -96,12 +104,15 @@ namespace Microsoft.AspNet.Identity.Authentication.Test var userManager = MockHelpers.MockUserManager(); var authManager = new Mock(); var claimsManager = new Mock>(); + var identityOptions = new IdentityOptions(); + var options = new Mock>(); + options.Setup(a => a.Options).Returns(identityOptions); var signInManager = new Mock>(userManager.Object, - authManager.Object, claimsManager.Object); - signInManager.Setup(s => s.ValidateSecurityStamp(It.IsAny(), user.Id)).ReturnsAsync(null).Verifiable(); + authManager.Object, claimsManager.Object, options.Object); + signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), user.Id, CancellationToken.None)).ReturnsAsync(null).Verifiable(); var services = new ServiceCollection(); services.AddInstance(signInManager.Object); - httpContext.Setup(c => c.ApplicationServices).Returns(services.BuildServiceProvider()); + httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); var id = new ClaimsIdentity(ClaimsIdentityOptions.DefaultAuthenticationType); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); @@ -124,13 +135,16 @@ namespace Microsoft.AspNet.Identity.Authentication.Test var userManager = MockHelpers.MockUserManager(); var authManager = new Mock(); var claimsManager = new Mock>(); + var identityOptions = new IdentityOptions(); + var options = new Mock>(); + options.Setup(a => a.Options).Returns(identityOptions); var signInManager = new Mock>(userManager.Object, - authManager.Object, claimsManager.Object); - signInManager.Setup(s => s.ValidateSecurityStamp(It.IsAny(), user.Id)).Throws(new Exception("Shouldn't be called")); - signInManager.Setup(s => s.SignInAsync(user, false)).Throws(new Exception("Shouldn't be called")); + authManager.Object, claimsManager.Object, options.Object); + signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), user.Id, CancellationToken.None)).Throws(new Exception("Shouldn't be called")); + signInManager.Setup(s => s.SignInAsync(user, false, CancellationToken.None)).Throws(new Exception("Shouldn't be called")); var services = new ServiceCollection(); services.AddInstance(signInManager.Object); - httpContext.Setup(c => c.ApplicationServices).Returns(services.BuildServiceProvider()); + httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); var id = new ClaimsIdentity(ClaimsIdentityOptions.DefaultAuthenticationType); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));