-
-
Notifications
You must be signed in to change notification settings - Fork 528
/
OpenIddictServerOptions.cs
396 lines (347 loc) · 20.7 KB
/
OpenIddictServerOptions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants;
using SR = OpenIddict.Abstractions.OpenIddictResources;
namespace OpenIddict.Server
{
/// <summary>
/// Provides various settings needed to configure the OpenIddict server handler.
/// </summary>
public class OpenIddictServerOptions
{
/// <summary>
/// Gets or sets the optional base address used to uniquely identify the authorization server.
/// The URI must be absolute and may contain a path, but no query string or fragment part.
/// </summary>
public Uri? Issuer { get; set; }
/// <summary>
/// Gets the list of encryption credentials used by the OpenIddict server services.
/// Multiple credentials can be added to support key rollover, but if X.509 keys
/// are used, at least one of them must have a valid creation/expiration date.
/// Note: the encryption credentials are not used to protect/unprotect tokens issued
/// by ASP.NET Core Data Protection, that uses its own key ring, configured separately.
/// </summary>
/// <remarks>
/// Note: OpenIddict automatically sorts the credentials based on the following algorithm:
/// <list type="bullet">
/// <item><description>Symmetric keys are always preferred when they can be used for the operation (e.g token encryption).</description></item>
/// <item><description>X.509 keys are always preferred to non-X.509 asymmetric keys.</description></item>
/// <item><description>X.509 keys with the furthest expiration date are preferred.</description></item>
/// <item><description>X.509 keys whose backing certificate is not yet valid are never preferred.</description></item>
/// </list>
/// </remarks>
public List<EncryptingCredentials> EncryptionCredentials { get; } = new List<EncryptingCredentials>();
/// <summary>
/// Gets the list of signing credentials used by the OpenIddict server services.
/// Multiple credentials can be added to support key rollover, but if X.509 keys
/// are used, at least one of them must have a valid creation/expiration date.
/// Note: the signing credentials are not used to protect/unprotect tokens issued
/// by ASP.NET Core Data Protection, that uses its own key ring, configured separately.
/// </summary>
/// <remarks>
/// Note: OpenIddict automatically sorts the credentials based on the following algorithm:
/// <list type="bullet">
/// <item><description>Symmetric keys are always preferred when they can be used for the operation (e.g token signing).</description></item>
/// <item><description>X.509 keys are always preferred to non-X.509 asymmetric keys.</description></item>
/// <item><description>X.509 keys with the furthest expiration date are preferred.</description></item>
/// <item><description>X.509 keys whose backing certificate is not yet valid are never preferred.</description></item>
/// </list>
/// </remarks>
public List<SigningCredentials> SigningCredentials { get; } = new List<SigningCredentials>();
/// <summary>
/// Gets the absolute and relative URIs associated to the authorization endpoint.
/// </summary>
public List<Uri> AuthorizationEndpointUris { get; } = new List<Uri>();
/// <summary>
/// Gets the absolute and relative URIs associated to the configuration endpoint.
/// </summary>
public List<Uri> ConfigurationEndpointUris { get; } = new List<Uri>
{
new Uri("/.well-known/openid-configuration", UriKind.Relative),
new Uri("/.well-known/oauth-authorization-server", UriKind.Relative)
};
/// <summary>
/// Gets the absolute and relative URIs associated to the cryptography endpoint.
/// </summary>
public List<Uri> CryptographyEndpointUris { get; } = new List<Uri>
{
new Uri("/.well-known/jwks", UriKind.Relative)
};
/// <summary>
/// Gets the absolute and relative URIs associated to the device endpoint.
/// </summary>
public List<Uri> DeviceEndpointUris { get; } = new List<Uri>();
/// <summary>
/// Gets the absolute and relative URIs associated to the introspection endpoint.
/// </summary>
public List<Uri> IntrospectionEndpointUris { get; } = new List<Uri>();
/// <summary>
/// Gets the absolute and relative URIs associated to the logout endpoint.
/// </summary>
public List<Uri> LogoutEndpointUris { get; } = new List<Uri>();
/// <summary>
/// Gets the absolute and relative URIs associated to the revocation endpoint.
/// </summary>
public List<Uri> RevocationEndpointUris { get; } = new List<Uri>();
/// <summary>
/// Gets the absolute and relative URIs associated to the token endpoint.
/// </summary>
public List<Uri> TokenEndpointUris { get; } = new List<Uri>();
/// <summary>
/// Gets the absolute and relative URIs associated to the userinfo endpoint.
/// </summary>
public List<Uri> UserinfoEndpointUris { get; } = new List<Uri>();
/// <summary>
/// Gets the absolute and relative URIs associated to the verification endpoint.
/// </summary>
public List<Uri> VerificationEndpointUris { get; } = new List<Uri>();
/// <summary>
/// Gets or sets the JWT handler used to protect and unprotect tokens.
/// </summary>
public JsonWebTokenHandler JsonWebTokenHandler { get; set; } = new JsonWebTokenHandler
{
SetDefaultTimesOnTokenCreation = false
};
/// <summary>
/// Gets the token validation parameters used by the OpenIddict server services.
/// </summary>
public TokenValidationParameters TokenValidationParameters { get; } = new TokenValidationParameters
{
AuthenticationType = TokenValidationParameters.DefaultAuthenticationType,
ClockSkew = TimeSpan.Zero,
NameClaimType = OpenIddictConstants.Claims.Name,
RoleClaimType = OpenIddictConstants.Claims.Role,
// In previous versions of OpenIddict (1.x and 2.x), all the JWT tokens (access and identity tokens)
// were issued with the generic "typ": "JWT" header. To prevent confused deputy and token substitution
// attacks, a special "token_usage" claim was added to the JWT payload to convey the actual token type.
// This validator overrides the default logic used by IdentityModel to resolve the type from this claim.
TypeValidator = (type, token, parameters) =>
{
// If available, try to resolve the actual type from the "token_usage" claim.
if (((JsonWebToken) token).TryGetPayloadValue(OpenIddictConstants.Claims.TokenUsage, out string usage))
{
type = usage switch
{
TokenTypeHints.AccessToken => JsonWebTokenTypes.AccessToken,
TokenTypeHints.IdToken => JsonWebTokenTypes.IdentityToken,
_ => throw new NotSupportedException(SR.GetResourceString(SR.ID0269))
};
}
// At this point, throw an exception if the type cannot be resolved from the "typ" header
// (provided via the type delegate parameter) or inferred from the token_usage claim.
if (string.IsNullOrEmpty(type))
{
throw new SecurityTokenInvalidTypeException(SR.GetResourceString(SR.ID0270));
}
// Note: unlike IdentityModel, this custom validator deliberately uses case-insensitive comparisons.
if (parameters.ValidTypes is not null && parameters.ValidTypes.Any() &&
!parameters.ValidTypes.Contains(type, StringComparer.OrdinalIgnoreCase))
{
throw new SecurityTokenInvalidTypeException(SR.GetResourceString(SR.ID0271))
{
InvalidType = type
};
}
return type;
},
// Note: audience and lifetime are manually validated by OpenIddict itself.
ValidateAudience = false,
ValidateLifetime = false
};
/// <summary>
/// Gets or sets the period of time authorization codes remain valid after being issued. The default value is 5 minutes.
/// While not recommended, this property can be set to <c>null</c> to issue codes that never expire.
/// </summary>
public TimeSpan? AuthorizationCodeLifetime { get; set; } = TimeSpan.FromMinutes(5);
/// <summary>
/// Gets or sets the period of time access tokens remain valid after being issued. The default value is 1 hour.
/// The client application is expected to refresh or acquire a new access token after the token has expired.
/// While not recommended, this property can be set to <c>null</c> to issue access tokens that never expire.
/// </summary>
public TimeSpan? AccessTokenLifetime { get; set; } = TimeSpan.FromHours(1);
/// <summary>
/// Gets or sets the period of time device codes remain valid after being issued. The default value is 10 minutes.
/// The client application is expected to start a whole new authentication flow after the device code has expired.
/// While not recommended, this property can be set to <c>null</c> to issue codes that never expire.
/// Note: the same value should be chosen for both <see cref="UserCodeLifetime"/> and this property.
/// </summary>
public TimeSpan? DeviceCodeLifetime { get; set; } = TimeSpan.FromMinutes(10);
/// <summary>
/// Gets or sets the period of time identity tokens remain valid after being issued. The default value is 20 minutes.
/// The client application is expected to refresh or acquire a new identity token after the token has expired.
/// While not recommended, this property can be set to <c>null</c> to issue identity tokens that never expire.
/// </summary>
public TimeSpan? IdentityTokenLifetime { get; set; } = TimeSpan.FromMinutes(20);
/// <summary>
/// Gets or sets the period of time refresh tokens remain valid after being issued. The default value is 14 days.
/// The client application is expected to start a whole new authentication flow after the refresh token has expired.
/// While not recommended, this property can be set to <c>null</c> to issue refresh tokens that never expire.
/// </summary>
public TimeSpan? RefreshTokenLifetime { get; set; } = TimeSpan.FromDays(14);
/// <summary>
/// Gets or sets the period of time rolling refresh tokens marked as redeemed can still be
/// used to make concurrent refresh token requests. The default value is 15 seconds.
/// </summary>
public TimeSpan? RefreshTokenReuseLeeway { get; set; } = TimeSpan.FromSeconds(15);
/// <summary>
/// Gets or sets the period of time user codes remain valid after being issued. The default value is 10 minutes.
/// The client application is expected to start a whole new authentication flow after the user code has expired.
/// While not recommended, this property can be set to <c>null</c> to issue codes that never expire.
/// Note: the same value should be chosen for both <see cref="DeviceCodeLifetime"/> and this property.
/// </summary>
public TimeSpan? UserCodeLifetime { get; set; } = TimeSpan.FromMinutes(10);
/// <summary>
/// Gets or sets a boolean indicating whether the degraded mode is enabled. When this degraded mode
/// is enabled, all the security checks that depend on the OpenIddict core managers are disabled.
/// This option MUST be enabled with extreme caution and custom handlers MUST be registered to
/// properly validate OpenID Connect requests.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public bool EnableDegradedMode { get; set; }
/// <summary>
/// Gets the list of the handlers responsible of processing the OpenIddict server operations.
/// Note: the list is automatically sorted based on the order assigned to each handler descriptor.
/// As such, it MUST NOT be mutated after options initialization to preserve the exact order.
/// </summary>
public List<OpenIddictServerHandlerDescriptor> Handlers { get; } =
new List<OpenIddictServerHandlerDescriptor>(OpenIddictServerHandlers.DefaultHandlers);
/// <summary>
/// Gets or sets a boolean determining whether client identification is optional.
/// Enabling this option allows client applications to communicate with the token,
/// introspection and revocation endpoints without having to send their client identifier.
/// </summary>
public bool AcceptAnonymousClients { get; set; }
/// <summary>
/// Gets the OAuth 2.0/OpenID Connect claims supported by this application.
/// </summary>
public HashSet<string> Claims { get; } = new HashSet<string>(StringComparer.Ordinal)
{
OpenIddictConstants.Claims.Audience,
OpenIddictConstants.Claims.ExpiresAt,
OpenIddictConstants.Claims.IssuedAt,
OpenIddictConstants.Claims.Issuer,
OpenIddictConstants.Claims.Subject
};
/// <summary>
/// Gets or sets a boolean indicating whether access token encryption should be disabled.
/// Disabling encryption is NOT recommended and SHOULD only be done when issuing tokens
/// to third-party resource servers/APIs you don't control and don't fully trust.
/// Note: disabling encryption has no effect when using ASP.NET Core Data Protection.
/// </summary>
public bool DisableAccessTokenEncryption { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether authorization storage should be disabled.
/// When disabled, ad-hoc authorizations are not created when an authorization code or
/// refresh token is issued and can't be revoked to prevent associated tokens from being used.
/// </summary>
public bool DisableAuthorizationStorage { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether rolling tokens are disabled.
/// When disabled, refresh tokens used in a token request are not marked
/// as redeemed and can still be used until they expire. Disabling
/// rolling refresh tokens is NOT recommended, for security reasons.
/// </summary>
public bool DisableRollingRefreshTokens { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether sliding expiration is disabled
/// for refresh tokens. When this option is set to <see langword="true"/>,
/// refresh tokens are issued with a fixed expiration date: when they expire,
/// a complete authorization flow must be started to retrieve a new refresh token.
/// </summary>
public bool DisableSlidingRefreshTokenExpiration { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether token storage should be disabled.
/// When disabled, no database entry is created for the tokens and codes
/// returned by OpenIddict. Using this option is generally NOT recommended
/// as it prevents the tokens and codes from being revoked (if needed).
/// </summary>
public bool DisableTokenStorage { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether scope validation is disabled.
/// </summary>
public bool DisableScopeValidation { get; set; }
/// <summary>
/// Gets the OAuth 2.0 code challenge methods enabled for this application.
/// By default, only the S256 method is allowed (if the code flow is enabled).
/// </summary>
public HashSet<string> CodeChallengeMethods { get; } = new HashSet<string>(StringComparer.Ordinal);
/// <summary>
/// Gets the OAuth 2.0/OpenID Connect flows enabled for this application.
/// </summary>
public HashSet<string> GrantTypes { get; } = new HashSet<string>(StringComparer.Ordinal);
/// <summary>
/// Gets or sets a boolean indicating whether PKCE must be used by client applications
/// when requesting an authorization code (e.g when using the code or hybrid flows).
/// If this property is set to <see langword="true"/>, authorization requests that
/// lack the code_challenge will be automatically rejected by OpenIddict.
/// </summary>
public bool RequireProofKeyForCodeExchange { get; set; }
/// <summary>
/// Gets the OAuth 2.0/OpenID Connect response types enabled for this application.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public HashSet<string> ResponseTypes { get; } = new HashSet<string>(StringComparer.Ordinal);
/// <summary>
/// Gets the OAuth 2.0/OpenID Connect response modes enabled for this application.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public HashSet<string> ResponseModes { get; } = new HashSet<string>(StringComparer.Ordinal);
/// <summary>
/// Gets or sets a boolean indicating whether endpoint permissions should be ignored.
/// Setting this property to <see langword="true"/> is NOT recommended.
/// </summary>
public bool IgnoreEndpointPermissions { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether grant type permissions should be ignored.
/// Setting this property to <see langword="true"/> is NOT recommended.
/// </summary>
public bool IgnoreGrantTypePermissions { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether response type permissions should be ignored.
/// Setting this property to <see langword="true"/> is NOT recommended.
/// </summary>
public bool IgnoreResponseTypePermissions { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether scope permissions should be ignored.
/// Setting this property to <see langword="true"/> is NOT recommended.
/// </summary>
public bool IgnoreScopePermissions { get; set; }
/// <summary>
/// Gets the OAuth 2.0/OpenID Connect scopes enabled for this application.
/// </summary>
public HashSet<string> Scopes { get; } = new HashSet<string>(StringComparer.Ordinal)
{
OpenIddictConstants.Scopes.OpenId
};
/// <summary>
/// Gets or sets a boolean indicating whether reference access tokens should be used.
/// When set to <see langword="true"/>, the token payload is stored in the database
/// and a crypto-secure random identifier is returned to the client application.
/// Enabling this option is useful when storing a very large number of claims
/// in the tokens, but it is RECOMMENDED to enable column encryption
/// in the database or use the ASP.NET Core Data Protection integration,
/// that provides additional protection against token leakage.
/// </summary>
public bool UseReferenceAccessTokens { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether reference refresh tokens should be used.
/// When set to <see langword="true"/>, the token payload is stored in the database
/// and a crypto-secure random identifier is returned to the client application.
/// Enabling this option is useful when storing a very large number of claims
/// in the tokens, but it is RECOMMENDED to enable column encryption
/// in the database or use the ASP.NET Core Data Protection integration,
/// that provides additional protection against token leakage.
/// </summary>
public bool UseReferenceRefreshTokens { get; set; }
}
}