From 82bc684c5f226261d11332061647f45f2665774c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Thu, 12 May 2016 23:25:23 +0200 Subject: [PATCH] Introduce UseSigningCertificate to make X.509 certificates easier to register in the OpenIddict options --- samples/Mvc.Server/Certificate.pfx | Bin 0 -> 2482 bytes samples/Mvc.Server/Startup.cs | 20 +++ samples/Mvc.Server/project.json | 4 + src/OpenIddict.Core/OpenIddictExtensions.cs | 136 +++++++++++++++++++- 4 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 samples/Mvc.Server/Certificate.pfx diff --git a/samples/Mvc.Server/Certificate.pfx b/samples/Mvc.Server/Certificate.pfx new file mode 100644 index 0000000000000000000000000000000000000000..8c05f9d4d414d5036c38f34f8755b711d4f8811d GIT binary patch literal 2482 zcmY*adpOi-8~)9~jG=@X8WTe~hS6ZwsihX>Y>NC<>g0B7;H%2Ny|7*MT)LXl75H2CWrbxRg^g!5{B?SkmJ19R%Qs-hi}4MT4(21l<7_QTC; zhFRy@iAohZig$N!6`CqnNIX-OrcKMTbXD>*;`^6iMf9U}dzi`ET}#p0kiX zn_E1rxtYUy_&BM~tp_t8;H-q*<=GUVUmD{P%#_n9H?OTv{+@XM2xMHjW5uGKg=k~f z2amqit^(MKN6($FO@8qb&GXH6QDHUc+>>gj!9;Ki*6b?iJ(r zH$ZEI!bbNfD(YJuWL1T|K3soS0x?9m{LHl8*pM|f7COg9o59RbqmdSdK6}rtaRh9R zh{}vxI>PL>d)zjmv8lG`tf;if2r{wa$W8_EVo2ualvRc({_ry4P0H5&`!V`2R?x7n zECIoRGmhIk;mY^m$#nQpF|*J}ILgR|Dl*ACh6 zL!uIQ)(bJ6l*Wh8Uxz<1U+DP6qMhf7rZ3^W&FxmCsO=W3B3h(y1O7maO3mg8x!O4t zKh>*~vIt9#M3Jm3(tPFYugc5>Y8Tab566wYYRQ~>x{j^%@phz=B`d$Y94Vye7!1lm zzopGDR_vuVxEgH~4auUn9&@&8QJ0tb^4H8=1<);5biZd3-6yU|4q6N`N~-JIb>yM< zVktlMx6;*l+0X*qlbDdN-?+~l7>^DFYAZW?`HJ>)Z}YNMo*pE zNt~>i|Kvvc<-WJa%cdlR`>fD}F(Y~`{V>n}QjcNGzS-J#@`rY%vnDsh+@dO5en!(U zBuQnf(^`bUxn-`?1x6G7kq=!e>-s1wDH5P$Xw|O8MMP)D%|lPsblz)f_GG}M4?bft z#XHkP4<^QM~7@0#~Sb)_|tN`J76Lmi5c(cd#O9Qnt3${(~@3g)(|Ev(?M zyFX?&UT*HrAcuu!pB+n38XeYb6D#TdoQ{;|d}$5Ux4hGF_k?q+XwsA%srzbUd-ncY zHs{490^Vvv^0hSM$B5{EzDtyZCISwJ002OA`nQSEw8WbOdVmk`6QBjc6VL}i0GS>L zUyzYNMglnjI0HKL0WXkg0^T5WK_>~UI-sHpYQDrk1WFA7fkSAzVh~MtyenV>1b_i5 z5CVjQ@CD8Ta=CuvR={Zy(+J6mza>Mr6C7Vvxv6 z4lrB08stzB^NX~KaiDBm(~oLwK>5wBpDCpxp=^J2gt*jX%-HPSw7t&j8z~12-6E;F zuGMuD#gAP0;TvL4-+jalN_ZpJpl>Vd4O&>YtR2mghGh+@E(XL?>m@#BjV45z;K{sv z+E?{{8{VMDHV~k*>lYa%pY+7Ex8hEliD!J|>$%&BCm)83Ck^AZ9O6W7aOcl=M@HdFaVt)rR! zyK?k{iUuJENoGWb{Q(eu4`y(Tn+V3eoRcG(DE;G37Wt3uH!^aZI6Up0 zF7kD2SCx3NHcZ7k)zSI+l9YG0wo?wH7_!&t3!4a3&8iE~fbe2fhy zS$9U~H&Pkt&7&o*miw1n9P_^F$o!iz&-6P6=udX)0hsaC;;m`bydX)+;We?F-0{!x zH+}6=f3Gl5Tiz|K9*a|YT+57jPsq9A28Sa}H&!&n6hzuu`@Iy37LO1YrYWlj{5!9C zwtX#^$=Ix{w=0Qaa$Z;4CJs3FZSPTk9G+~FL^#}$O;E5OnIP&CWr;|HfSL#lii2a` uIJb^0)}Y-Z<4p2IzGW4c$JV97F}teVFIaxKqA_Or9lZuCV;KvZEdB|+V@&1% literal 0 HcmV?d00001 diff --git a/samples/Mvc.Server/Startup.cs b/samples/Mvc.Server/Startup.cs index d9483681..439516b3 100644 --- a/samples/Mvc.Server/Startup.cs +++ b/samples/Mvc.Server/Startup.cs @@ -1,4 +1,5 @@ using System.Linq; +using System.Reflection; using AspNet.Security.OAuth.GitHub; using CryptoHelper; using Microsoft.AspNetCore.Builder; @@ -83,6 +84,25 @@ namespace Mvc.Server { app.UseOpenIddict(builder => { builder.Options.AllowInsecureHttp = true; + // 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 in-memory key is used instead: + // when the application shuts down, the key is definitely lost and the access/identity tokens + // will be considered as invalid by client applications/resource servers when validating them. + // + // 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: + // https://s3.amazonaws.com/pluralsight-free/keith-brown/samples/SelfCert.zip + // + // builder.UseSigningCertificate("7D2A741FE34CC2C7369237A5F2078988E17A6A75"); + // + // Alternatively, you can also store the certificate as an embedded .pfx resource + // directly in this assembly or in a file published alongside this project: + // + // builder.UseSigningCertificate( + // assembly: typeof(Startup).GetTypeInfo().Assembly, + // resource: "Nancy.Server.Certificate.pfx", + // password: "Owin.Security.OpenIdConnect.Server"); + // You can customize the default Content Security Policy (CSP) by calling UseNWebsec explicitly. // This can be useful to allow your HTML views to reference remote scripts/images/styles. builder.UseNWebsec(directives => { diff --git a/samples/Mvc.Server/project.json b/samples/Mvc.Server/project.json index c2f3504a..ada35516 100644 --- a/samples/Mvc.Server/project.json +++ b/samples/Mvc.Server/project.json @@ -5,6 +5,10 @@ "warningsAsErrors": true, "preserveCompilationContext": true, + "embed": { + "include": [ "Certificate.pfx" ] + }, + "copyToOutput": { "include": [ "wwwroot", diff --git a/src/OpenIddict.Core/OpenIddictExtensions.cs b/src/OpenIddict.Core/OpenIddictExtensions.cs index a8201bf5..ff7d5911 100644 --- a/src/OpenIddict.Core/OpenIddictExtensions.cs +++ b/src/OpenIddict.Core/OpenIddictExtensions.cs @@ -5,14 +5,17 @@ */ using System; +using System.IO; using System.Linq; using System.Reflection; +using System.Security.Cryptography.X509Certificates; using AspNet.Security.OpenIdConnect.Server; using JetBrains.Annotations; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.IdentityModel.Tokens; using OpenIddict; namespace Microsoft.AspNetCore.Builder { @@ -145,13 +148,14 @@ namespace Microsoft.AspNetCore.Builder { var environment = app.ApplicationServices.GetRequiredService(); builder.Options.AllowInsecureHttp = environment.IsDevelopment() || environment.IsEnvironment("Testing"); - configuration(builder); + // Run the configuration delegate + // provided by the application. + configuration.Invoke(builder); - - // Add OpenIdConnectServerMiddleware to the ASP.NET 5 pipeline. + // Add OpenIdConnectServerMiddleware to the ASP.NET Core pipeline. builder.AddModule("ASOS", 0, map => map.UseOpenIdConnectServer(builder.Options)); - // Register the OpenIddict modules in the ASP.NET 5 pipeline. + // Register the OpenIddict modules in the ASP.NET Core pipeline. foreach (var module in builder.Modules.OrderBy(module => module.Position)) { if (module.Registration == null) { throw new InvalidOperationException("The registration delegate cannot be null."); @@ -162,5 +166,129 @@ namespace Microsoft.AspNetCore.Builder { return app; } + + /// + /// Registers a used to sign the tokens issued by OpenIddict. + /// + /// The builder used to configure OpenIddict. + /// The certificate used to sign the security tokens issued by the server. + /// The . + public static OpenIddictBuilder UseSigningCertificate( + [NotNull] this OpenIddictBuilder builder, [NotNull] X509Certificate2 certificate) { + if (builder == null) { + throw new ArgumentNullException(nameof(builder)); + } + + // Register the certificate in the ASOS/OpenIddict options. + builder.Options.SigningCredentials.AddCertificate(certificate); + + return builder; + } + + /// + /// Registers a retrieved from + /// an embedded resource to sign the tokens issued by OpenIddict. + /// + /// The builder used to configure OpenIddict. + /// The assembly containing the certificate. + /// The name of the embedded resource. + /// The password used to open the certificate. + /// The . + public static OpenIddictBuilder UseSigningCertificate( + [NotNull] this OpenIddictBuilder builder, [NotNull] Assembly assembly, + [NotNull] string resource, [NotNull] string password) { + if (builder == null) { + throw new ArgumentNullException(nameof(builder)); + } + + // Register the certificate in the ASOS/OpenIddict options. + builder.Options.SigningCredentials.AddCertificate(assembly, resource, password); + + return builder; + } + + /// + /// Registers a extracted + /// from a stream to sign the tokens issued by OpenIddict. + /// + /// The builder used to configure OpenIddict. + /// The stream containing the certificate. + /// The password used to open the certificate. + /// The . + public static OpenIddictBuilder UseSigningCertificate( + [NotNull] this OpenIddictBuilder builder, + [NotNull] Stream stream, [NotNull] string password) { + if (builder == null) { + throw new ArgumentNullException(nameof(builder)); + } + + // Register the certificate in the ASOS/OpenIddict options. + builder.Options.SigningCredentials.AddCertificate(stream, password); + + return builder; + } + + /// + /// Registers a extracted + /// from a stream to sign the tokens issued by OpenIddict. + /// + /// The builder used to configure OpenIddict. + /// The stream containing the certificate. + /// The password used to open the certificate. + /// An enumeration of flags indicating how and where to store the private key of the certificate. + /// The . + public static OpenIddictBuilder UseSigningCertificate( + [NotNull] this OpenIddictBuilder builder, [NotNull] Stream stream, + [NotNull] string password, X509KeyStorageFlags flags) { + if (builder == null) { + throw new ArgumentNullException(nameof(builder)); + } + + // Register the certificate in the ASOS/OpenIddict options. + builder.Options.SigningCredentials.AddCertificate(stream, password, flags); + + return builder; + } + + /// + /// Registers a retrieved from the + /// X.509 machine store to sign the tokens issued by OpenIddict. + /// + /// The builder used to configure OpenIddict. + /// The thumbprint of the certificate used to identify it in the X.509 store. + /// The . + public static OpenIddictBuilder UseSigningCertificate( + [NotNull] this OpenIddictBuilder builder, [NotNull] string thumbprint) { + if (builder == null) { + throw new ArgumentNullException(nameof(builder)); + } + + // Register the certificate in the ASOS/OpenIddict options. + builder.Options.SigningCredentials.AddCertificate(thumbprint); + + return builder; + } + + /// + /// Registers a retrieved from the + /// given X.509 store to sign the tokens issued by OpenIddict. + /// + /// The builder used to configure OpenIddict. + /// The thumbprint of the certificate used to identify it in the X.509 store. + /// The name of the X.509 store. + /// The location of the X.509 store. + /// The . + public static OpenIddictBuilder UseSigningCertificate( + [NotNull] this OpenIddictBuilder builder, + [NotNull] string thumbprint, StoreName name, StoreLocation location) { + if (builder == null) { + throw new ArgumentNullException(nameof(builder)); + } + + // Register the certificate in the ASOS/OpenIddict options. + builder.Options.SigningCredentials.AddCertificate(thumbprint, name, location); + + return builder; + } } } \ No newline at end of file