Require ClaimsPrincipal.Identity.IsAuthenticated for SignIn by default (#9482)
This commit is contained in:
parent
2d2806b083
commit
5d6c2edab0
|
|
@ -51,6 +51,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
public string DefaultScheme { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public string DefaultSignInScheme { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public string DefaultSignOutScheme { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public bool RequireAuthenticatedSignIn { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public System.Collections.Generic.IDictionary<string, Microsoft.AspNetCore.Authentication.AuthenticationSchemeBuilder> SchemeMap { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Authentication.AuthenticationSchemeBuilder> Schemes { get { throw null; } }
|
||||
public void AddScheme(string name, System.Action<Microsoft.AspNetCore.Authentication.AuthenticationSchemeBuilder> configureBuilder) { }
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication
|
||||
|
|
@ -89,5 +90,10 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
/// Used as the default scheme by <see cref="IAuthenticationService.ForbidAsync(HttpContext, string, AuthenticationProperties)"/>.
|
||||
/// </summary>
|
||||
public string DefaultForbidScheme { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, SignIn should throw if attempted with a ClaimsPrincipal.Identity.IsAuthenticated = false.
|
||||
/// </summary>
|
||||
public bool RequireAuthenticatedSignIn { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,8 +33,9 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
}
|
||||
public partial class AuthenticationService : Microsoft.AspNetCore.Authentication.IAuthenticationService
|
||||
{
|
||||
public AuthenticationService(Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider schemes, Microsoft.AspNetCore.Authentication.IAuthenticationHandlerProvider handlers, Microsoft.AspNetCore.Authentication.IClaimsTransformation transform) { }
|
||||
public AuthenticationService(Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider schemes, Microsoft.AspNetCore.Authentication.IAuthenticationHandlerProvider handlers, Microsoft.AspNetCore.Authentication.IClaimsTransformation transform, Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Authentication.AuthenticationOptions> options) { }
|
||||
public Microsoft.AspNetCore.Authentication.IAuthenticationHandlerProvider Handlers { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public Microsoft.AspNetCore.Authentication.AuthenticationOptions Options { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider Schemes { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public Microsoft.AspNetCore.Authentication.IClaimsTransformation Transform { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication
|
||||
{
|
||||
|
|
@ -20,11 +21,13 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
/// <param name="schemes">The <see cref="IAuthenticationSchemeProvider"/>.</param>
|
||||
/// <param name="handlers">The <see cref="IAuthenticationRequestHandler"/>.</param>
|
||||
/// <param name="transform">The <see cref="IClaimsTransformation"/>.</param>
|
||||
public AuthenticationService(IAuthenticationSchemeProvider schemes, IAuthenticationHandlerProvider handlers, IClaimsTransformation transform)
|
||||
/// <param name="options">The <see cref="AuthenticationOptions"/>.</param>
|
||||
public AuthenticationService(IAuthenticationSchemeProvider schemes, IAuthenticationHandlerProvider handlers, IClaimsTransformation transform, IOptions<AuthenticationOptions> options)
|
||||
{
|
||||
Schemes = schemes;
|
||||
Handlers = handlers;
|
||||
Transform = transform;
|
||||
Options = options.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -42,6 +45,11 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
/// </summary>
|
||||
public IClaimsTransformation Transform { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="AuthenticationOptions"/>.
|
||||
/// </summary>
|
||||
public AuthenticationOptions Options { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Authenticate for the specified authentication scheme.
|
||||
/// </summary>
|
||||
|
|
@ -146,6 +154,18 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
throw new ArgumentNullException(nameof(principal));
|
||||
}
|
||||
|
||||
if (Options.RequireAuthenticatedSignIn)
|
||||
{
|
||||
if (principal.Identity == null)
|
||||
{
|
||||
throw new InvalidOperationException("SignInAsync when principal.Identity == null is not allowed when AuthenticationOptions.RequireAuthenticatedSignIn is true.");
|
||||
}
|
||||
if (!principal.Identity.IsAuthenticated)
|
||||
{
|
||||
throw new InvalidOperationException("SignInAsync when principal.Identity.IsAuthenticated is false is not allowed when AuthenticationOptions.RequireAuthenticatedSignIn is true.");
|
||||
}
|
||||
}
|
||||
|
||||
if (scheme == null)
|
||||
{
|
||||
var defaultScheme = await Schemes.GetDefaultSignInSchemeAsync();
|
||||
|
|
|
|||
|
|
@ -57,6 +57,35 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
Assert.Contains("base", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanOnlySignInWithIsAuthenticated()
|
||||
{
|
||||
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
|
||||
{
|
||||
o.AddScheme<SignInHandler>("signin", "whatever");
|
||||
}).BuildServiceProvider();
|
||||
var context = new DefaultHttpContext();
|
||||
context.RequestServices = services;
|
||||
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("signin", new ClaimsPrincipal(), null));
|
||||
await context.SignInAsync("signin", new ClaimsPrincipal(new ClaimsIdentity("whatever")), null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanSignInWithoutIsAuthenticated()
|
||||
{
|
||||
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
|
||||
{
|
||||
o.AddScheme<SignInHandler>("signin", "whatever");
|
||||
o.RequireAuthenticatedSignIn = false;
|
||||
}).BuildServiceProvider();
|
||||
var context = new DefaultHttpContext();
|
||||
context.RequestServices = services;
|
||||
|
||||
await context.SignInAsync("signin", new ClaimsPrincipal(), null);
|
||||
await context.SignInAsync("signin", new ClaimsPrincipal(new ClaimsIdentity("whatever")), null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanOnlySignInIfSupported()
|
||||
{
|
||||
|
|
@ -70,12 +99,12 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
var context = new DefaultHttpContext();
|
||||
context.RequestServices = services;
|
||||
|
||||
await context.SignInAsync("uber", new ClaimsPrincipal(), null);
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("base", new ClaimsPrincipal(), null));
|
||||
await context.SignInAsync("uber", new ClaimsPrincipal(new ClaimsIdentity("whatever")), null);
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("base", new ClaimsPrincipal(new ClaimsIdentity("whatever")), null));
|
||||
Assert.Contains("uber", ex.Message);
|
||||
Assert.Contains("signin", ex.Message);
|
||||
await context.SignInAsync("signin", new ClaimsPrincipal(), null);
|
||||
ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("signout", new ClaimsPrincipal(), null));
|
||||
await context.SignInAsync("signin", new ClaimsPrincipal(new ClaimsIdentity("whatever")), null);
|
||||
ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("signout", new ClaimsPrincipal(new ClaimsIdentity("whatever")), null));
|
||||
Assert.Contains("uber", ex.Message);
|
||||
Assert.Contains("signin", ex.Message);
|
||||
}
|
||||
|
|
@ -117,7 +146,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
await context.ForbidAsync();
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
|
||||
Assert.Contains("cannot be used for SignOutAsync", ex.Message);
|
||||
ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
|
||||
ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity("whatever"))));
|
||||
Assert.Contains("cannot be used for SignInAsync", ex.Message);
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +165,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
await context.ChallengeAsync();
|
||||
await context.ForbidAsync();
|
||||
await context.SignOutAsync();
|
||||
await context.SignInAsync(new ClaimsPrincipal());
|
||||
await context.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity("whatever")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -154,7 +183,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
await context.ChallengeAsync();
|
||||
await context.ForbidAsync();
|
||||
await context.SignOutAsync();
|
||||
await context.SignInAsync(new ClaimsPrincipal());
|
||||
await context.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity("whatever")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -172,7 +201,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
await context.ChallengeAsync();
|
||||
await context.ForbidAsync();
|
||||
await context.SignOutAsync();
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity("whatever"))));
|
||||
Assert.Contains("cannot be used for SignInAsync", ex.Message);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
request.Headers.Add("Cookie", authCookie);
|
||||
|
||||
response = await Client.SendAsync(request);
|
||||
await AssertAuthorizeResponse(response);
|
||||
await AssertForbiddenResponse(response);
|
||||
|
||||
authCookie = await GetAuthCookieAsync("LoginClaimAB");
|
||||
request = new HttpRequestMessage(HttpMethod.Get, action);
|
||||
|
|
@ -243,7 +243,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
request.Headers.Add("Cookie", authCookie);
|
||||
|
||||
response = await Client.SendAsync(request);
|
||||
await AssertAuthorizeResponse(response);
|
||||
await AssertForbiddenResponse(response);
|
||||
|
||||
authCookie = await GetAuthCookieAsync("LoginClaimAB");
|
||||
request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
|
|
@ -259,6 +259,12 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
Assert.Equal("/Account/Login", response.Headers.Location.LocalPath);
|
||||
}
|
||||
|
||||
private async Task AssertForbiddenResponse(HttpResponseMessage response)
|
||||
{
|
||||
await response.AssertStatusCodeAsync(HttpStatusCode.Redirect);
|
||||
Assert.Equal("/Account/AccessDenied", response.Headers.Location.LocalPath);
|
||||
}
|
||||
|
||||
private async Task<string> GetAuthCookieAsync(string action)
|
||||
{
|
||||
var response = await Client.PostAsync($"Login/{action}", null);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace SecurityWebSite.Controllers
|
|||
[HttpPost]
|
||||
public async Task<IActionResult> LoginClaimA()
|
||||
{
|
||||
var identity = new ClaimsIdentity(new[] { new Claim("ClaimA", "Value") });
|
||||
var identity = new ClaimsIdentity(new[] { new Claim("ClaimA", "Value") }, CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity));
|
||||
return Ok();
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ namespace SecurityWebSite.Controllers
|
|||
[HttpPost]
|
||||
public async Task<IActionResult> LoginClaimAB()
|
||||
{
|
||||
var identity = new ClaimsIdentity(new[] { new Claim("ClaimA", "Value"), new Claim("ClaimB", "Value") });
|
||||
var identity = new ClaimsIdentity(new[] { new Claim("ClaimA", "Value"), new Claim("ClaimB", "Value") }, CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity));
|
||||
return Ok();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1001,7 +1001,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
|
|||
.Configure(app =>
|
||||
{
|
||||
app.UseAuthentication();
|
||||
app.Run(context => context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity())));
|
||||
app.Run(context => context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity("whatever"))));
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
|
|
@ -1024,7 +1024,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
|
|||
.Configure(app =>
|
||||
{
|
||||
app.UseAuthentication();
|
||||
app.Run(context => context.SignInAsync("Cookie1", new ClaimsPrincipal(new ClaimsIdentity())));
|
||||
app.Run(context => context.SignInAsync("Cookie1", new ClaimsPrincipal(new ClaimsIdentity("whatever"))));
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
|
|
@ -1048,7 +1048,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
|
|||
{
|
||||
app.UseAuthentication();
|
||||
app.Map("/notlogin", signoutApp => signoutApp.Run(context => context.SignInAsync("Cookies",
|
||||
new ClaimsPrincipal())));
|
||||
new ClaimsPrincipal(new ClaimsIdentity("whatever")))));
|
||||
})
|
||||
.ConfigureServices(services => services.AddAuthentication().AddCookie(o => o.LoginPath = new PathString("/login")));
|
||||
var server = new TestServer(builder);
|
||||
|
|
@ -1065,7 +1065,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
|
|||
.Configure(app =>
|
||||
{
|
||||
app.UseAuthentication();
|
||||
app.Map("/login", signoutApp => signoutApp.Run(context => context.SignInAsync("Cookies", new ClaimsPrincipal())));
|
||||
app.Map("/login", signoutApp => signoutApp.Run(context => context.SignInAsync("Cookies", new ClaimsPrincipal(new ClaimsIdentity("whatever")))));
|
||||
})
|
||||
.ConfigureServices(services => services.AddAuthentication().AddCookie(o => o.LoginPath = new PathString("/login")));
|
||||
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
Assert.Equal(1, handler1.SignOutCount);
|
||||
Assert.Equal(0, handler2.SignOutCount);
|
||||
|
||||
await context.SignInAsync("forward", new ClaimsPrincipal());
|
||||
await context.SignInAsync("forward", new ClaimsPrincipal(new ClaimsIdentity("whatever")));
|
||||
Assert.Equal(1, handler1.SignInCount);
|
||||
Assert.Equal(0, handler2.SignInCount);
|
||||
}
|
||||
|
|
@ -156,7 +156,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
Assert.Equal(1, handler1.SignOutCount);
|
||||
Assert.Equal(0, handler2.SignOutCount);
|
||||
|
||||
await context.SignInAsync("forward", new ClaimsPrincipal());
|
||||
await context.SignInAsync("forward", new ClaimsPrincipal(new ClaimsIdentity("whatever")));
|
||||
Assert.Equal(1, handler1.SignInCount);
|
||||
Assert.Equal(0, handler2.SignInCount);
|
||||
}
|
||||
|
|
@ -216,7 +216,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
Assert.Equal(1, handler1.SignOutCount);
|
||||
Assert.Equal(0, handler2.SignOutCount);
|
||||
|
||||
await context.SignInAsync("forward", new ClaimsPrincipal());
|
||||
await context.SignInAsync("forward", new ClaimsPrincipal(new ClaimsIdentity("whatever")));
|
||||
Assert.Equal(1, handler1.SignInCount);
|
||||
Assert.Equal(0, handler2.SignInCount);
|
||||
}
|
||||
|
|
@ -268,7 +268,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
Assert.Equal(1, handler1.SignOutCount);
|
||||
Assert.Equal(0, handler2.SignOutCount);
|
||||
|
||||
await context.SignInAsync("forward", new ClaimsPrincipal());
|
||||
await context.SignInAsync("forward", new ClaimsPrincipal(new ClaimsIdentity("whatever")));
|
||||
Assert.Equal(1, handler1.SignInCount);
|
||||
Assert.Equal(0, handler2.SignInCount);
|
||||
}
|
||||
|
|
@ -325,7 +325,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
Assert.Equal(1, handler1.SignOutCount);
|
||||
Assert.Equal(0, handler2.SignOutCount);
|
||||
|
||||
await context.SignInAsync("forward", new ClaimsPrincipal());
|
||||
await context.SignInAsync("forward", new ClaimsPrincipal(new ClaimsIdentity("whatever")));
|
||||
Assert.Equal(0, handler1.SignInCount);
|
||||
Assert.Equal(1, handler2.SignInCount);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
|
||||
if (SupportsSignIn)
|
||||
{
|
||||
await context.SignInAsync(new ClaimsPrincipal());
|
||||
await context.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity("whatever")));
|
||||
Assert.Equal(1, forwardDefault.SignInCount);
|
||||
}
|
||||
else
|
||||
|
|
@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
var context = new DefaultHttpContext();
|
||||
context.RequestServices = sp;
|
||||
|
||||
await context.SignInAsync(new ClaimsPrincipal());
|
||||
await context.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity("whatever")));
|
||||
Assert.Equal(1, specific.SignInCount);
|
||||
Assert.Equal(0, specific.AuthenticateCount);
|
||||
Assert.Equal(0, specific.ForbidCount);
|
||||
|
|
@ -330,7 +330,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
|
||||
if (SupportsSignIn)
|
||||
{
|
||||
await context.SignInAsync(new ClaimsPrincipal());
|
||||
await context.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity("whatever")));
|
||||
Assert.Equal(1, selector.SignInCount);
|
||||
}
|
||||
else
|
||||
|
|
@ -399,7 +399,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
|
||||
if (SupportsSignIn)
|
||||
{
|
||||
await context.SignInAsync(new ClaimsPrincipal());
|
||||
await context.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity("whatever")));
|
||||
Assert.Equal(1, forwardDefault.SignInCount);
|
||||
}
|
||||
else
|
||||
|
|
@ -473,7 +473,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
|
||||
if (SupportsSignIn)
|
||||
{
|
||||
await context.SignInAsync(new ClaimsPrincipal());
|
||||
await context.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity("whatever")));
|
||||
Assert.Equal(1, specific.SignInCount);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
Loading…
Reference in New Issue