From 3aaa6283653a9d44b746767ec04fb7159553cb9e Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Mon, 2 Mar 2015 16:39:01 -0800 Subject: [PATCH] React to AuthN changes --- .../Controllers/AccountController.cs | 11 +- .../Controllers/ManageController.cs | 12 +- samples/IdentitySample.Mvc/LocalConfig.json | 2 +- .../Models/ManageViewModels.cs | 6 +- .../Views/Account/Login.cshtml | 2 +- .../Views/Manage/ManageLogins.cshtml | 2 +- .../Views/Shared/_LoginPartial.cshtml | 4 +- samples/IdentitySample.Mvc/project.json | 9 +- .../BuilderExtensions.cs | 8 +- .../ClaimsIdentityExtensions.cs | 61 ---- .../ExternalLoginInfo.cs | 6 +- .../ISecurityStampValidator.cs | 5 +- ...tory.cs => IUserClaimsPrincipalFactory.cs} | 9 +- .../IdentityOptions.cs | 17 +- .../IdentityServiceCollectionExtensions.cs | 38 +-- .../PrincipalExtensions.cs | 80 +++++ .../SecurityStampValidator.cs | 16 +- .../SignInManager.cs | 67 ++-- ...ctory.cs => UserClaimsPrincipalFactory.cs} | 20 +- src/Microsoft.AspNet.Identity/project.json | 8 +- .../HttpSignInTest.cs | 6 +- .../project.json | 4 +- .../ClaimsIdentityExtensionsTest.cs | 77 ----- .../PrincipalExtensionsTest.cs | 120 +++++++ .../SecurityStampValidatorTest.cs | 94 +++--- .../SignInManagerTest.cs | 297 +++++++++--------- ...t.cs => UserClaimsPrincipalFactoryTest.cs} | 15 +- 27 files changed, 534 insertions(+), 462 deletions(-) delete mode 100644 src/Microsoft.AspNet.Identity/ClaimsIdentityExtensions.cs rename src/Microsoft.AspNet.Identity/{IClaimsIdentityFactory.cs => IUserClaimsPrincipalFactory.cs} (69%) create mode 100644 src/Microsoft.AspNet.Identity/PrincipalExtensions.cs rename src/Microsoft.AspNet.Identity/{ClaimsIdentityFactory.cs => UserClaimsPrincipalFactory.cs} (86%) delete mode 100644 test/Microsoft.AspNet.Identity.Test/ClaimsIdentityExtensionsTest.cs create mode 100644 test/Microsoft.AspNet.Identity.Test/PrincipalExtensionsTest.cs rename test/Microsoft.AspNet.Identity.Test/{ClaimsIdentityFactoryTest.cs => UserClaimsPrincipalFactoryTest.cs} (89%) diff --git a/samples/IdentitySample.Mvc/Controllers/AccountController.cs b/samples/IdentitySample.Mvc/Controllers/AccountController.cs index 344341e979..2d2bcd4f85 100644 --- a/samples/IdentitySample.Mvc/Controllers/AccountController.cs +++ b/samples/IdentitySample.Mvc/Controllers/AccountController.cs @@ -2,10 +2,11 @@ using System.Security.Claims; using System.Security.Principal; using System.Threading.Tasks; +using Microsoft.AspNet.Authentication; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc.Rendering; -using Microsoft.AspNet.Security; +using Microsoft.AspNet.Authorization; namespace IdentitySample.Models { @@ -29,7 +30,7 @@ namespace IdentitySample.Models public IActionResult Login(string returnUrl = null) { ViewBag.ReturnUrl = returnUrl; - ViewBag.LoginProviders = SignInManager.GetExternalAuthenticationTypes().ToList(); + ViewBag.LoginProviders = SignInManager.GetExternalAuthenticationSchemes().ToList(); return View(); } @@ -164,7 +165,7 @@ namespace IdentitySample.Models ViewBag.ReturnUrl = returnUrl; ViewBag.LoginProvider = info.LoginProvider; // REVIEW: handle case where email not in claims? - var email = info.ExternalIdentity.FindFirstValue(ClaimTypes.Email); + var email = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Email); return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email }); } } @@ -176,7 +177,7 @@ namespace IdentitySample.Models [ValidateAntiForgeryToken] public async Task ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl = null) { - if (User.Identity.IsAuthenticated) + if (User.IsSignedIn()) { return RedirectToAction("Index", "Manage"); } @@ -414,7 +415,7 @@ namespace IdentitySample.Models private async Task GetCurrentUserAsync() { - return await UserManager.FindByIdAsync(Context.User.Identity.GetUserId()); + return await UserManager.FindByIdAsync(Context.User.GetUserId()); } private IActionResult RedirectToLocal(string returnUrl) diff --git a/samples/IdentitySample.Mvc/Controllers/ManageController.cs b/samples/IdentitySample.Mvc/Controllers/ManageController.cs index b378f9a3a6..5c7736baef 100644 --- a/samples/IdentitySample.Mvc/Controllers/ManageController.cs +++ b/samples/IdentitySample.Mvc/Controllers/ManageController.cs @@ -2,9 +2,9 @@ using System.Security.Principal; using System.Threading.Tasks; using IdentitySample.Models; +using Microsoft.AspNet.Authorization; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Mvc; -using Microsoft.AspNet.Security; namespace IdentitySample { @@ -300,7 +300,7 @@ namespace IdentitySample return View("Error"); } var userLogins = await UserManager.GetLoginsAsync(user); - var otherLogins = SignInManager.GetExternalAuthenticationTypes().Where(auth => userLogins.All(ul => auth.AuthenticationType != ul.LoginProvider)).ToList(); + var otherLogins = SignInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList(); ViewBag.ShowRemoveButton = user.PasswordHash != null || userLogins.Count > 1; return View(new ManageLoginsViewModel { @@ -317,7 +317,7 @@ namespace IdentitySample { // Request a redirect to the external login provider to link a login for the current user var redirectUrl = Url.Action("LinkLoginCallback", "Manage"); - var properties = SignInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, User.Identity.GetUserId()); + var properties = SignInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, User.GetUserId()); return new ChallengeResult(provider, properties); } @@ -331,7 +331,7 @@ namespace IdentitySample { return View("Error"); } - var info = await SignInManager.GetExternalLoginInfoAsync(User.Identity.GetUserId()); + var info = await SignInManager.GetExternalLoginInfoAsync(User.GetUserId()); if (info == null) { return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error }); @@ -353,7 +353,7 @@ namespace IdentitySample private async Task HasPhoneNumber() { - var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); + var user = await UserManager.FindByIdAsync(User.GetUserId()); if (user != null) { return user.PhoneNumber != null; @@ -375,7 +375,7 @@ namespace IdentitySample private async Task GetCurrentUserAsync() { - return await UserManager.FindByIdAsync(Context.User.Identity.GetUserId()); + return await UserManager.FindByIdAsync(Context.User.GetUserId()); } private IActionResult RedirectToLocal(string returnUrl) diff --git a/samples/IdentitySample.Mvc/LocalConfig.json b/samples/IdentitySample.Mvc/LocalConfig.json index 49b1ac00a4..d59d91ab96 100644 --- a/samples/IdentitySample.Mvc/LocalConfig.json +++ b/samples/IdentitySample.Mvc/LocalConfig.json @@ -3,7 +3,7 @@ "DefaultAdminPassword": "YouShouldChangeThisPassword1!", "Data": { "IdentityConnection": { - "Connectionstring": "Server=(localdb)\\mssqllocaldb;Database=IdentityMvc-1-7-15;Trusted_Connection=True;MultipleActiveResultSets=true" + "Connectionstring": "Server=(localdb)\\mssqllocaldb;Database=IdentityMvc-2-20-15-3;Trusted_Connection=True;MultipleActiveResultSets=true" } }, "Identity": { diff --git a/samples/IdentitySample.Mvc/Models/ManageViewModels.cs b/samples/IdentitySample.Mvc/Models/ManageViewModels.cs index 75469967ca..f5a85b41d9 100644 --- a/samples/IdentitySample.Mvc/Models/ManageViewModels.cs +++ b/samples/IdentitySample.Mvc/Models/ManageViewModels.cs @@ -1,8 +1,8 @@ -using Microsoft.AspNet.Http.Security; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNet.Http.Authentication; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Mvc.Rendering; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; namespace IdentitySample.Models { diff --git a/samples/IdentitySample.Mvc/Views/Account/Login.cshtml b/samples/IdentitySample.Mvc/Views/Account/Login.cshtml index ec3269be4b..7c43c1654f 100644 --- a/samples/IdentitySample.Mvc/Views/Account/Login.cshtml +++ b/samples/IdentitySample.Mvc/Views/Account/Login.cshtml @@ -74,7 +74,7 @@

@foreach (AuthenticationDescription p in ViewBag.LoginProviders) { - + }

diff --git a/samples/IdentitySample.Mvc/Views/Manage/ManageLogins.cshtml b/samples/IdentitySample.Mvc/Views/Manage/ManageLogins.cshtml index dd24e9c07a..afe4e48dfb 100644 --- a/samples/IdentitySample.Mvc/Views/Manage/ManageLogins.cshtml +++ b/samples/IdentitySample.Mvc/Views/Manage/ManageLogins.cshtml @@ -52,7 +52,7 @@

@foreach (AuthenticationDescription p in Model.OtherLogins) { - + }

diff --git a/samples/IdentitySample.Mvc/Views/Shared/_LoginPartial.cshtml b/samples/IdentitySample.Mvc/Views/Shared/_LoginPartial.cshtml index 5da720b97f..2bf5d2dbf1 100644 --- a/samples/IdentitySample.Mvc/Views/Shared/_LoginPartial.cshtml +++ b/samples/IdentitySample.Mvc/Views/Shared/_LoginPartial.cshtml @@ -1,6 +1,6 @@ @using System.Security.Principal -@if (User.Identity.IsAuthenticated) +@if (User.IsSignedIn()) { using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" })) { @@ -8,7 +8,7 @@ diff --git a/samples/IdentitySample.Mvc/project.json b/samples/IdentitySample.Mvc/project.json index b9497dc726..cb305d4802 100644 --- a/samples/IdentitySample.Mvc/project.json +++ b/samples/IdentitySample.Mvc/project.json @@ -11,10 +11,11 @@ "Microsoft.AspNet.Diagnostics": "1.0.0-*", "Microsoft.AspNet.Identity": "3.0.0-*", "Microsoft.AspNet.Identity.EntityFramework": "3.0.0-*", - "Microsoft.AspNet.Security.Cookies": "1.0.0-*", - "Microsoft.AspNet.Security.Facebook": "1.0.0-*", - "Microsoft.AspNet.Security.Google": "1.0.0-*", - "Microsoft.AspNet.Security.Twitter": "1.0.0-*", + "Microsoft.AspNet.Authentication.Cookies": "1.0.0-*", + "Microsoft.AspNet.Authentication.Facebook": "1.0.0-*", + "Microsoft.AspNet.Authentication.Google": "1.0.0-*", + "Microsoft.AspNet.Authentication.Twitter": "1.0.0-*", + "Microsoft.AspNet.Authorization": "1.0.0-*", "Microsoft.AspNet.StaticFiles": "1.0.0-*", "EntityFramework.SqlServer": "7.0.0-*", "Microsoft.Framework.ConfigurationModel.Json": "1.0.0-*", diff --git a/src/Microsoft.AspNet.Identity/BuilderExtensions.cs b/src/Microsoft.AspNet.Identity/BuilderExtensions.cs index d4d184e759..9221f753ed 100644 --- a/src/Microsoft.AspNet.Identity/BuilderExtensions.cs +++ b/src/Microsoft.AspNet.Identity/BuilderExtensions.cs @@ -23,10 +23,10 @@ namespace Microsoft.AspNet.Builder { throw new ArgumentNullException("app"); } - app.UseCookieAuthentication(null, IdentityOptions.ExternalCookieAuthenticationType); - app.UseCookieAuthentication(null, IdentityOptions.TwoFactorRememberMeCookieAuthenticationType); - app.UseCookieAuthentication(null, IdentityOptions.TwoFactorUserIdCookieAuthenticationType); - app.UseCookieAuthentication(null, IdentityOptions.ApplicationCookieAuthenticationType); + app.UseCookieAuthentication(null, IdentityOptions.ExternalCookieAuthenticationScheme); + app.UseCookieAuthentication(null, IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme); + app.UseCookieAuthentication(null, IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme); + app.UseCookieAuthentication(null, IdentityOptions.ApplicationCookieAuthenticationScheme); return app; } } diff --git a/src/Microsoft.AspNet.Identity/ClaimsIdentityExtensions.cs b/src/Microsoft.AspNet.Identity/ClaimsIdentityExtensions.cs deleted file mode 100644 index 23655ddcff..0000000000 --- a/src/Microsoft.AspNet.Identity/ClaimsIdentityExtensions.cs +++ /dev/null @@ -1,61 +0,0 @@ -// 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. - -using System.Security.Claims; - -namespace System.Security.Principal -{ - /// - /// Claims related extensions for . - /// - public static class ClaimsIdentityExtensions - { - /// - /// Returns the Name claim value if present otherwise returns null. - /// - /// The instance this method extends. - /// The Name claim value, or null if the claim is not present. - /// The name claim is identified by . - public static string GetUserName(this IIdentity identity) - { - if (identity == null) - { - throw new ArgumentNullException("identity"); - } - var ci = identity as ClaimsIdentity; - return ci != null ? ci.FindFirstValue(ClaimsIdentity.DefaultNameClaimType) : null; - } - - /// - /// Returns the User ID claim value if present otherwise returns null. - /// - /// The instance this method extends. - /// The User ID claim value, or null if the claim is not present. - /// The name claim is identified by . - public static string GetUserId(this IIdentity identity) - { - if (identity == null) - { - throw new ArgumentNullException("identity"); - } - var ci = identity as ClaimsIdentity; - return ci != null ? ci.FindFirstValue(ClaimTypes.NameIdentifier) : null; - } - - /// - /// Returns the value for the first claim of the specified type otherwise null the claim is not present. - /// - /// The instance this method extends. - /// The claim type whose first value should be returned. - /// The value of the first instance of the specifed claim type, or null if the claim is not present. - public static string FindFirstValue(this ClaimsIdentity identity, string claimType) - { - if (identity == null) - { - throw new ArgumentNullException("identity"); - } - var claim = identity.FindFirst(claimType); - return claim != null ? claim.Value : null; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/ExternalLoginInfo.cs b/src/Microsoft.AspNet.Identity/ExternalLoginInfo.cs index 6674d5e429..9cf1b0032e 100644 --- a/src/Microsoft.AspNet.Identity/ExternalLoginInfo.cs +++ b/src/Microsoft.AspNet.Identity/ExternalLoginInfo.cs @@ -7,12 +7,12 @@ namespace Microsoft.AspNet.Identity { public class ExternalLoginInfo : UserLoginInfo { - public ExternalLoginInfo(ClaimsIdentity externalIdentity, string loginProvider, string providerKey, + public ExternalLoginInfo(ClaimsPrincipal externalPrincipal, string loginProvider, string providerKey, string displayName) : base(loginProvider, providerKey, displayName) { - ExternalIdentity = externalIdentity; + ExternalPrincipal = externalPrincipal; } - public ClaimsIdentity ExternalIdentity { get; set; } + public ClaimsPrincipal ExternalPrincipal { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/ISecurityStampValidator.cs b/src/Microsoft.AspNet.Identity/ISecurityStampValidator.cs index 7f6b915482..5c0b38a545 100644 --- a/src/Microsoft.AspNet.Identity/ISecurityStampValidator.cs +++ b/src/Microsoft.AspNet.Identity/ISecurityStampValidator.cs @@ -1,14 +1,13 @@ // 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. -using System.Security.Claims; using System.Threading.Tasks; -using Microsoft.AspNet.Security.Cookies; +using Microsoft.AspNet.Authentication.Cookies; namespace Microsoft.AspNet.Identity { public interface ISecurityStampValidator { - Task ValidateAsync(CookieValidateIdentityContext context, ClaimsIdentity identity); + Task ValidateAsync(CookieValidatePrincipalContext context); } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/IClaimsIdentityFactory.cs b/src/Microsoft.AspNet.Identity/IUserClaimsPrincipalFactory.cs similarity index 69% rename from src/Microsoft.AspNet.Identity/IClaimsIdentityFactory.cs rename to src/Microsoft.AspNet.Identity/IUserClaimsPrincipalFactory.cs index ac1c950bb6..c29b6b8d0c 100644 --- a/src/Microsoft.AspNet.Identity/IClaimsIdentityFactory.cs +++ b/src/Microsoft.AspNet.Identity/IUserClaimsPrincipalFactory.cs @@ -2,24 +2,23 @@ // 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 { /// - /// Interface for creating a ClaimsIdentity from an user + /// Interface for creating a ClaimsPrincipal from an user /// /// - public interface IClaimsIdentityFactory + public interface IUserClaimsPrincipalFactory where TUser : class { /// - /// Create a ClaimsIdentity from an user + /// Create a ClaimsPrincipal from an user /// /// /// /// - Task CreateAsync(TUser user); + Task CreateAsync(TUser user); } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/IdentityOptions.cs b/src/Microsoft.AspNet.Identity/IdentityOptions.cs index 26e4092f38..7a8587f28a 100644 --- a/src/Microsoft.AspNet.Identity/IdentityOptions.cs +++ b/src/Microsoft.AspNet.Identity/IdentityOptions.cs @@ -1,9 +1,6 @@ // 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. -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Security; -using Microsoft.AspNet.Security.Cookies; using System; namespace Microsoft.AspNet.Identity @@ -31,9 +28,15 @@ namespace Microsoft.AspNet.Identity public string ChangeEmailTokenProvider { get; set; } = Resources.DefaultTokenProvider; - public static string ApplicationCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".Application"; - public static string ExternalCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".External"; - public static string TwoFactorUserIdCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".TwoFactorUserId"; - public static string TwoFactorRememberMeCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".TwoFactorRemeberMe"; + public static string ApplicationCookieAuthenticationScheme { get; set; } = typeof(IdentityOptions).Namespace + ".Application"; + public static string ExternalCookieAuthenticationScheme { get; set; } = typeof(IdentityOptions).Namespace + ".External"; + public static string TwoFactorUserIdCookieAuthenticationScheme { get; set; } = typeof(IdentityOptions).Namespace + ".TwoFactorUserId"; + public static string TwoFactorRememberMeCookieAuthenticationScheme { get; set; } = typeof(IdentityOptions).Namespace + ".TwoFactorRemeberMe"; + + public static string ApplicationCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".Application.AuthType"; + public static string ExternalCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".External.AuthType"; + public static string TwoFactorUserIdCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".TwoFactorUserId.AuthType"; + public static string TwoFactorRememberMeCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".TwoFactorRemeberMe.AuthType"; + } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs index 318fdae347..3e3736e4bd 100644 --- a/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs @@ -5,8 +5,8 @@ using System; using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Http; using Microsoft.AspNet.Identity; -using Microsoft.AspNet.Security; -using Microsoft.AspNet.Security.Cookies; +using Microsoft.AspNet.Authentication; +using Microsoft.AspNet.Authentication.Cookies; using Microsoft.Framework.ConfigurationModel; namespace Microsoft.Framework.DependencyInjection @@ -65,7 +65,7 @@ namespace Microsoft.Framework.DependencyInjection // No interface for the error describer so we can add errors without rev'ing the interface services.TryAdd(describe.Transient()); services.TryAdd(describe.Scoped>()); - services.TryAdd(describe.Scoped, ClaimsIdentityFactory>()); + services.TryAdd(describe.Scoped, UserClaimsPrincipalFactory>()); services.TryAdd(describe.Scoped, UserManager>()); services.TryAdd(describe.Scoped, SignInManager>()); services.TryAdd(describe.Scoped, RoleManager>()); @@ -76,39 +76,39 @@ namespace Microsoft.Framework.DependencyInjection } services.Configure(options => { - options.SignInAsAuthenticationType = IdentityOptions.ExternalCookieAuthenticationType; + options.SignInScheme = IdentityOptions.ExternalCookieAuthenticationScheme; }); // Configure all of the cookie middlewares services.Configure(options => { - options.AuthenticationType = IdentityOptions.ApplicationCookieAuthenticationType; + options.AuthenticationScheme = IdentityOptions.ApplicationCookieAuthenticationScheme; options.LoginPath = new PathString("/Account/Login"); options.Notifications = new CookieAuthenticationNotifications { - OnValidateIdentity = SecurityStampValidator.ValidateIdentityAsync + OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync }; - }, IdentityOptions.ApplicationCookieAuthenticationType); + }, IdentityOptions.ApplicationCookieAuthenticationScheme); services.Configure(options => { - options.AuthenticationType = IdentityOptions.ExternalCookieAuthenticationType; - options.AuthenticationMode = AuthenticationMode.Passive; - options.CookieName = IdentityOptions.ExternalCookieAuthenticationType; + options.AuthenticationScheme = IdentityOptions.ExternalCookieAuthenticationScheme; + options.AutomaticAuthentication = false; + options.CookieName = IdentityOptions.ExternalCookieAuthenticationScheme; options.ExpireTimeSpan = TimeSpan.FromMinutes(5); - }, IdentityOptions.ExternalCookieAuthenticationType); + }, IdentityOptions.ExternalCookieAuthenticationScheme); services.Configure(options => { - options.AuthenticationType = IdentityOptions.TwoFactorRememberMeCookieAuthenticationType; - options.AuthenticationMode = AuthenticationMode.Passive; - options.CookieName = IdentityOptions.TwoFactorRememberMeCookieAuthenticationType; - }, IdentityOptions.TwoFactorRememberMeCookieAuthenticationType); + options.AuthenticationScheme = IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme; + options.AutomaticAuthentication = false; + options.CookieName = IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme; + }, IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme); services.Configure(options => { - options.AuthenticationType = IdentityOptions.TwoFactorUserIdCookieAuthenticationType; - options.AuthenticationMode = AuthenticationMode.Passive; - options.CookieName = IdentityOptions.TwoFactorUserIdCookieAuthenticationType; + options.AuthenticationScheme = IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme; + options.AutomaticAuthentication = false; + options.CookieName = IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme; options.ExpireTimeSpan = TimeSpan.FromMinutes(5); - }, IdentityOptions.TwoFactorUserIdCookieAuthenticationType); + }, IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme); return new IdentityBuilder(typeof(TUser), typeof(TRole), services); } diff --git a/src/Microsoft.AspNet.Identity/PrincipalExtensions.cs b/src/Microsoft.AspNet.Identity/PrincipalExtensions.cs new file mode 100644 index 0000000000..669af4cfa3 --- /dev/null +++ b/src/Microsoft.AspNet.Identity/PrincipalExtensions.cs @@ -0,0 +1,80 @@ +// 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. + +using System.Linq; +using System.Security.Claims; +using Microsoft.AspNet.Identity; + +namespace System.Security.Principal +{ + /// + /// Claims related extensions for . + /// + public static class PrincipalExtensions + { + /// + /// Returns the Name claim value if present otherwise returns null. + /// + /// The instance this method extends. + /// The Name claim value, or null if the claim is not present. + /// The name claim is identified by . + public static string GetUserName(this IPrincipal principal) + { + if (principal == null) + { + throw new ArgumentNullException(nameof(principal)); + } + var cp = principal as ClaimsPrincipal; + return cp != null ? cp.FindFirstValue(ClaimsIdentity.DefaultNameClaimType) : null; + } + + /// + /// Returns the User ID claim value if present otherwise returns null. + /// + /// The instance this method extends. + /// The User ID claim value, or null if the claim is not present. + /// The name claim is identified by . + public static string GetUserId(this IPrincipal principal) + { + if (principal == null) + { + throw new ArgumentNullException(nameof(principal)); + } + var ci = principal as ClaimsPrincipal; + return ci != null ? ci.FindFirstValue(ClaimTypes.NameIdentifier) : null; + } + + /// + /// Returns true if the principal has an identity with the application cookie identity + /// + /// The instance this method extends. + /// True if the user is logged in with identity. + public static bool IsSignedIn(this IPrincipal principal) + { + if (principal == null) + { + throw new ArgumentNullException(nameof(principal)); + } + var p = principal as ClaimsPrincipal; + return p?.Identities != null && + p.Identities.Any(i => i.AuthenticationType == IdentityOptions.ApplicationCookieAuthenticationType); + } + + /// + /// Returns the value for the first claim of the specified type otherwise null the claim is not present. + /// + /// The instance this method extends. + /// The claim type whose first value should be returned. + /// The value of the first instance of the specifed claim type, or null if the claim is not present. + public static string FindFirstValue(this ClaimsPrincipal principal, string claimType) + { + if (principal == null) + { + throw new ArgumentNullException(nameof(principal)); + } + var claim = principal.FindFirst(claimType); + return claim != null ? claim.Value : null; + } + + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/SecurityStampValidator.cs b/src/Microsoft.AspNet.Identity/SecurityStampValidator.cs index 1b6abbdf4f..f8ba4b9e0b 100644 --- a/src/Microsoft.AspNet.Identity/SecurityStampValidator.cs +++ b/src/Microsoft.AspNet.Identity/SecurityStampValidator.cs @@ -2,11 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Security.Claims; using System.Security.Principal; -using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Security.Cookies; +using Microsoft.AspNet.Authentication.Cookies; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.OptionsModel; @@ -19,11 +17,11 @@ namespace Microsoft.AspNet.Identity /// ClaimsIdentity /// /// - public virtual async Task ValidateAsync(CookieValidateIdentityContext context, ClaimsIdentity identity) + public virtual async Task ValidateAsync(CookieValidatePrincipalContext context) { var manager = context.HttpContext.RequestServices.GetRequiredService>(); - var userId = identity.GetUserId(); - var user = await manager.ValidateSecurityStampAsync(identity, userId); + var userId = context.Principal.GetUserId(); + var user = await manager.ValidateSecurityStampAsync(context.Principal, userId); if (user != null) { var isPersistent = false; @@ -35,7 +33,7 @@ namespace Microsoft.AspNet.Identity } else { - context.RejectIdentity(); + context.RejectPrincipal(); manager.SignOut(); } } @@ -47,7 +45,7 @@ namespace Microsoft.AspNet.Identity /// public static class SecurityStampValidator { - public static Task ValidateIdentityAsync(CookieValidateIdentityContext context) + public static Task ValidatePrincipalAsync(CookieValidatePrincipalContext context) { var currentUtc = DateTimeOffset.UtcNow; if (context.Options != null && context.Options.SystemClock != null) @@ -72,7 +70,7 @@ namespace Microsoft.AspNet.Identity if (validate) { var validator = context.HttpContext.RequestServices.GetRequiredService(); - return validator.ValidateAsync(context, context.Identity); + return validator.ValidateAsync(context); } return Task.FromResult(0); } diff --git a/src/Microsoft.AspNet.Identity/SignInManager.cs b/src/Microsoft.AspNet.Identity/SignInManager.cs index d05a706a26..dd151431a0 100644 --- a/src/Microsoft.AspNet.Identity/SignInManager.cs +++ b/src/Microsoft.AspNet.Identity/SignInManager.cs @@ -9,7 +9,7 @@ using System.Security.Principal; using System.Threading.Tasks; using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Security; +using Microsoft.AspNet.Http.Authentication; using Microsoft.Framework.Logging; using Microsoft.Framework.OptionsModel; @@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Identity { public SignInManager(UserManager userManager, IHttpContextAccessor contextAccessor, - IClaimsIdentityFactory claimsFactory, + IUserClaimsPrincipalFactory claimsFactory, IOptions optionsAccessor = null, ILogger> logger = null) { @@ -50,12 +50,12 @@ namespace Microsoft.AspNet.Identity public UserManager UserManager { get; private set; } public HttpContext Context { get; private set; } - public IClaimsIdentityFactory ClaimsFactory { get; private set; } + public IUserClaimsPrincipalFactory ClaimsFactory { get; private set; } public IdentityOptions Options { get; private set; } public ILogger> Logger { get; set; } // Should this be a func? - public virtual async Task CreateUserIdentityAsync(TUser user) + public virtual async Task CreateUserPrincipalAsync(TUser user) { return await ClaimsFactory.CreateAsync(user); } @@ -75,19 +75,22 @@ namespace Microsoft.AspNet.Identity public virtual async Task SignInAsync(TUser user, bool isPersistent, string authenticationMethod = null) { - var userIdentity = await CreateUserIdentityAsync(user); + var userPrincipal = await CreateUserPrincipalAsync(user); + // Review: should we guard against CreateUserPrincipal returning null? if (authenticationMethod != null) { - userIdentity.AddClaim(new Claim(ClaimTypes.AuthenticationMethod, authenticationMethod)); + userPrincipal.Identities.First().AddClaim(new Claim(ClaimTypes.AuthenticationMethod, authenticationMethod)); } - Context.Response.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, userIdentity); + Context.Response.SignIn(IdentityOptions.ApplicationCookieAuthenticationScheme, + userPrincipal, + new AuthenticationProperties() { IsPersistent = isPersistent }); } public virtual void SignOut() { - Context.Response.SignOut(IdentityOptions.ApplicationCookieAuthenticationType); - Context.Response.SignOut(IdentityOptions.ExternalCookieAuthenticationType); - Context.Response.SignOut(IdentityOptions.TwoFactorUserIdCookieAuthenticationType); + Context.Response.SignOut(IdentityOptions.ApplicationCookieAuthenticationScheme); + Context.Response.SignOut(IdentityOptions.ExternalCookieAuthenticationScheme); + Context.Response.SignOut(IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme); } private async Task IsLockedOut(TUser user) @@ -124,13 +127,13 @@ namespace Microsoft.AspNet.Identity /// /// /// - public virtual async Task ValidateSecurityStampAsync(ClaimsIdentity identity, string userId) + public virtual async Task ValidateSecurityStampAsync(ClaimsPrincipal principal, string userId) { var user = await UserManager.FindByIdAsync(userId); if (user != null && UserManager.SupportsUserSecurityStamp) { var securityStamp = - identity.FindFirstValue(Options.ClaimsIdentity.SecurityStampClaimType); + principal.FindFirstValue(Options.ClaimsIdentity.SecurityStampClaimType); if (securityStamp == await UserManager.GetSecurityStampAsync(user)) { return user; @@ -221,8 +224,8 @@ namespace Microsoft.AspNet.Identity { var userId = await UserManager.GetUserIdAsync(user); var result = - await Context.AuthenticateAsync(IdentityOptions.TwoFactorRememberMeCookieAuthenticationType); - return (result != null && result.Identity != null && result.Identity.Name == userId); + await Context.AuthenticateAsync(IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme); + return (result?.Principal != null && result.Principal.FindFirstValue(ClaimTypes.Name) == userId); } public virtual async Task RememberTwoFactorClientAsync(TUser user) @@ -230,12 +233,14 @@ namespace Microsoft.AspNet.Identity var userId = await UserManager.GetUserIdAsync(user); var rememberBrowserIdentity = new ClaimsIdentity(IdentityOptions.TwoFactorRememberMeCookieAuthenticationType); rememberBrowserIdentity.AddClaim(new Claim(ClaimTypes.Name, userId)); - Context.Response.SignIn(new AuthenticationProperties { IsPersistent = true }, rememberBrowserIdentity); + Context.Response.SignIn(IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme, + new ClaimsPrincipal(rememberBrowserIdentity), + new AuthenticationProperties { IsPersistent = true }); } public virtual Task ForgetTwoFactorClientAsync() { - Context.Response.SignOut(IdentityOptions.TwoFactorRememberMeCookieAuthenticationType); + Context.Response.SignOut(IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme); return Task.FromResult(0); } @@ -264,7 +269,7 @@ namespace Microsoft.AspNet.Identity // Cleanup external cookie if (twoFactorInfo.LoginProvider != null) { - Context.Response.SignOut(IdentityOptions.ExternalCookieAuthenticationType); + Context.Response.SignOut(IdentityOptions.ExternalCookieAuthenticationScheme); } await SignInAsync(user, isPersistent, twoFactorInfo.LoginProvider); if (rememberClient) @@ -314,15 +319,15 @@ namespace Microsoft.AspNet.Identity private const string LoginProviderKey = "LoginProvider"; private const string XsrfKey = "XsrfId"; - public virtual IEnumerable GetExternalAuthenticationTypes() + public virtual IEnumerable GetExternalAuthenticationSchemes() { - return Context.GetAuthenticationTypes().Where(d => !string.IsNullOrEmpty(d.Caption)); + return Context.GetAuthenticationSchemes().Where(d => !string.IsNullOrEmpty(d.Caption)); } public virtual async Task GetExternalLoginInfoAsync(string expectedXsrf = null) { - var auth = await Context.AuthenticateAsync(IdentityOptions.ExternalCookieAuthenticationType); - if (auth == null || auth.Identity == null || auth.Properties.Dictionary == null || !auth.Properties.Dictionary.ContainsKey(LoginProviderKey)) + var auth = await Context.AuthenticateAsync(IdentityOptions.ExternalCookieAuthenticationScheme); + if (auth == null || auth.Principal == null || auth.Properties.Dictionary == null || !auth.Properties.Dictionary.ContainsKey(LoginProviderKey)) { return null; } @@ -340,13 +345,13 @@ namespace Microsoft.AspNet.Identity } } - var providerKey = auth.Identity.FindFirstValue(ClaimTypes.NameIdentifier); + var providerKey = auth.Principal.FindFirstValue(ClaimTypes.NameIdentifier); var provider = auth.Properties.Dictionary[LoginProviderKey] as string; if (providerKey == null || provider == null) { return null; } - return new ExternalLoginInfo(auth.Identity, provider, providerKey, auth.Description.Caption); + return new ExternalLoginInfo(auth.Principal, provider, providerKey, auth.Description.Caption); } public virtual AuthenticationProperties ConfigureExternalAuthenticationProperties(string provider, string redirectUrl, string userId = null) @@ -370,14 +375,14 @@ namespace Microsoft.AspNet.Identity { // Store the userId for use after two factor check var userId = await UserManager.GetUserIdAsync(user); - Context.Response.SignIn(StoreTwoFactorInfo(userId, loginProvider)); + Context.Response.SignIn(IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme, StoreTwoFactorInfo(userId, loginProvider)); return SignInResult.TwoFactorRequired; } } // Cleanup external cookie if (loginProvider != null) { - Context.Response.SignOut(IdentityOptions.ExternalCookieAuthenticationType); + Context.Response.SignOut(IdentityOptions.ExternalCookieAuthenticationScheme); } await SignInAsync(user, isPersistent, loginProvider); return SignInResult.Success; @@ -385,13 +390,13 @@ namespace Microsoft.AspNet.Identity private async Task RetrieveTwoFactorInfoAsync() { - var result = await Context.AuthenticateAsync(IdentityOptions.TwoFactorUserIdCookieAuthenticationType); - if (result != null && result.Identity != null) + var result = await Context.AuthenticateAsync(IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme); + if (result?.Principal != null) { return new TwoFactorAuthenticationInfo { - UserId = result.Identity.Name, - LoginProvider = result.Identity.FindFirstValue(ClaimTypes.AuthenticationMethod) + UserId = result.Principal.FindFirstValue(ClaimTypes.Name), + LoginProvider = result.Principal.FindFirstValue(ClaimTypes.AuthenticationMethod) }; } return null; @@ -426,7 +431,7 @@ namespace Microsoft.AspNet.Identity return status; } - internal static ClaimsIdentity StoreTwoFactorInfo(string userId, string loginProvider) + internal static ClaimsPrincipal StoreTwoFactorInfo(string userId, string loginProvider) { var identity = new ClaimsIdentity(IdentityOptions.TwoFactorUserIdCookieAuthenticationType); identity.AddClaim(new Claim(ClaimTypes.Name, userId)); @@ -434,7 +439,7 @@ namespace Microsoft.AspNet.Identity { identity.AddClaim(new Claim(ClaimTypes.AuthenticationMethod, loginProvider)); } - return identity; + return new ClaimsPrincipal(identity); } internal class TwoFactorAuthenticationInfo diff --git a/src/Microsoft.AspNet.Identity/ClaimsIdentityFactory.cs b/src/Microsoft.AspNet.Identity/UserClaimsPrincipalFactory.cs similarity index 86% rename from src/Microsoft.AspNet.Identity/ClaimsIdentityFactory.cs rename to src/Microsoft.AspNet.Identity/UserClaimsPrincipalFactory.cs index 8e079d6e3b..c39a7cfdbc 100644 --- a/src/Microsoft.AspNet.Identity/ClaimsIdentityFactory.cs +++ b/src/Microsoft.AspNet.Identity/UserClaimsPrincipalFactory.cs @@ -11,11 +11,11 @@ using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Identity { /// - /// Provides methods to create a claims identity for a given user. + /// Provides methods to create a claims principal for a given user. /// /// The type used to represent a user. /// The type used to represent a role. - public class ClaimsIdentityFactory : IClaimsIdentityFactory + public class UserClaimsPrincipalFactory : IUserClaimsPrincipalFactory where TUser : class where TRole : class { @@ -25,7 +25,7 @@ namespace Microsoft.AspNet.Identity /// The to retrieve user information from. /// The to retrieve a user's roles from. /// The configured . - public ClaimsIdentityFactory( + public UserClaimsPrincipalFactory( UserManager userManager, RoleManager roleManager, IOptions optionsAccessor) @@ -72,12 +72,11 @@ namespace Microsoft.AspNet.Identity public IdentityOptions Options { get; private set; } /// - /// Creates a populated for the specified . + /// Creates a populated for the specified . /// /// The user instance to create claims on. - /// A to observe while waiting for the tasks to complete. /// A that represents the started task. - public virtual async Task CreateAsync(TUser user) + public virtual async Task CreateAsync(TUser user) { if (user == null) { @@ -85,10 +84,11 @@ namespace Microsoft.AspNet.Identity } var userId = await UserManager.GetUserIdAsync(user); var userName = await UserManager.GetUserNameAsync(user); - var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType, Options.ClaimsIdentity.UserNameClaimType, + var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType, + Options.ClaimsIdentity.UserNameClaimType, Options.ClaimsIdentity.RoleClaimType); id.AddClaim(new Claim(Options.ClaimsIdentity.UserIdClaimType, userId)); - id.AddClaim(new Claim(Options.ClaimsIdentity.UserNameClaimType, userName, ClaimValueTypes.String)); + id.AddClaim(new Claim(Options.ClaimsIdentity.UserNameClaimType, userName)); if (UserManager.SupportsUserSecurityStamp) { id.AddClaim(new Claim(Options.ClaimsIdentity.SecurityStampClaimType, @@ -99,7 +99,7 @@ namespace Microsoft.AspNet.Identity var roles = await UserManager.GetRolesAsync(user); foreach (var roleName in roles) { - id.AddClaim(new Claim(Options.ClaimsIdentity.RoleClaimType, roleName, ClaimValueTypes.String)); + id.AddClaim(new Claim(Options.ClaimsIdentity.RoleClaimType, roleName)); if (RoleManager.SupportsRoleClaims) { var role = await RoleManager.FindByNameAsync(roleName); @@ -114,7 +114,7 @@ namespace Microsoft.AspNet.Identity { id.AddClaims(await UserManager.GetClaimsAsync(user)); } - return id; + return new ClaimsPrincipal(id); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/project.json b/src/Microsoft.AspNet.Identity/project.json index f44fb27676..924b80bd33 100644 --- a/src/Microsoft.AspNet.Identity/project.json +++ b/src/Microsoft.AspNet.Identity/project.json @@ -1,14 +1,14 @@ { "version": "3.0.0-*", "dependencies": { + "Microsoft.AspNet.Authentication" : "1.0.0-*", + "Microsoft.AspNet.Authentication.Cookies": "1.0.0-*", "Microsoft.AspNet.Cryptography.KeyDerivation": "1.0.0-*", "Microsoft.AspNet.Http" : "1.0.0-*", - "Microsoft.AspNet.Security" : "1.0.0-*", - "Microsoft.AspNet.Security.Cookies": "1.0.0-*", "Microsoft.Framework.ConfigurationModel": "1.0.0-*", "Microsoft.Framework.DependencyInjection" : "1.0.0-*", - "Microsoft.Framework.OptionsModel": "1.0.0-*", - "Microsoft.Framework.Logging": "1.0.0-*" + "Microsoft.Framework.Logging": "1.0.0-*", + "Microsoft.Framework.OptionsModel": "1.0.0-*" }, "frameworks": { "aspnet50": {}, diff --git a/test/Microsoft.AspNet.Identity.InMemory.Test/HttpSignInTest.cs b/test/Microsoft.AspNet.Identity.InMemory.Test/HttpSignInTest.cs index f765f8c162..07f6c82489 100644 --- a/test/Microsoft.AspNet.Identity.InMemory.Test/HttpSignInTest.cs +++ b/test/Microsoft.AspNet.Identity.InMemory.Test/HttpSignInTest.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Security; +using Microsoft.AspNet.Http.Authentication; using Microsoft.AspNet.Identity.Test; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Runtime.Infrastructure; @@ -30,7 +30,9 @@ namespace Microsoft.AspNet.Identity.InMemory.Test var context = new Mock(); var response = new Mock(); context.Setup(c => c.Response).Returns(response.Object).Verifiable(); - response.Setup(r => r.SignIn(It.Is(v => v.IsPersistent == isPersistent), It.IsAny())).Verifiable(); + response.Setup(r => r.SignIn(IdentityOptions.ApplicationCookieAuthenticationScheme, + It.IsAny(), + It.Is(v => v.IsPersistent == isPersistent))).Verifiable(); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(context.Object); app.UseServices(services => diff --git a/test/Microsoft.AspNet.Identity.InMemory.Test/project.json b/test/Microsoft.AspNet.Identity.InMemory.Test/project.json index c9eef4b87a..32aafec7e1 100644 --- a/test/Microsoft.AspNet.Identity.InMemory.Test/project.json +++ b/test/Microsoft.AspNet.Identity.InMemory.Test/project.json @@ -4,8 +4,8 @@ "Microsoft.AspNet.Http" : "1.0.0-*", "Microsoft.AspNet.Identity" : "3.0.0-*", "Microsoft.AspNet.RequestContainer" : "1.0.0-*", - "Microsoft.AspNet.Security" : "1.0.0-*", - "Microsoft.AspNet.Security.Cookies" : "1.0.0-*", + "Microsoft.AspNet.Authentication" : "1.0.0-*", + "Microsoft.AspNet.Authentication.Cookies" : "1.0.0-*", "Microsoft.AspNet.Testing" : "1.0.0-*", "Microsoft.Framework.ConfigurationModel": "1.0.0-*", "Microsoft.Framework.DependencyInjection" : "1.0.0-*", diff --git a/test/Microsoft.AspNet.Identity.Test/ClaimsIdentityExtensionsTest.cs b/test/Microsoft.AspNet.Identity.Test/ClaimsIdentityExtensionsTest.cs deleted file mode 100644 index 0bec49649a..0000000000 --- a/test/Microsoft.AspNet.Identity.Test/ClaimsIdentityExtensionsTest.cs +++ /dev/null @@ -1,77 +0,0 @@ -// 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. - -using System; -using System.Security.Claims; -using System.Security.Principal; -using Xunit; - -namespace Microsoft.AspNet.Identity.Test -{ - public class ClaimsIdentityExtensionsTest - { - public const string ExternalAuthenticationType = "TestExternalAuth"; - - [Fact] - public void IdentityNullCheckTest() - { - IIdentity identity = null; - Assert.Throws("identity", () => identity.GetUserId()); - Assert.Throws("identity", () => identity.GetUserName()); - ClaimsIdentity claimsIdentity = null; - Assert.Throws("identity", () => claimsIdentity.FindFirstValue(null)); - } - - [Fact] - public void IdentityNullIfNotClaimsIdentityTest() - { - IIdentity identity = new TestIdentity(); - Assert.Null(identity.GetUserId()); - Assert.Null(identity.GetUserName()); - } - - [Fact] - public void UserNameAndIdTest() - { - var id = CreateTestExternalIdentity(); - Assert.Equal("NameIdentifier", id.GetUserId()); - Assert.Equal("Name", id.GetUserName()); - } - - [Fact] - public void IdentityExtensionsFindFirstValueNullIfUnknownTest() - { - var id = CreateTestExternalIdentity(); - Assert.Null(id.FindFirstValue("bogus")); - } - - private static ClaimsIdentity CreateTestExternalIdentity() - { - return new ClaimsIdentity( - new[] - { - new Claim(ClaimTypes.NameIdentifier, "NameIdentifier", null, ExternalAuthenticationType), - new Claim(ClaimTypes.Name, "Name") - }, - ExternalAuthenticationType); - } - - private class TestIdentity : IIdentity - { - public string AuthenticationType - { - get { throw new NotImplementedException(); } - } - - public bool IsAuthenticated - { - get { throw new NotImplementedException(); } - } - - public string Name - { - get { throw new NotImplementedException(); } - } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Identity.Test/PrincipalExtensionsTest.cs b/test/Microsoft.AspNet.Identity.Test/PrincipalExtensionsTest.cs new file mode 100644 index 0000000000..8a2e5b3a47 --- /dev/null +++ b/test/Microsoft.AspNet.Identity.Test/PrincipalExtensionsTest.cs @@ -0,0 +1,120 @@ +// 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. + +using System; +using System.Security.Claims; +using System.Security.Principal; +using Xunit; + +namespace Microsoft.AspNet.Identity.Test +{ + public class ClaimsIdentityExtensionsTest + { + public const string ExternalAuthenticationScheme = "TestExternalAuth"; + + [Fact] + public void IdentityNullCheckTest() + { + IPrincipal p = null; + Assert.Throws("principal", () => p.GetUserId()); + Assert.Throws("principal", () => p.GetUserName()); + ClaimsPrincipal cp = null; + Assert.Throws("principal", () => cp.FindFirstValue(null)); + } + + [Fact] + public void IdentityNullIfNotClaimsIdentityTest() + { + IPrincipal identity = new TestPrincipal(); + Assert.Null(identity.GetUserId()); + Assert.Null(identity.GetUserName()); + } + + [Fact] + public void UserNameAndIdTest() + { + var p = CreateTestExternalIdentity(); + Assert.Equal("NameIdentifier", p.GetUserId()); + Assert.Equal("Name", p.GetUserName()); + } + + [Fact] + public void IdentityExtensionsFindFirstValueNullIfUnknownTest() + { + var id = CreateTestExternalIdentity(); + Assert.Null(id.FindFirstValue("bogus")); + } + + [Fact] + public void IsSignedInWithDefaultAppAuthenticationType() + { + var id = CreateAppIdentity(); + Assert.True(id.IsSignedIn()); + } + + [Fact] + public void IsSignedInFalseWithWrongAppAuthenticationType() + { + var id = CreateAppIdentity("bogus"); + Assert.False(id.IsSignedIn()); + } + + private static ClaimsPrincipal CreateAppIdentity(string authType = null) + { + authType = authType ?? IdentityOptions.ApplicationCookieAuthenticationType; + return new ClaimsPrincipal(new ClaimsIdentity( + new[] + { + new Claim(ClaimTypes.NameIdentifier, "NameIdentifier"), + new Claim(ClaimTypes.Name, "Name") + }, + authType)); + } + + + private static ClaimsPrincipal CreateTestExternalIdentity() + { + return new ClaimsPrincipal(new ClaimsIdentity( + new[] + { + new Claim(ClaimTypes.NameIdentifier, "NameIdentifier", null, ExternalAuthenticationScheme), + new Claim(ClaimTypes.Name, "Name") + }, + ExternalAuthenticationScheme)); + } + + private class TestPrincipal : IPrincipal + { + public IIdentity Identity + { + get + { + throw new NotImplementedException(); + } + } + + public bool IsInRole(string role) + { + throw new NotImplementedException(); + } + } + + private class TestIdentity : IIdentity + { + public string AuthenticationType + { + get { throw new NotImplementedException(); } + } + + public bool IsAuthenticated + { + get { throw new NotImplementedException(); } + } + + public string Name + { + get { throw new NotImplementedException(); } + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs b/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs index 6d5e605e4b..59836eb219 100644 --- a/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs @@ -3,13 +3,12 @@ using System; using System.Security.Claims; -using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Authentication; +using Microsoft.AspNet.Authentication.Cookies; using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Security; -using Microsoft.AspNet.Security; -using Microsoft.AspNet.Security.Cookies; +using Microsoft.AspNet.Http.Authentication; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.DependencyInjection.Fallback; using Microsoft.Framework.OptionsModel; @@ -21,25 +20,25 @@ namespace Microsoft.AspNet.Identity.Test public class SecurityStampTest { [Fact] - public async Task OnValidateIdentityThrowsWithEmptyServiceCollection() + public async Task OnValidatePrincipalThrowsWithEmptyServiceCollection() { var httpContext = new Mock(); httpContext.Setup(c => c.RequestServices).Returns(new ServiceCollection().BuildServiceProvider()); - var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType); - var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }); - var context = new CookieValidateIdentityContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); - var ex = await Assert.ThrowsAsync(() => SecurityStampValidator.ValidateIdentityAsync(context)); + var id = new ClaimsPrincipal(new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationScheme)); + var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }, IdentityOptions.ApplicationCookieAuthenticationScheme); + var context = new CookieValidatePrincipalContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); + var ex = await Assert.ThrowsAsync(() => SecurityStampValidator.ValidatePrincipalAsync(context)); Assert.True(ex.Message.Contains("No service for type 'Microsoft.Framework.OptionsModel.IOptions")); } [Theory] [InlineData(true)] [InlineData(false)] - public async Task OnValidateIdentityTestSuccess(bool isPersistent) + public async Task OnValidatePrincipalTestSuccess(bool isPersistent) { var user = new IdentityUser("test"); var userManager = MockHelpers.MockUserManager(); - var claimsManager = new Mock>(); + var claimsManager = new Mock>(); var identityOptions = new IdentityOptions { SecurityStampValidationInterval = TimeSpan.Zero }; var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); @@ -48,24 +47,26 @@ namespace Microsoft.AspNet.Identity.Test contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object); var signInManager = new Mock>(userManager.Object, contextAccessor.Object, claimsManager.Object, options.Object, null); - signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), user.Id)).ReturnsAsync(user).Verifiable(); + signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), user.Id)).ReturnsAsync(user).Verifiable(); signInManager.Setup(s => s.SignInAsync(user, isPersistent, null)).Returns(Task.FromResult(0)).Verifiable(); var services = new ServiceCollection(); services.AddInstance(options.Object); services.AddInstance(signInManager.Object); services.AddInstance(new SecurityStampValidator()); httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); - var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType); + var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationScheme); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); - var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow, IsPersistent = isPersistent }); - var context = new CookieValidateIdentityContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); + var ticket = new AuthenticationTicket(new ClaimsPrincipal(id), + new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow, IsPersistent = isPersistent }, + IdentityOptions.ApplicationCookieAuthenticationScheme); + var context = new CookieValidatePrincipalContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); Assert.NotNull(context.Properties); Assert.NotNull(context.Options); - Assert.NotNull(context.Identity); + Assert.NotNull(context.Principal); await - SecurityStampValidator.ValidateIdentityAsync(context); - Assert.NotNull(context.Identity); + SecurityStampValidator.ValidatePrincipalAsync(context); + Assert.NotNull(context.Principal); signInManager.VerifyAll(); } @@ -74,7 +75,7 @@ namespace Microsoft.AspNet.Identity.Test { var user = new IdentityUser("test"); var userManager = MockHelpers.MockUserManager(); - var claimsManager = new Mock>(); + var claimsManager = new Mock>(); var identityOptions = new IdentityOptions { SecurityStampValidationInterval = TimeSpan.Zero }; var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); @@ -83,23 +84,24 @@ namespace Microsoft.AspNet.Identity.Test contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object); var signInManager = new Mock>(userManager.Object, contextAccessor.Object, claimsManager.Object, options.Object, null); - signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), user.Id)).ReturnsAsync(null).Verifiable(); + signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), user.Id)).ReturnsAsync(null).Verifiable(); var services = new ServiceCollection(); services.AddInstance(options.Object); services.AddInstance(signInManager.Object); services.AddInstance(new SecurityStampValidator()); httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); - var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType); + var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationScheme); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); - var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }); - var context = new CookieValidateIdentityContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); + var ticket = new AuthenticationTicket(new ClaimsPrincipal(id), + new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }, + IdentityOptions.ApplicationCookieAuthenticationScheme); + var context = new CookieValidatePrincipalContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); Assert.NotNull(context.Properties); Assert.NotNull(context.Options); - Assert.NotNull(context.Identity); - await - SecurityStampValidator.ValidateIdentityAsync(context); - Assert.Null(context.Identity); + Assert.NotNull(context.Principal); + await SecurityStampValidator.ValidatePrincipalAsync(context); + Assert.Null(context.Principal); signInManager.VerifyAll(); } @@ -109,7 +111,7 @@ namespace Microsoft.AspNet.Identity.Test var user = new IdentityUser("test"); var httpContext = new Mock(); var userManager = MockHelpers.MockUserManager(); - var claimsManager = new Mock>(); + var claimsManager = new Mock>(); var identityOptions = new IdentityOptions { SecurityStampValidationInterval = TimeSpan.Zero }; var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); @@ -117,23 +119,24 @@ namespace Microsoft.AspNet.Identity.Test contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object); var signInManager = new Mock>(userManager.Object, contextAccessor.Object, claimsManager.Object, options.Object, null); - signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), user.Id)).ReturnsAsync(null).Verifiable(); + signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), user.Id)).ReturnsAsync(null).Verifiable(); var services = new ServiceCollection(); services.AddInstance(options.Object); services.AddInstance(signInManager.Object); services.AddInstance(new SecurityStampValidator()); httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); - var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType); + var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationScheme); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); - var ticket = new AuthenticationTicket(id, new AuthenticationProperties()); - var context = new CookieValidateIdentityContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); + var ticket = new AuthenticationTicket(new ClaimsPrincipal(id), + new AuthenticationProperties(), + IdentityOptions.ApplicationCookieAuthenticationScheme); + var context = new CookieValidatePrincipalContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); Assert.NotNull(context.Properties); Assert.NotNull(context.Options); - Assert.NotNull(context.Identity); - await - SecurityStampValidator.ValidateIdentityAsync(context); - Assert.Null(context.Identity); + Assert.NotNull(context.Principal); + await SecurityStampValidator.ValidatePrincipalAsync(context); + Assert.Null(context.Principal); signInManager.VerifyAll(); } @@ -143,7 +146,7 @@ namespace Microsoft.AspNet.Identity.Test var user = new IdentityUser("test"); var httpContext = new Mock(); var userManager = MockHelpers.MockUserManager(); - var claimsManager = new Mock>(); + var claimsManager = new Mock>(); var identityOptions = new IdentityOptions { SecurityStampValidationInterval = TimeSpan.FromDays(1) }; var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); @@ -151,24 +154,25 @@ namespace Microsoft.AspNet.Identity.Test contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object); var signInManager = new Mock>(userManager.Object, contextAccessor.Object, claimsManager.Object, options.Object, null); - signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), user.Id)).Throws(new Exception("Shouldn't be called")); + signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), user.Id)).Throws(new Exception("Shouldn't be called")); signInManager.Setup(s => s.SignInAsync(user, false, null)).Throws(new Exception("Shouldn't be called")); var services = new ServiceCollection(); services.AddInstance(options.Object); services.AddInstance(signInManager.Object); services.AddInstance(new SecurityStampValidator()); httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); - var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType); + var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationScheme); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); - var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }); - var context = new CookieValidateIdentityContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); + var ticket = new AuthenticationTicket(new ClaimsPrincipal(id), + new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }, + IdentityOptions.ApplicationCookieAuthenticationScheme); + var context = new CookieValidatePrincipalContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); Assert.NotNull(context.Properties); Assert.NotNull(context.Options); - Assert.NotNull(context.Identity); - await - SecurityStampValidator.ValidateIdentityAsync(context); - Assert.NotNull(context.Identity); + Assert.NotNull(context.Principal); + await SecurityStampValidator.ValidatePrincipalAsync(context); + Assert.NotNull(context.Principal); } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs b/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs index 701fbd715b..49ce3283f3 100644 --- a/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs @@ -3,15 +3,14 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Security.Claims; using System.Security.Principal; using System.Text; -using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Security; -using Microsoft.Framework.DependencyInjection; +using Microsoft.AspNet.Http.Authentication; using Microsoft.Framework.OptionsModel; using Moq; using Xunit; @@ -28,7 +27,7 @@ namespace Microsoft.AspNet.Identity.Test // var app = new ApplicationBuilder(new ServiceCollection().BuildServiceProvider()); // app.UseCookieAuthentication(new CookieAuthenticationOptions // { - // AuthenticationType = ClaimsIdentityOptions.DefaultAuthenticationType + // AuthenticationScheme = ClaimsIdentityOptions.DefaultAuthenticationScheme // }); // TODO: how to functionally test context? @@ -63,7 +62,7 @@ namespace Microsoft.AspNet.Identity.Test // // Assert // Assert.Equal(SignInStatus.Success, result); - // contextAccessor.VerifyAll(); + // contextAccessor.Verify(); //} [Fact] @@ -81,16 +80,16 @@ namespace Microsoft.AspNet.Identity.Test //TODO: Mock fails in K (this works fine in net45) //[Fact] - //public async Task EnsureClaimsIdentityFactoryCreateIdentityCalled() + //public async Task EnsureClaimsPrincipalFactoryCreateIdentityCalled() //{ // // Setup // var user = new TestUser { UserName = "Foo" }; // var userManager = MockHelpers.TestUserManager(); - // var identityFactory = new Mock>(); + // var identityFactory = new Mock>(); // const string authType = "Test"; // var testIdentity = new ClaimsIdentity(authType); // identityFactory.Setup(s => s.CreateAsync(userManager, user, authType)).ReturnsAsync(testIdentity).Verifiable(); - // userManager.ClaimsIdentityFactory = identityFactory.Object; + // userManager.UserClaimsPrincipalFactory = identityFactory.Object; // var context = new Mock(); // var response = new Mock(); // context.Setup(c => c.Response).Returns(response.Object).Verifiable(); @@ -103,10 +102,10 @@ namespace Microsoft.AspNet.Identity.Test // helper.SignIn(user, false); // // Assert - // identityFactory.VerifyAll(); - // context.VerifyAll(); - // contextAccessor.VerifyAll(); - // response.VerifyAll(); + // identityFactory.Verify(); + // context.Verify(); + // contextAccessor.Verify(); + // response.Verify(); //} [Fact] @@ -114,11 +113,9 @@ namespace Microsoft.AspNet.Identity.Test { // Setup var user = new TestUser { UserName = "Foo" }; - var manager = MockHelpers.MockUserManager(); + var manager = SetupUserManager(user); manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable(); manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(true).Verifiable(); - manager.Setup(m => m.FindByNameAsync(user.UserName)).ReturnsAsync(user).Verifiable(); - manager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id.ToString()).Verifiable(); var context = new Mock(); var contextAccessor = new Mock(); @@ -127,10 +124,10 @@ namespace Microsoft.AspNet.Identity.Test var identityOptions = new IdentityOptions(); var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); - var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); + var claimsFactory = new UserClaimsPrincipalFactory(manager.Object, roleManager.Object, options.Object); var logStore = new StringBuilder(); var logger = MockHelpers.MockILogger>(logStore); - var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, logger.Object); + var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory, options.Object, logger.Object); string expected = string.Format("{0} for user: {1} : Result : {2}", "PasswordSignInAsync", user.Id, "Lockedout"); // Act @@ -140,7 +137,17 @@ namespace Microsoft.AspNet.Identity.Test Assert.False(result.Succeeded); Assert.True(result.IsLockedOut); Assert.NotEqual(-1, logStore.ToString().IndexOf(expected)); - manager.VerifyAll(); + manager.Verify(); + } + + private static Mock> SetupUserManager(TestUser user) + { + var manager = MockHelpers.MockUserManager(); + manager.Setup(m => m.FindByNameAsync(user.UserName)).ReturnsAsync(user); + manager.Setup(m => m.FindByIdAsync(user.Id)).ReturnsAsync(user); + manager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id.ToString()); + manager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName); + return manager; } [Theory] @@ -150,29 +157,25 @@ namespace Microsoft.AspNet.Identity.Test { // Setup var user = new TestUser { UserName = "Foo" }; - var manager = MockHelpers.MockUserManager(); + var manager = SetupUserManager(user); manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable(); manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable(); - manager.Setup(m => m.FindByNameAsync(user.UserName)).ReturnsAsync(user).Verifiable(); manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable(); - manager.Setup(m => m.ResetAccessFailedCountAsync(user)).ReturnsAsync(IdentityResult.Success).Verifiable(); - manager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id.ToString()).Verifiable(); var context = new Mock(); var response = new Mock(); context.Setup(c => c.Response).Returns(response.Object).Verifiable(); - response.Setup(r => r.SignIn(It.Is(v => v.IsPersistent == isPersistent), It.IsAny())).Verifiable(); + SetupSignIn(response, user.Id, isPersistent); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); var identityOptions = new IdentityOptions(); var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); - var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); - claimsFactory.Setup(m => m.CreateAsync(user)).ReturnsAsync(new ClaimsIdentity("Microsoft.AspNet.Identity")).Verifiable(); + var claimsFactory = new UserClaimsPrincipalFactory(manager.Object, roleManager.Object, options.Object); var logStore = new StringBuilder(); var logger = MockHelpers.MockILogger>(logStore); - var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, logger.Object); + var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory, options.Object, logger.Object); string expected = string.Format("{0} for user: {1} : Result : {2}", "PasswordSignInAsync", user.Id, "Succeeded"); // Act @@ -181,11 +184,10 @@ namespace Microsoft.AspNet.Identity.Test // Assert Assert.True(result.Succeeded); Assert.NotEqual(-1, logStore.ToString().IndexOf(expected)); - manager.VerifyAll(); - context.VerifyAll(); - response.VerifyAll(); - contextAccessor.VerifyAll(); - claimsFactory.VerifyAll(); + manager.Verify(); + context.Verify(); + response.Verify(); + contextAccessor.Verify(); } [Fact] @@ -193,17 +195,15 @@ namespace Microsoft.AspNet.Identity.Test { // Setup var user = new TestUser { UserName = "Foo" }; - var manager = MockHelpers.MockUserManager(); + var manager = SetupUserManager(user); manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable(); manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable(); - manager.Setup(m => m.FindByNameAsync(user.UserName)).ReturnsAsync(user).Verifiable(); manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable(); manager.Setup(m => m.ResetAccessFailedCountAsync(user)).ReturnsAsync(IdentityResult.Success).Verifiable(); - manager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id.ToString()).Verifiable(); var context = new Mock(); var response = new Mock(); - response.Setup(r => r.SignIn(It.IsAny(), It.IsAny())).Verifiable(); + SetupSignIn(response); context.Setup(c => c.Response).Returns(response.Object).Verifiable(); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(context.Object); @@ -211,18 +211,18 @@ namespace Microsoft.AspNet.Identity.Test var identityOptions = new IdentityOptions(); var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); - var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); - var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object); + var claimsFactory = new UserClaimsPrincipalFactory(manager.Object, roleManager.Object, options.Object); + var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory, options.Object); // Act var result = await helper.PasswordSignInAsync(user.UserName, "password", false, false); // Assert Assert.True(result.Succeeded); - manager.VerifyAll(); - context.VerifyAll(); - response.VerifyAll(); - contextAccessor.VerifyAll(); + manager.Verify(); + context.Verify(); + response.Verify(); + contextAccessor.Verify(); } [Theory] @@ -232,7 +232,7 @@ namespace Microsoft.AspNet.Identity.Test { // Setup var user = new TestUser { UserName = "Foo" }; - var manager = MockHelpers.MockUserManager(); + var manager = SetupUserManager(user); manager.Setup(m => m.SupportsUserLockout).Returns(supportsLockout).Verifiable(); if (supportsLockout) { @@ -243,8 +243,6 @@ namespace Microsoft.AspNet.Identity.Test manager.Setup(m => m.GetValidTwoFactorProvidersAsync(user)).Returns(Task.FromResult(providers)).Verifiable(); manager.Setup(m => m.SupportsUserTwoFactor).Returns(true).Verifiable(); manager.Setup(m => m.GetTwoFactorEnabledAsync(user)).ReturnsAsync(true).Verifiable(); - manager.Setup(m => m.FindByNameAsync(user.UserName)).ReturnsAsync(user).Verifiable(); - manager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id).Verifiable(); manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable(); if (supportsLockout) { @@ -252,7 +250,9 @@ namespace Microsoft.AspNet.Identity.Test } var context = new Mock(); var response = new Mock(); - response.Setup(r => r.SignIn(It.Is(id => id.Name == user.Id))).Verifiable(); + response.Setup(r => r.SignIn(IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme, + It.Is(id => id.FindFirstValue(ClaimTypes.Name) == user.Id), + It.IsAny())).Verifiable(); context.Setup(c => c.Response).Returns(response.Object).Verifiable(); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(context.Object); @@ -262,7 +262,11 @@ namespace Microsoft.AspNet.Identity.Test options.Setup(a => a.Options).Returns(identityOptions); var logStore = new StringBuilder(); var logger = MockHelpers.MockILogger>(logStore); - var helper = new SignInManager(manager.Object, contextAccessor.Object, new ClaimsIdentityFactory(manager.Object, roleManager.Object, options.Object), options.Object, logger.Object); + var helper = new SignInManager(manager.Object, + contextAccessor.Object, + new UserClaimsPrincipalFactory(manager.Object, roleManager.Object, options.Object), + options.Object, + logger.Object); string expected = string.Format("{0} for user: {1} : Result : {2}", "PasswordSignInAsync", user.Id, "RequiresTwoFactor"); // Act @@ -272,10 +276,10 @@ namespace Microsoft.AspNet.Identity.Test Assert.False(result.Succeeded); Assert.True(result.RequiresTwoFactor); Assert.NotEqual(-1, logStore.ToString().IndexOf(expected)); - manager.VerifyAll(); - context.VerifyAll(); - response.VerifyAll(); - contextAccessor.VerifyAll(); + manager.Verify(); + context.Verify(); + response.Verify(); + contextAccessor.Verify(); } [Theory] @@ -289,33 +293,29 @@ namespace Microsoft.AspNet.Identity.Test var user = new TestUser { UserName = "Foo" }; const string loginProvider = "login"; const string providerKey = "fookey"; - var manager = MockHelpers.MockUserManager(); + var manager = SetupUserManager(user); manager.Setup(m => m.SupportsUserLockout).Returns(supportsLockout).Verifiable(); if (supportsLockout) { manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable(); } manager.Setup(m => m.FindByLoginAsync(loginProvider, providerKey)).ReturnsAsync(user).Verifiable(); - manager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id.ToString()).Verifiable(); var context = new Mock(); var response = new Mock(); context.Setup(c => c.Response).Returns(response.Object).Verifiable(); - response.Setup(r => r.SignIn( - It.Is(v => v.IsPersistent == isPersistent), - It.Is(i => i.FindFirstValue(ClaimTypes.AuthenticationMethod) == loginProvider))).Verifiable(); + SetupSignIn(response, user.Id, isPersistent, loginProvider); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); var identityOptions = new IdentityOptions(); - response.Setup(r => r.SignOut(IdentityOptions.ExternalCookieAuthenticationType)).Verifiable(); + response.Setup(r => r.SignOut(IdentityOptions.ExternalCookieAuthenticationScheme)).Verifiable(); var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); - var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); - claimsFactory.Setup(m => m.CreateAsync(user)).ReturnsAsync(new ClaimsIdentity("Microsoft.AspNet.Identity")).Verifiable(); + var claimsFactory = new UserClaimsPrincipalFactory(manager.Object, roleManager.Object, options.Object); var logStore = new StringBuilder(); var logger = MockHelpers.MockILogger>(logStore); - var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, logger.Object); + var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory, options.Object, logger.Object); string expected = string.Format("{0} for user: {1} : Result : {2}", "ExternalLoginSignInAsync", user.Id.ToString(), "Succeeded"); // Act @@ -324,11 +324,10 @@ namespace Microsoft.AspNet.Identity.Test // Assert Assert.True(result.Succeeded); Assert.NotEqual(-1, logStore.ToString().IndexOf(expected)); - manager.VerifyAll(); - context.VerifyAll(); - response.VerifyAll(); - contextAccessor.VerifyAll(); - claimsFactory.VerifyAll(); + manager.Verify(); + context.Verify(); + response.Verify(); + contextAccessor.Verify(); } [Theory] @@ -352,7 +351,7 @@ namespace Microsoft.AspNet.Identity.Test { // Setup var user = new TestUser { UserName = "Foo" }; - var manager = MockHelpers.MockUserManager(); + var manager = SetupUserManager(user); var provider = "twofactorprovider"; var code = "123456"; manager.Setup(m => m.SupportsUserLockout).Returns(supportsLockout).Verifiable(); @@ -361,10 +360,7 @@ namespace Microsoft.AspNet.Identity.Test manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable(); manager.Setup(m => m.ResetAccessFailedCountAsync(user)).ReturnsAsync(IdentityResult.Success).Verifiable(); } - manager.Setup(m => m.FindByIdAsync(user.Id)).ReturnsAsync(user).Verifiable(); manager.Setup(m => m.VerifyTwoFactorTokenAsync(user, provider, code)).ReturnsAsync(true).Verifiable(); - manager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id).Verifiable(); - manager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName).Verifiable(); var context = new Mock(); var response = new Mock(); var contextAccessor = new Mock(); @@ -376,30 +372,30 @@ namespace Microsoft.AspNet.Identity.Test var identityOptions = new IdentityOptions(); var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); - var claimsFactory = new ClaimsIdentityFactory(manager.Object, roleManager.Object, options.Object); + var claimsFactory = new UserClaimsPrincipalFactory(manager.Object, roleManager.Object, options.Object); if (externalLogin) { response.Setup(r => r.SignIn( - It.Is(v => v.IsPersistent == isPersistent), - It.Is(i => i.FindFirstValue(ClaimTypes.NameIdentifier) == user.Id - && i.FindFirstValue(ClaimTypes.AuthenticationMethod) == loginProvider))).Verifiable(); - response.Setup(r => r.SignOut(IdentityOptions.ExternalCookieAuthenticationType)).Verifiable(); + IdentityOptions.ApplicationCookieAuthenticationScheme, + It.Is(i => i.FindFirstValue(ClaimTypes.AuthenticationMethod) == loginProvider + && i.FindFirstValue(ClaimTypes.NameIdentifier) == user.Id), + It.Is(v => v.IsPersistent == isPersistent))).Verifiable(); + response.Setup(r => r.SignOut(IdentityOptions.ExternalCookieAuthenticationScheme)).Verifiable(); } else { - response.Setup(r => r.SignIn( - It.Is(v => v.IsPersistent == isPersistent), - It.Is(i => i.FindFirstValue(ClaimTypes.NameIdentifier) == user.Id))).Verifiable(); + SetupSignIn(response, user.Id); } if (rememberClient) { response.Setup(r => r.SignIn( - It.Is(v => v.IsPersistent == true), - It.Is(i => i.FindFirstValue(ClaimTypes.Name) == user.Id - && i.AuthenticationType == IdentityOptions.TwoFactorRememberMeCookieAuthenticationType))).Verifiable(); + IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme, + It.Is(i => i.FindFirstValue(ClaimTypes.Name) == user.Id + && i.Identities.First().AuthenticationType == IdentityOptions.TwoFactorRememberMeCookieAuthenticationType), + It.Is(v => v.IsPersistent == true))).Verifiable(); } context.Setup(c => c.Response).Returns(response.Object).Verifiable(); - context.Setup(c => c.AuthenticateAsync(IdentityOptions.TwoFactorUserIdCookieAuthenticationType)).ReturnsAsync(authResult).Verifiable(); + context.Setup(c => c.AuthenticateAsync(IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme)).ReturnsAsync(authResult).Verifiable(); contextAccessor.Setup(a => a.HttpContext).Returns(context.Object); var logStore = new StringBuilder(); var logger = MockHelpers.MockILogger>(logStore); @@ -412,10 +408,10 @@ namespace Microsoft.AspNet.Identity.Test // Assert Assert.True(result.Succeeded); Assert.NotEqual(-1, logStore.ToString().IndexOf(expected)); - manager.VerifyAll(); - context.VerifyAll(); - response.VerifyAll(); - contextAccessor.VerifyAll(); + manager.Verify(); + context.Verify(); + response.Verify(); + contextAccessor.Verify(); } [Fact] @@ -423,7 +419,7 @@ namespace Microsoft.AspNet.Identity.Test { // Setup var user = new TestUser { UserName = "Foo" }; - var manager = MockHelpers.MockUserManager(); + var manager = SetupUserManager(user); var context = new Mock(); var response = new Mock(); var contextAccessor = new Mock(); @@ -431,14 +427,14 @@ namespace Microsoft.AspNet.Identity.Test var identityOptions = new IdentityOptions(); var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); - var claimsFactory = new ClaimsIdentityFactory(manager.Object, roleManager.Object, options.Object); + var claimsFactory = new UserClaimsPrincipalFactory(manager.Object, roleManager.Object, options.Object); - manager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id).Verifiable(); context.Setup(c => c.Response).Returns(response.Object).Verifiable(); response.Setup(r => r.SignIn( - It.Is(v => v.IsPersistent == true), - It.Is(i => i.FindFirstValue(ClaimTypes.Name) == user.Id - && i.AuthenticationType == IdentityOptions.TwoFactorRememberMeCookieAuthenticationType))).Verifiable(); + IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme, + It.Is(i => i.FindFirstValue(ClaimTypes.Name) == user.Id + && i.Identities.First().AuthenticationType == IdentityOptions.TwoFactorRememberMeCookieAuthenticationType), + It.Is(v => v.IsPersistent == true))).Verifiable(); contextAccessor.Setup(a => a.HttpContext).Returns(context.Object).Verifiable(); options.Setup(a => a.Options).Returns(identityOptions).Verifiable(); @@ -448,11 +444,11 @@ namespace Microsoft.AspNet.Identity.Test await helper.RememberTwoFactorClientAsync(user); // Assert - manager.VerifyAll(); - context.VerifyAll(); - response.VerifyAll(); - contextAccessor.VerifyAll(); - options.VerifyAll(); + manager.Verify(); + context.Verify(); + response.Verify(); + contextAccessor.Verify(); + options.Verify(); } [Theory] @@ -462,7 +458,7 @@ namespace Microsoft.AspNet.Identity.Test { // Setup var user = new TestUser { UserName = "Foo" }; - var manager = MockHelpers.MockUserManager(); + var manager = SetupUserManager(user); manager.Setup(m => m.GetTwoFactorEnabledAsync(user)).ReturnsAsync(true).Verifiable(); IList providers = new List(); providers.Add("PhoneNumber"); @@ -470,25 +466,23 @@ namespace Microsoft.AspNet.Identity.Test manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable(); manager.Setup(m => m.SupportsUserTwoFactor).Returns(true).Verifiable(); manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable(); - manager.Setup(m => m.FindByNameAsync(user.UserName)).ReturnsAsync(user).Verifiable(); - manager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id).Verifiable(); manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable(); var context = new Mock(); var response = new Mock(); context.Setup(c => c.Response).Returns(response.Object).Verifiable(); - response.Setup(r => r.SignIn(It.Is(v => v.IsPersistent == isPersistent), It.Is(i => i.AuthenticationType == IdentityOptions.ApplicationCookieAuthenticationType))).Verifiable(); + SetupSignIn(response); var id = new ClaimsIdentity(IdentityOptions.TwoFactorRememberMeCookieAuthenticationType); id.AddClaim(new Claim(ClaimTypes.Name, user.Id)); - var authResult = new AuthenticationResult(id, new AuthenticationProperties(), new AuthenticationDescription()); - context.Setup(c => c.AuthenticateAsync(IdentityOptions.TwoFactorRememberMeCookieAuthenticationType)).ReturnsAsync(authResult).Verifiable(); + var authResult = new AuthenticationResult(new ClaimsPrincipal(id), new AuthenticationProperties(), new AuthenticationDescription()); + context.Setup(c => c.AuthenticateAsync(IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme)).ReturnsAsync(authResult).Verifiable(); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); var identityOptions = new IdentityOptions(); var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); - var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); - claimsFactory.Setup(m => m.CreateAsync(user)).ReturnsAsync(new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType)).Verifiable(); + var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); + claimsFactory.Setup(m => m.CreateAsync(user)).ReturnsAsync(new ClaimsPrincipal(new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType))).Verifiable(); var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object); // Act @@ -496,34 +490,34 @@ namespace Microsoft.AspNet.Identity.Test // Assert Assert.True(result.Succeeded); - manager.VerifyAll(); - context.VerifyAll(); - response.VerifyAll(); - contextAccessor.VerifyAll(); - claimsFactory.VerifyAll(); + manager.Verify(); + context.Verify(); + response.Verify(); + contextAccessor.Verify(); + claimsFactory.Verify(); } [Theory] [InlineData("Microsoft.AspNet.Identity.Authentication.Application")] [InlineData("Foo")] - public void SignOutCallsContextResponseSignOut(string authenticationType) + public void SignOutCallsContextResponseSignOut(string authenticationScheme) { // Setup var manager = MockHelpers.MockUserManager(); var context = new Mock(); var response = new Mock(); context.Setup(c => c.Response).Returns(response.Object).Verifiable(); - response.Setup(r => r.SignOut(authenticationType)).Verifiable(); - response.Setup(r => r.SignOut(IdentityOptions.TwoFactorUserIdCookieAuthenticationType)).Verifiable(); - response.Setup(r => r.SignOut(IdentityOptions.ExternalCookieAuthenticationType)).Verifiable(); + response.Setup(r => r.SignOut(authenticationScheme)).Verifiable(); + response.Setup(r => r.SignOut(IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme)).Verifiable(); + response.Setup(r => r.SignOut(IdentityOptions.ExternalCookieAuthenticationScheme)).Verifiable(); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); var identityOptions = new IdentityOptions(); var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); - IdentityOptions.ApplicationCookieAuthenticationType = authenticationType; - var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); + IdentityOptions.ApplicationCookieAuthenticationScheme = authenticationScheme; + var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); var logStore = new StringBuilder(); var logger = MockHelpers.MockILogger>(logStore); var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, logger.Object); @@ -532,10 +526,10 @@ namespace Microsoft.AspNet.Identity.Test helper.SignOut(); // Assert - context.VerifyAll(); - response.VerifyAll(); - contextAccessor.VerifyAll(); - claimsFactory.VerifyAll(); + context.Verify(); + response.Verify(); + contextAccessor.Verify(); + claimsFactory.Verify(); } [Fact] @@ -543,12 +537,10 @@ namespace Microsoft.AspNet.Identity.Test { // Setup var user = new TestUser { UserName = "Foo" }; - var manager = MockHelpers.MockUserManager(); + var manager = SetupUserManager(user); manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable(); manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable(); - manager.Setup(m => m.FindByNameAsync(user.UserName)).ReturnsAsync(user).Verifiable(); manager.Setup(m => m.CheckPasswordAsync(user, "bogus")).ReturnsAsync(false).Verifiable(); - manager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id.ToString()).Verifiable(); var context = new Mock(); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(context.Object); @@ -556,7 +548,7 @@ namespace Microsoft.AspNet.Identity.Test var identityOptions = new IdentityOptions(); var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); - var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); + var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); var logStore = new StringBuilder(); var logger = MockHelpers.MockILogger>(logStore); var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, logger.Object); @@ -567,9 +559,9 @@ namespace Microsoft.AspNet.Identity.Test // Assert Assert.False(result.Succeeded); Assert.NotEqual(-1, logStore.ToString().IndexOf(expected)); - manager.VerifyAll(); - context.VerifyAll(); - contextAccessor.VerifyAll(); + manager.Verify(); + context.Verify(); + contextAccessor.Verify(); } [Fact] @@ -585,7 +577,7 @@ namespace Microsoft.AspNet.Identity.Test var identityOptions = new IdentityOptions(); var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); - var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); + var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object); // Act @@ -593,9 +585,9 @@ namespace Microsoft.AspNet.Identity.Test // Assert Assert.False(result.Succeeded); - manager.VerifyAll(); - context.VerifyAll(); - contextAccessor.VerifyAll(); + manager.Verify(); + context.Verify(); + contextAccessor.Verify(); } [Fact] @@ -603,7 +595,7 @@ namespace Microsoft.AspNet.Identity.Test { // Setup var user = new TestUser { UserName = "Foo" }; - var manager = MockHelpers.MockUserManager(); + var manager = SetupUserManager(user); var lockedout = false; manager.Setup(m => m.AccessFailedAsync(user)).Returns(() => { @@ -612,7 +604,6 @@ namespace Microsoft.AspNet.Identity.Test }).Verifiable(); manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable(); manager.Setup(m => m.IsLockedOutAsync(user)).Returns(() => Task.FromResult(lockedout)); - manager.Setup(m => m.FindByNameAsync(user.UserName)).ReturnsAsync(user).Verifiable(); manager.Setup(m => m.CheckPasswordAsync(user, "bogus")).ReturnsAsync(false).Verifiable(); var context = new Mock(); var contextAccessor = new Mock(); @@ -621,7 +612,7 @@ namespace Microsoft.AspNet.Identity.Test var identityOptions = new IdentityOptions(); var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); - var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); + var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object); // Act @@ -630,7 +621,7 @@ namespace Microsoft.AspNet.Identity.Test // Assert Assert.False(result.Succeeded); Assert.True(result.IsLockedOut); - manager.VerifyAll(); + manager.Verify(); } [Theory] @@ -640,20 +631,19 @@ namespace Microsoft.AspNet.Identity.Test { // Setup var user = new TestUser { UserName = "Foo" }; - var manager = MockHelpers.MockUserManager(); + var manager = SetupUserManager(user); manager.Setup(m => m.IsEmailConfirmedAsync(user)).ReturnsAsync(confirmed).Verifiable(); if (confirmed) { manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable(); } - manager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id.ToString()).Verifiable(); var context = new Mock(); var response = new Mock(); if (confirmed) { manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable(); context.Setup(c => c.Response).Returns(response.Object).Verifiable(); - response.Setup(r => r.SignIn(It.Is(v => v.IsPersistent == false), It.IsAny())).Verifiable(); + SetupSignIn(response); } var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(context.Object); @@ -662,7 +652,7 @@ namespace Microsoft.AspNet.Identity.Test identityOptions.SignIn.RequireConfirmedEmail = true; var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); - var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); + var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); var logStore = new StringBuilder(); var logger = MockHelpers.MockILogger>(logStore); var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, logger.Object); @@ -676,10 +666,19 @@ namespace Microsoft.AspNet.Identity.Test Assert.Equal(confirmed, result.Succeeded); Assert.NotEqual(confirmed, result.IsNotAllowed); Assert.NotEqual(-1, logStore.ToString().IndexOf(expected)); - manager.VerifyAll(); - context.VerifyAll(); - response.VerifyAll(); - contextAccessor.VerifyAll(); + manager.Verify(); + context.Verify(); + response.Verify(); + contextAccessor.Verify(); + } + + private static void SetupSignIn(Mock response, string userId = null, bool? isPersistent = null, string loginProvider = null) + { + response.Setup(r => r.SignIn(IdentityOptions.ApplicationCookieAuthenticationScheme, + It.Is(id => + (userId == null || id.FindFirstValue(ClaimTypes.NameIdentifier) == userId) && + (loginProvider == null || id.FindFirstValue(ClaimTypes.AuthenticationMethod) == loginProvider)), + It.Is(v => isPersistent == null || v.IsPersistent == isPersistent))).Verifiable(); } [Theory] @@ -689,16 +688,15 @@ namespace Microsoft.AspNet.Identity.Test { // Setup var user = new TestUser { UserName = "Foo" }; - var manager = MockHelpers.MockUserManager(); + var manager = SetupUserManager(user); manager.Setup(m => m.IsPhoneNumberConfirmedAsync(user)).ReturnsAsync(confirmed).Verifiable(); - manager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id.ToString()).Verifiable(); var context = new Mock(); var response = new Mock(); if (confirmed) { manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable(); context.Setup(c => c.Response).Returns(response.Object).Verifiable(); - response.Setup(r => r.SignIn(It.Is(v => v.IsPersistent == false), It.IsAny())).Verifiable(); + SetupSignIn(response); } var contextAccessor = new Mock(); @@ -708,7 +706,7 @@ namespace Microsoft.AspNet.Identity.Test identityOptions.SignIn.RequireConfirmedPhoneNumber = true; var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); - var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); + var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); var logStore = new StringBuilder(); var logger = MockHelpers.MockILogger>(logStore); var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, logger.Object); @@ -721,11 +719,10 @@ namespace Microsoft.AspNet.Identity.Test Assert.Equal(confirmed, result.Succeeded); Assert.NotEqual(confirmed, result.IsNotAllowed); Assert.NotEqual(-1, logStore.ToString().IndexOf(expected)); - manager.VerifyAll(); - context.VerifyAll(); - response.VerifyAll(); - contextAccessor.VerifyAll(); + manager.Verify(); + context.Verify(); + response.Verify(); + contextAccessor.Verify(); } - } } diff --git a/test/Microsoft.AspNet.Identity.Test/ClaimsIdentityFactoryTest.cs b/test/Microsoft.AspNet.Identity.Test/UserClaimsPrincipalFactoryTest.cs similarity index 89% rename from test/Microsoft.AspNet.Identity.Test/ClaimsIdentityFactoryTest.cs rename to test/Microsoft.AspNet.Identity.Test/UserClaimsPrincipalFactoryTest.cs index 68aa9939d6..ec26a91577 100644 --- a/test/Microsoft.AspNet.Identity.Test/ClaimsIdentityFactoryTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/UserClaimsPrincipalFactoryTest.cs @@ -4,15 +4,14 @@ using System; using System.Linq; using System.Security.Claims; -using System.Threading; using System.Threading.Tasks; +using Microsoft.Framework.OptionsModel; using Moq; using Xunit; -using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Identity.Test { - public class ClaimsIdentityFactoryTest + public class UserClaimsPrincipalFactoryTest { [Fact] public async Task CreateIdentityNullChecks() @@ -21,10 +20,10 @@ namespace Microsoft.AspNet.Identity.Test var roleManager = MockHelpers.MockRoleManager().Object; var options = new Mock>(); Assert.Throws("optionsAccessor", - () => new ClaimsIdentityFactory(userManager, roleManager, options.Object)); + () => new UserClaimsPrincipalFactory(userManager, roleManager, options.Object)); var identityOptions = new IdentityOptions(); options.Setup(a => a.Options).Returns(identityOptions); - var factory = new ClaimsIdentityFactory(userManager, roleManager, options.Object); + var factory = new UserClaimsPrincipalFactory(userManager, roleManager, options.Object); await Assert.ThrowsAsync("user", async () => await factory.CreateAsync(null)); } @@ -74,14 +73,16 @@ namespace Microsoft.AspNet.Identity.Test var options = new Mock>(); var identityOptions = new IdentityOptions(); options.Setup(a => a.Options).Returns(identityOptions); - var factory = new ClaimsIdentityFactory(userManager.Object, roleManager.Object, options.Object); + var factory = new UserClaimsPrincipalFactory(userManager.Object, roleManager.Object, options.Object); // Act - var identity = await factory.CreateAsync(user); + var principal = await factory.CreateAsync(user); + var identity = principal.Identities.First(); // Assert var manager = userManager.Object; Assert.NotNull(identity); + Assert.Equal(1, principal.Identities.Count()); Assert.Equal(IdentityOptions.ApplicationCookieAuthenticationType, identity.AuthenticationType); var claims = identity.Claims.ToList(); Assert.NotNull(claims);