Skip to content

Commit 1d87f65

Browse files
committed
(#181) Adding OpenIddict
1 parent 7a762f2 commit 1d87f65

File tree

22 files changed

+485
-109
lines changed

22 files changed

+485
-109
lines changed

src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Certs/CreateSelfSignedCertificate.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
$date_now = Get-Date
2-
$extended_date = $date_now.AddYears(3)
2+
$extended_date = $date_now.AddYears(10)
33
$cert = New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname classifiedads.identityserver -notafter $extended_date
44
$pwd = ConvertTo-SecureString -String 'password1234' -Force -AsPlainText
55
$path = 'cert:\localMachine\my\' + $cert.thumbprint

src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/ConfigurationOptions/IdentityServerOptions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ namespace ClassifiedAds.IdentityServer.ConfigurationOptions
44
{
55
public class IdentityServerOptions
66
{
7-
public CertificateOption Certificate { get; set; }
7+
public CertificateOption EncryptionCertificate { get; set; }
8+
9+
public CertificateOption SigningCertificate { get; set; }
810
}
911
}

src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Controllers/AuthorizationController.cs

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Microsoft.AspNetCore.Http;
55
using Microsoft.AspNetCore.Identity;
66
using Microsoft.AspNetCore.Mvc;
7+
using Microsoft.IdentityModel.Tokens;
78
using OpenIddict.Abstractions;
89
using OpenIddict.Server.AspNetCore;
910
using System;
@@ -16,10 +17,14 @@ namespace ClassifiedAds.IdentityServer.Controllers
1617
{
1718
public class AuthorizationController : Controller
1819
{
20+
private readonly UserManager<User> _userManager;
1921
private readonly SignInManager<User> _signInManager;
2022

21-
public AuthorizationController(SignInManager<User> signInManager)
23+
public AuthorizationController(
24+
UserManager<User> userManager,
25+
SignInManager<User> signInManager)
2226
{
27+
_userManager = userManager;
2328
_signInManager = signInManager;
2429
}
2530

@@ -69,8 +74,7 @@ public async Task<IActionResult> Authorize()
6974
[HttpPost("~/connect/token")]
7075
public async Task<IActionResult> Exchange()
7176
{
72-
var request = HttpContext.GetOpenIddictServerRequest() ??
73-
throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");
77+
var request = HttpContext.GetOpenIddictServerRequest() ?? throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");
7478

7579
ClaimsPrincipal claimsPrincipal;
7680

@@ -101,6 +105,57 @@ public async Task<IActionResult> Exchange()
101105
// Retrieve the claims principal stored in the refresh token.
102106
claimsPrincipal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal;
103107
}
108+
else if (request.IsPasswordGrantType())
109+
{
110+
var user = await _userManager.FindByNameAsync(request.Username);
111+
if (user == null)
112+
{
113+
var properties = new AuthenticationProperties(new Dictionary<string, string>
114+
{
115+
[OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
116+
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The username/password couple is invalid."
117+
});
118+
119+
return Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
120+
}
121+
122+
// Validate the username/password parameters and ensure the account is not locked out.
123+
var result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, lockoutOnFailure: true);
124+
if (!result.Succeeded)
125+
{
126+
var properties = new AuthenticationProperties(new Dictionary<string, string>
127+
{
128+
[OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
129+
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The username/password couple is invalid."
130+
});
131+
132+
return Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
133+
}
134+
135+
// Create the claims-based identity that will be used by OpenIddict to generate tokens.
136+
var identity = new ClaimsIdentity(
137+
authenticationType: TokenValidationParameters.DefaultAuthenticationType,
138+
nameType: OpenIddictConstants.Claims.Name,
139+
roleType: OpenIddictConstants.Claims.Role);
140+
141+
// Add the claims that will be persisted in the tokens.
142+
identity.SetClaim(OpenIddictConstants.Claims.Subject, await _userManager.GetUserIdAsync(user))
143+
.SetClaim(OpenIddictConstants.Claims.Email, await _userManager.GetEmailAsync(user))
144+
.SetClaim(OpenIddictConstants.Claims.Name, await _userManager.GetUserNameAsync(user));
145+
146+
// Set the list of scopes granted to the client application.
147+
identity.SetScopes(new[]
148+
{
149+
OpenIddictConstants.Scopes.OpenId,
150+
OpenIddictConstants.Scopes.Email,
151+
OpenIddictConstants.Scopes.Profile,
152+
OpenIddictConstants.Scopes.Roles
153+
}.Intersect(request.GetScopes()));
154+
155+
identity.SetDestinations(GetDestinations);
156+
157+
return SignIn(new ClaimsPrincipal(identity), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
158+
}
104159
else
105160
{
106161
throw new InvalidOperationException("The specified grant type is not supported.");
@@ -134,5 +189,51 @@ public async Task<IActionResult> LogoutPost()
134189
});
135190
}
136191

192+
private static IEnumerable<string> GetDestinations(Claim claim)
193+
{
194+
// Note: by default, claims are NOT automatically included in the access and identity tokens.
195+
// To allow OpenIddict to serialize them, you must attach them a destination, that specifies
196+
// whether they should be included in access tokens, in identity tokens or in both.
197+
198+
switch (claim.Type)
199+
{
200+
case OpenIddictConstants.Claims.Name:
201+
yield return OpenIddictConstants.Destinations.AccessToken;
202+
203+
if (claim.Subject.HasScope(OpenIddictConstants.Scopes.Profile))
204+
{
205+
yield return OpenIddictConstants.Destinations.IdentityToken;
206+
}
207+
208+
yield break;
209+
210+
case OpenIddictConstants.Claims.Email:
211+
yield return OpenIddictConstants.Destinations.AccessToken;
212+
213+
if (claim.Subject.HasScope(OpenIddictConstants.Scopes.Email))
214+
{
215+
yield return OpenIddictConstants.Destinations.IdentityToken;
216+
}
217+
218+
yield break;
219+
220+
case OpenIddictConstants.Claims.Role:
221+
yield return OpenIddictConstants.Destinations.AccessToken;
222+
223+
if (claim.Subject.HasScope(OpenIddictConstants.Scopes.Roles))
224+
{
225+
yield return OpenIddictConstants.Destinations.IdentityToken;
226+
}
227+
228+
yield break;
229+
230+
// Never include the security stamp in the access and identity tokens, as it's a secret value.
231+
case "AspNet.Identity.SecurityStamp": yield break;
232+
233+
default:
234+
yield return OpenIddictConstants.Destinations.AccessToken;
235+
yield break;
236+
}
237+
}
137238
}
138239
}

src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Extensions/PrincipalExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using IdentityModel;
1+
using OpenIddict.Abstractions;
22
using System.Security.Claims;
33

44
namespace ClassifiedAds.IdentityServer.Extensions
@@ -13,7 +13,7 @@ public static string GetDisplayName(this ClaimsPrincipal principal)
1313
return name;
1414
}
1515

16-
var sub = principal.FindFirst(JwtClaimTypes.Subject);
16+
var sub = principal.FindFirst(OpenIddictConstants.Claims.Subject);
1717
if (sub != null)
1818
{
1919
return sub.Value;

0 commit comments

Comments
 (0)