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

Commit d894584

Browse files
authored
Add DefaultScheme, remove single fallback (#891)
1 parent 0e66e75 commit d894584

File tree

6 files changed

+75
-129
lines changed

6 files changed

+75
-129
lines changed

src/Microsoft.AspNetCore.Authentication.Abstractions/AuthenticationOptions.cs

+5
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ public void AddScheme<THandler>(string name, string displayName) where THandler
6060
b.HandlerType = typeof(THandler);
6161
});
6262

63+
/// <summary>
64+
/// Used by as the fallback default scheme for all the other defaults."/>.
65+
/// </summary>
66+
public string DefaultScheme { get; set; }
67+
6368
/// <summary>
6469
/// Used by as the default scheme by <see cref="IAuthenticationService.AuthenticateAsync(HttpContext, string)"/>.
6570
/// </summary>

src/Microsoft.AspNetCore.Authentication.Abstractions/IAuthenticationSchemeProvider.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ public interface IAuthenticationSchemeProvider
2828
/// <summary>
2929
/// Returns the scheme that will be used by default for <see cref="IAuthenticationService.AuthenticateAsync(HttpContext, string)"/>.
3030
/// This is typically specified via <see cref="AuthenticationOptions.DefaultAuthenticateScheme"/>.
31-
/// Otherwise, if only a single scheme exists, that will be used, if more than one exists, null will be returned.
31+
/// Otherwise, this will fallback to <see cref="AuthenticationOptions.DefaultScheme"/>.
3232
/// </summary>
3333
/// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.AuthenticateAsync(HttpContext, string)"/>.</returns>
3434
Task<AuthenticationScheme> GetDefaultAuthenticateSchemeAsync();
3535

3636
/// <summary>
3737
/// Returns the scheme that will be used by default for <see cref="IAuthenticationService.ChallengeAsync(HttpContext, string, AuthenticationProperties)"/>.
3838
/// This is typically specified via <see cref="AuthenticationOptions.DefaultChallengeScheme"/>.
39-
/// Otherwise, if only a single scheme exists, that will be used, if more than one exists, null will be returned.
39+
/// Otherwise, this will fallback to <see cref="AuthenticationOptions.DefaultScheme"/>.
4040
/// </summary>
4141
/// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.ChallengeAsync(HttpContext, string, AuthenticationProperties)"/>.</returns>
4242
Task<AuthenticationScheme> GetDefaultChallengeSchemeAsync();
@@ -52,7 +52,7 @@ public interface IAuthenticationSchemeProvider
5252
/// <summary>
5353
/// Returns the scheme that will be used by default for <see cref="IAuthenticationService.SignInAsync(HttpContext, string, System.Security.Claims.ClaimsPrincipal, AuthenticationProperties)"/>.
5454
/// This is typically specified via <see cref="AuthenticationOptions.DefaultSignInScheme"/>.
55-
/// Otherwise, if only a single scheme exists, that will be used, if more than one exists, null will be returned.
55+
/// Otherwise, this will fallback to <see cref="AuthenticationOptions.DefaultScheme"/>.
5656
/// </summary>
5757
/// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.SignInAsync(HttpContext, string, System.Security.Claims.ClaimsPrincipal, AuthenticationProperties)"/>.</returns>
5858
Task<AuthenticationScheme> GetDefaultSignInSchemeAsync();

src/Microsoft.AspNetCore.Authentication.Core/AuthenticationSchemeProvider.cs

+26-76
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System;
55
using System.Collections.Generic;
6-
using System.Linq;
76
using System.Threading.Tasks;
87
using Microsoft.AspNetCore.Http;
98
using Microsoft.Extensions.Options;
@@ -35,42 +34,33 @@ public AuthenticationSchemeProvider(IOptions<AuthenticationOptions> options)
3534

3635
private IDictionary<string, AuthenticationScheme> _map = new Dictionary<string, AuthenticationScheme>(StringComparer.Ordinal);
3736
private List<AuthenticationScheme> _requestHandlers = new List<AuthenticationScheme>();
38-
private List<AuthenticationScheme> _signOutHandlers = new List<AuthenticationScheme>();
39-
private List<AuthenticationScheme> _signInHandlers = new List<AuthenticationScheme>();
37+
38+
private Task<AuthenticationScheme> GetDefaultSchemeAsync()
39+
=> _options.DefaultScheme != null
40+
? GetSchemeAsync(_options.DefaultScheme)
41+
: Task.FromResult<AuthenticationScheme>(null);
4042

4143
/// <summary>
4244
/// Returns the scheme that will be used by default for <see cref="IAuthenticationService.AuthenticateAsync(HttpContext, string)"/>.
4345
/// This is typically specified via <see cref="AuthenticationOptions.DefaultAuthenticateScheme"/>.
44-
/// Otherwise, if only a single scheme exists, that will be used, if more than one exists, null will be returned.
46+
/// Otherwise, this will fallback to <see cref="AuthenticationOptions.DefaultScheme"/>.
4547
/// </summary>
4648
/// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.AuthenticateAsync(HttpContext, string)"/>.</returns>
4749
public virtual Task<AuthenticationScheme> GetDefaultAuthenticateSchemeAsync()
48-
{
49-
if (_options.DefaultAuthenticateScheme != null)
50-
{
51-
return GetSchemeAsync(_options.DefaultAuthenticateScheme);
52-
}
53-
if (_map.Count == 1)
54-
{
55-
return Task.FromResult(_map.Values.First());
56-
}
57-
return Task.FromResult<AuthenticationScheme>(null);
58-
}
50+
=> _options.DefaultAuthenticateScheme != null
51+
? GetSchemeAsync(_options.DefaultAuthenticateScheme)
52+
: GetDefaultSchemeAsync();
5953

6054
/// <summary>
6155
/// Returns the scheme that will be used by default for <see cref="IAuthenticationService.ChallengeAsync(HttpContext, string, AuthenticationProperties)"/>.
6256
/// This is typically specified via <see cref="AuthenticationOptions.DefaultChallengeScheme"/>.
63-
/// Otherwise, this will fallback to <see cref="GetDefaultAuthenticateSchemeAsync"/>.
57+
/// Otherwise, this will fallback to <see cref="AuthenticationOptions.DefaultScheme"/>.
6458
/// </summary>
6559
/// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.ChallengeAsync(HttpContext, string, AuthenticationProperties)"/>.</returns>
6660
public virtual Task<AuthenticationScheme> GetDefaultChallengeSchemeAsync()
67-
{
68-
if (_options.DefaultChallengeScheme != null)
69-
{
70-
return GetSchemeAsync(_options.DefaultChallengeScheme);
71-
}
72-
return GetDefaultAuthenticateSchemeAsync();
73-
}
61+
=> _options.DefaultChallengeScheme != null
62+
? GetSchemeAsync(_options.DefaultChallengeScheme)
63+
: GetDefaultSchemeAsync();
7464

7565
/// <summary>
7666
/// Returns the scheme that will be used by default for <see cref="IAuthenticationService.ForbidAsync(HttpContext, string, AuthenticationProperties)"/>.
@@ -79,76 +69,46 @@ public virtual Task<AuthenticationScheme> GetDefaultChallengeSchemeAsync()
7969
/// </summary>
8070
/// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.ForbidAsync(HttpContext, string, AuthenticationProperties)"/>.</returns>
8171
public virtual Task<AuthenticationScheme> GetDefaultForbidSchemeAsync()
82-
{
83-
if (_options.DefaultForbidScheme != null)
84-
{
85-
return GetSchemeAsync(_options.DefaultForbidScheme);
86-
}
87-
return GetDefaultChallengeSchemeAsync();
88-
}
72+
=> _options.DefaultForbidScheme != null
73+
? GetSchemeAsync(_options.DefaultForbidScheme)
74+
: GetDefaultChallengeSchemeAsync();
8975

9076
/// <summary>
9177
/// Returns the scheme that will be used by default for <see cref="IAuthenticationService.SignInAsync(HttpContext, string, System.Security.Claims.ClaimsPrincipal, AuthenticationProperties)"/>.
9278
/// This is typically specified via <see cref="AuthenticationOptions.DefaultSignInScheme"/>.
93-
/// If only a single sign in handler scheme exists, that will be used, if more than one exists,
94-
/// this will fallback to <see cref="GetDefaultAuthenticateSchemeAsync"/>.
79+
/// Otherwise, this will fallback to <see cref="AuthenticationOptions.DefaultScheme"/>.
9580
/// </summary>
9681
/// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.SignInAsync(HttpContext, string, System.Security.Claims.ClaimsPrincipal, AuthenticationProperties)"/>.</returns>
9782
public virtual Task<AuthenticationScheme> GetDefaultSignInSchemeAsync()
98-
{
99-
if (_options.DefaultSignInScheme != null)
100-
{
101-
return GetSchemeAsync(_options.DefaultSignInScheme);
102-
}
103-
if (_signInHandlers.Count == 1)
104-
{
105-
return Task.FromResult(_signInHandlers[0]);
106-
}
107-
return GetDefaultAuthenticateSchemeAsync();
108-
}
83+
=> _options.DefaultSignInScheme != null
84+
? GetSchemeAsync(_options.DefaultSignInScheme)
85+
: GetDefaultSchemeAsync();
10986

11087
/// <summary>
11188
/// Returns the scheme that will be used by default for <see cref="IAuthenticationService.SignOutAsync(HttpContext, string, AuthenticationProperties)"/>.
11289
/// This is typically specified via <see cref="AuthenticationOptions.DefaultSignOutScheme"/>.
113-
/// If only a single sign out handler scheme exists, that will be used, if more than one exists,
114-
/// this will fallback to <see cref="GetDefaultSignInSchemeAsync"/> if that supoorts sign out.
90+
/// Otherwise this will fallback to <see cref="GetDefaultSignInSchemeAsync"/> if that supoorts sign out.
11591
/// </summary>
11692
/// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.SignOutAsync(HttpContext, string, AuthenticationProperties)"/>.</returns>
11793
public virtual Task<AuthenticationScheme> GetDefaultSignOutSchemeAsync()
118-
{
119-
if (_options.DefaultSignOutScheme != null)
120-
{
121-
return GetSchemeAsync(_options.DefaultSignOutScheme);
122-
}
123-
if (_signOutHandlers.Count == 1)
124-
{
125-
return Task.FromResult(_signOutHandlers[0]);
126-
}
127-
return GetDefaultSignInSchemeAsync();
128-
}
94+
=> _options.DefaultSignOutScheme != null
95+
? GetSchemeAsync(_options.DefaultSignOutScheme)
96+
: GetDefaultSignInSchemeAsync();
12997

13098
/// <summary>
13199
/// Returns the <see cref="AuthenticationScheme"/> matching the name, or null.
132100
/// </summary>
133101
/// <param name="name">The name of the authenticationScheme.</param>
134102
/// <returns>The scheme or null if not found.</returns>
135103
public virtual Task<AuthenticationScheme> GetSchemeAsync(string name)
136-
{
137-
if (_map.ContainsKey(name))
138-
{
139-
return Task.FromResult(_map[name]);
140-
}
141-
return Task.FromResult<AuthenticationScheme>(null);
142-
}
104+
=> Task.FromResult(_map.ContainsKey(name) ? _map[name] : null);
143105

144106
/// <summary>
145107
/// Returns the schemes in priority order for request handling.
146108
/// </summary>
147109
/// <returns>The schemes in priority order for request handling</returns>
148110
public virtual Task<IEnumerable<AuthenticationScheme>> GetRequestHandlerSchemesAsync()
149-
{
150-
return Task.FromResult<IEnumerable<AuthenticationScheme>>(_requestHandlers);
151-
}
111+
=> Task.FromResult<IEnumerable<AuthenticationScheme>>(_requestHandlers);
152112

153113
/// <summary>
154114
/// Registers a scheme for use by <see cref="IAuthenticationService"/>.
@@ -170,14 +130,6 @@ public virtual void AddScheme(AuthenticationScheme scheme)
170130
{
171131
_requestHandlers.Add(scheme);
172132
}
173-
if (typeof(IAuthenticationSignInHandler).IsAssignableFrom(scheme.HandlerType))
174-
{
175-
_signInHandlers.Add(scheme);
176-
}
177-
if (typeof(IAuthenticationSignOutHandler).IsAssignableFrom(scheme.HandlerType))
178-
{
179-
_signOutHandlers.Add(scheme);
180-
}
181133
_map[scheme.Name] = scheme;
182134
}
183135
}
@@ -198,8 +150,6 @@ public virtual void RemoveScheme(string name)
198150
{
199151
var scheme = _map[name];
200152
_requestHandlers.Remove(scheme);
201-
_signInHandlers.Remove(scheme);
202-
_signOutHandlers.Remove(scheme);
203153
_map.Remove(name);
204154
}
205155
}

test/Microsoft.AspNetCore.Authentication.Core.Test/AuthenticationSchemeProviderTests.cs

+32-49
Original file line numberDiff line numberDiff line change
@@ -14,69 +14,69 @@ namespace Microsoft.AspNetCore.Authentication
1414
public class AuthenticationSchemeProviderTests
1515
{
1616
[Fact]
17-
public async Task DefaultSignOutFallsbackToSignIn()
17+
public async Task NoDefaultsByDefault()
1818
{
1919
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
2020
{
21-
o.AddScheme<SignInHandler>("signin", "whatever");
22-
o.AddScheme<Handler>("foobly", "whatever");
23-
o.DefaultSignInScheme = "signin";
21+
o.AddScheme<SignInHandler>("B", "whatever");
2422
}).BuildServiceProvider();
2523

2624
var provider = services.GetRequiredService<IAuthenticationSchemeProvider>();
27-
var scheme = await provider.GetDefaultSignOutSchemeAsync();
28-
Assert.NotNull(scheme);
29-
Assert.Equal("signin", scheme.Name);
25+
Assert.Null(await provider.GetDefaultForbidSchemeAsync());
26+
Assert.Null(await provider.GetDefaultAuthenticateSchemeAsync());
27+
Assert.Null(await provider.GetDefaultChallengeSchemeAsync());
28+
Assert.Null(await provider.GetDefaultSignInSchemeAsync());
29+
Assert.Null(await provider.GetDefaultSignOutSchemeAsync());
3030
}
3131

3232
[Fact]
33-
public async Task DefaultForbidFallsbackToChallenge()
33+
public async Task DefaultSchemesFallbackToDefaultScheme()
3434
{
3535
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
3636
{
37-
o.AddScheme<Handler>("challenge", "whatever");
38-
o.AddScheme<Handler>("foobly", "whatever");
39-
o.DefaultChallengeScheme = "challenge";
37+
o.DefaultScheme = "B";
38+
o.AddScheme<SignInHandler>("B", "whatever");
4039
}).BuildServiceProvider();
4140

4241
var provider = services.GetRequiredService<IAuthenticationSchemeProvider>();
43-
var scheme = await provider.GetDefaultForbidSchemeAsync();
44-
Assert.NotNull(scheme);
45-
Assert.Equal("challenge", scheme.Name);
42+
Assert.Equal("B", (await provider.GetDefaultForbidSchemeAsync()).Name);
43+
Assert.Equal("B", (await provider.GetDefaultAuthenticateSchemeAsync()).Name);
44+
Assert.Equal("B", (await provider.GetDefaultChallengeSchemeAsync()).Name);
45+
Assert.Equal("B", (await provider.GetDefaultSignInSchemeAsync()).Name);
46+
Assert.Equal("B", (await provider.GetDefaultSignOutSchemeAsync()).Name);
4647
}
4748

49+
4850
[Fact]
49-
public async Task DefaultSchemesFallbackToOnlyScheme()
51+
public async Task DefaultSignOutFallsbackToSignIn()
5052
{
5153
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
5254
{
53-
o.AddScheme<SignInHandler>("single", "whatever");
55+
o.AddScheme<SignInHandler>("signin", "whatever");
56+
o.AddScheme<Handler>("foobly", "whatever");
57+
o.DefaultSignInScheme = "signin";
5458
}).BuildServiceProvider();
5559

5660
var provider = services.GetRequiredService<IAuthenticationSchemeProvider>();
57-
Assert.Equal("single", (await provider.GetDefaultForbidSchemeAsync()).Name);
58-
Assert.Equal("single", (await provider.GetDefaultAuthenticateSchemeAsync()).Name);
59-
Assert.Equal("single", (await provider.GetDefaultChallengeSchemeAsync()).Name);
60-
Assert.Equal("single", (await provider.GetDefaultSignInSchemeAsync()).Name);
61-
Assert.Equal("single", (await provider.GetDefaultSignOutSchemeAsync()).Name);
61+
var scheme = await provider.GetDefaultSignOutSchemeAsync();
62+
Assert.NotNull(scheme);
63+
Assert.Equal("signin", scheme.Name);
6264
}
6365

6466
[Fact]
65-
public async Task DefaultSchemesFallbackToAuthenticateScheme()
67+
public async Task DefaultForbidFallsbackToChallenge()
6668
{
6769
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
6870
{
69-
o.DefaultAuthenticateScheme = "B";
70-
o.AddScheme<Handler>("A", "whatever");
71-
o.AddScheme<SignInHandler>("B", "whatever");
71+
o.AddScheme<Handler>("challenge", "whatever");
72+
o.AddScheme<Handler>("foobly", "whatever");
73+
o.DefaultChallengeScheme = "challenge";
7274
}).BuildServiceProvider();
7375

7476
var provider = services.GetRequiredService<IAuthenticationSchemeProvider>();
75-
Assert.Equal("B", (await provider.GetDefaultForbidSchemeAsync()).Name);
76-
Assert.Equal("B", (await provider.GetDefaultAuthenticateSchemeAsync()).Name);
77-
Assert.Equal("B", (await provider.GetDefaultChallengeSchemeAsync()).Name);
78-
Assert.Equal("B", (await provider.GetDefaultSignInSchemeAsync()).Name);
79-
Assert.Equal("B", (await provider.GetDefaultSignOutSchemeAsync()).Name);
77+
var scheme = await provider.GetDefaultForbidSchemeAsync();
78+
Assert.NotNull(scheme);
79+
Assert.Equal("challenge", scheme.Name);
8080
}
8181

8282
[Fact]
@@ -87,6 +87,8 @@ public async Task DefaultSchemesAreSet()
8787
o.AddScheme<SignInHandler>("A", "whatever");
8888
o.AddScheme<SignInHandler>("B", "whatever");
8989
o.AddScheme<SignInHandler>("C", "whatever");
90+
o.AddScheme<SignInHandler>("Def", "whatever");
91+
o.DefaultScheme = "Def";
9092
o.DefaultChallengeScheme = "A";
9193
o.DefaultForbidScheme = "B";
9294
o.DefaultSignInScheme = "C";
@@ -102,25 +104,6 @@ public async Task DefaultSchemesAreSet()
102104
Assert.Equal("A", (await provider.GetDefaultSignOutSchemeAsync()).Name);
103105
}
104106

105-
[Fact]
106-
public async Task SignInSignOutDefaultsToOnlyOne()
107-
{
108-
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
109-
{
110-
o.AddScheme<Handler>("basic", "whatever");
111-
o.AddScheme<SignOutHandler>("signout", "whatever");
112-
o.AddScheme<SignInHandler>("signin", "whatever");
113-
o.DefaultAuthenticateScheme = "basic";
114-
}).BuildServiceProvider();
115-
116-
var provider = services.GetRequiredService<IAuthenticationSchemeProvider>();
117-
Assert.Equal("basic", (await provider.GetDefaultForbidSchemeAsync()).Name);
118-
Assert.Equal("basic", (await provider.GetDefaultAuthenticateSchemeAsync()).Name);
119-
Assert.Equal("basic", (await provider.GetDefaultChallengeSchemeAsync()).Name);
120-
Assert.Equal("signin", (await provider.GetDefaultSignInSchemeAsync()).Name);
121-
Assert.Equal("signin", (await provider.GetDefaultSignOutSchemeAsync()).Name); // Defaults to single sign in scheme
122-
}
123-
124107
[Fact]
125108
public async Task SignOutWillDefaultsToSignInThatDoesNotSignOut()
126109
{

0 commit comments

Comments
 (0)