Add authorization storage documentation

This commit is contained in:
Kévin Chalet 2021-01-25 18:35:05 +01:00
parent ecc8a7ae8a
commit 2eb825416f
3 changed files with 123 additions and 19 deletions

View File

@ -0,0 +1,118 @@
# Authorization storage
To keep track of logical chains of tokens and user consents, OpenIddict supports storing authorizations
(also known as "grants" in some OpenID Connect implementations) in the database.
## Types of authorizations
Authorizations can be of two types: permanent and ad-hoc.
### Permanent authorizations
**Permanent authorizations are developer-defined authorizations** created using the `IOpenIddictAuthorizationManager.CreateAsync()` API
and explicitly attached to a `ClaimsPrincipal` using the OpenIddict-specific `principal.SetAuthorizationId()` extension method.
Such authorizations are typically used to remember user consents and avoid displaying a consent view for each authorization request.
For that, a "consent type" can be defined per-application, as in the following example:
```csharp
// Retrieve the application details from the database.
var application = await _applicationManager.FindByClientIdAsync(request.ClientId) ??
throw new InvalidOperationException("The application cannot be found.");
// Retrieve the permanent authorizations associated with the user and the application.
var authorizations = await _authorizationManager.FindAsync(
subject: await _userManager.GetUserIdAsync(user),
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.Any():
return Forbid(
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
properties: new AuthenticationProperties(new Dictionary<string, string>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] =
Errors.ConsentRequired,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
"The logged in user is not allowed to access this client application."
}));
// 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.Any():
case ConsentTypes.Explicit when authorizations.Any() &&
!request.HasPrompt(Prompts.Consent):
var principal = await _signInManager.CreateUserPrincipalAsync(user);
// 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.
principal.SetScopes(request.GetScopes());
principal.SetResources(await _scopeManager.ListResourcesAsync(
principal.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();
if (authorization is null)
{
authorization = await _authorizationManager.CreateAsync(
principal: principal,
subject : await _userManager.GetUserIdAsync(user),
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);
// 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):
return Forbid(
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
properties: new AuthenticationProperties(new Dictionary<string, string>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] =
Errors.ConsentRequired,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
"Interactive user consent is required."
}));
// In every other case, render the consent form.
default: return View(new AuthorizeViewModel
{
ApplicationName = await _applicationManager.GetLocalizedDisplayNameAsync(application),
Scope = request.Scope
});
}
```
### Ad-hoc authorizations
**Ad-hoc authorizations are automatically created by OpenIddict when a chain of tokens needs to be tracked for security reasons**,
but no explicit permanent authorization was attached by the developer to the `ClaimsPrincipal` used for the sign-in operation.
Such authorizations are typically created in the authorization code flow to link all the tokens associated with the original authorization code,
so that they can be automatically revoked if the authorization code was redeemed multiple times (which may indicate a token leakage).
In the same vein, ad-hoc authorizations are also created when a refresh token is returned during a resource owner password credentials grant request.
> [!INFO]
> When using the [OpenIddict.Quartz](https://www.nuget.org/packages/OpenIddict.Quartz/) integration, ad-hoc authorizations are automatically
> removed from the database after a short period of time (14 days by default). Unlike ad-hoc authorizations, permanent authorizations
> never removed from the database.

View File

@ -1,20 +1,3 @@
# Configuration and settings
<div class="row">
<div class="col-md-4">
<div class="panel panel-default" style="min-height: 120px;">
<div class="panel-body">
<p><strong><a href="application-permissions.md">Application permissions</a></strong></p>
<p>Learn how to leverage permissions to control the OIDC features a client is allowed to use.</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="panel panel-default" style="min-height: 120px;">
<div class="panel-body">
<p><strong><a href="token-formats.md">Token formats</a></strong></p>
<p>Learn more about the token formats supported by OpenIddict.</p>
</div>
</div>
</div>
</div>
OpenIddict 3.0 comes with sensible defaults, but depending on the scenarios, the default settings can be amended to change how OpenIddict reacts to requests.

View File

@ -6,3 +6,6 @@
- name: Token formats
href: token-formats.md
- name: Authorization storage
href: authorization-storage.md