Skip to content

Commit

Permalink
Bump OpenIddict to 4.7.0
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinchalet committed Aug 9, 2023
1 parent eb5cc20 commit cb72e02
Show file tree
Hide file tree
Showing 10 changed files with 244 additions and 107 deletions.
20 changes: 10 additions & 10 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
<PackageVersion Include="Microsoft.Owin.Security.OpenIdConnect" Version="4.2.2" />
<PackageVersion Include="Microsoft.Owin.Security.Twitter" Version="4.2.2" />
<PackageVersion Include="Microsoft.Web.Infrastructure" Version="1.0.0" />
<PackageVersion Include="OpenIddict.EntityFramework" Version="4.6.0" />
<PackageVersion Include="OpenIddict.Owin" Version="4.6.0" />
<PackageVersion Include="OpenIddict.EntityFramework" Version="4.7.0" />
<PackageVersion Include="OpenIddict.Owin" Version="4.7.0" />
<PackageVersion Include="WebGrease" Version="1.6.0" />
</ItemGroup>

Expand Down Expand Up @@ -80,14 +80,14 @@
<PackageVersion Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.6" />
<PackageVersion Include="OpenIddict.Abstractions" Version="4.6.0" />
<PackageVersion Include="OpenIddict.AspNetCore" Version="4.6.0" />
<PackageVersion Include="OpenIddict.Client.SystemIntegration" Version="4.6.0" />
<PackageVersion Include="OpenIddict.Client.SystemNetHttp" Version="4.6.0" />
<PackageVersion Include="OpenIddict.EntityFrameworkCore" Version="4.6.0" />
<PackageVersion Include="OpenIddict.Quartz" Version="4.6.0" />
<PackageVersion Include="OpenIddict.Validation.AspNetCore" Version="4.6.0" />
<PackageVersion Include="OpenIddict.Validation.SystemNetHttp" Version="4.6.0" />
<PackageVersion Include="OpenIddict.Abstractions" Version="4.7.0" />
<PackageVersion Include="OpenIddict.AspNetCore" Version="4.7.0" />
<PackageVersion Include="OpenIddict.Client.SystemIntegration" Version="4.7.0" />
<PackageVersion Include="OpenIddict.Client.SystemNetHttp" Version="4.7.0" />
<PackageVersion Include="OpenIddict.EntityFrameworkCore" Version="4.7.0" />
<PackageVersion Include="OpenIddict.Quartz" Version="4.7.0" />
<PackageVersion Include="OpenIddict.Validation.AspNetCore" Version="4.7.0" />
<PackageVersion Include="OpenIddict.Validation.SystemNetHttp" Version="4.7.0" />
<PackageVersion Include="Quartz.Extensions.Hosting" Version="3.5.0" />
<PackageVersion Include="Spectre.Console" Version="0.46.0" />
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ public async Task<IActionResult> Authorize()
// - If the user principal can't be extracted or the cookie is too old.
// - If prompt=login was specified by the client application.
// - If a max_age parameter was provided and the authentication cookie is not considered "fresh" enough.
var result = await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme);
//
// For scenarios where the default authentication handler configured in the ASP.NET Core
// authentication options shouldn't be used, a specific scheme can be specified here.
var result = await HttpContext.AuthenticateAsync();
if (result == null || !result.Succeeded || request.HasPrompt(Prompts.Login) ||
(request.MaxAge != null && result.Properties?.IssuedUtc != null &&
DateTimeOffset.UtcNow - result.Properties.IssuedUtc > TimeSpan.FromSeconds(request.MaxAge.Value)))
Expand Down Expand Up @@ -85,12 +88,12 @@ public async Task<IActionResult> Authorize()

parameters.Add(KeyValuePair.Create(Parameters.Prompt, new StringValues(prompt)));

return Challenge(
authenticationSchemes: IdentityConstants.ApplicationScheme,
properties: new AuthenticationProperties
{
RedirectUri = Request.PathBase + Request.Path + QueryString.Create(parameters)
});
// For scenarios where the default challenge handler configured in the ASP.NET Core
// authentication options shouldn't be used, a specific scheme can be specified here.
return Challenge(new AuthenticationProperties
{
RedirectUri = Request.PathBase + Request.Path + QueryString.Create(parameters)
});
}

// Retrieve the profile of the logged in user.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ public async Task<IActionResult> Authorize()
// - If the user principal can't be extracted or the cookie is too old.
// - If prompt=login was specified by the client application.
// - If a max_age parameter was provided and the authentication cookie is not considered "fresh" enough.
var result = await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme);
//
// For scenarios where the default authentication handler configured in the ASP.NET Core
// authentication options shouldn't be used, a specific scheme can be specified here.
var result = await HttpContext.AuthenticateAsync();
if (result == null || !result.Succeeded || request.HasPrompt(Prompts.Login) ||
(request.MaxAge != null && result.Properties?.IssuedUtc != null &&
DateTimeOffset.UtcNow - result.Properties.IssuedUtc > TimeSpan.FromSeconds(request.MaxAge.Value)))
Expand Down Expand Up @@ -85,12 +88,12 @@ public async Task<IActionResult> Authorize()

parameters.Add(KeyValuePair.Create(Parameters.Prompt, new StringValues(prompt)));

return Challenge(
authenticationSchemes: IdentityConstants.ApplicationScheme,
properties: new AuthenticationProperties
{
RedirectUri = Request.PathBase + Request.Path + QueryString.Create(parameters)
});
// For scenarios where the default challenge handler configured in the ASP.NET Core
// authentication options shouldn't be used, a specific scheme can be specified here.
return Challenge(new AuthenticationProperties
{
RedirectUri = Request.PathBase + Request.Path + QueryString.Create(parameters)
});
}

// Retrieve the profile of the logged in user.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
using OpenIddict.Abstractions;
using OpenIddict.Client.AspNetCore;
using static OpenIddict.Abstractions.OpenIddictConstants;

Expand All @@ -31,15 +32,21 @@ public async Task<ActionResult> LogOut(string returnUrl)
{
// Retrieve the identity stored in the local authentication cookie. If it's not available,
// this indicate that the user is already logged out locally (or has not logged in yet).
var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
//
// For scenarios where the default authentication handler configured in the ASP.NET Core
// authentication options shouldn't be used, a specific scheme can be specified here.
var result = await HttpContext.AuthenticateAsync();
if (result is not { Succeeded: true })
{
// Only allow local return URLs to prevent open redirect attacks.
return Redirect(Url.IsLocalUrl(returnUrl) ? returnUrl : "/");
}

// Remove the local authentication cookie before triggering a redirection to the remote server.
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
//
// For scenarios where the default sign-out handler configured in the ASP.NET Core
// authentication options shouldn't be used, a specific scheme can be specified here.
await HttpContext.SignOutAsync();

var properties = new AuthenticationProperties(new Dictionary<string, string>
{
Expand Down Expand Up @@ -93,47 +100,32 @@ public async Task<ActionResult> LogInCallback()
// Such identities cannot be used as-is to build an authentication cookie in ASP.NET Core (as the
// antiforgery stack requires at least a name claim to bind CSRF cookies to the user's identity) but
// the access/refresh tokens can be retrieved using result.Properties.GetTokens() to make API calls.
if (result.Principal.Identity is not ClaimsIdentity { IsAuthenticated: true })
if (result.Principal is not ClaimsPrincipal { Identity.IsAuthenticated: true })
{
throw new InvalidOperationException("The external authorization data cannot be used for authentication.");
}

// Build an identity based on the external claims and that will be used to create the authentication cookie.
//
// By default, all claims extracted during the authorization dance are available. The claims collection stored
// in the cookie can be filtered out or mapped to different names depending the claim name or its issuer.
var claims = new List<Claim>(result.Principal.Claims
.Select(claim => claim switch
{
// Map the standard "sub" and custom "id" claims to ClaimTypes.NameIdentifier, which is
// the default claim type used by .NET and is required by the antiforgery components.
{ Type: Claims.Subject }
=> new Claim(ClaimTypes.NameIdentifier, claim.Value, claim.ValueType, claim.Issuer),
// Map the standard "name" claim to ClaimTypes.Name.
{ Type: Claims.Name }
=> new Claim(ClaimTypes.Name, claim.Value, claim.ValueType, claim.Issuer),
_ => claim
})
.Where(claim => claim switch
{
// Preserve the basic claims that are necessary for the application to work correctly.
{ Type: ClaimTypes.NameIdentifier or ClaimTypes.Name } => true,
var identity = new ClaimsIdentity(authenticationType: "ExternalLogin");

// Don't preserve the other claims.
_ => false
}));
// By default, OpenIddict will automatically try to map the email/name and name identifier claims from
// their standard OpenID Connect or provider-specific equivalent, if available. If needed, additional
// claims can be resolved from the external identity and copied to the final authentication cookie.
identity.SetClaim(ClaimTypes.Email, result.Principal.GetClaim(ClaimTypes.Email))
.SetClaim(ClaimTypes.Name, result.Principal.GetClaim(ClaimTypes.Name))
.SetClaim(ClaimTypes.NameIdentifier, result.Principal.GetClaim(ClaimTypes.NameIdentifier));

var identity = new ClaimsIdentity(claims,
authenticationType: CookieAuthenticationDefaults.AuthenticationScheme,
nameType: ClaimTypes.Name,
roleType: ClaimTypes.Role);
// Preserve the registration identifier to be able to resolve it later.
identity.SetClaim(Claims.Private.RegistrationId, result.Principal.GetClaim(Claims.Private.RegistrationId));

// Build the authentication properties based on the properties that were added when the challenge was triggered.
var properties = new AuthenticationProperties(result.Properties.Items);
var properties = new AuthenticationProperties(result.Properties.Items)
{
RedirectUri = result.Properties.RedirectUri ?? "/"
};

// If needed, the tokens returned by the authorization server can be stored in the authentication cookie.
//
// To make cookies less heavy, tokens that are not used are filtered out before creating the cookie.
properties.StoreTokens(result.Properties.GetTokens().Where(token => token switch
{
Expand All @@ -148,9 +140,12 @@ OpenIddictClientAspNetCoreConstants.Tokens.BackchannelIdentityToken or
_ => false
}));

// Ask the cookie authentication handler to return a new cookie and redirect
// the user agent to the return URL stored in the authentication properties.
return SignIn(new ClaimsPrincipal(identity), properties, CookieAuthenticationDefaults.AuthenticationScheme);
// Ask the default sign-in handler to return a new cookie and redirect the
// user agent to the return URL stored in the authentication properties.
//
// For scenarios where the default sign-in handler configured in the ASP.NET Core
// authentication options shouldn't be used, a specific scheme can be specified here.
return SignIn(new ClaimsPrincipal(identity), properties);
}

// Note: this controller uses the same callback action for all providers
Expand Down
11 changes: 8 additions & 3 deletions samples/Mimban/Mimban.Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,22 +157,27 @@ await manager.CreateAsync(new OpenIddictApplicationDescriptor
// Resolve the claims extracted by OpenIddict from the userinfo response returned by GitHub.
var result = await context.AuthenticateAsync(OpenIddictClientAspNetCoreDefaults.AuthenticationScheme);
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
var identity = new ClaimsIdentity(authenticationType: "ExternalLogin");
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, result.Principal!.FindFirst("id")!.Value));
var properties = new AuthenticationProperties
{
RedirectUri = result.Properties!.RedirectUri
};
return Results.SignIn(new ClaimsPrincipal(identity), properties, CookieAuthenticationDefaults.AuthenticationScheme);
// For scenarios where the default sign-in handler configured in the ASP.NET Core
// authentication options shouldn't be used, a specific scheme can be specified here.
return Results.SignIn(new ClaimsPrincipal(identity), properties);
});

app.MapGet("/authorize", async (HttpContext context) =>
{
// Resolve the claims stored in the cookie created after the GitHub authentication dance.
// If the principal cannot be found, trigger a new challenge to redirect the user to GitHub.
var principal = (await context.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme))?.Principal;
//
// For scenarios where the default authentication handler configured in the ASP.NET Core
// authentication options shouldn't be used, a specific scheme can be specified here.
var principal = (await context.AuthenticateAsync())?.Principal;
if (principal is null)
{
var properties = new AuthenticationProperties
Expand Down
Loading

0 comments on commit cb72e02

Please sign in to comment.