in src/OrchardCore.Modules/OrchardCore.OpenId/Controllers/AccessController.cs [51:192]
public async Task<IActionResult> Authorize()
{
var response = HttpContext.GetOpenIddictServerResponse();
if (response != null)
{
return View("Error", new ErrorViewModel
{
Error = response.Error,
ErrorDescription = response.ErrorDescription
});
}
var request = HttpContext.GetOpenIddictServerRequest();
if (request == null)
{
return NotFound();
}
// Retrieve the claims stored in the authentication cookie.
// If they can't be extracted, redirect the user to the login page.
var result = await HttpContext.AuthenticateAsync();
if (result == null || !result.Succeeded || request.HasPrompt(Prompts.Login))
{
return RedirectToLoginPage(request);
}
// If a max_age parameter was provided, ensure that the cookie is not too old.
// If it's too old, automatically redirect the user agent to the login page.
if (request.MaxAge != null && result.Properties.IssuedUtc != null &&
DateTimeOffset.UtcNow - result.Properties.IssuedUtc > TimeSpan.FromSeconds(request.MaxAge.Value))
{
return RedirectToLoginPage(request);
}
var application = await _applicationManager.FindByClientIdAsync(request.ClientId) ??
throw new InvalidOperationException("The application details cannot be found.");
var authorizations = await _authorizationManager.FindAsync(
subject: result.Principal.GetUserIdentifier(),
client : await _applicationManager.GetIdAsync(application),
status : Statuses.Valid,
type : AuthorizationTypes.Permanent,
scopes : request.GetScopes()).ToListAsync();
switch (await _applicationManager.GetConsentTypeAsync(application))
{
case ConsentTypes.External when !authorizations.Any():
return Forbid(new AuthenticationProperties(new Dictionary<string, string>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
S["The logged in user is not allowed to access this client application."]
}), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
case ConsentTypes.Implicit:
case ConsentTypes.External when authorizations.Any():
case ConsentTypes.Explicit when authorizations.Any() && !request.HasPrompt(Prompts.Consent):
var identity = new ClaimsIdentity(result.Principal.Claims, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
identity.AddClaim(OpenIdConstants.Claims.EntityType, OpenIdConstants.EntityTypes.User,
Destinations.AccessToken, Destinations.IdentityToken);
// Note: while ASP.NET Core Identity uses the legacy WS-Federation claims (exposed by the ClaimTypes class),
// OpenIddict uses the newer JWT claims defined by the OpenID Connect specification. To ensure the mandatory
// subject claim is correctly populated (and avoid an InvalidOperationException), it's manually added here.
if (string.IsNullOrEmpty(result.Principal.FindFirst(Claims.Subject)?.Value))
{
identity.AddClaim(new Claim(Claims.Subject, result.Principal.GetUserIdentifier()));
}
principal.SetScopes(request.GetScopes());
principal.SetResources(await GetResourcesAsync(request.GetScopes()));
// Automatically create a permanent authorization to avoid requiring explicit consent
// for future authorization or token requests containing the same scopes.
var authorization = authorizations.LastOrDefault();
if (authorization == null)
{
authorization = await _authorizationManager.CreateAsync(
principal: principal,
subject : principal.GetUserIdentifier(),
client : await _applicationManager.GetIdAsync(application),
type : AuthorizationTypes.Permanent,
scopes : principal.GetScopes());
}
principal.SetAuthorizationId(await _authorizationManager.GetIdAsync(authorization));
foreach (var claim in principal.Claims)
{
claim.SetDestinations(GetDestinations(claim, principal));
}
return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
case ConsentTypes.Explicit when request.HasPrompt(Prompts.None):
return Forbid(new AuthenticationProperties(new Dictionary<string, string>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
S["Interactive user consent is required."]
}), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
default:
return View(new AuthorizeViewModel
{
ApplicationName = await _applicationManager.GetLocalizedDisplayNameAsync(application),
RequestId = request.RequestId,
Scope = request.Scope
});
}
IActionResult RedirectToLoginPage(OpenIddictRequest request)
{
// If the client application requested promptless authentication,
// return an error indicating that the user is not logged in.
if (request.HasPrompt(Prompts.None))
{
return Forbid(new AuthenticationProperties(new Dictionary<string, string>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.LoginRequired,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
S["The user is not logged in."]
}), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
}
string GetRedirectUrl()
{
// Override the prompt parameter to prevent infinite authentication/authorization loops.
var parameters = Request.Query.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
parameters[Parameters.Prompt] = "continue";
return Request.PathBase + Request.Path + QueryString.Create(parameters);
}
return Challenge(new AuthenticationProperties
{
RedirectUri = GetRedirectUrl()
});
}
}