Skip to content

Commit

Permalink
Switch from X509Certificates as keys to JWKs
Browse files Browse the repository at this point in the history
  • Loading branch information
kirill-abblix committed Apr 2, 2024
1 parent 9534654 commit 9a56f5f
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 174 deletions.
52 changes: 43 additions & 9 deletions Abblix.Jwt/JsonWebKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,49 +34,57 @@ namespace Abblix.Jwt;

//TODO consider to split this class into specialized subclasses (RSA/EllipticCurve)
/// <summary>
/// Represents a JSON Web Key (JWK), a data structure that represents a cryptographic key in JSON format.
/// The class supports various key types including RSA and Elliptic Curve, and is capable of representing both public and private keys.
/// Represents a JSON Web Key (JWK), a versatile structure for representing cryptographic keys using JSON.
/// It supports various cryptographic algorithms, including RSA and Elliptic Curve, and can represent both
/// public and private keys. JWKs are crucial for digital signatures, encryption, and ensuring secure
/// communication in web-based protocols.
/// </summary>
public class JsonWebKey
public record JsonWebKey
{
/// <summary>
/// Key type (kty). Identifies the cryptographic algorithm family used with the key, such as "RSA" or "EC" for Elliptic Curve.
/// Identifies the cryptographic algorithm family used with the key, such as RSA or EC (Elliptic Curve),
/// specifying the key's type and its intended cryptographic use.
/// </summary>
[JsonPropertyName("kty")]
[JsonPropertyOrder(1)]
public string? KeyType { get; set; }

/// <summary>
/// Intended use of the key (use). Indicates how the key is meant to be used, such as "sig" for signing or "enc" for encryption.
/// Indicates the intended use of the key, for example, "sig" (signature) for signing operations or
/// "enc" (encryption) for encryption operations, guiding clients on how to use the key appropriately.
/// </summary>
[JsonPropertyName("use")]
[JsonPropertyOrder(2)]
public string? Usage { get; set; }

/// <summary>
/// Algorithm (alg). Specifies the algorithm that the key is intended to be used with.
/// Specifies the algorithm intended for use with the key, aligning with JWT and JWA specifications
/// to ensure interoperability and secure key management.
/// </summary>
[JsonPropertyName("alg")]
[JsonPropertyOrder(3)]
public string? Algorithm { get; set; }

/// <summary>
/// Key ID (kid). A hint indicating which specific key owned by the signer should be used.
/// A unique identifier for the key, facilitating key selection and management in multi-key environments,
/// enabling clients and servers to reference and utilize the correct key for cryptographic operations.
/// </summary>
[JsonPropertyName("kid")]
[JsonPropertyOrder(4)]
public string? KeyId { get; set; }

/// <summary>
/// X.509 Certificate Chain (x5c). Contains a chain of one or more PKIX certificates.
/// Contains a chain of one or more PKIX certificates (RFC 5280), offering a method to associate X.509
/// certificates with the key for validation and trust chain establishment in secure communications.
/// </summary>
[JsonPropertyName("x5c")]
[JsonPropertyOrder(5)]
[JsonConverter(typeof(ArrayConverter<byte[]?, Base64UrlTextEncoderConverter>))]
public byte[][]? Certificates { get; set; }

/// <summary>
/// X.509 Certificate SHA-1 Thumbprint (x5t). A base64url-encoded SHA-1 thumbprint (a.k.a. digest) of the DER encoding of an X.509 certificate.
/// A base64url-encoded SHA-1 thumbprint of the DER encoding of an X.509 certificate, providing a compact
/// means to associate a certificate with the JWK for verification purposes without transmitting the full certificate.
/// </summary>
[JsonPropertyName("x5t")]
[JsonPropertyOrder(5)]
Expand Down Expand Up @@ -169,4 +177,30 @@ public class JsonWebKey
[JsonPropertyOrder(16)]
[JsonConverter(typeof(Base64UrlTextEncoderConverter))]
public byte[]? FirstCrtCoefficient { get; set; }

/// <summary>
/// Prepares a sanitized version of the JWK that excludes private key information unless explicitly included,
/// suitable for public sharing while preserving the integrity of sensitive data.
/// </summary>
/// <param name="includePrivateKeys">Whether to include private key data in the sanitized output.</param>
/// <returns>
/// A new instance of <see cref="JsonWebKey"/> with or without private key data based on the input parameter.
/// </returns>
public JsonWebKey Sanitize(bool includePrivateKeys)
{
return includePrivateKeys switch
{
true when PrivateKey is { Length: > 0} => this,
true => throw new InvalidOperationException($"There is no private key for kid={KeyId}"),
false => this with
{
PrivateKey = null,
FirstCrtCoefficient = null,
FirstPrimeFactor = null,
FirstFactorCrtExponent = null,
SecondPrimeFactor = null,
SecondFactorCrtExponent = null,
}
};
}
}
211 changes: 58 additions & 153 deletions Abblix.Oidc.Server/Common/Configuration/OidcOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@
// For more information, please refer to the license agreement located at:
// https://github.com/Abblix/Oidc.Server/blob/master/README.md

using System.Security.Cryptography.X509Certificates;
using Abblix.Jwt;
using Abblix.Oidc.Server.Common.Constants;
using Abblix.Oidc.Server.Features.ClientInformation;
using Abblix.Oidc.Server.Model;

Expand All @@ -41,215 +39,122 @@ namespace Abblix.Oidc.Server.Common.Configuration;
public record OidcOptions
{
/// <summary>
/// The OIDC discovery options.
/// Configuration options for OIDC discovery. These options control how the OIDC server advertises its capabilities
/// and endpoints to clients through the OIDC Discovery mechanism. Proper configuration ensures that clients can
/// dynamically discover information about the OIDC server, such as URLs for authorization, token, userinfo, and
/// JWKS endpoints, supported scopes, response types, and more.
/// </summary>
public DiscoveryOptions Discovery { get; set; } = new();

/// <summary>
/// The issuer identifier to be used in tokens. It is useful for scenarios where the issuer
/// needs to be consistent and predefined, such as environments with multiple hosts.
/// Represents the unique identifier of the OIDC server.
/// It is recommended to use a URL that is controlled by the entity operating the OIDC server, and it should be
/// consistent across different environments to maintain trust with client applications.
/// </summary>
public string? Issuer { get; set; }

/// <summary>
/// The client configurations supported by the OIDC server.
/// A collection of client configurations supported by this OIDC server. Each <see cref="ClientInfo"/> object
/// defines the settings and capabilities of a registered client, including client ID, client secrets,
/// redirect URIs, and other OAuth2/OIDC parameters. Proper client configuration is essential for securing client
/// applications and enabling them to interact with the OIDC server according to the OAuth2 and OIDC specifications.
/// </summary>
public IEnumerable<ClientInfo> Clients { get; set; } = Array.Empty<ClientInfo>();

/// <summary>
/// The URI for account selection during authentication.
/// The URL to a user interface or service that allows users to select an account during the authentication process.
/// This is useful in scenarios where users have multiple accounts and need to choose which one to use for signing in.
/// </summary>
public Uri? AccountSelectionUri { get; set; }

/// <summary>
/// The URI for obtaining user consent during authentication.
/// The URL to a user interface or service for obtaining user consent during the authentication process. Consent is
/// often required when the client application requests access to user data or when sharing information between
/// different parties. This URI should point to a page or API that can manage consent workflows and communicate
/// the user's decisions back to the OIDC server.
/// </summary>
public Uri? ConsentUri { get; set; }

/// <summary>
/// The URI for handling interactions during the authentication process.
/// The URL to a user interface or service for handling additional interactions required during the authentication
/// process. This can include multi-factor authentication, user consent, or any custom interaction required by the
/// authentication flow. The OIDC server can redirect users to this URI when additional interaction is needed.
/// </summary>
public Uri? InteractionUri { get; set; }

/// <summary>
/// The URI for initiating a login process.
/// The URL to initiate the login process. This URI is typically used in scenarios where the OIDC server needs to
/// direct users to a specific login interface or when integrating with external identity providers. Configuring
/// this URI allows the OIDC server to delegate the initial user authentication step to another service or UI.
/// </summary>
public Uri? LoginUri { get; set; }

/// <summary>
/// The parameter name for authorization request identifier.
/// The name of the parameter used by the OIDC server to pass the authorization request identifier. This parameter
/// name is used in URLs and requests to reference specific authorization requests, especially in advanced features
/// like Pushed Authorization Requests (PAR). Customizing this parameter name can help align with specific client
/// requirements or naming conventions.
/// </summary>
public string RequestUriParameterName { get; set; } = AuthorizationRequest.Parameters.RequestUri;

/// <summary>
/// Specifies which OIDC endpoints are enabled.
/// Specifies which OIDC endpoints are enabled on the server. This property allows for fine-grained control over
/// the available functionality, enabling or disabling specific endpoints based on the server's role, security
/// considerations, or operational requirements. By default, all endpoints are enabled.
/// </summary>
public OidcEndpoints EnabledEndpoints { get; set; } = OidcEndpoints.All;

/// <summary>
/// The certificates used for signing tokens.
/// The collection of JSON Web Keys (JWK) used for signing tokens issued by the OIDC server.
/// Signing tokens is a critical security measure that ensures the integrity and authenticity of the tokens.
/// These keys are used to digitally sign ID tokens, access tokens, and other JWTs issued by the server,
/// allowing clients to verify that the tokens have not been tampered with and were indeed issued by this server.
/// It is recommended to rotate these keys periodically to maintain the security of the token signing process.
/// </summary>
public IReadOnlyCollection<X509Certificate2> SigningCertificates { get; set; } = Array.AsReadOnly(Array.Empty<X509Certificate2>());
public IReadOnlyCollection<JsonWebKey> SigningKeys { get; set; } = Array.Empty<JsonWebKey>();

/// <summary>
/// The options related to the check session cookie.
/// Options related to the check session mechanism in OIDC. This configuration controls how the OIDC server manages
/// session state information, allowing clients to monitor the login session's status. Properly configuring these
/// options ensures that clients can react to session changes (e.g., logout) in a timely and secure manner.
/// </summary>
public CheckSessionCookieOptions CheckSessionCookie { get; set; } = new();

/// <summary>
/// The duration of a login session's expiration.
/// The duration after which a login session expires. This setting determines how long a user's authentication
/// session remains valid before requiring re-authentication. Configuring this duration is essential for balancing
/// security concerns with usability, particularly in environments with varying security requirements.
/// </summary>
public TimeSpan LoginSessionExpiresIn { get; set; } = TimeSpan.FromMinutes(10);

/// <summary>
/// Indicates support for claims parameters in requests.
/// </summary>
public bool ClaimsParameterSupported { get; set; } = true;

/// <summary>
/// A list of scopes supported by the service.
/// </summary>
public IList<string> ScopesSupported { get; set; } = new List<string>
{
Scopes.OpenId,
Scopes.Profile,
Scopes.Email,
Scopes.Phone,
Scopes.Address,
Scopes.OfflineAccess,
};

/// <summary>
/// The claims supported by the service.
/// </summary>
public IList<string> ClaimsSupported { get; set; } = new List<string>
{
JwtClaimTypes.Subject,
JwtClaimTypes.Email,
JwtClaimTypes.EmailVerified,
JwtClaimTypes.PhoneNumber,
JwtClaimTypes.PhoneNumberVerified,
};

/// <summary>
/// The response types supported by the service.
/// </summary>
public IList<string> ResponseTypesSupported { get; set; } = new List<string>
{
ResponseTypes.Code,
ResponseTypes.Token,
ResponseTypes.IdToken,
string.Join(" ", ResponseTypes.IdToken, ResponseTypes.Token),
string.Join(" ", ResponseTypes.Code, ResponseTypes.IdToken),
string.Join(" ", ResponseTypes.Code, ResponseTypes.Token),
string.Join(" ", ResponseTypes.Code, ResponseTypes.IdToken, ResponseTypes.Token),
};

/// <summary>
/// The response modes supported by the service.
/// </summary>
public IList<string> ResponseModesSupported { get; set; } = new List<string>
{
ResponseModes.FormPost,
ResponseModes.Query,
ResponseModes.Fragment,
};

/// <summary>
/// A list of algorithms supported for signing ID tokens.
/// </summary>
public IList<string> IdTokenSigningAlgorithmValuesSupported { get; set; } = new List<string>
{
SigningAlgorithms.None,
SigningAlgorithms.RS256,
};

/// <summary>
/// A list of subject types supported by the OIDC service.
/// </summary>
public IList<string> SubjectTypesSupported { get; set; } = new List<string>
{
SubjectTypes.Public,
SubjectTypes.Pairwise,
};

/// <summary>
/// A list of supported methods for code challenge in PKCE (Proof Key for Code Exchange).
/// </summary>
public IList<string> CodeChallengeMethodsSupported { get; set; } = new List<string>
{
CodeChallengeMethods.Plain,
CodeChallengeMethods.S256,
};

/// <summary>
/// Indicates whether the request parameter is supported by the OIDC service.
/// </summary>
public bool RequestParameterSupported { get; set; } = true;

/// <summary>
/// A list of prompt values supported by the OIDC service.
/// </summary>
public IList<string> PromptValuesSupported { get; set; } = new List<string>
{
Prompts.None,
Prompts.Login,
Prompts.Consent,
Prompts.SelectAccount,
Prompts.Create,
};

/// <summary>
/// Options for configuring a new client in the OIDC service.
/// Configuration options for registering new clients dynamically in the OIDC server. These options define default
/// values and constraints for new client registrations, facilitating dynamic and secure client onboarding processes.
/// </summary>
public NewClientOptions NewClientOptions { get; init; } = new();

/// <summary>
/// A list of algorithms supported for signing UserInfo responses.
/// </summary>
public IList<string> UserInfoSigningAlgValuesSupported { get; set; } = new List<string>
{
SigningAlgorithms.None,
SigningAlgorithms.RS256,
};

/// <summary>
/// A list of algorithms supported for signing request objects.
/// </summary>
public IList<string> RequestObjectSigningAlgValuesSupported { get; set; } = new List<string>
{
SigningAlgorithms.None,
SigningAlgorithms.RS256,
};

/// <summary>
/// The encryption certificates for the OpenID Connect service tokens.
/// The collection of JSON Web Keys (JWK) used for encrypting tokens or sensitive information sent to the clients.
/// Encryption is essential for protecting sensitive data within tokens, especially when tokens are passed through
/// less secure channels or when storing tokens at the client side. These keys are utilized to encrypt ID tokens and,
/// optionally, access tokens when the OIDC server sends them to clients. Clients use the corresponding public keys
/// to decrypt the tokens and access the contained claims.
/// </summary>
public IList<X509Certificate2> EncryptionCertificates { get; set; } = new List<X509Certificate2>();
public IReadOnlyCollection<JsonWebKey> EncryptionKeys { get; set; } = Array.Empty<JsonWebKey>();

/// <summary>
/// The duration for which a pushed authorization request (PAR) is considered valid.
/// The duration for which a Pushed Authorization Request (PAR) is valid. PAR is a security enhancement that allows
/// clients to pre-register authorization requests directly with the authorization server. This duration specifies
/// the maximum time a pre-registered request is considered valid, balancing the need for security with usability
/// in completing the authorization process.
/// </summary>
/// <remarks>
/// This property defines the lifespan of a pushed authorization request. Pushed authorization requests are
/// a security feature in OIDC that allows clients to send authorization requests directly to the authorization
/// server via a backchannel connection, rather than through the user's browser. This duration specifies
/// how long the server should consider the request valid after it has been received. It is important to balance
/// security and usability when configuring this value, ensuring that requests are valid long enough for users
/// to complete the authentication process without leaving too large a window for potential misuse.
/// </remarks>
public TimeSpan PushedAuthorizationRequestExpiresIn { get; set; } = TimeSpan.FromMinutes(1);

/// <summary>
/// The JWT used for licensing and configuration validation of the OIDC service.
/// A JWT used for licensing and configuration validation of the OIDC service. This token contains claims that the
/// OIDC service uses to validate its configuration, features, and licensing status, ensuring the service operates
/// within its licensed capabilities. Proper validation of this token is crucial for the service's legal and functional
/// compliance.
/// </summary>
/// <remarks>
/// This property holds a JSON Web Token (JWT) that the OIDC service uses to validate its configuration and
/// licensing status. The token typically contains claims that the service decodes to determine the features
/// and capabilities that are enabled, based on the licensing agreement. Proper validation of this token
/// is crucial for ensuring that the service operates within the terms of its licensing and has access
/// to the correct set of features. The format and content of this token are determined by the service provider
/// and may include information such as the license expiry date, the licensed feature set and other relevant data.
/// </remarks>
public string? LicenseJwt { get; set; }
}
Loading

0 comments on commit 9a56f5f

Please sign in to comment.