diff --git a/src/Microsoft.AspNetCore.Authentication.Abstractions/AuthenticateResult.cs b/src/Microsoft.AspNetCore.Authentication.Abstractions/AuthenticateResult.cs
index bb9bbb97..1da6a0b9 100644
--- a/src/Microsoft.AspNetCore.Authentication.Abstractions/AuthenticateResult.cs
+++ b/src/Microsoft.AspNetCore.Authentication.Abstractions/AuthenticateResult.cs
@@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Authentication
///
public class AuthenticateResult
{
- private AuthenticateResult() { }
+ protected AuthenticateResult() { }
///
/// If a ticket was produced, authenticate was successful.
@@ -21,7 +21,7 @@ private AuthenticateResult() { }
///
/// The authentication ticket.
///
- public AuthenticationTicket Ticket { get; private set; }
+ public AuthenticationTicket Ticket { get; protected set; }
///
/// Gets the claims-principal with authenticated user identities.
@@ -36,18 +36,12 @@ private AuthenticateResult() { }
///
/// Holds failure information from the authentication.
///
- public Exception Failure { get; private set; }
-
- ///
- /// Indicates that stage of authentication was directly handled by user intervention and no
- /// further processing should be attempted.
- ///
- public bool Handled { get; private set; }
+ public Exception Failure { get; protected set; }
///
/// Indicates that there was no information returned for this authentication scheme.
///
- public bool Nothing { get; private set; }
+ public bool None { get; protected set; }
///
/// Indicates that authentication was successful.
@@ -63,23 +57,13 @@ public static AuthenticateResult Success(AuthenticationTicket ticket)
return new AuthenticateResult() { Ticket = ticket };
}
- ///
- /// Indicates that stage of authentication was directly handled by user intervention and no
- /// further processing should be attempted.
- ///
- /// The result.
- public static AuthenticateResult Handle()
- {
- return new AuthenticateResult() { Handled = true };
- }
-
///
/// Indicates that there was no information returned for this authentication scheme.
///
/// The result.
- public static AuthenticateResult None()
+ public static AuthenticateResult NoResult()
{
- return new AuthenticateResult() { Nothing = true };
+ return new AuthenticateResult() { None = true };
}
///
diff --git a/src/Microsoft.AspNetCore.Authentication.Abstractions/AuthenticationHttpContextExtensions.cs b/src/Microsoft.AspNetCore.Authentication.Abstractions/AuthenticationHttpContextExtensions.cs
index cb8f1fb4..050e6c57 100644
--- a/src/Microsoft.AspNetCore.Authentication.Abstractions/AuthenticationHttpContextExtensions.cs
+++ b/src/Microsoft.AspNetCore.Authentication.Abstractions/AuthenticationHttpContextExtensions.cs
@@ -76,7 +76,7 @@ public static Task ForbidAsync(this HttpContext context, string scheme) =>
context.ForbidAsync(scheme, properties: null);
///
- /// Extension method for Forbid.
+ /// Extension method for Forbid using the scheme..
///
/// The context.
/// The task.
@@ -142,6 +142,13 @@ public static Task SignInAsync(this HttpContext context, ClaimsPrincipal princip
public static Task SignInAsync(this HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties) =>
context.RequestServices.GetRequiredService().SignInAsync(context, scheme, principal, properties);
+ ///
+ /// Extension method for SignOut using the .
+ ///
+ /// The context.
+ /// The task.
+ public static Task SignOutAsync(this HttpContext context) => context.SignOutAsync(scheme: null, properties: null);
+
///
/// Extension method for SignOut.
///
diff --git a/src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationHandler.cs b/src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationHandler.cs
index af92cc76..aeb373e1 100644
--- a/src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationHandler.cs
+++ b/src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationHandler.cs
@@ -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 @@ public interface IAuthenticationHandler
/// The that contains the extra meta-data arriving with the authentication.
/// A task.
Task ForbidAsync(AuthenticationProperties properties);
-
- ///
- /// Handle sign in.
- ///
- /// The user.
- /// The that contains the extra meta-data arriving with the authentication.
- /// A task.
- Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties);
-
- ///
- /// Signout behavior.
- ///
- /// The that contains the extra meta-data arriving with the authentication.
- /// A task.
- Task SignOutAsync(AuthenticationProperties properties);
}
}
diff --git a/src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationRequestHandler.cs b/src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationRequestHandler.cs
index fffe08f4..fb1b227a 100644
--- a/src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationRequestHandler.cs
+++ b/src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationRequestHandler.cs
@@ -10,7 +10,6 @@ namespace Microsoft.AspNetCore.Authentication
///
public interface IAuthenticationRequestHandler : IAuthenticationHandler
{
-
///
/// Returns true if request processing should stop.
///
diff --git a/src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationSignInHandler.cs b/src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationSignInHandler.cs
new file mode 100644
index 00000000..69b88032
--- /dev/null
+++ b/src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationSignInHandler.cs
@@ -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
+{
+ ///
+ /// Used to determine if a handler supports SignIn.
+ ///
+ public interface IAuthenticationSignInHandler : IAuthenticationSignOutHandler
+ {
+ ///
+ /// Handle sign in.
+ ///
+ /// The user.
+ /// The that contains the extra meta-data arriving with the authentication.
+ /// A task.
+ Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties);
+ }
+}
diff --git a/src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationSignOutHandler.cs b/src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationSignOutHandler.cs
new file mode 100644
index 00000000..f76d116a
--- /dev/null
+++ b/src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationSignOutHandler.cs
@@ -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
+{
+ ///
+ /// Used to determine if a handler supports SignOut.
+ ///
+ public interface IAuthenticationSignOutHandler : IAuthenticationHandler
+ {
+ ///
+ /// Signout behavior.
+ ///
+ /// The that contains the extra meta-data arriving with the authentication.
+ /// A task.
+ Task SignOutAsync(AuthenticationProperties properties);
+ }
+
+}
diff --git a/src/Microsoft.AspNetCore.Authentication.Abstractions/IClaimsTransformation.cs b/src/Microsoft.AspNetCore.Authentication.Abstractions/IClaimsTransformation.cs
index 3aed710a..83719015 100644
--- a/src/Microsoft.AspNetCore.Authentication.Abstractions/IClaimsTransformation.cs
+++ b/src/Microsoft.AspNetCore.Authentication.Abstractions/IClaimsTransformation.cs
@@ -18,4 +18,4 @@ public interface IClaimsTransformation
/// The transformed principal.
Task TransformAsync(ClaimsPrincipal principal);
}
-}
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Authentication.Core/AuthenticationSchemeProvider.cs b/src/Microsoft.AspNetCore.Authentication.Core/AuthenticationSchemeProvider.cs
index e56247e1..be02a5c3 100644
--- a/src/Microsoft.AspNetCore.Authentication.Core/AuthenticationSchemeProvider.cs
+++ b/src/Microsoft.AspNetCore.Authentication.Core/AuthenticationSchemeProvider.cs
@@ -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 @@ public AuthenticationSchemeProvider(IOptions options)
private IDictionary _map = new Dictionary(StringComparer.Ordinal);
private List _requestHandlers = new List();
+ private List _signOutHandlers = new List();
+ private List _signInHandlers = new List();
///
/// Returns the scheme that will be used by default for .
@@ -43,7 +44,7 @@ public AuthenticationSchemeProvider(IOptions options)
/// Otherwise, if only a single scheme exists, that will be used, if more than one exists, null will be returned.
///
/// The scheme that will be used by default for .
- public Task GetDefaultAuthenticateSchemeAsync()
+ public virtual Task GetDefaultAuthenticateSchemeAsync()
{
if (_options.DefaultAuthenticateScheme != null)
{
@@ -59,20 +60,16 @@ public Task GetDefaultAuthenticateSchemeAsync()
///
/// Returns the scheme that will be used by default for .
/// This is typically specified via .
- /// 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 .
///
/// The scheme that will be used by default for .
- public Task GetDefaultChallengeSchemeAsync()
+ public virtual Task GetDefaultChallengeSchemeAsync()
{
if (_options.DefaultChallengeScheme != null)
{
return GetSchemeAsync(_options.DefaultChallengeScheme);
}
- if (_map.Count == 1)
- {
- return Task.FromResult(_map.Values.First());
- }
- return Task.FromResult(null);
+ return GetDefaultAuthenticateSchemeAsync();
}
///
@@ -81,7 +78,7 @@ public Task GetDefaultChallengeSchemeAsync()
/// Otherwise, this will fallback to .
///
/// The scheme that will be used by default for .
- public Task GetDefaultForbidSchemeAsync()
+ public virtual Task GetDefaultForbidSchemeAsync()
{
if (_options.DefaultForbidScheme != null)
{
@@ -93,34 +90,40 @@ public Task GetDefaultForbidSchemeAsync()
///
/// Returns the scheme that will be used by default for .
/// This is typically specified via .
- /// 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 .
///
/// The scheme that will be used by default for .
- public Task GetDefaultSignInSchemeAsync()
+ public virtual Task 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(null);
+ return GetDefaultAuthenticateSchemeAsync();
}
///
/// Returns the scheme that will be used by default for .
/// This is typically specified via .
- /// Otherwise, this will fallback to .
+ /// If only a single sign out handler scheme exists, that will be used, if more than one exists,
+ /// this will fallback to if that supoorts sign out.
///
/// The scheme that will be used by default for .
- public Task GetDefaultSignOutSchemeAsync()
+ public virtual Task GetDefaultSignOutSchemeAsync()
{
if (_options.DefaultSignOutScheme != null)
{
return GetSchemeAsync(_options.DefaultSignOutScheme);
}
+ if (_signOutHandlers.Count == 1)
+ {
+ return Task.FromResult(_signOutHandlers[0]);
+ }
return GetDefaultSignInSchemeAsync();
}
@@ -129,7 +132,7 @@ public Task GetDefaultSignOutSchemeAsync()
///
/// The name of the authenticationScheme.
/// The scheme or null if not found.
- public Task GetSchemeAsync(string name)
+ public virtual Task GetSchemeAsync(string name)
{
if (_map.ContainsKey(name))
{
@@ -142,7 +145,7 @@ public Task GetSchemeAsync(string name)
/// Returns the schemes in priority order for request handling.
///
/// The schemes in priority order for request handling
- public Task> GetRequestHandlerSchemesAsync()
+ public virtual Task> GetRequestHandlerSchemesAsync()
{
return Task.FromResult>(_requestHandlers);
}
@@ -151,7 +154,7 @@ public Task> GetRequestHandlerSchemesAsync()
/// Registers a scheme for use by .
///
/// The scheme.
- public void AddScheme(AuthenticationScheme scheme)
+ public virtual void AddScheme(AuthenticationScheme scheme)
{
if (_map.ContainsKey(scheme.Name))
{
@@ -167,6 +170,14 @@ public void AddScheme(AuthenticationScheme scheme)
{
_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 @@ public void AddScheme(AuthenticationScheme scheme)
/// Removes a scheme, preventing it from being used by .
///
/// The name of the authenticationScheme being removed.
- public void RemoveScheme(string name)
+ public virtual void RemoveScheme(string name)
{
if (!_map.ContainsKey(name))
{
@@ -186,15 +197,15 @@ public void RemoveScheme(string name)
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> GetAllSchemesAsync()
- {
- return Task.FromResult>(_map.Values);
- }
+ public virtual Task> GetAllSchemesAsync()
+ => Task.FromResult>(_map.Values);
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Authentication.Core/AuthenticationService.cs b/src/Microsoft.AspNetCore.Authentication.Core/AuthenticationService.cs
index 326b277f..e9fcfc0b 100644
--- a/src/Microsoft.AspNetCore.Authentication.Core/AuthenticationService.cs
+++ b/src/Microsoft.AspNetCore.Authentication.Core/AuthenticationService.cs
@@ -155,10 +155,10 @@ public virtual async Task SignInAsync(HttpContext context, string scheme, Claims
}
}
- 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 @@ public virtual async Task SignInAsync(HttpContext context, string scheme, Claims
/// A task.
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);
diff --git a/test/Microsoft.AspNetCore.Authentication.Core.Test/AuthenticationSchemeProviderTests.cs b/test/Microsoft.AspNetCore.Authentication.Core.Test/AuthenticationSchemeProviderTests.cs
index 3810f833..fc647138 100644
--- a/test/Microsoft.AspNetCore.Authentication.Core.Test/AuthenticationSchemeProviderTests.cs
+++ b/test/Microsoft.AspNetCore.Authentication.Core.Test/AuthenticationSchemeProviderTests.cs
@@ -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 @@ public async Task DefaultSignOutFallsbackToSignIn()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
- o.AddScheme("signin", "whatever");
+ o.AddScheme("signin", "whatever");
o.AddScheme("foobly", "whatever");
o.DefaultSignInScheme = "signin";
}).BuildServiceProvider();
@@ -49,7 +50,7 @@ public async Task DefaultSchemesFallbackToOnlyScheme()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
- o.AddScheme("single", "whatever");
+ o.AddScheme("single", "whatever");
}).BuildServiceProvider();
var provider = services.GetRequiredService();
@@ -61,13 +62,31 @@ public async Task DefaultSchemesFallbackToOnlyScheme()
}
[Fact]
- public async Task DefaultSchemesAreSet()
+ public async Task DefaultSchemesFallbackToAuthenticateScheme()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
+ o.DefaultAuthenticateScheme = "B";
o.AddScheme("A", "whatever");
- o.AddScheme("B", "whatever");
- o.AddScheme("C", "whatever");
+ o.AddScheme("B", "whatever");
+ }).BuildServiceProvider();
+
+ var provider = services.GetRequiredService();
+ 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("A", "whatever");
+ o.AddScheme("B", "whatever");
+ o.AddScheme("C", "whatever");
o.DefaultChallengeScheme = "A";
o.DefaultForbidScheme = "B";
o.DefaultSignInScheme = "C";
@@ -83,6 +102,38 @@ public async Task DefaultSchemesAreSet()
Assert.Equal("A", (await provider.GetDefaultSignOutSchemeAsync()).Name);
}
+ [Fact]
+ public async Task SignInSignOutDefaultsToOnlyOne()
+ {
+ var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
+ {
+ o.AddScheme("basic", "whatever");
+ o.AddScheme("signout", "whatever");
+ o.AddScheme("signin", "whatever");
+ o.DefaultAuthenticateScheme = "basic";
+ }).BuildServiceProvider();
+
+ var provider = services.GetRequiredService();
+ 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("signin", "whatever");
+ o.DefaultSignInScheme = "signin";
+ }).BuildServiceProvider();
+
+ var provider = services.GetRequiredService();
+ Assert.NotNull(await provider.GetDefaultSignOutSchemeAsync());
+ }
+
private class Handler : IAuthenticationHandler
{
public Task AuthenticateAsync()
@@ -104,7 +155,10 @@ public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
throw new NotImplementedException();
}
+ }
+ private class SignInHandler : Handler, IAuthenticationSignInHandler
+ {
public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
{
throw new NotImplementedException();
@@ -116,5 +170,12 @@ public Task SignOutAsync(AuthenticationProperties properties)
}
}
+ private class SignOutHandler : Handler, IAuthenticationSignOutHandler
+ {
+ public Task SignOutAsync(AuthenticationProperties properties)
+ {
+ throw new NotImplementedException();
+ }
+ }
}
}
diff --git a/test/Microsoft.AspNetCore.Authentication.Core.Test/AuthenticationServiceTests.cs b/test/Microsoft.AspNetCore.Authentication.Core.Test/AuthenticationServiceTests.cs
new file mode 100644
index 00000000..471053e6
--- /dev/null
+++ b/test/Microsoft.AspNetCore.Authentication.Core.Test/AuthenticationServiceTests.cs
@@ -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("uber", "whatever");
+ o.AddScheme("base", "whatever");
+ o.AddScheme("signin", "whatever");
+ o.AddScheme("signout", "whatever");
+ }).BuildServiceProvider();
+ var context = new DefaultHttpContext();
+ context.RequestServices = services;
+
+ await context.SignInAsync("uber", new ClaimsPrincipal(), null);
+ await Assert.ThrowsAsync(() => context.SignInAsync("base", new ClaimsPrincipal(), null));
+ await context.SignInAsync("signin", new ClaimsPrincipal(), null);
+ await Assert.ThrowsAsync(() => context.SignInAsync("signout", new ClaimsPrincipal(), null));
+ }
+
+ [Fact]
+ public async Task CanOnlySignOutIfSupported()
+ {
+ var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
+ {
+ o.AddScheme("uber", "whatever");
+ o.AddScheme("base", "whatever");
+ o.AddScheme("signin", "whatever");
+ o.AddScheme("signout", "whatever");
+ }).BuildServiceProvider();
+ var context = new DefaultHttpContext();
+ context.RequestServices = services;
+
+ await context.SignOutAsync("uber");
+ await Assert.ThrowsAsync(() => 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("base", "whatever");
+ }).BuildServiceProvider();
+ var context = new DefaultHttpContext();
+ context.RequestServices = services;
+
+ await context.AuthenticateAsync();
+ await context.ChallengeAsync();
+ await context.ForbidAsync();
+ await Assert.ThrowsAsync(() => context.SignOutAsync());
+ await Assert.ThrowsAsync(() => context.SignInAsync(new ClaimsPrincipal()));
+ }
+
+ [Fact]
+ public async Task ServicesWithDefaultUberMethodsTest()
+ {
+ var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
+ {
+ o.AddScheme("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("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("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(() => context.SignInAsync(new ClaimsPrincipal()));
+ }
+
+
+ private class BaseHandler : IAuthenticationHandler
+ {
+ public Task 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 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 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 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 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);
+ }
+ }
+
+ }
+}