Browse Source

Throw an exception when no signing key is explicitly registered and introduce OpenIddictBuilder.AddEphemeralSigningKey()

pull/170/head
Kévin Chalet 10 years ago
parent
commit
7f646c8554
  1. 10
      samples/Mvc.Server/Startup.cs
  2. 55
      src/OpenIddict.Core/OpenIddictBuilder.cs
  3. 6
      src/OpenIddict.Core/OpenIddictExtensions.cs

10
samples/Mvc.Server/Startup.cs

@ -44,11 +44,13 @@ namespace Mvc.Server {
.AllowRefreshTokenFlow() .AllowRefreshTokenFlow()
// During development, you can disable the HTTPS requirement. // During development, you can disable the HTTPS requirement.
.DisableHttpsRequirement(); .DisableHttpsRequirement()
// Register a new ephemeral key, that is discarded when the application
// shuts down. Tokens signed using this key are automatically invalidated.
// This method should only be used during development.
.AddEphemeralSigningKey();
// Note: if you don't explicitly register a signing key, one is automatically generated and
// persisted on the disk. If the key cannot be persisted, an exception is thrown.
//
// On production, using a X.509 certificate stored in the machine store is recommended. // On production, using a X.509 certificate stored in the machine store is recommended.
// You can generate a self-signed certificate using Pluralsight's self-cert utility: // You can generate a self-signed certificate using Pluralsight's self-cert utility:
// https://s3.amazonaws.com/pluralsight-free/keith-brown/samples/SelfCert.zip // https://s3.amazonaws.com/pluralsight-free/keith-brown/samples/SelfCert.zip

55
src/OpenIddict.Core/OpenIddictBuilder.cs

@ -10,11 +10,13 @@ using System.IdentityModel.Tokens.Jwt;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using AspNet.Security.OpenIdConnect.Extensions; using AspNet.Security.OpenIdConnect.Extensions;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using OpenIddict; using OpenIddict;
namespace Microsoft.AspNetCore.Builder { namespace Microsoft.AspNetCore.Builder {
@ -276,6 +278,59 @@ namespace Microsoft.AspNetCore.Builder {
}); });
} }
/// <summary>
/// Registers a new ephemeral key used to sign the tokens issued by OpenIddict: the key
/// is discarded when the application shuts down and tokens signed using this key are
/// automatically invalidated. This method should only be used during development:
/// on production, using a X.509 certificate stored in the machine store is recommended.
/// </summary>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public virtual OpenIddictBuilder AddEphemeralSigningKey() {
// Note: a 1024-bit key might be returned by RSA.Create() on .NET Desktop/Mono,
// where RSACryptoServiceProvider is still the default implementation and
// where custom implementations can be registered via CryptoConfig.
// To ensure the key size is always acceptable, replace it if necessary.
var algorithm = RSA.Create();
if (algorithm.KeySize < 2048) {
algorithm.KeySize = 2048;
}
#if NET451
// Note: RSACng cannot be used as it's not available on Mono.
if (algorithm.KeySize < 2048 && algorithm is RSACryptoServiceProvider) {
algorithm.Dispose();
algorithm = new RSACryptoServiceProvider(2048);
}
#endif
if (algorithm.KeySize < 2048) {
throw new InvalidOperationException("The ephemeral key generation failed.");
}
// Note: the RSA instance cannot be flowed as-is due to a bug in IdentityModel that disposes
// the underlying algorithm when it can be cast to RSACryptoServiceProvider. To work around
// this bug, the RSA public/private parameters are manually exported and re-imported when needed.
SecurityKey key;
#if NET451
if (algorithm is RSACryptoServiceProvider) {
var parameters = algorithm.ExportParameters(includePrivateParameters: true);
key = new RsaSecurityKey(parameters);
// Dispose the algorithm instance.
algorithm.Dispose();
}
else {
#endif
key = new RsaSecurityKey(algorithm);
#if NET451
}
#endif
return Configure(options => options.SigningCredentials.AddKey(key));
}
/// <summary> /// <summary>
/// Registers a <see cref="X509Certificate2"/> used to sign the tokens issued by OpenIddict. /// Registers a <see cref="X509Certificate2"/> used to sign the tokens issued by OpenIddict.
/// </summary> /// </summary>

6
src/OpenIddict.Core/OpenIddictExtensions.cs

@ -93,6 +93,12 @@ namespace Microsoft.AspNetCore.Builder {
options.Cache = app.ApplicationServices.GetRequiredService<IDistributedCache>(); options.Cache = app.ApplicationServices.GetRequiredService<IDistributedCache>();
} }
if (options.SigningCredentials.Count == 0) {
throw new InvalidOperationException("At least one signing key must be registered. Consider registering a X.509 " +
"certificate using 'services.AddOpenIddict().AddSigningCertificate()' or call " +
"'services.AddOpenIddict().AddEphemeralSigningKey()' to use an ephemeral key.");
}
// Ensure at least one flow has been enabled. // Ensure at least one flow has been enabled.
if (options.GrantTypes.Count == 0) { if (options.GrantTypes.Count == 0) {
throw new InvalidOperationException("At least one OAuth2/OpenID Connect flow must be enabled."); throw new InvalidOperationException("At least one OAuth2/OpenID Connect flow must be enabled.");

Loading…
Cancel
Save