Skip to content

Commit 8925dfd

Browse files
committed
Added OpenID Connect user authentication.
1 parent dea3490 commit 8925dfd

35 files changed

+338
-151
lines changed

AppCore.Extensions.sln

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkerService", "Http\sampl
6464
EndProject
6565
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppCore.Extensions.Http.Authentication.OAuth.AspNetCore", "Http\src\AppCore.Extensions.Http.Authentication.OAuth.AspNetCore\AppCore.Extensions.Http.Authentication.OAuth.AspNetCore.csproj", "{9301436D-85F6-4845-AAD6-33103F49F018}"
6666
EndProject
67-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppCore.Extensions.Http.Authentication.OAuth.AspNetCore.OpenIdConnect", "Http\src\AppCore.Extensions.Http.Authentication.OAuth.AspNetCore.OpenIdConnect\AppCore.Extensions.Http.Authentication.OAuth.AspNetCore.OpenIdConnect.csproj", "{91754F75-CC7A-48C8-A133-9F087BE10CFE}"
67+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppCore.Extensions.Http.Authentication.OAuth.OpenIdConnect", "Http\src\AppCore.Extensions.Http.Authentication.OAuth.OpenIdConnect\AppCore.Extensions.Http.Authentication.OAuth.OpenIdConnect.csproj", "{91754F75-CC7A-48C8-A133-9F087BE10CFE}"
6868
EndProject
6969
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "Http\samples\Web\Web.csproj", "{7D72ABA6-5EBE-491A-A599-65D15FD10308}"
7070
EndProject

Http/samples/Web/Web.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
</PropertyGroup>
77

88
<ItemGroup>
9-
<ProjectReference Include="..\..\src\AppCore.Extensions.Http.Authentication.OAuth.AspNetCore.OpenIdConnect\AppCore.Extensions.Http.Authentication.OAuth.AspNetCore.OpenIdConnect.csproj" />
9+
<ProjectReference Include="..\..\src\AppCore.Extensions.Http.Authentication.OAuth.OpenIdConnect\AppCore.Extensions.Http.Authentication.OAuth.OpenIdConnect.csproj" />
1010
</ItemGroup>
1111

1212
</Project>

Http/src/AppCore.Extensions.Http.Authentication.OAuth.AspNetCore.OpenIdConnect/OpenIdConnectUserHandler.cs

Lines changed: 0 additions & 13 deletions
This file was deleted.

Http/src/AppCore.Extensions.Http.Authentication.OAuth.AspNetCore.OpenIdConnect/OpenIdConnectUserOptions.cs

Lines changed: 0 additions & 8 deletions
This file was deleted.

Http/src/AppCore.Extensions.Http.Authentication.OAuth.AspNetCore.OpenIdConnect/OpenIdConnectUserParameters.cs

Lines changed: 0 additions & 5 deletions
This file was deleted.

Http/src/AppCore.Extensions.Http.Authentication.OAuth.AspNetCore.OpenIdConnect/OpenIdConnectUserTokenService.cs

Lines changed: 0 additions & 25 deletions
This file was deleted.

Http/src/AppCore.Extensions.Http.Authentication.OAuth.AspNetCore/AuthenticationSessionOAuthUserTokenStore.cs

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using System.Collections.Generic;
1+
// Licensed under the MIT License.
2+
// Copyright (c) 2018-2022 the AppCore .NET project.
3+
4+
using System.Collections.Generic;
25
using System.Security.Authentication;
36
using System.Security.Claims;
47
using System.Threading;
@@ -12,6 +15,11 @@
1215

1316
namespace AppCore.Extensions.Http.Authentication.OAuth.AspNetCore;
1417

18+
/// <summary>
19+
/// Provides the base class for <see cref="IOAuthUserTokenStore"/> which stores tokens in the authentication
20+
/// session.
21+
/// </summary>
22+
/// <typeparam name="TOptions">The type of the <see cref="OAuthUserOptions"/>.</typeparam>
1523
public abstract class AuthenticationSessionOAuthUserTokenStore<TOptions> : IOAuthUserTokenStore
1624
where TOptions : OAuthUserOptions
1725
{
@@ -23,6 +31,12 @@ public abstract class AuthenticationSessionOAuthUserTokenStore<TOptions> : IOAut
2331
// this requires this service to be added as scoped to the DI system
2432
private readonly Dictionary<string, AuthenticateResult> _cache = new();
2533

34+
/// <summary>
35+
/// Initializes a new instance of the <see cref="AuthenticationSessionOAuthUserTokenStore{TOptions}"/> class.
36+
/// </summary>
37+
/// <param name="httpContextAccessor">The <see cref="IHttpContextAccessor"/>.</param>
38+
/// <param name="optionsMonitor">The <see cref="IOptionsMonitor{TOptions}"/>.</param>
39+
/// <param name="logger">The <see cref="ILogger{TCategoryName}"/>.</param>
2640
protected AuthenticationSessionOAuthUserTokenStore(
2741
IHttpContextAccessor httpContextAccessor,
2842
IOptionsMonitor<TOptions> optionsMonitor,
@@ -67,7 +81,7 @@ private async Task<string> GetSignInScheme(HttpContext context, TOptions options
6781
return scheme;
6882
}
6983

70-
private async Task<AuthenticateResult?> TryAuthenticateAsync(HttpContext httpContext, string signInScheme, TOptions options)
84+
private async Task<AuthenticateResult?> TryAuthenticateAsync(HttpContext httpContext, string signInScheme)
7185
{
7286
// check the cache in case the token was re-issued via StoreTokenAsync
7387
if (!_cache.TryGetValue(signInScheme, out AuthenticateResult? result))
@@ -92,13 +106,17 @@ private async Task<string> GetSignInScheme(HttpContext context, TOptions options
92106
return result;
93107
}
94108

109+
/// <summary>
110+
/// Ensures that the <paramref name="scheme"/> is compatible.
111+
/// </summary>
112+
/// <param name="scheme">The <see cref="AuthenticationScheme"/>.</param>
95113
protected abstract void EnsureCompatibleScheme(AuthenticationScheme scheme);
96114

115+
/// <inheritdoc />
97116
public async Task StoreTokenAsync(
98117
AuthenticationScheme scheme,
99118
ClaimsPrincipal user,
100119
OAuthUserToken token,
101-
OAuthUserParameters? parameters = null,
102120
CancellationToken cancellationToken = default)
103121
{
104122
Ensure.Arg.NotNull(scheme);
@@ -111,12 +129,12 @@ public async Task StoreTokenAsync(
111129
TOptions options = _optionsMonitor.Get(scheme.Name);
112130
string signInScheme = await GetSignInScheme(httpContext, options);
113131

114-
AuthenticateResult? result = await TryAuthenticateAsync(httpContext, signInScheme, options);
132+
AuthenticateResult? result = await TryAuthenticateAsync(httpContext, signInScheme);
115133
if (result == null)
116134
throw new AuthenticationException("User is not authenticated, cannot store tokens.");
117135

118136
ClaimsPrincipal principal = result.Principal!;
119-
SetUserToken(principal, result.Properties!, token, options);
137+
StoreToken(principal, result.Properties!, token, options);
120138

121139
if (result.Properties!.AllowRefresh.GetValueOrDefault(true))
122140
{
@@ -128,16 +146,23 @@ public async Task StoreTokenAsync(
128146
_cache[signInScheme] = AuthenticateResult.Success(new AuthenticationTicket(principal, result.Properties, signInScheme));
129147
}
130148

131-
protected abstract void SetUserToken(
149+
/// <summary>
150+
/// Stores the token in the authentication session.
151+
/// </summary>
152+
/// <param name="principal"></param>
153+
/// <param name="properties"></param>
154+
/// <param name="token"></param>
155+
/// <param name="options"></param>
156+
protected abstract void StoreToken(
132157
ClaimsPrincipal principal,
133158
AuthenticationProperties properties,
134159
OAuthUserToken token,
135160
TOptions options);
136161

162+
/// <inheritdoc />
137163
public async Task<OAuthUserToken> GetTokenAsync(
138164
AuthenticationScheme scheme,
139165
ClaimsPrincipal user,
140-
OAuthUserParameters? parameters = null,
141166
CancellationToken cancellationToken = default)
142167
{
143168
Ensure.Arg.NotNull(scheme);
@@ -149,22 +174,29 @@ public async Task<OAuthUserToken> GetTokenAsync(
149174
TOptions options = _optionsMonitor.Get(scheme.Name);
150175
string signInScheme = await GetSignInScheme(httpContext, options);
151176

152-
AuthenticateResult? result = await TryAuthenticateAsync(httpContext, signInScheme, options);
177+
AuthenticateResult? result = await TryAuthenticateAsync(httpContext, signInScheme);
153178
if (result == null)
154179
throw new AuthenticationException("User is not authenticated, cannot get tokens.");
155180

156-
return GetUserToken(result.Principal!, result.Properties!, options);
181+
return GetToken(result.Principal!, result.Properties!, options);
157182
}
158183

159-
protected abstract OAuthUserToken GetUserToken(
184+
/// <summary>
185+
/// Gets the token from the authentication session.
186+
/// </summary>
187+
/// <param name="principal"></param>
188+
/// <param name="properties"></param>
189+
/// <param name="options"></param>
190+
/// <returns></returns>
191+
protected abstract OAuthUserToken GetToken(
160192
ClaimsPrincipal principal,
161193
AuthenticationProperties properties,
162194
TOptions options);
163195

196+
/// <inheritdoc />
164197
public Task ClearTokenAsync(
165198
AuthenticationScheme scheme,
166199
ClaimsPrincipal user,
167-
OAuthUserParameters? parameters = null,
168200
CancellationToken cancellationToken = default)
169201
{
170202
Ensure.Arg.NotNull(scheme);

Http/src/AppCore.Extensions.Http.Authentication.OAuth.AspNetCore/IOAuthUserTokenService.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,9 @@ Task<OAuthUserToken> GetAccessTokenAsync(
3232
/// </summary>
3333
/// <param name="scheme">The <see cref="AuthenticationScheme"/>.</param>
3434
/// <param name="user">The user.</param>
35-
/// <param name="parameters">Optional parameters.</param>
3635
/// <param name="cancellationToken"></param>
3736
Task RevokeRefreshTokenAsync(
3837
AuthenticationScheme scheme,
3938
ClaimsPrincipal user,
40-
OAuthUserParameters? parameters = null,
4139
CancellationToken cancellationToken = default);
4240
}
Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,49 @@
1-
using System.Security.Claims;
1+
// Licensed under the MIT License.
2+
// Copyright (c) 2018-2022 the AppCore .NET project.
3+
4+
using System.Security.Claims;
25
using System.Threading;
36
using System.Threading.Tasks;
47

58
namespace AppCore.Extensions.Http.Authentication.OAuth.AspNetCore;
69

10+
/// <summary>
11+
/// Abstraction for the OAuth user token store.
12+
/// </summary>
713
public interface IOAuthUserTokenStore
814
{
15+
/// <summary>
16+
/// Stores the token for the specified authentication scheme and user.
17+
/// </summary>
18+
/// <param name="scheme">The <see cref="AuthenticationScheme"/>.</param>
19+
/// <param name="user">The <see cref="ClaimsPrincipal"/>.</param>
20+
/// <param name="token">The <see cref="OAuthUserToken"/>.</param>
21+
/// <param name="cancellationToken">Optional <see cref="CancellationToken"/>.</param>
922
Task StoreTokenAsync(
1023
AuthenticationScheme scheme,
1124
ClaimsPrincipal user,
1225
OAuthUserToken token,
13-
OAuthUserParameters? parameters = null,
1426
CancellationToken cancellationToken = default);
1527

28+
/// <summary>
29+
/// Gets the token for the specified authentication scheme and user.
30+
/// </summary>
31+
/// <param name="scheme">The <see cref="AuthenticationScheme"/>.</param>
32+
/// <param name="user">The <see cref="ClaimsPrincipal"/>.</param>
33+
/// <param name="cancellationToken">Optional <see cref="CancellationToken"/>.</param>
1634
Task<OAuthUserToken> GetTokenAsync(
1735
AuthenticationScheme scheme,
1836
ClaimsPrincipal user,
19-
OAuthUserParameters? parameters = null,
2037
CancellationToken cancellationToken = default);
2138

39+
/// <summary>
40+
/// Clears the token for the specified authentication scheme and user.
41+
/// </summary>
42+
/// <param name="scheme">The <see cref="AuthenticationScheme"/>.</param>
43+
/// <param name="user">The <see cref="ClaimsPrincipal"/>.</param>
44+
/// <param name="cancellationToken">Optional <see cref="CancellationToken"/>.</param>
2245
Task ClearTokenAsync(
2346
AuthenticationScheme scheme,
2447
ClaimsPrincipal user,
25-
OAuthUserParameters? parameters = null,
2648
CancellationToken cancellationToken = default);
2749
}

Http/src/AppCore.Extensions.Http.Authentication.OAuth.AspNetCore/OAuthUserHandler.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using System.Net.Http;
1+
// Licensed under the MIT License.
2+
// Copyright (c) 2018-2022 the AppCore .NET project.
3+
4+
using System.Net.Http;
25
using System.Net.Http.Headers;
36
using System.Security.Authentication;
47
using System.Security.Claims;
@@ -10,7 +13,7 @@
1013
namespace AppCore.Extensions.Http.Authentication.OAuth.AspNetCore;
1114

1215
/// <summary>
13-
/// Provides a OAuth user authentication handler.
16+
/// Provides a base class for a OAuth user authentication handler.
1417
/// </summary>
1518
public abstract class OAuthUserHandler<TParameters> : IAuthenticationSchemeHandler<TParameters>
1619
where TParameters : OAuthUserParameters
@@ -32,13 +35,24 @@ protected OAuthUserHandler(IHttpContextAccessor httpContextAccessor, IOAuthUserT
3235
_authTokenService = authTokenService;
3336
}
3437

38+
/// <summary>
39+
/// Ensures that the <paramref name="scheme"/> is compatible.
40+
/// </summary>
41+
/// <param name="scheme">The <see cref="AuthenticationScheme"/>.</param>
42+
protected abstract void EnsureCompatibleScheme(AuthenticationScheme scheme);
43+
3544
/// <inheritdoc />
3645
public async Task AuthenticateAsync(
3746
AuthenticationScheme scheme,
38-
TParameters? parameters,
3947
HttpRequestMessage request,
48+
TParameters? parameters = null,
4049
CancellationToken cancellationToken = default)
4150
{
51+
Ensure.Arg.NotNull(scheme);
52+
Ensure.Arg.NotNull(request);
53+
54+
EnsureCompatibleScheme(scheme);
55+
4256
ClaimsPrincipal? user = _httpContextAccessor.HttpContext?.User;
4357
if (user == null)
4458
throw new AuthenticationException("User is not authenticated.");

0 commit comments

Comments
 (0)