Merge branch 'main' into jmdc/merge-7.3-forward

This commit is contained in:
Joe DeCock 2025-07-24 20:41:30 -05:00
commit 70a470f35b
51 changed files with 127 additions and 119 deletions

View file

@ -11,8 +11,10 @@ internal class Decorator<TService>
public Decorator(TService instance) => Instance = instance;
}
#pragma warning disable CA1812 // This class is not instantiated directly, but rather used by the DI container
internal class Decorator<TService, TImpl> : Decorator<TService>
where TImpl : class, TService
#pragma warning restore CA1812
{
public Decorator(TImpl instance) : base(instance)
{

View file

@ -8,8 +8,10 @@ using Microsoft.AspNetCore.Identity;
namespace Duende.IdentityServer.AspNetIdentity;
#pragma warning disable CA1812 // This class is not instantiated directly, but rather used by the DI container
internal class UserClaimsFactory<TUser> : IUserClaimsPrincipalFactory<TUser>
where TUser : class
#pragma warning restore CA1812
{
private readonly Decorator<IUserClaimsPrincipalFactory<TUser>> _inner;
private UserManager<TUser> _userManager;

View file

@ -10,7 +10,9 @@ namespace Duende.IdentityServer.Configuration.EntityFramework;
/// <summary>
/// Provides cancellation tokens based on the incoming http request
/// </summary>
#pragma warning disable CA1812 // This class is not instantiated directly, but rather used by the DI container
internal class DefaultCancellationTokenProvider : ICancellationTokenProvider
#pragma warning restore CA1812
{
private readonly IHttpContextAccessor _httpContextAccessor;

View file

@ -20,6 +20,6 @@
Currently all existing warnings are suppressed. We will remove them as we address them. But this configuration
allows us to prevent new warnings from being introduced while we work on the existing ones.
-->
<NoWarn>$(NoWarn);CA1002;CA1008;CA1031;CA1034;CA1040;CA1051;CA1054;CA1055;CA1056;CA1062;CA1716;CA1724;CA1725;CA1727;CA1805;CA1806;CA1810;CA1812;CA1819;CA1822;CA1825;CA1845;CA1848;CA1849;CA1851;CA1852;CA1854;CA1859;CA1861;CA1860;CA1863;CA1864;CA1870;CA1872;CA2000;CA2008;CA2201;CA2007;CA2208;CA2016;CA2211;CA2227;CA2234;CA2249;CA2253;CA2254;CA2263;CA5404;CA5394;</NoWarn>
<NoWarn>$(NoWarn);CA1002;CA1008;CA1031;CA1034;CA1040;CA1051;CA1054;CA1055;CA1056;CA1062;CA1716;CA1724;CA1725;CA1727;CA1819;CA1825;CA1845;CA1848;CA1849;CA1851;CA1852;CA1854;CA1859;CA1861;CA1860;CA1863;CA1864;CA1870;CA1872;CA2000;CA2008;CA2201;CA2007;CA2208;CA2016;CA2211;CA2227;CA2234;CA2249;CA2253;CA2254;CA2263;CA5404;CA5394;</NoWarn>
</PropertyGroup>
</Project>

View file

@ -20,7 +20,7 @@ public class Client
public string Description { get; set; }
public string ClientUri { get; set; }
public string LogoUri { get; set; }
public bool RequireConsent { get; set; } = false;
public bool RequireConsent { get; set; }
public bool AllowRememberConsent { get; set; } = true;
public bool AlwaysIncludeUserClaimsInIdToken { get; set; }
public List<ClientGrantType> AllowedGrantTypes { get; set; }
@ -43,13 +43,13 @@ public class Client
public string AllowedIdentityTokenSigningAlgorithms { get; set; }
public int AccessTokenLifetime { get; set; } = 3600;
public int AuthorizationCodeLifetime { get; set; } = 300;
public int? ConsentLifetime { get; set; } = null;
public int? ConsentLifetime { get; set; }
public int AbsoluteRefreshTokenLifetime { get; set; } = 2592000;
public int SlidingRefreshTokenLifetime { get; set; } = 1296000;
public int RefreshTokenUsage { get; set; } = (int)TokenUsage.OneTimeOnly;
public bool UpdateAccessTokenClaimsOnRefresh { get; set; }
public int RefreshTokenExpiration { get; set; } = (int)TokenExpiration.Absolute;
public int AccessTokenType { get; set; } = 0; // AccessTokenType.Jwt;
public int AccessTokenType { get; set; } // Default is AccessTokenType.Jwt;
public bool EnableLocalLogin { get; set; } = true;
public List<ClientIdPRestriction> IdentityProviderRestrictions { get; set; }
public bool IncludeJwtId { get; set; }

View file

@ -35,7 +35,7 @@ public class ConfigurationStoreOptions
/// <value>
/// The default schema.
/// </value>
public string? DefaultSchema { get; set; } = null;
public string? DefaultSchema { get; set; }
/// <summary>
/// Gets or sets the identity resource table configuration.
@ -216,7 +216,7 @@ public class ConfigurationStoreOptions
/// <summary>
/// Gets or set if EF DbContext pooling is enabled.
/// </summary>
public bool EnablePooling { get; set; } = false;
public bool EnablePooling { get; set; }
/// <summary>
/// Gets or set the pool size to use when DbContext pooling is enabled. If not set, the EF default is used.

View file

@ -35,7 +35,7 @@ public class OperationalStoreOptions
/// <value>
/// The default schema.
/// </value>
public string? DefaultSchema { get; set; } = null;
public string? DefaultSchema { get; set; }
/// <summary>
/// Gets or sets the persisted grants table configuration.
@ -82,7 +82,7 @@ public class OperationalStoreOptions
/// <value>
/// <c>true</c> if [enable token cleanup]; otherwise, <c>false</c>.
/// </value>
public bool EnableTokenCleanup { get; set; } = false;
public bool EnableTokenCleanup { get; set; }
/// <summary>
/// Gets or sets a value indicating whether consumed tokens will be included in the automatic clean up.
@ -90,7 +90,7 @@ public class OperationalStoreOptions
/// <value>
/// <c>true</c> if consumed tokens are to be included in cleanup; otherwise, <c>false</c>.
/// </value>
public bool RemoveConsumedTokens { get; set; } = false;
public bool RemoveConsumedTokens { get; set; }
/// <summary>
/// Gets or sets the consumed token cleanup delay (in seconds). The default
@ -98,7 +98,7 @@ public class OperationalStoreOptions
/// marked as consumed can be deleted. Note that only refresh tokens with
/// OneTimeOnly usage can be marked as consumed.
/// </summary>
public int ConsumedTokenCleanupDelay { get; set; } = 0;
public int ConsumedTokenCleanupDelay { get; set; }
/// <summary>
/// Gets or sets the token cleanup interval (in seconds). The default is 3600 (1 hour).
@ -129,7 +129,7 @@ public class OperationalStoreOptions
/// <summary>
/// Gets or set if EF DbContext pooling is enabled.
/// </summary>
public bool EnablePooling { get; set; } = false;
public bool EnablePooling { get; set; }
/// <summary>
/// Gets or set the pool size to use when DbContext pooling is enabled. If not set, the EF default is used.

View file

@ -167,7 +167,7 @@ public class PersistedGrantStore : Duende.IdentityServer.Stores.IPersistedGrantS
}
private IQueryable<PersistedGrant> Filter(IQueryable<PersistedGrant> query, PersistedGrantFilter filter)
private static IQueryable<PersistedGrant> Filter(IQueryable<PersistedGrant> query, PersistedGrantFilter filter)
{
if (filter.ClientIds != null)
{

View file

@ -240,7 +240,7 @@ public class ServerSideSessionStore : IServerSideSessionStore
}
}
private IQueryable<Entities.ServerSideSession> Filter(IQueryable<Entities.ServerSideSession> query, SessionFilter filter)
private static IQueryable<Entities.ServerSideSession> Filter(IQueryable<Entities.ServerSideSession> query, SessionFilter filter)
{
if (!string.IsNullOrWhiteSpace(filter.SubjectId))
{
@ -471,8 +471,8 @@ public class ServerSideSessionStore : IServerSideSessionStore
var parts = filter.ResultsToken.Split(',', StringSplitOptions.RemoveEmptyEntries);
if (parts != null && parts.Length == 2)
{
int.TryParse(parts[0], out first);
int.TryParse(parts[1], out last);
_ = int.TryParse(parts[0], out first);
_ = int.TryParse(parts[1], out last);
}
}
@ -508,8 +508,8 @@ public class ServerSideSessionStore : IServerSideSessionStore
public int First { get; init; }
public int Last { get; init; }
public int CurrentPage { get; set; } = 1;
public bool HasNext { get; set; } = false;
public bool HasPrev { get; set; } = false;
public bool HasNext { get; set; }
public bool HasPrev { get; set; }
public Entities.ServerSideSession[] Items { get; set; } = Array.Empty<Entities.ServerSideSession>();
}
}

View file

@ -22,7 +22,7 @@ internal class ConfigureOpenIdConnectOptions : IPostConfigureOptions<OpenIdConne
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
}
private static bool warnedInMemory = false;
private static bool warnedInMemory;
public void PostConfigure(string name, OpenIdConnectOptions options)
{

View file

@ -27,7 +27,7 @@ public class AuthenticationOptions
/// <summary>
/// Specifies if the cookie should be sliding or not (only effective if the built-in cookie middleware is used)
/// </summary>
public bool CookieSlidingExpiration { get; set; } = false;
public bool CookieSlidingExpiration { get; set; }
/// <summary>
/// Specifies the SameSite mode for the internal authentication and temp cookie
@ -40,7 +40,7 @@ public class AuthenticationOptions
/// <value>
/// <c>true</c> if required; otherwise, <c>false</c>.
/// </value>
public bool RequireAuthenticatedUserForSignOutMessage { get; set; } = false;
public bool RequireAuthenticatedUserForSignOutMessage { get; set; }
/// <summary>
/// Gets or sets the name of the cookie used for the check session endpoint.

View file

@ -73,7 +73,7 @@ public class DiscoveryOptions
/// <value>
/// The cache interval in seconds.
/// </value>
public int? ResponseCacheInterval { get; set; } = null;
public int? ResponseCacheInterval { get; set; }
/// <summary>
/// Adds custom entries to the discovery document

View file

@ -20,9 +20,9 @@ public class EndpointsOptions
public bool EnableAuthorizeEndpoint { get; set; } = true;
/// <summary>
/// Gets or sets if JWT request_uri processing is enabled on the authorize endpoint.
/// Gets or sets if JWT request_uri processing is enabled on the authorize endpoint.
/// </summary>
public bool EnableJwtRequestUri { get; set; } = false;
public bool EnableJwtRequestUri { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the token endpoint is enabled.

View file

@ -17,7 +17,7 @@ public class EventsOptions
/// <value>
/// <c>true</c> if success event should be raised; otherwise, <c>false</c>.
/// </value>
public bool RaiseSuccessEvents { get; set; } = false;
public bool RaiseSuccessEvents { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to raise failure events.
@ -25,7 +25,7 @@ public class EventsOptions
/// <value>
/// <c>true</c> if failure events should be raised; otherwise, <c>false</c>.
/// </value>
public bool RaiseFailureEvents { get; set; } = false;
public bool RaiseFailureEvents { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to raise information events.
@ -33,7 +33,7 @@ public class EventsOptions
/// <value>
/// <c>true</c> if information events should be raised; otherwise, <c>false</c>.
/// </value>
public bool RaiseInformationEvents { get; set; } = false;
public bool RaiseInformationEvents { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to raise error events.
@ -41,5 +41,5 @@ public class EventsOptions
/// <value>
/// <c>true</c> if error events should be raised; otherwise, <c>false</c>.
/// </value>
public bool RaiseErrorEvents { get; set; } = false;
public bool RaiseErrorEvents { get; set; }
}

View file

@ -48,12 +48,12 @@ public class IdentityServerOptions
/// <summary>
/// Emits an aud claim with the format issuer/resources. That's needed for some older access token validation plumbing. Defaults to false.
/// </summary>
public bool EmitStaticAudienceClaim { get; set; } = false;
public bool EmitStaticAudienceClaim { get; set; }
/// <summary>
/// Specifies whether scopes in JWTs are emitted as array or string
/// </summary>
public bool EmitScopesAsSpaceDelimitedStringInJwt { get; set; } = false;
public bool EmitScopesAsSpaceDelimitedStringInJwt { get; set; }
/// <summary>
/// Specifies whether authorize responses contain the iss parameter (https://www.rfc-editor.org/rfc/rfc9207.html)
@ -63,18 +63,18 @@ public class IdentityServerOptions
/// <summary>
/// Specifies whether the s_hash claim gets emitted in identity tokens. Defaults to false.
/// </summary>
public bool EmitStateHash { get; set; } = false;
public bool EmitStateHash { get; set; }
/// <summary>
/// Specifies whether the JWT typ and content-type for JWT secured authorization requests is checked according to IETF spec.
/// This might break older OIDC conformant request objects.
/// </summary>
public bool StrictJarValidation { get; set; } = false;
public bool StrictJarValidation { get; set; }
/// <summary>
/// Specifies if a user's tenant claim is compared to the tenant acr_values parameter value to determine if the login page is displayed. Defaults to false.
/// </summary>
public bool ValidateTenantOnAuthorization { get; set; } = false;
public bool ValidateTenantOnAuthorization { get; set; }
/// <summary>
/// Gets or sets the endpoint configuration.

View file

@ -9,14 +9,14 @@ namespace Duende.IdentityServer.Configuration;
public class PreviewFeatureOptions
{
/// <summary>
/// Enables Caching of Discovery Document based on ResponseCaching Interval
/// Enables Caching of Discovery Document based on ResponseCaching Interval
/// </summary>
public bool EnableDiscoveryDocumentCache { get; set; } = false;
public bool EnableDiscoveryDocumentCache { get; set; }
/// <summary>
/// When clients authenticate with private_key_jwt assertions, validate the audience of the assertion strictly: the audience must be this IdentityServer's issuer identifier as a single string.
/// </summary>
public bool StrictClientAssertionAudienceValidation { get; set; } = false;
public bool StrictClientAssertionAudienceValidation { get; set; }
/// <summary>
/// DiscoveryDocument Cache Duration

View file

@ -106,5 +106,5 @@ internal class BackchannelAuthenticationEndpoint : IEndpointHandler
private void LogResponse(BackchannelAuthenticationResponse response, BackchannelAuthenticationRequestValidationResult requestResult) => _logger.LogTrace("BackchannelAuthenticationResponse: {@response} for subject {subjectId}", response, requestResult.ValidatedRequest.Subject.GetSubjectId());
private BackchannelAuthenticationResult Error(string error, string errorDescription = null) => new BackchannelAuthenticationResult(new BackchannelAuthenticationResponse(error, errorDescription));
private static BackchannelAuthenticationResult Error(string error, string errorDescription = null) => new BackchannelAuthenticationResult(new BackchannelAuthenticationResponse(error, errorDescription));
}

View file

@ -35,7 +35,7 @@ internal class CheckSessionHttpWriter : IHttpResponseWriter<CheckSessionResult>
}
private void AddCspHeaders(HttpContext context) => context.Response.AddScriptCspHeaders(_options.Csp, IdentityServerConstants.ContentSecurityPolicyHashes.CheckSessionScript);
private string GetHtml(string cookieName)
private static string GetHtml(string cookieName)
{
if (cookieName != LastCheckSessionCookieName)
{

View file

@ -77,7 +77,7 @@ internal class EndSessionCallbackHttpWriter : IHttpResponseWriter<EndSessionCall
}
}
private string GetHtml(EndSessionCallbackResult result)
private static string GetHtml(EndSessionCallbackResult result)
{
var sb = new StringBuilder();
sb.Append("<!DOCTYPE html><html><style>iframe{{display:none;width:0;height:0;}}</style><body>");

View file

@ -170,7 +170,7 @@ internal class TokenEndpoint : IEndpointHandler
return null;
}
private TokenErrorResult Error(string error, string errorDescription = null, Dictionary<string, object> custom = null)
private static TokenErrorResult Error(string error, string errorDescription = null, Dictionary<string, object> custom = null)
{
var response = new TokenErrorResponse
{

View file

@ -93,5 +93,5 @@ internal class UserInfoEndpoint : IEndpointHandler
return new UserInfoResult(response);
}
private IEndpointResult Error(string error, string description = null) => new ProtectedResourceErrorResult(error, description);
private static IEndpointResult Error(string error, string description = null) => new ProtectedResourceErrorResult(error, description);
}

View file

@ -88,7 +88,7 @@ internal class IdentityServerAuthenticationService : IAuthenticationService
public Task ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties) => _inner.ForbidAsync(context, scheme, properties);
private void AssertRequiredClaims(ClaimsPrincipal principal)
private static void AssertRequiredClaims(ClaimsPrincipal principal)
{
// for now, we don't allow more than one identity in the principal/cookie
if (principal.Identities.Count() != 1)

View file

@ -119,7 +119,7 @@ public class MutualTlsEndpointMiddleware
}
private bool RequestedHostMatches(HostString requestHost, string configuredDomain)
private static bool RequestedHostMatches(HostString requestHost, string configuredDomain)
{
// Parse the configured domain which might contain a port
var configuredHostname = configuredDomain;

View file

@ -28,7 +28,7 @@ public class DistributedCacheStateDataFormatter : ISecureDataFormat<Authenticati
_name = name;
}
private string CacheKeyPrefix => "DistributedCacheStateDataFormatter";
private static string CacheKeyPrefix => "DistributedCacheStateDataFormatter";
private IDistributedCache Cache => _provider.GetRequiredService<IDistributedCache>();
private IDataProtector Protector => _provider.GetRequiredService<IDataProtectionProvider>().CreateProtector(CacheKeyPrefix, _name);

View file

@ -35,7 +35,7 @@ internal class MessageCookie<TModel>
_protector = provider.CreateProtector(MessageType);
}
private string MessageType => typeof(TModel).Name;
private static string MessageType => typeof(TModel).Name;
private string Protect(Message<TModel> message)
{
@ -52,9 +52,9 @@ internal class MessageCookie<TModel>
return message;
}
private string CookiePrefix => MessageType + ".";
private static string CookiePrefix => MessageType + ".";
private string GetCookieFullName(string id) => CookiePrefix + id;
private static string GetCookieFullName(string id) => CookiePrefix + id;
private string CookiePath => _urls.BasePath.CleanUrlPath();

View file

@ -64,7 +64,7 @@ internal class IdentityServerLicenseValidator : LicenseValidator<IdentityServerL
}
}
private void EnsureAdded(ref HashSet<string> hashSet, object lockObject, string key)
private static void EnsureAdded(ref HashSet<string> hashSet, object lockObject, string key)
{
// Lock free test first.
if (!hashSet.Contains(key))
@ -144,7 +144,7 @@ internal class IdentityServerLicenseValidator : LicenseValidator<IdentityServerL
}
}
private bool ValidateServerSideSessionsWarned = false;
private bool ValidateServerSideSessionsWarned;
public void ValidateServerSideSessions()
{
if (License != null)
@ -161,7 +161,7 @@ internal class IdentityServerLicenseValidator : LicenseValidator<IdentityServerL
}
}
private bool CanUseDPoPWarned = false;
private bool CanUseDPoPWarned;
public void ValidateDPoP()
{
if (License != null)
@ -178,7 +178,7 @@ internal class IdentityServerLicenseValidator : LicenseValidator<IdentityServerL
}
}
private bool ValidateResourceIndicatorsWarned = false;
private bool ValidateResourceIndicatorsWarned;
public void ValidateResourceIndicators(string resourceIndicator)
{
if (!string.IsNullOrWhiteSpace(resourceIndicator))
@ -198,7 +198,7 @@ internal class IdentityServerLicenseValidator : LicenseValidator<IdentityServerL
}
}
private bool ValidateParWarned = false;
private bool ValidateParWarned;
public void ValidatePar()
{
if (License != null)
@ -234,7 +234,7 @@ internal class IdentityServerLicenseValidator : LicenseValidator<IdentityServerL
}
}
private bool ValidateDynamicProvidersWarned = false;
private bool ValidateDynamicProvidersWarned;
public void ValidateDynamicProviders()
{
if (License != null)
@ -251,7 +251,7 @@ internal class IdentityServerLicenseValidator : LicenseValidator<IdentityServerL
}
}
private bool ValidateCibaWarned = false;
private bool ValidateCibaWarned;
public void ValidateCiba()
{
if (License != null)

View file

@ -84,7 +84,7 @@ internal class ClientLoadedTracker : IDisposable
}
}
private bool JsonElementEquals(JsonElement a, JsonElement b)
private static bool JsonElementEquals(JsonElement a, JsonElement b)
{
if (a.ValueKind != b.ValueKind)
{

View file

@ -63,7 +63,7 @@ internal class AssemblyInfoDiagnosticEntry : IDiagnosticEntry
return Task.CompletedTask;
}
private List<Assembly> GetAssemblyInfo()
private static List<Assembly> GetAssemblyInfo()
{
var assemblies = AssemblyLoadContext.Default.Assemblies
.OrderBy(a => a.FullName)

View file

@ -110,7 +110,7 @@ internal class TokenIssueCountDiagnosticEntry : IDiagnosticEntry, IDisposable
}
break;
case Telemetry.Metrics.Tags.RefreshTokenIssued:
bool.TryParse(tag.Value?.ToString(), out refreshTokenIssued);
_ = bool.TryParse(tag.Value?.ToString(), out refreshTokenIssued);
break;
case Telemetry.Metrics.Tags.ProofType:
if (!Enum.TryParse(tag.Value?.ToString(), out proofType))
@ -119,10 +119,10 @@ internal class TokenIssueCountDiagnosticEntry : IDiagnosticEntry, IDisposable
}
break;
case Telemetry.Metrics.Tags.AccessTokenIssued:
bool.TryParse(tag.Value?.ToString(), out accessTokenIssued);
_ = bool.TryParse(tag.Value?.ToString(), out accessTokenIssued);
break;
case Telemetry.Metrics.Tags.IdTokenIssued:
bool.TryParse(tag.Value?.ToString(), out identityTokenIssued);
_ = bool.TryParse(tag.Value?.ToString(), out identityTokenIssued);
break;
case Telemetry.Metrics.Tags.GrantType:
grantType = tag.Value?.ToString();

View file

@ -97,7 +97,7 @@ internal class License
if (!claims.HasClaim("feature", "unlimited_issuers"))
{
// default
// default
IssuerLimit = 1;
if (int.TryParse(claims.FindFirst("issuer_limit")?.Value, out var issuerLimit))
@ -137,7 +137,7 @@ internal class License
public DateTimeOffset? Expiration { get; init; }
/// <summary>
/// The license edition
/// The license edition
/// </summary>
public LicenseEdition? Edition { get; init; }
@ -208,7 +208,7 @@ internal class License
}
}
private LicenseFeature ToFeatureEnum(string claimValue)
private static LicenseFeature ToFeatureEnum(string claimValue)
{
foreach (var field in typeof(LicenseFeature).GetFields())
{
@ -257,7 +257,7 @@ internal class License
_ => throw new ArgumentException(),
};
private ulong FeatureMaskForFeatures(params LicenseFeature[] licenseFeatures)
private static ulong FeatureMaskForFeatures(params LicenseFeature[] licenseFeatures)
{
var result = 0UL;
foreach (var feature in licenseFeatures)

View file

@ -34,7 +34,7 @@ public class RefreshTokenCreationRequest
public IEnumerable<string> AuthorizedScopes { get; set; } = default!;
/// <summary>
/// The resource indicators. Null indicates there was no authorization step, thus no restrictions.
/// The resource indicators. Null indicates there was no authorization step, thus no restrictions.
/// Non-null means there was an authorization step, and subsequent requested resource indicators must be in the original list.
/// </summary>
public IEnumerable<string>? AuthorizedResourceIndicators { get; set; }
@ -57,7 +57,9 @@ public class RefreshTokenCreationRequest
/// <summary>
/// Called to validate the <see cref="RefreshTokenCreationRequest"/> before it is processed.
/// </summary>
#pragma warning disable CA1822 // Changing this on a public method in a public class would be a breaking change.
public void Validate()
#pragma warning restore CA1822
{
//if (ValidatedResources == null) throw new ArgumentNullException(nameof(ValidatedResources));
//if (ValidatedRequest == null) throw new ArgumentNullException(nameof(ValidatedRequest));

View file

@ -161,7 +161,9 @@ public class DefaultBackChannelLogoutService : IBackChannelLogoutService
/// </summary>
/// <param name="request"></param>
/// <returns>The claims to include in the token.</returns>
#pragma warning disable CA1822 // Changing this on a protected method in a public class would be a breaking change.
protected Task<IEnumerable<Claim>> CreateClaimsForTokenAsync(BackChannelLogoutRequest request)
#pragma warning restore CA1822
{
if (request.SessionIdRequired && request.SessionId == null)
{

View file

@ -131,7 +131,7 @@ public class DefaultPersistedGrantService : IPersistedGrantService
return Enumerable.Empty<Grant>();
}
private IEnumerable<Grant> Join(IEnumerable<Grant> first, IEnumerable<Grant> second)
private static IEnumerable<Grant> Join(IEnumerable<Grant> first, IEnumerable<Grant> second)
{
var list = first.ToList();

View file

@ -67,7 +67,7 @@ public class CachingResourceStore<T> : IResourceStore
_apiResourceNames = apiResourceNames;
}
private string GetKey(IEnumerable<string> names)
private static string GetKey(IEnumerable<string> names)
{
using var activity = Tracing.StoreActivitySource.StartActivity("CachingResourceStore.GetKey");
@ -119,7 +119,7 @@ public class CachingResourceStore<T> : IResourceStore
if (uncachedScopes.Any())
{
// now we need to lookup the remaining items. it's possible this is happening concurrently, so
// now we need to lookup the remaining items. it's possible this is happening concurrently, so
// we're going to use the "allcache" to throttle this lookup since the cache has concurrency lock.
// also, the "allcache" conveniently holds Resources objects so it can handle all three of our resource types.
// the results will then be put into the correct and specific cache as individual items for subsequent lookups.
@ -225,7 +225,7 @@ public class CachingResourceStore<T> : IResourceStore
if (uncachedNames.Any())
{
// now we need to lookup the remaining items. it's possible this is happening concurrently, so
// now we need to lookup the remaining items. it's possible this is happening concurrently, so
// we're going to use the "allcache" to throttle this lookup since the cache has concurrency lock.
// also, the "allcache" conveniently holds Resources objects so it can handle all three of our resource types.
// the results will then be put into the correct and specific cache as individual items for subsequent lookups.

View file

@ -30,7 +30,7 @@ public class DefaultUserConsentStore : DefaultGrantStore<Consent>, IUserConsentS
{
}
private string GetConsentKey(string subjectId, string clientId, bool useHexEncoding = true)
private static string GetConsentKey(string subjectId, string clientId, bool useHexEncoding = true)
{
if (useHexEncoding)
{

View file

@ -28,7 +28,7 @@ public class DistributedCacheAuthorizationParametersMessageStore : IAuthorizatio
_handleGenerationService = handleGenerationService;
}
private string CacheKeyPrefix => "DistributedCacheAuthorizationParametersMessageStore";
private static string CacheKeyPrefix => "DistributedCacheAuthorizationParametersMessageStore";
/// <inheritdoc/>
public virtual async Task<string> WriteAsync(Message<IDictionary<string, string[]>> message)

View file

@ -818,9 +818,9 @@ internal class AuthorizeRequestValidator : IAuthorizeRequestValidator
return true;
}
private AuthorizeRequestValidationResult Invalid(ValidatedAuthorizeRequest request, string error = OidcConstants.AuthorizeErrors.InvalidRequest, string description = null) => new AuthorizeRequestValidationResult(request, error, description);
private static AuthorizeRequestValidationResult Invalid(ValidatedAuthorizeRequest request, string error = OidcConstants.AuthorizeErrors.InvalidRequest, string description = null) => new AuthorizeRequestValidationResult(request, error, description);
private AuthorizeRequestValidationResult Valid(ValidatedAuthorizeRequest request) => new AuthorizeRequestValidationResult(request);
private static AuthorizeRequestValidationResult Valid(ValidatedAuthorizeRequest request) => new AuthorizeRequestValidationResult(request);
private void LogError(string message, ValidatedAuthorizeRequest request)
{

View file

@ -159,7 +159,7 @@ public class BasicAuthenticationSecretParser : ISecretParser
return notfound;
}
private string UrlDecode(string value)
private static string UrlDecode(string value)
{
if (value.IsMissing())
{

View file

@ -88,7 +88,7 @@ internal class BearerTokenUsageValidator
/// </summary>
/// <param name="context">The context.</param>
/// <returns></returns>
public async Task<BearerTokenUsageValidationResult> ValidatePostBodyAsync(HttpContext context)
public static async Task<BearerTokenUsageValidationResult> ValidatePostBodyAsync(HttpContext context)
{
var token = (await context.Request.ReadFormAsync())["access_token"].FirstOrDefault();
if (token.IsPresent())

View file

@ -56,9 +56,9 @@ internal class DeviceAuthorizationRequestValidator : IDeviceAuthorizationRequest
return Valid(request);
}
private DeviceAuthorizationRequestValidationResult Valid(ValidatedDeviceAuthorizationRequest request) => new DeviceAuthorizationRequestValidationResult(request);
private static DeviceAuthorizationRequestValidationResult Valid(ValidatedDeviceAuthorizationRequest request) => new DeviceAuthorizationRequestValidationResult(request);
private DeviceAuthorizationRequestValidationResult Invalid(ValidatedDeviceAuthorizationRequest request, string error = OidcConstants.AuthorizeErrors.InvalidRequest, string description = null) => new DeviceAuthorizationRequestValidationResult(request, error, description);
private static DeviceAuthorizationRequestValidationResult Invalid(ValidatedDeviceAuthorizationRequest request, string error = OidcConstants.AuthorizeErrors.InvalidRequest, string description = null) => new DeviceAuthorizationRequestValidationResult(request, error, description);
private void LogError(string message, ValidatedDeviceAuthorizationRequest request)
{

View file

@ -152,7 +152,7 @@ internal class PushedAuthorizationRequestValidator(
/// context.</param>
/// <returns>A task containing the <see
/// cref="PushedAuthorizationValidationResult"/>.</returns>
private Task<PushedAuthorizationValidationResult> ValidateRequestUriAsync(PushedAuthorizationRequestValidationContext context)
private static Task<PushedAuthorizationValidationResult> ValidateRequestUriAsync(PushedAuthorizationRequestValidationContext context)
{
// Reject request_uri parameter
if (context.RequestParameters.Get(OidcConstants.AuthorizeRequest.RequestUri).IsPresent())

View file

@ -114,7 +114,7 @@ internal class RequestObjectValidator : IRequestObjectValidator
private static bool IsParRequestUri(string requestUri) => requestUri.StartsWith(IdentityServerConstants.PushedAuthorizationRequestUri, StringComparison.Ordinal);
private string? LoadRequestObjectFromPushedAuthorizationRequest(ValidatedAuthorizeRequest request) => request.Raw.Get(OidcConstants.AuthorizeRequest.Request);
private static string? LoadRequestObjectFromPushedAuthorizationRequest(ValidatedAuthorizeRequest request) => request.Raw.Get(OidcConstants.AuthorizeRequest.Request);
public async Task<AuthorizeRequestValidationResult?> ValidatePushedAuthorizationRequest(ValidatedAuthorizeRequest request)
{
@ -168,7 +168,7 @@ internal class RequestObjectValidator : IRequestObjectValidator
return null;
}
public AuthorizeRequestValidationResult? ValidatePushedAuthorizationBindingToClient(DeserializedPushedAuthorizationRequest pushedAuthorizationRequest, ValidatedAuthorizeRequest authorizeRequest)
public static AuthorizeRequestValidationResult? ValidatePushedAuthorizationBindingToClient(DeserializedPushedAuthorizationRequest pushedAuthorizationRequest, ValidatedAuthorizeRequest authorizeRequest)
{
var parClientId = pushedAuthorizationRequest.PushedParameters.Get(OidcConstants.AuthorizeRequest.ClientId);
if (parClientId != authorizeRequest.ClientId)
@ -181,7 +181,7 @@ internal class RequestObjectValidator : IRequestObjectValidator
return null;
}
public AuthorizeRequestValidationResult? ValidatePushedAuthorizationExpiration(DeserializedPushedAuthorizationRequest pushedAuthorizationRequest, ValidatedAuthorizeRequest authorizeRequest)
public static AuthorizeRequestValidationResult? ValidatePushedAuthorizationExpiration(DeserializedPushedAuthorizationRequest pushedAuthorizationRequest, ValidatedAuthorizeRequest authorizeRequest)
{
if (DateTime.UtcNow > pushedAuthorizationRequest.ExpiresAtUtc)
{
@ -203,7 +203,7 @@ internal class RequestObjectValidator : IRequestObjectValidator
return null;
}
private string? GetReferenceValue(ValidatedAuthorizeRequest request)
private static string? GetReferenceValue(ValidatedAuthorizeRequest request)
{
var requestUri = request.Raw.Get(OidcConstants.AuthorizeRequest.RequestUri);
if (requestUri.IsPresent())
@ -335,9 +335,9 @@ internal class RequestObjectValidator : IRequestObjectValidator
return Valid(request);
}
private AuthorizeRequestValidationResult Invalid(ValidatedAuthorizeRequest request, string error = OidcConstants.AuthorizeErrors.InvalidRequest, string? description = null) => new AuthorizeRequestValidationResult(request, error, description);
private static AuthorizeRequestValidationResult Invalid(ValidatedAuthorizeRequest request, string error = OidcConstants.AuthorizeErrors.InvalidRequest, string? description = null) => new AuthorizeRequestValidationResult(request, error, description);
private AuthorizeRequestValidationResult Valid(ValidatedAuthorizeRequest request) => new AuthorizeRequestValidationResult(request);
private static AuthorizeRequestValidationResult Valid(ValidatedAuthorizeRequest request) => new AuthorizeRequestValidationResult(request);
private void LogError(string message, ValidatedAuthorizeRequest request)
{

View file

@ -28,7 +28,9 @@ public class StrictRedirectUriValidator : IRedirectUriValidator
/// <param name="uris">The uris.</param>
/// <param name="requestedUri">The requested URI.</param>
/// <returns></returns>
#pragma warning disable CA1822 // Changing this on a protected method in a public class would be a breaking change.
protected bool StringCollectionContainsString(IEnumerable<string> uris, string requestedUri)
#pragma warning restore CA1822
{
if (IEnumerableExtensions.IsNullOrEmpty(uris))
{

View file

@ -1222,7 +1222,7 @@ internal class TokenRequestValidator : ITokenRequestValidator
return Valid();
}
private bool ValidateCodeVerifierAgainstCodeChallenge(string codeVerifier, string codeChallenge, string codeChallengeMethod)
private static bool ValidateCodeVerifierAgainstCodeChallenge(string codeVerifier, string codeChallenge, string codeChallengeMethod)
{
if (codeChallengeMethod == OidcConstants.CodeChallengeMethods.Plain)
{

View file

@ -409,7 +409,7 @@ internal class TokenValidator : ITokenValidator
};
}
private IEnumerable<Claim> ReferenceTokenToClaims(Token token)
private static IEnumerable<Claim> ReferenceTokenToClaims(Token token)
{
var claims = new List<Claim>
{
@ -458,7 +458,7 @@ internal class TokenValidator : ITokenValidator
}
}
private TokenValidationResult Invalid(string error) => new TokenValidationResult
private static TokenValidationResult Invalid(string error) => new TokenValidationResult
{
IsError = true,
Error = error

View file

@ -147,7 +147,7 @@ public class GrantValidationResult : ValidationResult
CustomResponse = customResponse;
}
private string ConvertTokenErrorEnumToString(TokenRequestErrors error) => error switch
private static string ConvertTokenErrorEnumToString(TokenRequestErrors error) => error switch
{
TokenRequestErrors.InvalidClient => OidcConstants.TokenErrors.InvalidClient,
TokenRequestErrors.InvalidGrant => OidcConstants.TokenErrors.InvalidGrant,

View file

@ -82,10 +82,10 @@ public class ApiScope : Resource
/// <summary>
/// Specifies whether the user can de-select the scope on the consent screen. Defaults to false.
/// </summary>
public bool Required { get; set; } = false;
public bool Required { get; set; }
/// <summary>
/// Specifies whether the consent screen will emphasize this scope. Use this setting for sensitive or important scopes. Defaults to false.
/// </summary>
public bool Emphasize { get; set; } = false;
public bool Emphasize { get; set; }
}

View file

@ -70,7 +70,7 @@ public class Client
/// <summary>
/// Specifies whether a consent screen is required (defaults to <c>false</c>)
/// </summary>
public bool RequireConsent { get; set; } = false;
public bool RequireConsent { get; set; }
/// <summary>
/// Specifies whether user can choose to store consent decisions (defaults to <c>true</c>)
@ -98,12 +98,12 @@ public class Client
/// <summary>
/// Specifies whether a proof key can be sent using plain method (not recommended and defaults to <c>false</c>.)
/// </summary>
public bool AllowPlainTextPkce { get; set; } = false;
public bool AllowPlainTextPkce { get; set; }
/// <summary>
/// Specifies whether the client must use a request object on authorize requests (defaults to <c>false</c>.)
/// </summary>
public bool RequireRequestObject { get; set; } = false;
public bool RequireRequestObject { get; set; }
/// <summary>
/// Controls whether access tokens are transmitted via the browser for this client (defaults to <c>false</c>).
@ -112,7 +112,7 @@ public class Client
/// <value>
/// <c>true</c> if access tokens can be transmitted via the browser; otherwise, <c>false</c>.
/// </value>
public bool AllowAccessTokensViaBrowser { get; set; } = false;
public bool AllowAccessTokensViaBrowser { get; set; }
/// <summary>
/// Specifies whether a DPoP (Demonstrating Proof-of-Possession) token is requied to be used by this client (defaults to <c>false</c>).
@ -164,7 +164,7 @@ public class Client
/// <summary>
/// Gets or sets a value indicating whether [allow offline access]. Defaults to <c>false</c>.
/// </summary>
public bool AllowOfflineAccess { get; set; } = false;
public bool AllowOfflineAccess { get; set; }
/// <summary>
/// Specifies the api scopes that the client is allowed to request. If empty, the client can't access any scope
@ -175,7 +175,7 @@ public class Client
/// When requesting both an id token and access token, should the user claims always be added to the id token instead of requiring the client to use the userinfo endpoint.
/// Defaults to <c>false</c>.
/// </summary>
public bool AlwaysIncludeUserClaimsInIdToken { get; set; } = false;
public bool AlwaysIncludeUserClaimsInIdToken { get; set; }
/// <summary>
/// Lifetime of identity token in seconds (defaults to 300 seconds / 5 minutes)
@ -210,7 +210,7 @@ public class Client
/// <summary>
/// Lifetime of a user consent in seconds. Defaults to null (no expiration)
/// </summary>
public int? ConsentLifetime { get; set; } = null;
public int? ConsentLifetime { get; set; }
/// <summary>
/// Lifetime of pushed authorization requests for this client. If this lifetime is set, it takes precedence over
@ -224,7 +224,7 @@ public class Client
/// configuration flag to require pushed authorization in PushedAuthorizationOptions. Pushed authorization is
/// required for a client if either the global configuration flag is enabled or if this flag is set for that client.
/// </summary>
public bool RequirePushedAuthorization { get; set; } = false;
public bool RequirePushedAuthorization { get; set; }
/// <summary>
/// Specifies if tokens should be rotated when they are used. Defaults to
@ -246,7 +246,7 @@ public class Client
/// <value>
/// <c>true</c> if the token should be updated; otherwise, <c>false</c>.
/// </value>
public bool UpdateAccessTokenClaimsOnRefresh { get; set; } = false;
public bool UpdateAccessTokenClaimsOnRefresh { get; set; }
/// <summary>
/// Absolute: the refresh token will expire on a fixed point in time (specified by the AbsoluteRefreshTokenLifetime)
@ -295,7 +295,7 @@ public class Client
/// <value>
/// <c>true</c> if claims should always be sent; otherwise, <c>false</c>.
/// </value>
public bool AlwaysSendClientClaims { get; set; } = false;
public bool AlwaysSendClientClaims { get; set; }
/// <summary>
/// Gets or sets a value to prefix it on client claim types. Defaults to <c>client_</c>.

View file

@ -66,11 +66,11 @@ public class IdentityResource : Resource
/// <summary>
/// Specifies whether the user can de-select the scope on the consent screen (if the consent screen wants to implement such a feature). Defaults to false.
/// </summary>
public bool Required { get; set; } = false;
public bool Required { get; set; }
/// <summary>
/// Specifies whether the consent screen will emphasize this scope (if the consent screen wants to implement such a feature).
/// Specifies whether the consent screen will emphasize this scope (if the consent screen wants to implement such a feature).
/// Use this setting for sensitive or important scopes. Defaults to false.
/// </summary>
public bool Emphasize { get; set; } = false;
public bool Emphasize { get; set; }
}

View file

@ -15,24 +15,21 @@ namespace Duende.IdentityServer.Stores.Serialization;
/// <seealso cref="IPersistentGrantSerializer" />
public class PersistentGrantSerializer : IPersistentGrantSerializer
{
private static readonly JsonSerializerOptions Settings;
private static readonly JsonSerializerOptions Settings = new()
{
IgnoreReadOnlyFields = true,
IgnoreReadOnlyProperties = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
Converters =
{
new ClaimConverter(),
new ClaimsPrincipalConverter()
}
};
private readonly PersistentGrantOptions _options;
private readonly IDataProtector _provider;
static PersistentGrantSerializer()
{
Settings = new JsonSerializerOptions
{
IgnoreReadOnlyFields = true,
IgnoreReadOnlyProperties = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
Settings.Converters.Add(new ClaimConverter());
Settings.Converters.Add(new ClaimsPrincipalConverter());
}
/// <summary>
/// Ctor.
/// </summary>
@ -110,7 +107,7 @@ public class PersistentGrantSerializer : IPersistentGrantSerializer
throw new Exception($"Invalid version in persisted grant data: '{container.PersistentGrantDataContainerVersion}'.");
}
private void PostProcess(RefreshToken refreshToken)
private static void PostProcess(RefreshToken refreshToken)
{
if (refreshToken != null && refreshToken.Version < 5)
{

View file

@ -34,8 +34,7 @@ public class Authorize_ProtocolValidation_Valid_PAR
ClientId = differentClientInAuthorizeRequest
};
var validator = Factory.CreateRequestObjectValidator();
var result = validator.ValidatePushedAuthorizationBindingToClient(par, request);
var result = RequestObjectValidator.ValidatePushedAuthorizationBindingToClient(par, request);
result.ShouldNotBeNull();
result.IsError.ShouldBe(true);
@ -55,7 +54,7 @@ public class Authorize_ProtocolValidation_Valid_PAR
};
var validator = Factory.CreateRequestObjectValidator();
var result = validator.ValidatePushedAuthorizationExpiration(par, authorizeRequest);
var result = RequestObjectValidator.ValidatePushedAuthorizationExpiration(par, authorizeRequest);
result.ShouldNotBeNull();
result.IsError.ShouldBe(true);