/// <summary> /// Adds a specific <see cref="X509Certificate2"/> retrieved from an /// embedded resource to sign the tokens issued by the OpenID Connect server. /// </summary> /// <param name="credentials">The options used to configure the OpenID Connect server.</param> /// <param name="assembly">The assembly containing the certificate.</param> /// <param name="resource">The name of the embedded resource.</param> /// <param name="password">The password used to open the certificate.</param> /// <returns>The signing credentials.</returns> public static IList <SigningCredentials> AddCertificate( [NotNull] this IList <SigningCredentials> credentials, [NotNull] Assembly assembly, [NotNull] string resource, [NotNull] string password) { if (credentials == null) { throw new ArgumentNullException(nameof(credentials)); } if (assembly == null) { throw new ArgumentNullException(nameof(assembly)); } if (string.IsNullOrEmpty(resource)) { throw new ArgumentException("The resource cannot be null or empty.", nameof(resource)); } if (string.IsNullOrEmpty(password)) { throw new ArgumentException("The password cannot be null or empty.", nameof(password)); } using (var stream = assembly.GetManifestResourceStream(resource)) { if (stream == null) { throw new InvalidOperationException("The certificate was not found in the specified assembly."); } return(credentials.AddCertificate(stream, password)); } }
/// <summary> /// Adds a specific <see cref="X509Certificate2"/> contained in /// a stream to sign the tokens issued by the OpenID Connect server. /// </summary> /// <param name="credentials">The options used to configure the OpenID Connect server.</param> /// <param name="stream">The stream containing the certificate.</param> /// <param name="password">The password used to open the certificate.</param> /// <param name="flags">An enumeration of flags indicating how and where to store the private key of the certificate.</param> /// <returns>The signing credentials.</returns> public static IList <SigningCredentials> AddCertificate( [NotNull] this IList <SigningCredentials> credentials, [NotNull] Stream stream, [NotNull] string password, X509KeyStorageFlags flags) { if (credentials == null) { throw new ArgumentNullException(nameof(credentials)); } if (stream == null) { throw new ArgumentNullException(nameof(stream)); } if (string.IsNullOrEmpty(password)) { throw new ArgumentException("The password cannot be null or empty.", nameof(password)); } using (var buffer = new MemoryStream()) { stream.CopyTo(buffer); return(credentials.AddCertificate(new X509Certificate2(buffer.ToArray(), password, flags))); } }
/// <summary> /// Adds a specific <see cref="X509Certificate2"/> contained in /// a stream to sign tokens issued by the OpenID Connect server. /// </summary> /// <param name="credentials">The options used to configure the OpenID Connect server.</param> /// <param name="stream">The stream containing the certificate.</param> /// <param name="password">The password used to open the certificate.</param> /// <returns>The signing credentials.</returns> public static IList <SigningCredentials> AddCertificate( this IList <SigningCredentials> credentials, Stream stream, string password) { return(credentials.AddCertificate(stream, password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet)); }
/// <summary> /// Adds a specific <see cref="X509Certificate2"/> contained in a stream /// to decrypt authorization requests received by the OpenID Connect server. /// </summary> /// <param name="credentials">The options used to configure the OpenID Connect server.</param> /// <param name="stream">The stream containing the certificate.</param> /// <param name="password">The password used to open the certificate.</param> /// <returns>The encryption credentials.</returns> public static IList <EncryptingCredentials> AddCertificate( [NotNull] this IList <EncryptingCredentials> credentials, [NotNull] Stream stream, [NotNull] string password) { return(credentials.AddCertificate(stream, password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet)); }
/// <summary> /// Registers (and generates if necessary) a user-specific development certificate /// used to sign the tokens issued by the OpenID Connect server. /// </summary> /// <param name="credentials">The signing credentials.</param> /// <param name="subject">The subject name associated with the certificate.</param> /// <returns>The signing credentials.</returns> public static IList <SigningCredentials> AddDevelopmentCertificate( [NotNull] this IList <SigningCredentials> credentials, [NotNull] X500DistinguishedName subject) { if (credentials == null) { throw new ArgumentNullException(nameof(credentials)); } if (subject == null) { throw new ArgumentNullException(nameof(subject)); } // Try to retrieve the development certificate from the specified store. // If a certificate was found but is not yet or no longer valid, remove it // from the store before creating and persisting a new signing certificate. var certificate = OpenIdConnectServerHelpers.GetDevelopmentCertificate(subject); if (certificate != null && (certificate.NotBefore > DateTime.Now || certificate.NotAfter < DateTime.Now)) { OpenIdConnectServerHelpers.RemoveDevelopmentCertificate(certificate); certificate = null; } #if SUPPORTS_CERTIFICATE_GENERATION // If no appropriate certificate can be found, generate // and persist a new certificate in the specified store. if (certificate == null) { certificate = OpenIdConnectServerHelpers.GenerateDevelopmentCertificate(subject); OpenIdConnectServerHelpers.PersistDevelopmentCertificate(certificate); } return(credentials.AddCertificate(certificate)); #else throw new PlatformNotSupportedException("X.509 certificate generation is not supported on this platform."); #endif }
/// <summary> /// Adds a specific <see cref="X509Certificate2"/> retrieved from the given /// X.509 store to sign the tokens issued by the OpenID Connect server. /// </summary> /// <param name="credentials">The options used to configure the OpenID Connect server.</param> /// <param name="thumbprint">The thumbprint of the certificate used to identify it in the X.509 store.</param> /// <param name="name">The name of the X.509 store.</param> /// <param name="location">The location of the X.509 store.</param> /// <returns>The signing credentials.</returns> public static IList <SigningCredentials> AddCertificate( [NotNull] this IList <SigningCredentials> credentials, [NotNull] string thumbprint, StoreName name, StoreLocation location) { if (credentials == null) { throw new ArgumentNullException(nameof(credentials)); } if (string.IsNullOrEmpty(thumbprint)) { throw new ArgumentException("The thumbprint cannot be null or empty.", nameof(thumbprint)); } var certificate = OpenIdConnectServerHelpers.GetCertificate(name, location, thumbprint); if (certificate == null) { throw new InvalidOperationException("The certificate corresponding to the specified thumbprint was not found."); } return(credentials.AddCertificate(certificate)); }
/// <summary> /// Adds a specific <see cref="X509Certificate2"/> retrieved from the X.509 machine store /// to decrypt authorization requests received by the OpenID Connect server. /// </summary> /// <param name="credentials">The options used to configure the OpenID Connect server.</param> /// <param name="thumbprint">The thumbprint of the certificate used to identify it in the X.509 store.</param> /// <returns>The encryption credentials.</returns> public static IList <EncryptingCredentials> AddCertificate( [NotNull] this IList <EncryptingCredentials> credentials, [NotNull] string thumbprint) { if (credentials == null) { throw new ArgumentNullException(nameof(credentials)); } if (string.IsNullOrEmpty(thumbprint)) { throw new ArgumentException("The thumbprint cannot be null or empty.", nameof(thumbprint)); } var certificate = OpenIdConnectServerHelpers.GetCertificate(StoreName.My, StoreLocation.CurrentUser, thumbprint) ?? OpenIdConnectServerHelpers.GetCertificate(StoreName.My, StoreLocation.LocalMachine, thumbprint); if (certificate == null) { throw new InvalidOperationException("The certificate corresponding to the given thumbprint was not found."); } return(credentials.AddCertificate(certificate)); }
/// <summary> /// Adds a specific <see cref="SecurityKey"/> to sign tokens issued by the OpenID Connect server. /// </summary> /// <param name="credentials">The options used to configure the OpenID Connect server.</param> /// <param name="key">The key used to sign security tokens issued by the server.</param> /// <returns>The signing credentials.</returns> public static IList <SigningCredentials> AddKey( [NotNull] this IList <SigningCredentials> credentials, [NotNull] SecurityKey key) { if (credentials == null) { throw new ArgumentNullException(nameof(credentials)); } if (key == null) { throw new ArgumentNullException(nameof(key)); } if (key.IsSupportedAlgorithm(SecurityAlgorithms.RsaSha256Signature)) { var x509SecurityKey = key as X509SecurityKey; if (x509SecurityKey != null) { return(credentials.AddCertificate(x509SecurityKey.Certificate)); } var x509AsymmetricSecurityKey = key as X509AsymmetricSecurityKey; if (x509AsymmetricSecurityKey != null) { // The X.509 certificate is not directly accessible when using X509AsymmetricSecurityKey. // Reflection is the only way to get the certificate used to create the security key. var field = typeof(X509AsymmetricSecurityKey).GetField( name: "certificate", bindingAttr: BindingFlags.Instance | BindingFlags.NonPublic); Debug.Assert(field != null); return(credentials.AddCertificate((X509Certificate2)field.GetValue(x509AsymmetricSecurityKey))); } // Create an empty security key identifier. var identifier = new SecurityKeyIdentifier(); var rsaSecurityKey = key as RsaSecurityKey; if (rsaSecurityKey != null) { // Resolve the underlying algorithm from the security key. var algorithm = (RSA)rsaSecurityKey.GetAsymmetricAlgorithm( algorithm: SecurityAlgorithms.RsaSha256Signature, requiresPrivateKey: false); Debug.Assert(algorithm != null, "SecurityKey.GetAsymmetricAlgorithm() shouldn't return a null algorithm."); // Export the RSA public key to extract a key identifier based on the modulus component. var parameters = algorithm.ExportParameters(includePrivateParameters: false); Debug.Assert(parameters.Modulus != null, "RSA.ExportParameters() shouldn't return a null modulus."); // Only use the 40 first chars of the base64url-encoded modulus. var kid = Base64UrlEncoder.Encode(parameters.Modulus); kid = kid.Substring(0, Math.Min(kid.Length, 40)).ToUpperInvariant(); identifier.Add(new RsaKeyIdentifierClause(algorithm)); identifier.Add(new LocalIdKeyIdentifierClause(kid)); } // Mark the security key identifier as read-only to // ensure it can't be altered during a request. identifier.MakeReadOnly(); credentials.Add(new SigningCredentials(key, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest, identifier)); return(credentials); } else if (key.IsSupportedAlgorithm(SecurityAlgorithms.HmacSha256Signature)) { // When using an in-memory symmetric key, no identifier clause can be inferred from the key itself. // To prevent the built-in security token handlers from throwing an exception, a default identifier is added. var identifier = new SecurityKeyIdentifier(new LocalIdKeyIdentifierClause("Default")); // Mark the security key identifier as read-only to // ensure it can't be altered during a request. identifier.MakeReadOnly(); credentials.Add(new SigningCredentials(key, SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.Sha256Digest, identifier)); return(credentials); } throw new InvalidOperationException("A signature algorithm cannot be automatically inferred from the signing key. " + "Consider using 'options.SigningCredentials.Add(SigningCredentials)' instead."); }
/// <summary> /// Adds a specific <see cref="X509Certificate2"/> retrieved from the /// X.509 machine store to sign tokens issued by the OpenID Connect server. /// </summary> /// <param name="credentials">The options used to configure the OpenID Connect server.</param> /// <param name="thumbprint">The thumbprint of the certificate used to identify it in the X.509 store.</param> /// <returns>The signing credentials.</returns> public static IList <SigningCredentials> AddCertificate( [NotNull] this IList <SigningCredentials> credentials, [NotNull] string thumbprint) { return(credentials.AddCertificate(thumbprint, StoreName.My, StoreLocation.LocalMachine)); }
/// <summary> /// Adds a specific <see cref="SecurityKey"/> to decrypt /// authorization requests received by the OpenID Connect server. /// </summary> /// <param name="credentials">The options used to configure the OpenID Connect server.</param> /// <param name="key">The key used to sign security tokens issued by the server.</param> /// <returns>The encryption credentials.</returns> public static IList <EncryptingCredentials> AddKey( [NotNull] this IList <EncryptingCredentials> credentials, [NotNull] SecurityKey key) { if (credentials == null) { throw new ArgumentNullException(nameof(credentials)); } if (key == null) { throw new ArgumentNullException(nameof(key)); } if (key.IsSupportedAlgorithm(SecurityAlgorithms.RsaOaepKeyWrap)) { var x509SecurityKey = key as X509SecurityKey; if (x509SecurityKey != null) { return(credentials.AddCertificate(x509SecurityKey.Certificate)); } var x509AsymmetricSecurityKey = key as X509AsymmetricSecurityKey; if (x509AsymmetricSecurityKey != null) { // The X.509 certificate is not directly accessible when using X509AsymmetricSecurityKey. // Reflection is the only way to get the certificate used to create the security key. var field = typeof(X509AsymmetricSecurityKey).GetField( name: "certificate", bindingAttr: BindingFlags.Instance | BindingFlags.NonPublic); Debug.Assert(field != null); return(credentials.AddCertificate((X509Certificate2)field.GetValue(x509AsymmetricSecurityKey))); } // Create an empty security key identifier. var identifier = new SecurityKeyIdentifier(); var rsaSecurityKey = key as RsaSecurityKey; if (rsaSecurityKey != null) { // When using a RSA key, the public part is used to uniquely identify the key. var algorithm = (RSA)rsaSecurityKey.GetAsymmetricAlgorithm( algorithm: SecurityAlgorithms.RsaOaepKeyWrap, requiresPrivateKey: false); Debug.Assert(algorithm != null); // Export the RSA public key to extract a key identifier based on the modulus component. var parameters = algorithm.ExportParameters(includePrivateParameters: false); // Only use the 40 first chars of the base64url-encoded modulus. var kid = Base64UrlEncoder.Encode(parameters.Modulus); kid = kid.Substring(0, Math.Min(kid.Length, 40)).ToUpperInvariant(); identifier.Add(new LocalIdKeyIdentifierClause(kid)); identifier.Add(new RsaKeyIdentifierClause(algorithm)); } credentials.Add(new EncryptingCredentials(key, identifier, SecurityAlgorithms.RsaOaepKeyWrap)); return(credentials); } else if (key.IsSupportedAlgorithm(SecurityAlgorithms.Aes256Encryption)) { // When using an in-memory symmetric key, no identifier clause can be inferred from the key itself. // To prevent the built-in security token handlers from throwing an exception, a default identifier is added. var identifier = new SecurityKeyIdentifier(new LocalIdKeyIdentifierClause("Default")); credentials.Add(new EncryptingCredentials(key, identifier, SecurityAlgorithms.Aes256Encryption)); return(credentials); } throw new InvalidOperationException("The encryption key type is not supported."); }
/// <summary> /// Adds a specific <see cref="X509Certificate2"/> contained in /// a stream to sign the tokens issued by the OpenID Connect server. /// </summary> /// <param name="credentials">The options used to configure the OpenID Connect server.</param> /// <param name="stream">The stream containing the certificate.</param> /// <param name="password">The password used to open the certificate.</param> /// <returns>The signing credentials.</returns> public static IList <SigningCredentials> AddCertificate( [NotNull] this IList <SigningCredentials> credentials, [NotNull] Stream stream, [NotNull] string password) => credentials.AddCertificate(stream, password, X509KeyStorageFlags.MachineKeySet);
/// <summary> /// Adds a specific <see cref="X509Certificate2"/> retrieved from an /// embedded resource to sign the tokens issued by the OpenID Connect server. /// </summary> /// <param name="credentials">The options used to configure the OpenID Connect server.</param> /// <param name="assembly">The assembly containing the certificate.</param> /// <param name="resource">The name of the embedded resource.</param> /// <param name="password">The password used to open the certificate.</param> /// <returns>The signing credentials.</returns> public static IList <SigningCredentials> AddCertificate( [NotNull] this IList <SigningCredentials> credentials, [NotNull] Assembly assembly, [NotNull] string resource, [NotNull] string password) => credentials.AddCertificate(assembly, resource, password, X509KeyStorageFlags.MachineKeySet);