Skip to content
This repository has been archived by the owner on Dec 20, 2018. It is now read-only.

Commit

Permalink
Remove ClaimsPrincipal extensions, replace with instance
Browse files Browse the repository at this point in the history
  • Loading branch information
HaoK committed Jan 4, 2016
1 parent 042588e commit 3399a76
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 159 deletions.
7 changes: 1 addition & 6 deletions samples/IdentitySample.Mvc/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null)
[ValidateAntiForgeryToken]
public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl = null)
{
if (User.IsSignedIn())
if (SignInManager.IsSignedIn(User))
{
return RedirectToAction("Index", "Manage");
}
Expand Down Expand Up @@ -423,11 +423,6 @@ private void AddErrors(IdentityResult result)
}
}

private async Task<ApplicationUser> GetCurrentUserAsync()
{
return await UserManager.FindByIdAsync(HttpContext.User.GetUserId());
}

private IActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
Expand Down
8 changes: 4 additions & 4 deletions samples/IdentitySample.Mvc/Controllers/ManageController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ public IActionResult LinkLogin(string provider)
{
// 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.GetUserId());
var properties = SignInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, SignInManager.GetUserId(User));
return new ChallengeResult(provider, properties);
}

Expand All @@ -326,7 +326,7 @@ public async Task<ActionResult> LinkLoginCallback()
{
return View("Error");
}
var info = await SignInManager.GetExternalLoginInfoAsync(User.GetUserId());
var info = await SignInManager.GetExternalLoginInfoAsync(await UserManager.GetUserIdAsync(user));
if (info == null)
{
return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error });
Expand All @@ -348,7 +348,7 @@ private void AddErrors(IdentityResult result)

private async Task<bool> HasPhoneNumber()
{
var user = await UserManager.FindByIdAsync(User.GetUserId());
var user = await GetCurrentUserAsync();
if (user != null)
{
return user.PhoneNumber != null;
Expand All @@ -370,7 +370,7 @@ public enum ManageMessageId

private async Task<ApplicationUser> GetCurrentUserAsync()
{
return await UserManager.FindByIdAsync(HttpContext.User.GetUserId());
return await SignInManager.GetUserAsync(HttpContext.User);
}

private IActionResult RedirectToLocal(string returnUrl)
Expand Down
1 change: 0 additions & 1 deletion samples/IdentitySample.Mvc/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ public void ConfigureServices(IServiceCollection services)
services.AddIdentity<ApplicationUser, IdentityRole>(
options => {
options.Cookies.ApplicationCookieAuthenticationScheme = "ApplicationCookie";
options.Cookies.ApplicationCookie.AuthenticationScheme = IdentityCookieOptions.ApplicationCookieAuthenticationType = "ApplicationCookie";
options.Cookies.ApplicationCookie.DataProtectionProvider = new DataProtectionProvider(new DirectoryInfo("C:\\Github\\Identity\\artifacts"));
options.Cookies.ApplicationCookie.CookieName = "Interop";
})
Expand Down
8 changes: 1 addition & 7 deletions src/Microsoft.AspNet.Identity/IdentityCookieOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public IdentityCookieOptions()
/// Gets or sets the scheme used to identify application authentication cookies.
/// </summary>
/// <value>The scheme used to identify application authentication cookies.</value>
public string ApplicationCookieAuthenticationScheme { get; set; } = ApplicationCookieAuthenticationType;
public string ApplicationCookieAuthenticationScheme { get; set; } = typeof(IdentityCookieOptions).Namespace + ".Application";

/// <summary>
/// Gets or sets the scheme used to identify external authentication cookies.
Expand All @@ -77,11 +77,5 @@ public IdentityCookieOptions()
/// </summary>
/// <value>The scheme used to identify remember me application authentication cookies.</value>
public string TwoFactorRememberMeCookieAuthenticationScheme { get; set; } = typeof(IdentityCookieOptions).Namespace + ".TwoFactorRemeberMe";

/// <summary>
/// Gets or sets the authentication type used when constructing an <see cref="ClaimsIdentity"/> from an application cookie.
/// </summary>
/// <value>The authentication type used when constructing an <see cref="ClaimsIdentity"/> from an application cookie.</value>
public static string ApplicationCookieAuthenticationType { get; set; } = typeof(IdentityCookieOptions).Namespace + ".Application";
}
}
45 changes: 0 additions & 45 deletions src/Microsoft.AspNet.Identity/PrincipalExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,51 +11,6 @@ namespace System.Security.Claims
/// </summary>
public static class PrincipalExtensions
{
/// <summary>
/// Returns the Name claim value if present otherwise returns null.
/// </summary>
/// <param name="principal">The <see cref="ClaimsPrincipal"/> instance this method extends.</param>
/// <returns>The Name claim value, or null if the claim is not present.</returns>
/// <remarks>The Name claim is identified by <see cref="ClaimsIdentity.DefaultNameClaimType"/>.</remarks>
public static string GetUserName(this ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
return principal.FindFirstValue(ClaimsIdentity.DefaultNameClaimType);
}

/// <summary>
/// Returns the User ID claim value if present otherwise returns null.
/// </summary>
/// <param name="principal">The <see cref="ClaimsPrincipal"/> instance this method extends.</param>
/// <returns>The User ID claim value, or null if the claim is not present.</returns>
/// <remarks>The User ID claim is identified by <see cref="ClaimTypes.NameIdentifier"/>.</remarks>
public static string GetUserId(this ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
return principal.FindFirstValue(ClaimTypes.NameIdentifier);
}

/// <summary>
/// Returns true if the principal has an identity with the application cookie identity
/// </summary>
/// <param name="principal">The <see cref="ClaimsPrincipal"/> instance this method extends.</param>
/// <returns>True if the user is logged in with identity.</returns>
public static bool IsSignedIn(this ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
return principal?.Identities != null &&
principal.Identities.Any(i => i.AuthenticationType == IdentityCookieOptions.ApplicationCookieAuthenticationType);
}

/// <summary>
/// Returns the value for the first claim of the specified type otherwise null the claim is not present.
/// </summary>
Expand Down
79 changes: 45 additions & 34 deletions src/Microsoft.AspNet.Identity/SecurityStampValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
// 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.Threading.Tasks;
using Microsoft.AspNet.Authentication.Cookies;
using Microsoft.AspNet.Http.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

Expand All @@ -17,6 +15,23 @@ namespace Microsoft.AspNet.Identity
/// <typeparam name="TUser">The type encapsulating a user.</typeparam>
public class SecurityStampValidator<TUser> : ISecurityStampValidator where TUser : class
{
private readonly SignInManager<TUser> _signInManager;
private readonly IdentityOptions _options;

public SecurityStampValidator(IOptions<IdentityOptions> options, SignInManager<TUser> signInManager)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
if (signInManager == null)
{
throw new ArgumentNullException(nameof(signInManager));
}
_signInManager = signInManager;
_options = options.Value;
}

/// <summary>
/// Validates a security stamp of an identity as an asynchronous operation, and rebuilds the identity if the validation succeeds, otherwise rejects
/// the identity.
Expand All @@ -25,19 +40,34 @@ public class SecurityStampValidator<TUser> : ISecurityStampValidator where TUser
/// <returns>The <see cref="Task"/> that represents the asynchronous validation operation.</returns>
public virtual async Task ValidateAsync(CookieValidatePrincipalContext context)
{
var manager = context.HttpContext.RequestServices.GetRequiredService<SignInManager<TUser>>();
var userId = context.Principal.GetUserId();
var user = await manager.ValidateSecurityStampAsync(context.Principal, userId);
if (user != null)
var currentUtc = DateTimeOffset.UtcNow;
if (context.Options != null && context.Options.SystemClock != null)
{
currentUtc = context.Options.SystemClock.UtcNow;
}
var issuedUtc = context.Properties.IssuedUtc;

// Only validate if enough time has elapsed
var validate = (issuedUtc == null);
if (issuedUtc != null)
{
// REVIEW: note we lost login authenticaiton method
context.ReplacePrincipal(await manager.CreateUserPrincipalAsync(user));
context.ShouldRenew = true;
var timeElapsed = currentUtc.Subtract(issuedUtc.Value);
validate = timeElapsed > _options.SecurityStampValidationInterval;
}
else
if (validate)
{
context.RejectPrincipal();
await manager.SignOutAsync();
var user = await _signInManager.ValidateSecurityStampAsync(context.Principal);
if (user != null)
{
// REVIEW: note we lost login authenticaiton method
context.ReplacePrincipal(await _signInManager.CreateUserPrincipalAsync(user));
context.ShouldRenew = true;
}
else
{
context.RejectPrincipal();
await _signInManager.SignOutAsync();
}
}
}
}
Expand All @@ -56,32 +86,13 @@ public static class SecurityStampValidator
/// <returns>The <see cref="Task"/> that represents the asynchronous validation operation.</returns>
public static Task ValidatePrincipalAsync(CookieValidatePrincipalContext context)
{
var currentUtc = DateTimeOffset.UtcNow;
if (context.Options != null && context.Options.SystemClock != null)
{
currentUtc = context.Options.SystemClock.UtcNow;
}
var issuedUtc = context.Properties.IssuedUtc;

if (context.HttpContext.RequestServices == null)
{
throw new InvalidOperationException("TODO: RequestServices is null, missing Use[Request]Services?");
throw new InvalidOperationException("RequestServices is null.");
}

// Only validate if enough time has elapsed
var validate = (issuedUtc == null);
if (issuedUtc != null)
{
var timeElapsed = currentUtc.Subtract(issuedUtc.Value);
var accessor = context.HttpContext.RequestServices.GetRequiredService<IOptions<IdentityOptions>>();
validate = timeElapsed > accessor.Value.SecurityStampValidationInterval;
}
if (validate)
{
var validator = context.HttpContext.RequestServices.GetRequiredService<ISecurityStampValidator>();
return validator.ValidateAsync(context);
}
return Task.FromResult(0);
var validator = context.HttpContext.RequestServices.GetRequiredService<ISecurityStampValidator>();
return validator.ValidateAsync(context);
}
}
}
58 changes: 57 additions & 1 deletion src/Microsoft.AspNet.Identity/SignInManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,61 @@ public SignInManager(UserManager<TUser> userManager,
/// <returns>The task object representing the asynchronous operation, containing the ClaimsPrincipal for the specified user.</returns>
public virtual async Task<ClaimsPrincipal> CreateUserPrincipalAsync(TUser user) => await ClaimsFactory.CreateAsync(user);

/// <summary>
/// Returns the Name claim value if present otherwise returns null.
/// </summary>
/// <param name="principal">The <see cref="ClaimsPrincipal"/> instance.</param>
/// <returns>The Name claim value, or null if the claim is not present.</returns>
/// <remarks>The Name claim is identified by <see cref="ClaimsIdentity.DefaultNameClaimType"/>.</remarks>
public virtual string GetUserName(ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
return principal.FindFirstValue(Options.ClaimsIdentity.UserNameClaimType);
}

/// <summary>
/// Returns the User ID claim value if present otherwise returns null.
/// </summary>
/// <param name="principal">The <see cref="ClaimsPrincipal"/> instance.</param>
/// <returns>The User ID claim value, or null if the claim is not present.</returns>
/// <remarks>The User ID claim is identified by <see cref="ClaimTypes.NameIdentifier"/>.</remarks>
public virtual string GetUserId(ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
return principal.FindFirstValue(Options.ClaimsIdentity.UserIdClaimType);
}

public virtual Task<TUser> GetUserAsync(ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
var id = GetUserId(principal);
return id == null ? null : UserManager.FindByIdAsync(id);
}

/// <summary>
/// Returns true if the principal has an identity with the application cookie identity
/// </summary>
/// <param name="principal">The <see cref="ClaimsPrincipal"/> instance.</param>
/// <returns>True if the user is logged in with identity.</returns>
public virtual bool IsSignedIn(ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
return principal?.Identities != null &&
principal.Identities.Any(i => i.AuthenticationType == Options.Cookies.ApplicationCookieAuthenticationScheme);
}

/// <summary>
/// Returns a flag indicating whether the specified user can sign in.
/// </summary>
Expand Down Expand Up @@ -164,8 +219,9 @@ public virtual async Task SignOutAsync()
/// <param name="userId">The ID for the user.</param>
/// <returns>The task object representing the asynchronous operation. The task will contain the <typeparamref name="TUser"/>
/// if the stamp matches the persisted value, otherwise it will return false.</returns>
public virtual async Task<TUser> ValidateSecurityStampAsync(ClaimsPrincipal principal, string userId)
public virtual async Task<TUser> ValidateSecurityStampAsync(ClaimsPrincipal principal)
{
var userId = GetUserId(principal);
var user = await UserManager.FindByIdAsync(userId);
if (user != null && UserManager.SupportsUserSecurityStamp)
{
Expand Down
44 changes: 0 additions & 44 deletions test/Microsoft.AspNet.Identity.Test/PrincipalExtensionsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,57 +11,13 @@ public class ClaimsIdentityExtensionsTest
{
public const string ExternalAuthenticationScheme = "TestExternalAuth";

[Fact]
public void IdentityNullCheckTest()
{
ClaimsPrincipal p = null;
Assert.Throws<ArgumentNullException>("principal", () => p.GetUserId());
Assert.Throws<ArgumentNullException>("principal", () => p.GetUserName());
Assert.Throws<ArgumentNullException>("principal", () => p.FindFirstValue(null));
}

[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 ?? new IdentityCookieOptions().ApplicationCookieAuthenticationScheme;
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(
Expand Down
Loading

0 comments on commit 3399a76

Please sign in to comment.