Refactor IAuthenticationHandler/Result

This commit is contained in:
Hao Kung 2017-06-29 16:25:24 -07:00
parent f9e0439ef1
commit 271faf11bb
11 changed files with 425 additions and 78 deletions

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Authentication
/// </summary>
public class AuthenticateResult
{
private AuthenticateResult() { }
protected AuthenticateResult() { }
/// <summary>
/// If a ticket was produced, authenticate was successful.
@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Authentication
/// <summary>
/// The authentication ticket.
/// </summary>
public AuthenticationTicket Ticket { get; private set; }
public AuthenticationTicket Ticket { get; protected set; }
/// <summary>
/// Gets the claims-principal with authenticated user identities.
@ -36,18 +36,12 @@ namespace Microsoft.AspNetCore.Authentication
/// <summary>
/// Holds failure information from the authentication.
/// </summary>
public Exception Failure { get; private set; }
/// <summary>
/// Indicates that stage of authentication was directly handled by user intervention and no
/// further processing should be attempted.
/// </summary>
public bool Handled { get; private set; }
public Exception Failure { get; protected set; }
/// <summary>
/// Indicates that there was no information returned for this authentication scheme.
/// </summary>
public bool Nothing { get; private set; }
public bool None { get; protected set; }
/// <summary>
/// Indicates that authentication was successful.
@ -63,23 +57,13 @@ namespace Microsoft.AspNetCore.Authentication
return new AuthenticateResult() { Ticket = ticket };
}
/// <summary>
/// Indicates that stage of authentication was directly handled by user intervention and no
/// further processing should be attempted.
/// </summary>
/// <returns>The result.</returns>
public static AuthenticateResult Handle()
{
return new AuthenticateResult() { Handled = true };
}
/// <summary>
/// Indicates that there was no information returned for this authentication scheme.
/// </summary>
/// <returns>The result.</returns>
public static AuthenticateResult None()
public static AuthenticateResult NoResult()
{
return new AuthenticateResult() { Nothing = true };
return new AuthenticateResult() { None = true };
}
/// <summary>

View File

@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.Authentication
context.ForbidAsync(scheme, properties: null);
/// <summary>
/// Extension method for Forbid.
/// Extension method for Forbid using the <see cref="AuthenticationOptions.DefaultForbidScheme"/> scheme..
/// </summary>
/// <param name="context">The <see cref="HttpContext"/> context.</param>
/// <returns>The task.</returns>
@ -142,6 +142,21 @@ namespace Microsoft.AspNetCore.Authentication
public static Task SignInAsync(this HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties) =>
context.RequestServices.GetRequiredService<IAuthenticationService>().SignInAsync(context, scheme, principal, properties);
/// <summary>
/// Extension method for SignOut using the <see cref="AuthenticationOptions.DefaultSignOutScheme"/>.
/// </summary>
/// <param name="context">The <see cref="HttpContext"/> context.</param>
/// <returns>The task.</returns>
public static Task SignOutAsync(this HttpContext context) => context.SignOutAsync(scheme: null, properties: null);
/// <summary>
/// Extension method for SignOut using the <see cref="AuthenticationOptions.DefaultSignOutScheme"/>.
/// </summary>
/// <param name="context">The <see cref="HttpContext"/> context.</param>
/// <param name="properties">The <see cref="AuthenticationProperties"/> properties.</param>
/// <returns>The task.</returns>
public static Task SignOutAsync(this HttpContext context, AuthenticationProperties properties) => context.SignOutAsync(scheme: null, properties: properties);
/// <summary>
/// Extension method for SignOut.
/// </summary>

View File

@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation. 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.AspNetCore.Http;
@ -39,20 +38,5 @@ namespace Microsoft.AspNetCore.Authentication
/// <param name="properties">The <see cref="AuthenticationProperties"/> that contains the extra meta-data arriving with the authentication.</param>
/// <returns>A task.</returns>
Task ForbidAsync(AuthenticationProperties properties);
/// <summary>
/// Handle sign in.
/// </summary>
/// <param name="user">The <see cref="ClaimsPrincipal"/> user.</param>
/// <param name="properties">The <see cref="AuthenticationProperties"/> that contains the extra meta-data arriving with the authentication.</param>
/// <returns>A task.</returns>
Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties);
/// <summary>
/// Signout behavior.
/// </summary>
/// <param name="properties">The <see cref="AuthenticationProperties"/> that contains the extra meta-data arriving with the authentication.</param>
/// <returns>A task.</returns>
Task SignOutAsync(AuthenticationProperties properties);
}
}

View File

@ -10,7 +10,6 @@ namespace Microsoft.AspNetCore.Authentication
/// </summary>
public interface IAuthenticationRequestHandler : IAuthenticationHandler
{
/// <summary>
/// Returns true if request processing should stop.
/// </summary>

View File

@ -0,0 +1,22 @@
// Copyright (c) .NET Foundation. 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;
namespace Microsoft.AspNetCore.Authentication
{
/// <summary>
/// Used to determine if a handler supports SignIn.
/// </summary>
public interface IAuthenticationSignInHandler : IAuthenticationSignOutHandler
{
/// <summary>
/// Handle sign in.
/// </summary>
/// <param name="user">The <see cref="ClaimsPrincipal"/> user.</param>
/// <param name="properties">The <see cref="AuthenticationProperties"/> that contains the extra meta-data arriving with the authentication.</param>
/// <returns>A task.</returns>
Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties);
}
}

View File

@ -0,0 +1,21 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Authentication
{
/// <summary>
/// Used to determine if a handler supports SignOut.
/// </summary>
public interface IAuthenticationSignOutHandler : IAuthenticationHandler
{
/// <summary>
/// Signout behavior.
/// </summary>
/// <param name="properties">The <see cref="AuthenticationProperties"/> that contains the extra meta-data arriving with the authentication.</param>
/// <returns>A task.</returns>
Task SignOutAsync(AuthenticationProperties properties);
}
}

View File

@ -18,4 +18,4 @@ namespace Microsoft.AspNetCore.Authentication
/// <returns>The transformed principal.</returns>
Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal);
}
}
}

View File

@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
@ -36,6 +35,8 @@ namespace Microsoft.AspNetCore.Authentication
private IDictionary<string, AuthenticationScheme> _map = new Dictionary<string, AuthenticationScheme>(StringComparer.Ordinal);
private List<AuthenticationScheme> _requestHandlers = new List<AuthenticationScheme>();
private List<AuthenticationScheme> _signOutHandlers = new List<AuthenticationScheme>();
private List<AuthenticationScheme> _signInHandlers = new List<AuthenticationScheme>();
/// <summary>
/// Returns the scheme that will be used by default for <see cref="IAuthenticationService.AuthenticateAsync(HttpContext, string)"/>.
@ -43,7 +44,7 @@ namespace Microsoft.AspNetCore.Authentication
/// Otherwise, if only a single scheme exists, that will be used, if more than one exists, null will be returned.
/// </summary>
/// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.AuthenticateAsync(HttpContext, string)"/>.</returns>
public Task<AuthenticationScheme> GetDefaultAuthenticateSchemeAsync()
public virtual Task<AuthenticationScheme> GetDefaultAuthenticateSchemeAsync()
{
if (_options.DefaultAuthenticateScheme != null)
{
@ -59,20 +60,16 @@ namespace Microsoft.AspNetCore.Authentication
/// <summary>
/// Returns the scheme that will be used by default for <see cref="IAuthenticationService.ChallengeAsync(HttpContext, string, AuthenticationProperties)"/>.
/// This is typically specified via <see cref="AuthenticationOptions.DefaultChallengeScheme"/>.
/// Otherwise, if only a single scheme exists, that will be used, if more than one exists, null will be returned.
/// Otherwise, this will fallback to <see cref="GetDefaultAuthenticateSchemeAsync"/>.
/// </summary>
/// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.ChallengeAsync(HttpContext, string, AuthenticationProperties)"/>.</returns>
public Task<AuthenticationScheme> GetDefaultChallengeSchemeAsync()
public virtual Task<AuthenticationScheme> GetDefaultChallengeSchemeAsync()
{
if (_options.DefaultChallengeScheme != null)
{
return GetSchemeAsync(_options.DefaultChallengeScheme);
}
if (_map.Count == 1)
{
return Task.FromResult(_map.Values.First());
}
return Task.FromResult<AuthenticationScheme>(null);
return GetDefaultAuthenticateSchemeAsync();
}
/// <summary>
@ -81,7 +78,7 @@ namespace Microsoft.AspNetCore.Authentication
/// Otherwise, this will fallback to <see cref="GetDefaultChallengeSchemeAsync"/> .
/// </summary>
/// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.ForbidAsync(HttpContext, string, AuthenticationProperties)"/>.</returns>
public Task<AuthenticationScheme> GetDefaultForbidSchemeAsync()
public virtual Task<AuthenticationScheme> GetDefaultForbidSchemeAsync()
{
if (_options.DefaultForbidScheme != null)
{
@ -93,34 +90,40 @@ namespace Microsoft.AspNetCore.Authentication
/// <summary>
/// Returns the scheme that will be used by default for <see cref="IAuthenticationService.SignInAsync(HttpContext, string, System.Security.Claims.ClaimsPrincipal, AuthenticationProperties)"/>.
/// This is typically specified via <see cref="AuthenticationOptions.DefaultSignInScheme"/>.
/// Otherwise, if only a single scheme exists, that will be used, if more than one exists, null will be returned.
/// If only a single sign in handler scheme exists, that will be used, if more than one exists,
/// this will fallback to <see cref="GetDefaultAuthenticateSchemeAsync"/>.
/// </summary>
/// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.SignInAsync(HttpContext, string, System.Security.Claims.ClaimsPrincipal, AuthenticationProperties)"/>.</returns>
public Task<AuthenticationScheme> GetDefaultSignInSchemeAsync()
public virtual Task<AuthenticationScheme> GetDefaultSignInSchemeAsync()
{
if (_options.DefaultSignInScheme != null)
{
return GetSchemeAsync(_options.DefaultSignInScheme);
}
if (_map.Count == 1)
if (_signInHandlers.Count == 1)
{
return Task.FromResult(_map.Values.First());
return Task.FromResult(_signInHandlers[0]);
}
return Task.FromResult<AuthenticationScheme>(null);
return GetDefaultAuthenticateSchemeAsync();
}
/// <summary>
/// Returns the scheme that will be used by default for <see cref="IAuthenticationService.SignOutAsync(HttpContext, string, AuthenticationProperties)"/>.
/// This is typically specified via <see cref="AuthenticationOptions.DefaultSignOutScheme"/>.
/// Otherwise, this will fallback to <see cref="GetDefaultSignInSchemeAsync"/> .
/// If only a single sign out handler scheme exists, that will be used, if more than one exists,
/// this will fallback to <see cref="GetDefaultSignInSchemeAsync"/> if that supoorts sign out.
/// </summary>
/// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.SignOutAsync(HttpContext, string, AuthenticationProperties)"/>.</returns>
public Task<AuthenticationScheme> GetDefaultSignOutSchemeAsync()
public virtual Task<AuthenticationScheme> GetDefaultSignOutSchemeAsync()
{
if (_options.DefaultSignOutScheme != null)
{
return GetSchemeAsync(_options.DefaultSignOutScheme);
}
if (_signOutHandlers.Count == 1)
{
return Task.FromResult(_signOutHandlers[0]);
}
return GetDefaultSignInSchemeAsync();
}
@ -129,7 +132,7 @@ namespace Microsoft.AspNetCore.Authentication
/// </summary>
/// <param name="name">The name of the authenticationScheme.</param>
/// <returns>The scheme or null if not found.</returns>
public Task<AuthenticationScheme> GetSchemeAsync(string name)
public virtual Task<AuthenticationScheme> GetSchemeAsync(string name)
{
if (_map.ContainsKey(name))
{
@ -142,7 +145,7 @@ namespace Microsoft.AspNetCore.Authentication
/// Returns the schemes in priority order for request handling.
/// </summary>
/// <returns>The schemes in priority order for request handling</returns>
public Task<IEnumerable<AuthenticationScheme>> GetRequestHandlerSchemesAsync()
public virtual Task<IEnumerable<AuthenticationScheme>> GetRequestHandlerSchemesAsync()
{
return Task.FromResult<IEnumerable<AuthenticationScheme>>(_requestHandlers);
}
@ -151,7 +154,7 @@ namespace Microsoft.AspNetCore.Authentication
/// Registers a scheme for use by <see cref="IAuthenticationService"/>.
/// </summary>
/// <param name="scheme">The scheme.</param>
public void AddScheme(AuthenticationScheme scheme)
public virtual void AddScheme(AuthenticationScheme scheme)
{
if (_map.ContainsKey(scheme.Name))
{
@ -167,6 +170,14 @@ namespace Microsoft.AspNetCore.Authentication
{
_requestHandlers.Add(scheme);
}
if (typeof(IAuthenticationSignInHandler).IsAssignableFrom(scheme.HandlerType))
{
_signInHandlers.Add(scheme);
}
if (typeof(IAuthenticationSignOutHandler).IsAssignableFrom(scheme.HandlerType))
{
_signOutHandlers.Add(scheme);
}
_map[scheme.Name] = scheme;
}
}
@ -175,7 +186,7 @@ namespace Microsoft.AspNetCore.Authentication
/// Removes a scheme, preventing it from being used by <see cref="IAuthenticationService"/>.
/// </summary>
/// <param name="name">The name of the authenticationScheme being removed.</param>
public void RemoveScheme(string name)
public virtual void RemoveScheme(string name)
{
if (!_map.ContainsKey(name))
{
@ -186,15 +197,15 @@ namespace Microsoft.AspNetCore.Authentication
if (_map.ContainsKey(name))
{
var scheme = _map[name];
_requestHandlers.Remove(_requestHandlers.Where(s => s.Name == name).FirstOrDefault());
_requestHandlers.Remove(scheme);
_signInHandlers.Remove(scheme);
_signOutHandlers.Remove(scheme);
_map.Remove(name);
}
}
}
public Task<IEnumerable<AuthenticationScheme>> GetAllSchemesAsync()
{
return Task.FromResult<IEnumerable<AuthenticationScheme>>(_map.Values);
}
public virtual Task<IEnumerable<AuthenticationScheme>> GetAllSchemesAsync()
=> Task.FromResult<IEnumerable<AuthenticationScheme>>(_map.Values);
}
}

View File

@ -155,10 +155,10 @@ namespace Microsoft.AspNetCore.Authentication
}
}
var handler = await Handlers.GetHandlerAsync(context, scheme);
var handler = await Handlers.GetHandlerAsync(context, scheme) as IAuthenticationSignInHandler;
if (handler == null)
{
throw new InvalidOperationException($"No authentication handler is configured to handle the scheme: {scheme}");
throw new InvalidOperationException($"No IAuthenticationSignInHandler is configured to handle sign in for the scheme: {scheme}");
}
await handler.SignInAsync(principal, properties);
@ -173,15 +173,20 @@ namespace Microsoft.AspNetCore.Authentication
/// <returns>A task.</returns>
public virtual async Task SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties)
{
if (string.IsNullOrEmpty(scheme))
if (scheme == null)
{
throw new ArgumentException(nameof(scheme));
var defaultScheme = await Schemes.GetDefaultSignOutSchemeAsync();
scheme = defaultScheme?.Name;
if (scheme == null)
{
throw new InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultSignOutScheme found.");
}
}
var handler = await Handlers.GetHandlerAsync(context, scheme);
var handler = await Handlers.GetHandlerAsync(context, scheme) as IAuthenticationSignOutHandler;
if (handler == null)
{
throw new InvalidOperationException($"No authentication handler is configured to handle the scheme: {scheme}");
throw new InvalidOperationException($"No IAuthenticationSignOutHandler is configured to handle sign out for the scheme: {scheme}");
}
await handler.SignOutAsync(properties);

View File

@ -1,3 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
@ -17,7 +18,7 @@ namespace Microsoft.AspNetCore.Authentication
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<Handler>("signin", "whatever");
o.AddScheme<SignInHandler>("signin", "whatever");
o.AddScheme<Handler>("foobly", "whatever");
o.DefaultSignInScheme = "signin";
}).BuildServiceProvider();
@ -49,7 +50,7 @@ namespace Microsoft.AspNetCore.Authentication
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<Handler>("single", "whatever");
o.AddScheme<SignInHandler>("single", "whatever");
}).BuildServiceProvider();
var provider = services.GetRequiredService<IAuthenticationSchemeProvider>();
@ -60,14 +61,32 @@ namespace Microsoft.AspNetCore.Authentication
Assert.Equal("single", (await provider.GetDefaultSignOutSchemeAsync()).Name);
}
[Fact]
public async Task DefaultSchemesFallbackToAuthenticateScheme()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.DefaultAuthenticateScheme = "B";
o.AddScheme<Handler>("A", "whatever");
o.AddScheme<SignInHandler>("B", "whatever");
}).BuildServiceProvider();
var provider = services.GetRequiredService<IAuthenticationSchemeProvider>();
Assert.Equal("B", (await provider.GetDefaultForbidSchemeAsync()).Name);
Assert.Equal("B", (await provider.GetDefaultAuthenticateSchemeAsync()).Name);
Assert.Equal("B", (await provider.GetDefaultChallengeSchemeAsync()).Name);
Assert.Equal("B", (await provider.GetDefaultSignInSchemeAsync()).Name);
Assert.Equal("B", (await provider.GetDefaultSignOutSchemeAsync()).Name);
}
[Fact]
public async Task DefaultSchemesAreSet()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<Handler>("A", "whatever");
o.AddScheme<Handler>("B", "whatever");
o.AddScheme<Handler>("C", "whatever");
o.AddScheme<SignInHandler>("A", "whatever");
o.AddScheme<SignInHandler>("B", "whatever");
o.AddScheme<SignInHandler>("C", "whatever");
o.DefaultChallengeScheme = "A";
o.DefaultForbidScheme = "B";
o.DefaultSignInScheme = "C";
@ -83,6 +102,38 @@ namespace Microsoft.AspNetCore.Authentication
Assert.Equal("A", (await provider.GetDefaultSignOutSchemeAsync()).Name);
}
[Fact]
public async Task SignInSignOutDefaultsToOnlyOne()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<Handler>("basic", "whatever");
o.AddScheme<SignOutHandler>("signout", "whatever");
o.AddScheme<SignInHandler>("signin", "whatever");
o.DefaultAuthenticateScheme = "basic";
}).BuildServiceProvider();
var provider = services.GetRequiredService<IAuthenticationSchemeProvider>();
Assert.Equal("basic", (await provider.GetDefaultForbidSchemeAsync()).Name);
Assert.Equal("basic", (await provider.GetDefaultAuthenticateSchemeAsync()).Name);
Assert.Equal("basic", (await provider.GetDefaultChallengeSchemeAsync()).Name);
Assert.Equal("signin", (await provider.GetDefaultSignInSchemeAsync()).Name);
Assert.Equal("signin", (await provider.GetDefaultSignOutSchemeAsync()).Name); // Defaults to single sign in scheme
}
[Fact]
public async Task SignOutWillDefaultsToSignInThatDoesNotSignOut()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<Handler>("signin", "whatever");
o.DefaultSignInScheme = "signin";
}).BuildServiceProvider();
var provider = services.GetRequiredService<IAuthenticationSchemeProvider>();
Assert.NotNull(await provider.GetDefaultSignOutSchemeAsync());
}
private class Handler : IAuthenticationHandler
{
public Task<AuthenticateResult> AuthenticateAsync()
@ -104,7 +155,10 @@ namespace Microsoft.AspNetCore.Authentication
{
throw new NotImplementedException();
}
}
private class SignInHandler : Handler, IAuthenticationSignInHandler
{
public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
{
throw new NotImplementedException();
@ -116,5 +170,12 @@ namespace Microsoft.AspNetCore.Authentication
}
}
private class SignOutHandler : Handler, IAuthenticationSignOutHandler
{
public Task SignOutAsync(AuthenticationProperties properties)
{
throw new NotImplementedException();
}
}
}
}

View File

@ -0,0 +1,245 @@
// Copyright (c) .NET Foundation. 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.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace Microsoft.AspNetCore.Authentication
{
public class AuthenticationServiceTests
{
[Fact]
public async Task CanOnlySignInIfSupported()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<UberHandler>("uber", "whatever");
o.AddScheme<BaseHandler>("base", "whatever");
o.AddScheme<SignInHandler>("signin", "whatever");
o.AddScheme<SignOutHandler>("signout", "whatever");
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.SignInAsync("uber", new ClaimsPrincipal(), null);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("base", new ClaimsPrincipal(), null));
await context.SignInAsync("signin", new ClaimsPrincipal(), null);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("signout", new ClaimsPrincipal(), null));
}
[Fact]
public async Task CanOnlySignOutIfSupported()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<UberHandler>("uber", "whatever");
o.AddScheme<BaseHandler>("base", "whatever");
o.AddScheme<SignInHandler>("signin", "whatever");
o.AddScheme<SignOutHandler>("signout", "whatever");
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.SignOutAsync("uber");
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync("base"));
await context.SignOutAsync("signout");
await context.SignOutAsync("signin");
}
[Fact]
public async Task ServicesWithDefaultIAuthenticationHandlerMethodsTest()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<BaseHandler>("base", "whatever");
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.AuthenticateAsync();
await context.ChallengeAsync();
await context.ForbidAsync();
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
[Fact]
public async Task ServicesWithDefaultUberMethodsTest()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<UberHandler>("base", "whatever");
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.AuthenticateAsync();
await context.ChallengeAsync();
await context.ForbidAsync();
await context.SignOutAsync();
await context.SignInAsync(new ClaimsPrincipal());
}
[Fact]
public async Task ServicesWithDefaultSignInMethodsTest()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<SignInHandler>("base", "whatever");
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.AuthenticateAsync();
await context.ChallengeAsync();
await context.ForbidAsync();
await context.SignOutAsync();
await context.SignInAsync(new ClaimsPrincipal());
}
[Fact]
public async Task ServicesWithDefaultSignOutMethodsTest()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<SignOutHandler>("base", "whatever");
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.AuthenticateAsync();
await context.ChallengeAsync();
await context.ForbidAsync();
await context.SignOutAsync();
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
private class BaseHandler : IAuthenticationHandler
{
public Task<AuthenticateResult> AuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.NoResult());
}
public Task ChallengeAsync(AuthenticationProperties properties)
{
return Task.FromResult(0);
}
public Task ForbidAsync(AuthenticationProperties properties)
{
return Task.FromResult(0);
}
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
return Task.FromResult(0);
}
}
private class SignInHandler : IAuthenticationSignInHandler
{
public Task<AuthenticateResult> AuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.NoResult());
}
public Task ChallengeAsync(AuthenticationProperties properties)
{
return Task.FromResult(0);
}
public Task ForbidAsync(AuthenticationProperties properties)
{
return Task.FromResult(0);
}
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
return Task.FromResult(0);
}
public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
{
return Task.FromResult(0);
}
public Task SignOutAsync(AuthenticationProperties properties)
{
return Task.FromResult(0);
}
}
public class SignOutHandler : IAuthenticationSignOutHandler
{
public Task<AuthenticateResult> AuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.NoResult());
}
public Task ChallengeAsync(AuthenticationProperties properties)
{
return Task.FromResult(0);
}
public Task ForbidAsync(AuthenticationProperties properties)
{
return Task.FromResult(0);
}
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
return Task.FromResult(0);
}
public Task SignOutAsync(AuthenticationProperties properties)
{
return Task.FromResult(0);
}
}
private class UberHandler : IAuthenticationHandler, IAuthenticationRequestHandler, IAuthenticationSignInHandler, IAuthenticationSignOutHandler
{
public Task<AuthenticateResult> AuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.NoResult());
}
public Task ChallengeAsync(AuthenticationProperties properties)
{
return Task.FromResult(0);
}
public Task ForbidAsync(AuthenticationProperties properties)
{
return Task.FromResult(0);
}
public Task<bool> HandleRequestAsync()
{
return Task.FromResult(false);
}
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
return Task.FromResult(0);
}
public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
{
return Task.FromResult(0);
}
public Task SignOutAsync(AuthenticationProperties properties)
{
return Task.FromResult(0);
}
}
}
}