/// <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)));
            }
        }
Example #3
0
 /// <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));
 }
Example #4
0
 /// <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));
 }
Example #5
0
        /// <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));
        }
Example #7
0
        /// <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));
        }
Example #8
0
        /// <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.");
        }
Example #9
0
 /// <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));
 }
Example #10
0
        /// <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.");
        }
Example #11
0
 /// <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);
Example #12
0
 /// <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);