@ -24,229 +24,106 @@ using OpenIddict.Server.Owin;
using Owin ;
using static OpenIddict . Abstractions . OpenIddictConstants ;
namespace OpenIddict.Sandbox.AspNet.Server.Controllers
namespace OpenIddict.Sandbox.AspNet.Server.Controllers ;
public class AuthorizationController : Controller
{
public class AuthorizationController : Controller
private readonly IOpenIddictApplicationManager _ applicationManager ;
private readonly IOpenIddictAuthorizationManager _ authorizationManager ;
private readonly OpenIddictClientService _ clientService ;
private readonly IOpenIddictScopeManager _ scopeManager ;
public AuthorizationController (
IOpenIddictApplicationManager applicationManager ,
IOpenIddictAuthorizationManager authorizationManager ,
OpenIddictClientService clientService ,
IOpenIddictScopeManager scopeManager )
{
private readonly IOpenIddictApplicationManager _ applicationManager ;
private readonly IOpenIddictAuthorizationManager _ authorizationManager ;
private readonly OpenIddictClientService _ clientService ;
private readonly IOpenIddictScopeManager _ scopeManager ;
public AuthorizationController (
IOpenIddictApplicationManager applicationManager ,
IOpenIddictAuthorizationManager authorizationManager ,
OpenIddictClientService clientService ,
IOpenIddictScopeManager scopeManager )
{
_ applicationManager = applicationManager ;
_ authorizationManager = authorizationManager ;
_ clientService = clientService ;
_ scopeManager = scopeManager ;
}
_ applicationManager = applicationManager ;
_ authorizationManager = authorizationManager ;
_ clientService = clientService ;
_ scopeManager = scopeManager ;
}
[HttpGet, Route("~/connect/authorize")]
public async Task < ActionResult > Authorize ( )
[HttpGet, Route("~/connect/authorize")]
public async Task < ActionResult > Authorize ( )
{
var context = HttpContext . GetOwinContext ( ) ;
var request = context . GetOpenIddictServerRequest ( ) ? ?
throw new InvalidOperationException ( "The OpenID Connect request cannot be retrieved." ) ;
// Retrieve the user principal stored in the authentication cookie.
// If a max_age parameter was provided, ensure that the cookie is not too old.
// If the user principal can't be extracted or the cookie is too old, redirect the user to the login page.
var result = await context . Authentication . AuthenticateAsync ( DefaultAuthenticationTypes . ApplicationCookie ) ;
if ( result ? . Identity = = null | | ( request . MaxAge ! = null & & result . Properties ? . IssuedUtc ! = null & &
DateTimeOffset . UtcNow - result . Properties . IssuedUtc > TimeSpan . FromSeconds ( request . MaxAge . Value ) ) )
{
var context = HttpContext . GetOwinContext ( ) ;
var request = context . GetOpenIddictServerRequest ( ) ? ?
throw new InvalidOperationException ( "The OpenID Connect request cannot be retrieved." ) ;
// Retrieve the user principal stored in the authentication cookie.
// If a max_age parameter was provided, ensure that the cookie is not too old.
// If the user principal can't be extracted or the cookie is too old, redirect the user to the login page.
var result = await context . Authentication . AuthenticateAsync ( DefaultAuthenticationTypes . ApplicationCookie ) ;
if ( result ? . Identity = = null | | ( request . MaxAge ! = null & & result . Properties ? . IssuedUtc ! = null & &
DateTimeOffset . UtcNow - result . Properties . IssuedUtc > TimeSpan . FromSeconds ( request . MaxAge . Value ) ) )
// For applications that want to allow the client to select the external authentication provider
// that will be used to authenticate the user, the identity_provider parameter can be used for that.
if ( ! string . IsNullOrEmpty ( request . IdentityProvider ) )
{
// For applications that want to allow the client to select the external authentication provider
// that will be used to authenticate the user, the identity_provider parameter can be used for that.
if ( ! string . IsNullOrEmpty ( request . IdentityProvider ) )
var registrations = await _ clientService . GetClientRegistrationsAsync ( ) ;
if ( ! registrations . Any ( registration = > string . Equals ( registration . ProviderName ,
request . IdentityProvider , StringComparison . Ordinal ) ) )
{
var registrations = await _ clientService . GetClientRegistrationsAsync ( ) ;
if ( ! registrations . Any ( registration = > string . Equals ( registration . ProviderName ,
request . IdentityProvider , StringComparison . Ordinal ) ) )
{
context . Authentication . Challenge (
authenticationTypes : OpenIddictServerOwinDefaults . AuthenticationType ,
properties : new AuthenticationProperties ( new Dictionary < string , string >
{
[OpenIddictServerOwinConstants.Properties.Error] = Errors . InvalidRequest ,
[OpenIddictServerOwinConstants.Properties.ErrorDescription] =
"The specified identity provider is not valid."
} ) ) ;
return new EmptyResult ( ) ;
}
var properties = new AuthenticationProperties ( new Dictionary < string , string >
{
// Note: when only one client is registered in the client options,
// specifying the issuer URI or the provider name is not required.
[OpenIddictClientOwinConstants.Properties.ProviderName] = request . IdentityProvider
} )
{
// Once the callback is handled, redirect the user agent to the ASP.NET Identity
// page responsible for showing the external login confirmation form if necessary.
RedirectUri = Url . Action ( "ExternalLoginCallback" , "Account" , new
{
ReturnUrl = Request . RawUrl
} )
} ;
// Ask the OpenIddict client middleware to redirect the user agent to the identity provider.
context . Authentication . Challenge ( properties , OpenIddictClientOwinDefaults . AuthenticationType ) ;
return new EmptyResult ( ) ;
}
context . Authentication . Challenge ( DefaultAuthenticationTypes . ApplicationCookie ) ;
return new EmptyResult ( ) ;
}
// Retrieve the profile of the logged in user.
var user = await context . GetUserManager < ApplicationUserManager > ( ) . FindByIdAsync ( result . Identity . GetUserId ( ) ) ? ?
throw new InvalidOperationException ( "The user details cannot be retrieved." ) ;
// Retrieve the application details from the database.
var application = await _ applicationManager . FindByClientIdAsync ( request . ClientId ) ? ?
throw new InvalidOperationException ( "Details concerning the calling client application cannot be found." ) ;
// Retrieve the permanent authorizations associated with the user and the calling client application.
var authorizations = await _ authorizationManager . FindAsync (
subject : user . Id ,
client : await _ applicationManager . GetIdAsync ( application ) ,
status : Statuses . Valid ,
type : AuthorizationTypes . Permanent ,
scopes : request . GetScopes ( ) ) . ToListAsync ( ) ;
switch ( await _ applicationManager . GetConsentTypeAsync ( application ) )
{
// If the consent is external (e.g when authorizations are granted by a sysadmin),
// immediately return an error if no authorization can be found in the database.
case ConsentTypes . External when authorizations . Count is 0 :
context . Authentication . Challenge (
authenticationTypes : OpenIddictServerOwinDefaults . AuthenticationType ,
properties : new AuthenticationProperties ( new Dictionary < string , string >
{
[OpenIddictServerOwinConstants.Properties.Error] = Errors . ConsentRequired ,
[OpenIddictServerOwinConstants.Properties.Error] = Errors . InvalidRequest ,
[OpenIddictServerOwinConstants.Properties.ErrorDescription] =
"The logged in user is not allowed to access this client application."
} ) ) ;
return new EmptyResult ( ) ;
// If the consent is implicit or if an authorization was found,
// return an authorization response without displaying the consent form.
case ConsentTypes . Implicit :
case ConsentTypes . External when authorizations . Count is not 0 :
case ConsentTypes . Explicit when authorizations . Count is not 0 & & ! request . HasPrompt ( Prompts . Consent ) :
// Create the claims-based identity that will be used by OpenIddict to generate tokens.
var identity = new ClaimsIdentity (
authenticationType : OpenIddictServerOwinDefaults . AuthenticationType ,
nameType : Claims . Name ,
roleType : Claims . Role ) ;
// Add the claims that will be persisted in the tokens.
identity . SetClaim ( Claims . Subject , user . Id )
. SetClaim ( Claims . Email , user . Email )
. SetClaim ( Claims . Name , user . UserName )
. SetClaim ( Claims . PreferredUsername , user . UserName )
. SetClaims ( Claims . Role , ( await context . Get < ApplicationUserManager > ( ) . GetRolesAsync ( user . Id ) ) . ToImmutableArray ( ) ) ;
// Note: in this sample, the granted scopes match the requested scope
// but you may want to allow the user to uncheck specific scopes.
// For that, simply restrict the list of scopes before calling SetScopes.
identity . SetScopes ( request . GetScopes ( ) ) ;
identity . SetResources ( await _ scopeManager . ListResourcesAsync ( identity . GetScopes ( ) ) . ToListAsync ( ) ) ;
// Automatically create a permanent authorization to avoid requiring explicit consent
// for future authorization or token requests containing the same scopes.
var authorization = authorizations . LastOrDefault ( ) ;
authorization ? ? = await _ authorizationManager . CreateAsync (
identity : identity ,
subject : user . Id ,
client : await _ applicationManager . GetIdAsync ( application ) ,
type : AuthorizationTypes . Permanent ,
scopes : identity . GetScopes ( ) ) ;
identity . SetAuthorizationId ( await _ authorizationManager . GetIdAsync ( authorization ) ) ;
identity . SetDestinations ( GetDestinations ) ;
context . Authentication . SignIn ( new AuthenticationProperties ( ) , identity ) ;
return new EmptyResult ( ) ;
// At this point, no authorization was found in the database and an error must be returned
// if the client application specified prompt=none in the authorization request.
case ConsentTypes . Explicit when request . HasPrompt ( Prompts . None ) :
case ConsentTypes . Systematic when request . HasPrompt ( Prompts . None ) :
context . Authentication . Challenge (
authenticationTypes : OpenIddictServerOwinDefaults . AuthenticationType ,
properties : new AuthenticationProperties ( new Dictionary < string , string >
{
[OpenIddictServerOwinConstants.Properties.Error] = Errors . ConsentRequired ,
[OpenIddictServerOwinConstants.Properties.ErrorDescription] =
"Interactive user consent is required."
"The specified identity provider is not valid."
} ) ) ;
return new EmptyResult ( ) ;
}
// In every other case, render the consent form.
default : return View ( new AuthorizeViewModel
var properties = new AuthenticationProperties ( new Dictionary < string , string >
{
ApplicationName = await _ applicationManager . GetDisplayNameAsync ( application ) ,
Scope = request . Scope ,
// Flow the request parameters so they can be received by the Accept/Reject actions.
Parameters = string . Equals ( Request . HttpMethod , "POST" , StringComparison . OrdinalIgnoreCase ) ?
from name in Request . Form . AllKeys
from value in Request . Form . GetValues ( name )
select new KeyValuePair < string , string > ( name , value ) :
from name in Request . QueryString . AllKeys
from value in Request . QueryString . GetValues ( name )
select new KeyValuePair < string , string > ( name , value )
} ) ;
// Note: when only one client is registered in the client options,
// specifying the issuer URI or the provider name is not required.
[OpenIddictClientOwinConstants.Properties.ProviderName] = request . IdentityProvider
} )
{
// Once the callback is handled, redirect the user agent to the ASP.NET Identity
// page responsible for showing the external login confirmation form if necessary.
RedirectUri = Url . Action ( "ExternalLoginCallback" , "Account" , new
{
ReturnUrl = Request . RawUrl
} )
} ;
// Ask the OpenIddict client middleware to redirect the user agent to the identity provider.
context . Authentication . Challenge ( properties , OpenIddictClientOwinDefaults . AuthenticationType ) ;
return new EmptyResult ( ) ;
}
context . Authentication . Challenge ( DefaultAuthenticationTypes . ApplicationCookie ) ;
return new EmptyResult ( ) ;
}
[Authorize, FormValueRequired("submit.Accept")]
[HttpPost, Route("~/connect/authorize"), ValidateAntiForgeryToken]
public async Task < ActionResult > Accept ( )
{
var context = HttpContext . GetOwinContext ( ) ;
var request = context . GetOpenIddictServerRequest ( ) ? ?
throw new InvalidOperationException ( "The OpenID Connect request cannot be retrieved." ) ;
// Retrieve the profile of the logged in user.
var user = await context . GetUserManager < ApplicationUserManager > ( ) . FindByIdAsync ( result . Identity . GetUserId ( ) ) ? ?
throw new InvalidOperationException ( "The user details cannot be retrieved." ) ;
// Retrieve the user principal stored in the authentication cookie.
var result = await context . Authentication . AuthenticateAsync ( DefaultAuthenticationTypes . ApplicationCookie ) ;
if ( result = = null | | result . Identity = = null )
{
context . Authentication . Challenge ( DefaultAuthenticationTypes . ApplicationCookie ) ;
// Retrieve the application details from the database.
var application = await _ applicationManager . FindByClientIdAsync ( request . ClientId ) ? ?
throw new InvalidOperationException ( "Details concerning the calling client application cannot be found." ) ;
return new EmptyResult ( ) ;
}
// Retrieve the permanent authorizations associated with the user and the calling client application.
var authorizations = await _ authorizationManager . FindAsync (
subject : user . Id ,
client : await _ applicationManager . GetIdAsync ( application ) ,
status : Statuses . Valid ,
type : AuthorizationTypes . Permanent ,
scopes : request . GetScopes ( ) ) . ToListAsync ( ) ;
// Retrieve the profile of the logged in user.
var user = await context . GetUserManager < ApplicationUserManager > ( ) . FindByIdAsync ( result . Identity . GetUserId ( ) ) ? ?
throw new InvalidOperationException ( "The user details cannot be retrieved." ) ;
// Retrieve the application details from the database.
var application = await _ applicationManager . FindByClientIdAsync ( request . ClientId ) ? ?
throw new InvalidOperationException ( "Details concerning the calling client application cannot be found." ) ;
// Retrieve the permanent authorizations associated with the user and the calling client application.
var authorizations = await _ authorizationManager . FindAsync (
subject : user . Id ,
client : await _ applicationManager . GetIdAsync ( application ) ,
status : Statuses . Valid ,
type : AuthorizationTypes . Permanent ,
scopes : request . GetScopes ( ) ) . ToListAsync ( ) ;
// Note: the same check is already made in the other action but is repeated
// here to ensure a malicious user can't abuse this POST-only endpoint and
// force it to return a valid response without the external authorization.
if ( authorizations . Count is 0 & & await _ applicationManager . HasConsentTypeAsync ( application , ConsentTypes . External ) )
{
switch ( await _ applicationManager . GetConsentTypeAsync ( application ) )
{
// If the consent is external (e.g when authorizations are granted by a sysadmin),
// immediately return an error if no authorization can be found in the database.
case ConsentTypes . External when authorizations . Count is 0 :
context . Authentication . Challenge (
authenticationTypes : OpenIddictServerOwinDefaults . AuthenticationType ,
properties : new AuthenticationProperties ( new Dictionary < string , string >
@ -257,191 +134,313 @@ namespace OpenIddict.Sandbox.AspNet.Server.Controllers
} ) ) ;
return new EmptyResult ( ) ;
}
// Create the claims-based identity that will be used by OpenIddict to generate tokens.
var identity = new ClaimsIdentity (
authenticationType : OpenIddictServerOwinDefaults . AuthenticationType ,
nameType : Claims . Name ,
roleType : Claims . Role ) ;
// If the consent is implicit or if an authorization was found,
// return an authorization response without displaying the consent form.
case ConsentTypes . Implicit :
case ConsentTypes . External when authorizations . Count is not 0 :
case ConsentTypes . Explicit when authorizations . Count is not 0 & & ! request . HasPrompt ( Prompts . Consent ) :
// Create the claims-based identity that will be used by OpenIddict to generate tokens.
var identity = new ClaimsIdentity (
authenticationType : OpenIddictServerOwinDefaults . AuthenticationType ,
nameType : Claims . Name ,
roleType : Claims . Role ) ;
// Add the claims that will be persisted in the tokens.
identity . SetClaim ( Claims . Subject , user . Id )
. SetClaim ( Claims . Email , user . Email )
. SetClaim ( Claims . Name , user . UserName )
. SetClaim ( Claims . PreferredUsername , user . UserName )
. SetClaims ( Claims . Role , ( await context . Get < ApplicationUserManager > ( ) . GetRolesAsync ( user . Id ) ) . ToImmutableArray ( ) ) ;
// Add the claims that will be persisted in the tokens.
identity . SetClaim ( Claims . Subject , user . Id )
. SetClaim ( Claims . Email , user . Email )
. SetClaim ( Claims . Name , user . UserName )
. SetClaim ( Claims . PreferredUsername , user . UserName )
. SetClaims ( Claims . Role , ( await context . Get < ApplicationUserManager > ( ) . GetRolesAsync ( user . Id ) ) . ToImmutableArray ( ) ) ;
// Note: in this sample, the granted scopes match the requested scope
// but you may want to allow the user to uncheck specific scopes.
// For that, simply restrict the list of scopes before calling SetScopes.
identity . SetScopes ( request . GetScopes ( ) ) ;
identity . SetResources ( await _ scopeManager . ListResourcesAsync ( identity . GetScopes ( ) ) . ToListAsync ( ) ) ;
// Automatically create a permanent authorization to avoid requiring explicit consent
// for future authorization or token requests containing the same scopes.
var authorization = authorizations . LastOrDefault ( ) ;
authorization ? ? = await _ authorizationManager . CreateAsync (
identity : identity ,
subject : user . Id ,
client : await _ applicationManager . GetIdAsync ( application ) ,
type : AuthorizationTypes . Permanent ,
scopes : identity . GetScopes ( ) ) ;
identity . SetAuthorizationId ( await _ authorizationManager . GetIdAsync ( authorization ) ) ;
identity . SetDestinations ( GetDestinations ) ;
// Note: in this sample, the granted scopes match the requested scope
// but you may want to allow the user to uncheck specific scopes.
// For that, simply restrict the list of scopes before calling SetScopes.
identity . SetScopes ( request . GetScopes ( ) ) ;
identity . SetResources ( await _ scopeManager . ListResourcesAsync ( identity . GetScopes ( ) ) . ToListAsync ( ) ) ;
// Automatically create a permanent authorization to avoid requiring explicit consent
// for future authorization or token requests containing the same scopes.
var authorization = authorizations . LastOrDefault ( ) ;
authorization ? ? = await _ authorizationManager . CreateAsync (
identity : identity ,
subject : user . Id ,
client : await _ applicationManager . GetIdAsync ( application ) ,
type : AuthorizationTypes . Permanent ,
scopes : identity . GetScopes ( ) ) ;
identity . SetAuthorizationId ( await _ authorizationManager . GetIdAsync ( authorization ) ) ;
identity . SetDestinations ( GetDestinations ) ;
// Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
context . Authentication . SignIn ( new AuthenticationProperties ( ) , identity ) ;
context . Authentication . SignIn ( new AuthenticationProperties ( ) , identity ) ;
return new EmptyResult ( ) ;
return new EmptyResult ( ) ;
// At this point, no authorization was found in the database and an error must be returned
// if the client application specified prompt=none in the authorization request.
case ConsentTypes . Explicit when request . HasPrompt ( Prompts . None ) :
case ConsentTypes . Systematic when request . HasPrompt ( Prompts . None ) :
context . Authentication . Challenge (
authenticationTypes : OpenIddictServerOwinDefaults . AuthenticationType ,
properties : new AuthenticationProperties ( new Dictionary < string , string >
{
[OpenIddictServerOwinConstants.Properties.Error] = Errors . ConsentRequired ,
[OpenIddictServerOwinConstants.Properties.ErrorDescription] =
"Interactive user consent is required."
} ) ) ;
return new EmptyResult ( ) ;
// In every other case, render the consent form.
default : return View ( new AuthorizeViewModel
{
ApplicationName = await _ applicationManager . GetDisplayNameAsync ( application ) ,
Scope = request . Scope ,
// Flow the request parameters so they can be received by the Accept/Reject actions.
Parameters = string . Equals ( Request . HttpMethod , "POST" , StringComparison . OrdinalIgnoreCase ) ?
from name in Request . Form . AllKeys
from value in Request . Form . GetValues ( name )
select new KeyValuePair < string , string > ( name , value ) :
from name in Request . QueryString . AllKeys
from value in Request . QueryString . GetValues ( name )
select new KeyValuePair < string , string > ( name , value )
} ) ;
}
}
[Authorize, FormValueRequired("submit.Deny")]
[HttpPost, Route("~/connect/authorize"), ValidateAntiForgeryToken]
// Notify OpenIddict that the authorization grant has been denied by the resource owner
// to redirect the user agent to the client application using the appropriate response_mode.
public ActionResult Deny ( )
[Authorize, FormValueRequired("submit.Accept")]
[HttpPost, Route("~/connect/authorize"), ValidateAntiForgeryToken]
public async Task < ActionResult > Accept ( )
{
var context = HttpContext . GetOwinContext ( ) ;
var request = context . GetOpenIddictServerRequest ( ) ? ?
throw new InvalidOperationException ( "The OpenID Connect request cannot be retrieved." ) ;
// Retrieve the user principal stored in the authentication cookie.
var result = await context . Authentication . AuthenticateAsync ( DefaultAuthenticationTypes . ApplicationCookie ) ;
if ( result = = null | | result . Identity = = null )
{
var context = HttpContext . GetOwinContext ( ) ;
context . Authentication . Challenge ( OpenIddictServerOwinDefaults . AuthenticationType ) ;
context . Authentication . Challenge ( DefaultAuthenticationTypes . ApplicationCookie ) ;
return new EmptyResult ( ) ;
}
[HttpGet, Route("~/connect/logout")]
public ActionResult Logout ( ) = > View ( new AuthorizeViewModel
{
// Flow the request parameters so they can be received by the Accept/Reject actions.
Parameters = string . Equals ( Request . HttpMethod , "POST" , StringComparison . OrdinalIgnoreCase ) ?
from name in Request . Form . AllKeys
from value in Request . Form . GetValues ( name )
select new KeyValuePair < string , string > ( name , value ) :
from name in Request . QueryString . AllKeys
from value in Request . QueryString . GetValues ( name )
select new KeyValuePair < string , string > ( name , value )
} ) ;
[ActionName(nameof(Logout)), HttpPost, Route("~/connect/logout"), ValidateAntiForgeryToken]
public ActionResult LogoutPost ( )
// Retrieve the profile of the logged in user.
var user = await context . GetUserManager < ApplicationUserManager > ( ) . FindByIdAsync ( result . Identity . GetUserId ( ) ) ? ?
throw new InvalidOperationException ( "The user details cannot be retrieved." ) ;
// Retrieve the application details from the database.
var application = await _ applicationManager . FindByClientIdAsync ( request . ClientId ) ? ?
throw new InvalidOperationException ( "Details concerning the calling client application cannot be found." ) ;
// Retrieve the permanent authorizations associated with the user and the calling client application.
var authorizations = await _ authorizationManager . FindAsync (
subject : user . Id ,
client : await _ applicationManager . GetIdAsync ( application ) ,
status : Statuses . Valid ,
type : AuthorizationTypes . Permanent ,
scopes : request . GetScopes ( ) ) . ToListAsync ( ) ;
// Note: the same check is already made in the other action but is repeated
// here to ensure a malicious user can't abuse this POST-only endpoint and
// force it to return a valid response without the external authorization.
if ( authorizations . Count is 0 & & await _ applicationManager . HasConsentTypeAsync ( application , ConsentTypes . External ) )
{
var context = HttpContext . GetOwinContext ( ) ;
context . Authentication . SignOut ( DefaultAuthenticationTypes . ApplicationCookie ) ;
context . Authentication . SignOut (
context . Authentication . Challenge (
authenticationTypes : OpenIddictServerOwinDefaults . AuthenticationType ,
properties : new AuthenticationProperties
properties : new AuthenticationProperties ( new Dictionary < string , string >
{
RedirectUri = "/"
} ) ;
[OpenIddictServerOwinConstants.Properties.Error] = Errors . ConsentRequired ,
[OpenIddictServerOwinConstants.Properties.ErrorDescription] =
"The logged in user is not allowed to access this client application."
} ) ) ;
return new EmptyResult ( ) ;
}
[HttpPost, Route("~/connect/token")]
public async Task < ActionResult > Exchange ( )
{
var context = HttpContext . GetOwinContext ( ) ;
var request = context . GetOpenIddictServerRequest ( ) ? ?
throw new InvalidOperationException ( "The OpenID Connect request cannot be retrieved." ) ;
// Create the claims-based identity that will be used by OpenIddict to generate tokens.
var identity = new ClaimsIdentity (
authenticationType : OpenIddictServerOwinDefaults . AuthenticationType ,
nameType : Claims . Name ,
roleType : Claims . Role ) ;
// Add the claims that will be persisted in the tokens.
identity . SetClaim ( Claims . Subject , user . Id )
. SetClaim ( Claims . Email , user . Email )
. SetClaim ( Claims . Name , user . UserName )
. SetClaim ( Claims . PreferredUsername , user . UserName )
. SetClaims ( Claims . Role , ( await context . Get < ApplicationUserManager > ( ) . GetRolesAsync ( user . Id ) ) . ToImmutableArray ( ) ) ;
// Note: in this sample, the granted scopes match the requested scope
// but you may want to allow the user to uncheck specific scopes.
// For that, simply restrict the list of scopes before calling SetScopes.
identity . SetScopes ( request . GetScopes ( ) ) ;
identity . SetResources ( await _ scopeManager . ListResourcesAsync ( identity . GetScopes ( ) ) . ToListAsync ( ) ) ;
// Automatically create a permanent authorization to avoid requiring explicit consent
// for future authorization or token requests containing the same scopes.
var authorization = authorizations . LastOrDefault ( ) ;
authorization ? ? = await _ authorizationManager . CreateAsync (
identity : identity ,
subject : user . Id ,
client : await _ applicationManager . GetIdAsync ( application ) ,
type : AuthorizationTypes . Permanent ,
scopes : identity . GetScopes ( ) ) ;
identity . SetAuthorizationId ( await _ authorizationManager . GetIdAsync ( authorization ) ) ;
identity . SetDestinations ( GetDestinations ) ;
// Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
context . Authentication . SignIn ( new AuthenticationProperties ( ) , identity ) ;
return new EmptyResult ( ) ;
}
if ( request . IsAuthorizationCodeGrantType ( ) | | request . IsRefreshTokenGrantType ( ) )
{
// Retrieve the claims identity stored in the authorization code/device code/refresh token.
var result = await context . Authentication . AuthenticateAsync ( OpenIddictServerOwinDefaults . AuthenticationType ) ;
[Authorize, FormValueRequired("submit.Deny")]
[HttpPost, Route("~/connect/authorize"), ValidateAntiForgeryToken]
// Notify OpenIddict that the authorization grant has been denied by the resource owner
// to redirect the user agent to the client application using the appropriate response_mode.
public ActionResult Deny ( )
{
var context = HttpContext . GetOwinContext ( ) ;
context . Authentication . Challenge ( OpenIddictServerOwinDefaults . AuthenticationType ) ;
// Retrieve the user profile corresponding to the authorization code/refresh token.
var user = await context . GetUserManager < ApplicationUserManager > ( ) . FindByIdAsync ( result . Identity . GetClaim ( Claims . Subject ) ) ;
if ( user = = null )
{
context . Authentication . Challenge (
authenticationTypes : OpenIddictServerOwinDefaults . AuthenticationType ,
properties : new AuthenticationProperties ( new Dictionary < string , string >
{
[OpenIddictServerOwinConstants.Properties.Error] = Errors . InvalidGrant ,
[OpenIddictServerOwinConstants.Properties.ErrorDescription] = "The token is no longer valid."
} ) ) ;
return new EmptyResult ( ) ;
}
return new EmptyResult ( ) ;
}
[HttpGet, Route("~/connect/logout")]
public ActionResult Logout ( ) = > View ( new AuthorizeViewModel
{
// Flow the request parameters so they can be received by the Accept/Reject actions.
Parameters = string . Equals ( Request . HttpMethod , "POST" , StringComparison . OrdinalIgnoreCase ) ?
from name in Request . Form . AllKeys
from value in Request . Form . GetValues ( name )
select new KeyValuePair < string , string > ( name , value ) :
from name in Request . QueryString . AllKeys
from value in Request . QueryString . GetValues ( name )
select new KeyValuePair < string , string > ( name , value )
} ) ;
[ActionName(nameof(Logout)), HttpPost, Route("~/connect/logout"), ValidateAntiForgeryToken]
public ActionResult LogoutPost ( )
{
var context = HttpContext . GetOwinContext ( ) ;
context . Authentication . SignOut ( DefaultAuthenticationTypes . ApplicationCookie ) ;
// Ensure the user is still allowed to sign in.
if ( context . GetUserManager < ApplicationUserManager > ( ) . IsLockedOut ( user . Id ) )
{
context . Authentication . Challenge (
authenticationTypes : OpenIddictServerOwinDefaults . AuthenticationType ,
properties : new AuthenticationProperties ( new Dictionary < string , string >
{
[OpenIddictServerOwinConstants.Properties.Error] = Errors . InvalidGrant ,
[OpenIddictServerOwinConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in."
} ) ) ;
context . Authentication . SignOut (
authenticationTypes : OpenIddictServerOwinDefaults . AuthenticationType ,
properties : new AuthenticationProperties
{
RedirectUri = "/"
} ) ;
return new EmptyResult ( ) ;
}
return new EmptyResult ( ) ;
}
var identity = new ClaimsIdentity ( result . Identity . Claims ,
authenticationType : OpenIddictServerOwinDefaults . AuthenticationType ,
nameType : Claims . Name ,
roleType : Claims . Role ) ;
[HttpPost, Route("~/connect/token")]
public async Task < ActionResult > Exchange ( )
{
var context = HttpContext . GetOwinContext ( ) ;
var request = context . GetOpenIddictServerRequest ( ) ? ?
throw new InvalidOperationException ( "The OpenID Connect request cannot be retrieved." ) ;
// Override the user claims present in the principal in case they
// changed since the authorization code/refresh token was issued.
identity . SetClaim ( Claims . Subject , user . Id )
. SetClaim ( Claims . Email , user . Email )
. SetClaim ( Claims . Name , user . UserName )
. SetClaim ( Claims . PreferredUsername , user . UserName )
. SetClaims ( Claims . Role , ( await context . Get < ApplicationUserManager > ( ) . GetRolesAsync ( user . Id ) ) . ToImmutableArray ( ) ) ;
if ( request . IsAuthorizationCodeGrantType ( ) | | request . IsRefreshTokenGrantType ( ) )
{
// Retrieve the claims identity stored in the authorization code/device code/refresh token.
var result = await context . Authentication . AuthenticateAsync ( OpenIddictServerOwinDefaults . AuthenticationType ) ;
identity . SetDestinations ( GetDestinations ) ;
// Retrieve the user profile corresponding to the authorization code/refresh token.
var user = await context . GetUserManager < ApplicationUserManager > ( ) . FindByIdAsync ( result . Identity . GetClaim ( Claims . Subject ) ) ;
if ( user = = null )
{
context . Authentication . Challenge (
authenticationTypes : OpenIddictServerOwinDefaults . AuthenticationType ,
properties : new AuthenticationProperties ( new Dictionary < string , string >
{
[OpenIddictServerOwinConstants.Properties.Error] = Errors . InvalidGrant ,
[OpenIddictServerOwinConstants.Properties.ErrorDescription] = "The token is no longer valid."
} ) ) ;
// Ask OpenIddict to issue the appropriate access/identity tokens.
context . Authentication . SignIn ( new AuthenticationProperties ( ) , identity ) ;
return new EmptyResult ( ) ;
}
// Ensure the user is still allowed to sign in.
if ( context . GetUserManager < ApplicationUserManager > ( ) . IsLockedOut ( user . Id ) )
{
context . Authentication . Challenge (
authenticationTypes : OpenIddictServerOwinDefaults . AuthenticationType ,
properties : new AuthenticationProperties ( new Dictionary < string , string >
{
[OpenIddictServerOwinConstants.Properties.Error] = Errors . InvalidGrant ,
[OpenIddictServerOwinConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in."
} ) ) ;
return new EmptyResult ( ) ;
}
throw new InvalidOperationException ( "The specified grant type is not supported." ) ;
var identity = new ClaimsIdentity ( result . Identity . Claims ,
authenticationType : OpenIddictServerOwinDefaults . AuthenticationType ,
nameType : Claims . Name ,
roleType : Claims . Role ) ;
// Override the user claims present in the principal in case they
// changed since the authorization code/refresh token was issued.
identity . SetClaim ( Claims . Subject , user . Id )
. SetClaim ( Claims . Email , user . Email )
. SetClaim ( Claims . Name , user . UserName )
. SetClaim ( Claims . PreferredUsername , user . UserName )
. SetClaims ( Claims . Role , ( await context . Get < ApplicationUserManager > ( ) . GetRolesAsync ( user . Id ) ) . ToImmutableArray ( ) ) ;
identity . SetDestinations ( GetDestinations ) ;
// Ask OpenIddict to issue the appropriate access/identity tokens.
context . Authentication . SignIn ( new AuthenticationProperties ( ) , identity ) ;
return new EmptyResult ( ) ;
}
private static IEnumerable < string > GetDestinations ( Claim claim )
{
// Note: by default, claims are NOT automatically included in the access and identity tokens.
// To allow OpenIddict to serialize them, you must attach them a destination, that specifies
// whether they should be included in access tokens, in identity tokens or in both.
throw new InvalidOperationException ( "The specified grant type is not supported." ) ;
}
switch ( claim . Type )
{
case Claims . Name or Claims . PreferredUsername :
yield return Destinations . AccessToken ;
private static IEnumerable < string > GetDestinations ( Claim claim )
{
// Note: by default, claims are NOT automatically included in the access and identity tokens.
// To allow OpenIddict to serialize them, you must attach them a destination, that specifies
// whether they should be included in access tokens, in identity tokens or in both.
if ( claim . Subject . HasScope ( Scopes . Profile ) )
yield return Destinations . IdentityToken ;
switch ( claim . Type )
{
case Claims . Name or Claims . PreferredUsername :
yield return Destinations . AccessToken ;
yield break ;
if ( claim . Subject . HasScope ( Scopes . Profile ) )
yield return Destinations . IdentityToken ;
case Claims . Email :
yield return Destinations . AccessToken ;
yield break ;
if ( claim . Subject . HasScope ( Scopes . Email ) )
yield return Destinations . Identity Token;
case Claims . Email :
yield return Destinations . Access Token;
yield break ;
if ( claim . Subject . HasScope ( Scopes . Email ) )
yield return Destinations . IdentityToken ;
case Claims . Role :
yield return Destinations . AccessToken ;
yield break ;
if ( claim . Subject . HasScope ( Scopes . Roles ) )
yield return Destinations . Identity Token;
case Claims . Role :
yield return Destinations . Access Token;
yield break ;
if ( claim . Subject . HasScope ( Scopes . Roles ) )
yield return Destinations . IdentityToken ;
// Never include the security stamp in the access and identity tokens, as it's a secret value.
case "AspNet.Identity.SecurityStamp" : yield break ;
yield break ;
default :
yield return Destinations . AccessToken ;
yield break ;
}
// Never include the security stamp in the access and identity tokens, as it's a secret value.
case "AspNet.Identity.SecurityStamp" : yield break ;
default :
yield return Destinations . AccessToken ;
yield break ;
}
}
}