diff options
9 files changed, 130 insertions, 146 deletions
diff --git a/projecttemplates/RelyingPartyLogic/OAuthAuthenticationModule.cs b/projecttemplates/RelyingPartyLogic/OAuthAuthenticationModule.cs index 0e4dc5c..2c9dc66 100644 --- a/projecttemplates/RelyingPartyLogic/OAuthAuthenticationModule.cs +++ b/projecttemplates/RelyingPartyLogic/OAuthAuthenticationModule.cs @@ -49,13 +49,15 @@ namespace RelyingPartyLogic { return; } - var tokenAnalyzer = new SpecialAccessTokenAnalyzer(OAuthAuthorizationServer.AsymmetricKeyServiceProvider, OAuthAuthorizationServer.AsymmetricKeyServiceProvider); - var resourceServer = new ResourceServer(tokenAnalyzer); + using (var crypto = OAuthAuthorizationServer.CreateAsymmetricKeyServiceProvider()) { + var tokenAnalyzer = new SpecialAccessTokenAnalyzer(crypto, crypto); + var resourceServer = new ResourceServer(tokenAnalyzer); - IPrincipal principal; - var errorMessage = resourceServer.VerifyAccess(new HttpRequestInfo(this.application.Context.Request), out principal); - if (errorMessage == null) { - this.application.Context.User = principal; + IPrincipal principal; + var errorMessage = resourceServer.VerifyAccess(new HttpRequestInfo(this.application.Context.Request), out principal); + if (errorMessage == null) { + this.application.Context.User = principal; + } } } diff --git a/projecttemplates/RelyingPartyLogic/OAuthAuthorizationManager.cs b/projecttemplates/RelyingPartyLogic/OAuthAuthorizationManager.cs index 5266eb5..c4bcbba 100644 --- a/projecttemplates/RelyingPartyLogic/OAuthAuthorizationManager.cs +++ b/projecttemplates/RelyingPartyLogic/OAuthAuthorizationManager.cs @@ -32,38 +32,40 @@ namespace RelyingPartyLogic { var httpDetails = operationContext.RequestContext.RequestMessage.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty; var requestUri = operationContext.RequestContext.RequestMessage.Properties.Via; - var tokenAnalyzer = new SpecialAccessTokenAnalyzer(OAuthAuthorizationServer.AsymmetricKeyServiceProvider, OAuthAuthorizationServer.AsymmetricKeyServiceProvider); - var resourceServer = new ResourceServer(tokenAnalyzer); + using (var crypto = OAuthAuthorizationServer.CreateAsymmetricKeyServiceProvider()) { + var tokenAnalyzer = new SpecialAccessTokenAnalyzer(crypto, crypto); + var resourceServer = new ResourceServer(tokenAnalyzer); - try { - IPrincipal principal; - var errorResponse = resourceServer.VerifyAccess(httpDetails, requestUri, out principal); - if (errorResponse == null) { - var policy = new OAuthPrincipalAuthorizationPolicy(principal); - var policies = new List<IAuthorizationPolicy> { + try { + IPrincipal principal; + var errorResponse = resourceServer.VerifyAccess(httpDetails, requestUri, out principal); + if (errorResponse == null) { + var policy = new OAuthPrincipalAuthorizationPolicy(principal); + var policies = new List<IAuthorizationPolicy> { policy, }; - var securityContext = new ServiceSecurityContext(policies.AsReadOnly()); - if (operationContext.IncomingMessageProperties.Security != null) { - operationContext.IncomingMessageProperties.Security.ServiceSecurityContext = securityContext; - } else { - operationContext.IncomingMessageProperties.Security = new SecurityMessageProperty { - ServiceSecurityContext = securityContext, - }; - } + var securityContext = new ServiceSecurityContext(policies.AsReadOnly()); + if (operationContext.IncomingMessageProperties.Security != null) { + operationContext.IncomingMessageProperties.Security.ServiceSecurityContext = securityContext; + } else { + operationContext.IncomingMessageProperties.Security = new SecurityMessageProperty { + ServiceSecurityContext = securityContext, + }; + } - securityContext.AuthorizationContext.Properties["Identities"] = new List<IIdentity> { + securityContext.AuthorizationContext.Properties["Identities"] = new List<IIdentity> { principal.Identity, }; - // Only allow this method call if the access token scope permits it. - if (principal.IsInRole(operationContext.IncomingMessageHeaders.Action)) { - return true; + // Only allow this method call if the access token scope permits it. + if (principal.IsInRole(operationContext.IncomingMessageHeaders.Action)) { + return true; + } } + } catch (ProtocolException /*ex*/) { + ////Logger.Error("Error processing OAuth messages.", ex); } - } catch (ProtocolException /*ex*/) { - ////Logger.Error("Error processing OAuth messages.", ex); } return false; diff --git a/projecttemplates/RelyingPartyLogic/OAuthAuthorizationServer.cs b/projecttemplates/RelyingPartyLogic/OAuthAuthorizationServer.cs index 034afeb..2e791ff 100644 --- a/projecttemplates/RelyingPartyLogic/OAuthAuthorizationServer.cs +++ b/projecttemplates/RelyingPartyLogic/OAuthAuthorizationServer.cs @@ -21,29 +21,37 @@ namespace RelyingPartyLogic { /// Provides OAuth 2.0 authorization server information to DotNetOpenAuth. /// </summary> public class OAuthAuthorizationServer : IAuthorizationServer { - private static readonly RSAParameters AsymmetricKey; + private static readonly RSAParameters AsymmetricKey = CreateRSAKey(); - [ThreadStatic] - internal static readonly RSACryptoServiceProvider AsymmetricKeyServiceProvider = CreateAsymmetricKeyServiceProvider(); - - private static readonly byte[] secret; + private static readonly byte[] secret = CreateSecret(); private readonly INonceStore nonceStore = new NonceDbStore(); - static OAuthAuthorizationServer() { + /// <summary> + /// Creates a symmetric secret used to sign and encrypt authorization server refresh tokens. + /// </summary> + /// <returns>A cryptographically strong symmetric key.</returns> + private static byte[] CreateSecret() { // TODO: Replace this sample code with real code. // For this sample, we just generate random secrets. RandomNumberGenerator crypto = new RNGCryptoServiceProvider(); - secret = new byte[16]; + var secret = new byte[16]; crypto.GetBytes(secret); + return secret; + } + /// <summary> + /// Creates the RSA key used by all the crypto service provider instances we create. + /// </summary> + /// <returns>RSA data that includes the private key.</returns> + private static RSAParameters CreateRSAKey() { // As we generate a new random key, we need to set the UseMachineKeyStore flag so that this doesn't // crash on IIS. For more information: // http://social.msdn.microsoft.com/Forums/en-US/clr/thread/7ea48fd0-8d6b-43ed-b272-1a0249ae490f?prof=required var cspParameters = new CspParameters(); cspParameters.Flags = CspProviderFlags.UseArchivableKey | CspProviderFlags.UseMachineKeyStore; var asymmetricKey = new RSACryptoServiceProvider(cspParameters); - AsymmetricKey = asymmetricKey.ExportParameters(true); + return asymmetricKey.ExportParameters(true); } /// <summary> @@ -54,7 +62,7 @@ namespace RelyingPartyLogic { /// Since <see cref="RSACryptoServiceProvider"/> are not thread-safe, one must be created for each thread. /// In this sample we just create one for each incoming request. Be sure to call Dispose on them to release native handles. /// </remarks> - private static RSACryptoServiceProvider CreateAsymmetricKeyServiceProvider() { + internal static RSACryptoServiceProvider CreateAsymmetricKeyServiceProvider() { var serviceProvider = new RSACryptoServiceProvider(); serviceProvider.ImportParameters(AsymmetricKey); return serviceProvider; @@ -81,16 +89,8 @@ namespace RelyingPartyLogic { get { return secret; } } - /// <summary> - /// Gets the asymmetric private key to use for signing access tokens. - /// </summary> - /// <value></value> - /// <remarks> - /// The public key in the private/public key pair will be used by the resource - /// servers to validate that the access token is minted by a trusted authorization server. - /// </remarks> - public RSACryptoServiceProvider AccessTokenSigningPrivateKey { - get { return AsymmetricKeyServiceProvider; } + public RSACryptoServiceProvider CreateAccessTokenSigningCryptoServiceProvider() { + return CreateAsymmetricKeyServiceProvider(); } /// <summary> diff --git a/samples/OAuthAuthorizationServer/Code/OAuth2AuthorizationServer.cs b/samples/OAuthAuthorizationServer/Code/OAuth2AuthorizationServer.cs index d71416e..7e4dba6 100644 --- a/samples/OAuthAuthorizationServer/Code/OAuth2AuthorizationServer.cs +++ b/samples/OAuthAuthorizationServer/Code/OAuth2AuthorizationServer.cs @@ -11,62 +11,62 @@ using DotNetOpenAuth.OAuth2.Messages; internal class OAuth2AuthorizationServer : IAuthorizationServer { - private static readonly RSAParameters AsymmetricTokenSigningPrivateKey; + private static readonly RSAParameters AsymmetricTokenSigningPrivateKey = CreateRSAKey(); - [ThreadStatic] - internal static readonly RSACryptoServiceProvider AsymmetricTokenSigningServiceProvider = CreateAsymmetricTokenSigningServiceProvider(); - - private static readonly byte[] secret; + private static readonly byte[] secret = CreateSecret(); private readonly INonceStore nonceStore = new DatabaseNonceStore(); - static OAuth2AuthorizationServer() { + /// <summary> + /// Creates a symmetric secret used to sign and encrypt authorization server refresh tokens. + /// </summary> + /// <returns>A cryptographically strong symmetric key.</returns> + private static byte[] CreateSecret() { + // TODO: Replace this sample code with real code. // For this sample, we just generate random secrets. RandomNumberGenerator crypto = new RNGCryptoServiceProvider(); - secret = new byte[16]; + var secret = new byte[16]; crypto.GetBytes(secret); + return secret; + } + /// <summary> + /// Creates the RSA key used by all the crypto service provider instances we create. + /// </summary> + /// <returns>RSA data that includes the private key.</returns> + private static RSAParameters CreateRSAKey() { #if SAMPLESONLY // Since the sample authorization server and the sample resource server must work together, // we hard-code a FOR SAMPLE USE ONLY key pair. The matching public key information is hard-coded into the OAuthResourceServer sample. // In a real app, the RSA parameters would typically come from a certificate that may already exist. It may simply be the HTTPS certificate for the auth server. - AsymmetricTokenSigningPrivateKey = new RSAParameters { + return new RSAParameters { Exponent = new byte[] { 1, 0, 1 }, - Modulus = new byte[] { 210, 95, 53, 12, 203, 114, 150, 23, 23, 88, 4, 200, 47, 219, 73, 54, 146, 253, 126, 121, 105, 91, 118, 217, 182, 167, 140, 6, 67, 112, 97, 183, 66, 112, 245, 103, 136, 222, 205, 28, 196, 45, 6, 223, 192, 76, 56, 180, 90, 120, 144, 19, 31, 193, 37, 129, 186, 214, 36, 53, 204, 53, 108, 133, 112, 17, 133, 244, 3, 12, 230, 29, 243, 51, 79, 253, 10, 111, 185, 23, 74, 230, 99, 94, 78, 49, 209, 39, 95, 213, 248, 212, 22, 4, 222, 145, 77, 190, 136, 230, 134, 70, 228, 241, 194, 216, 163, 234, 52, 1, 64, 181, 139, 128, 90, 255, 214, 60, 168, 233, 254, 110, 31, 102, 58, 67, 201, 33 }, - P = new byte[] { 237, 238, 79, 75, 29, 57, 145, 201, 57, 177, 215, 108, 40, 77, 232, 237, 113, 38, 157, 195, 174, 134, 188, 175, 121, 28, 11, 236, 80, 146, 12, 38, 8, 12, 104, 46, 6, 247, 14, 149, 196, 23, 130, 116, 141, 137, 225, 74, 84, 111, 44, 163, 55, 10, 246, 154, 195, 158, 186, 241, 162, 11, 217, 77 }, - Q = new byte[] { 226, 89, 29, 67, 178, 205, 30, 152, 184, 165, 15, 152, 131, 245, 141, 80, 150, 3, 224, 136, 188, 248, 149, 36, 200, 250, 207, 156, 224, 79, 150, 191, 84, 214, 233, 173, 95, 192, 55, 123, 124, 255, 53, 85, 11, 233, 156, 66, 14, 27, 27, 163, 108, 199, 90, 37, 118, 38, 78, 171, 80, 26, 101, 37 }, - DP = new byte[] { 108, 176, 122, 132, 131, 187, 50, 191, 203, 157, 84, 29, 82, 100, 20, 205, 178, 236, 195, 17, 10, 254, 253, 222, 226, 226, 79, 8, 10, 222, 76, 178, 106, 230, 208, 8, 134, 162, 1, 133, 164, 232, 96, 109, 193, 226, 132, 138, 33, 252, 15, 86, 23, 228, 232, 54, 86, 186, 130, 7, 179, 208, 217, 217 }, - DQ = new byte[] { 175, 63, 252, 46, 140, 99, 208, 138, 194, 123, 218, 101, 101, 214, 91, 65, 199, 196, 220, 182, 66, 73, 221, 128, 11, 180, 85, 198, 202, 206, 20, 147, 179, 102, 106, 170, 247, 245, 229, 127, 81, 58, 111, 218, 151, 76, 154, 213, 114, 2, 127, 21, 187, 133, 102, 64, 151, 7, 245, 229, 34, 50, 45, 153 }, + Modulus = new byte[] { 210, 95, 53, 12, 203, 114, 150, 23, 23, 88, 4, 200, 47, 219, 73, 54, 146, 253, 126, 121, 105, 91, 118, 217, 182, 167, 140, 6, 67, 112, 97, 183, 66, 112, 245, 103, 136, 222, 205, 28, 196, 45, 6, 223, 192, 76, 56, 180, 90, 120, 144, 19, 31, 193, 37, 129, 186, 214, 36, 53, 204, 53, 108, 133, 112, 17, 133, 244, 3, 12, 230, 29, 243, 51, 79, 253, 10, 111, 185, 23, 74, 230, 99, 94, 78, 49, 209, 39, 95, 213, 248, 212, 22, 4, 222, 145, 77, 190, 136, 230, 134, 70, 228, 241, 194, 216, 163, 234, 52, 1, 64, 181, 139, 128, 90, 255, 214, 60, 168, 233, 254, 110, 31, 102, 58, 67, 201, 33 }, + P = new byte[] { 237, 238, 79, 75, 29, 57, 145, 201, 57, 177, 215, 108, 40, 77, 232, 237, 113, 38, 157, 195, 174, 134, 188, 175, 121, 28, 11, 236, 80, 146, 12, 38, 8, 12, 104, 46, 6, 247, 14, 149, 196, 23, 130, 116, 141, 137, 225, 74, 84, 111, 44, 163, 55, 10, 246, 154, 195, 158, 186, 241, 162, 11, 217, 77 }, + Q = new byte[] { 226, 89, 29, 67, 178, 205, 30, 152, 184, 165, 15, 152, 131, 245, 141, 80, 150, 3, 224, 136, 188, 248, 149, 36, 200, 250, 207, 156, 224, 79, 150, 191, 84, 214, 233, 173, 95, 192, 55, 123, 124, 255, 53, 85, 11, 233, 156, 66, 14, 27, 27, 163, 108, 199, 90, 37, 118, 38, 78, 171, 80, 26, 101, 37 }, + DP = new byte[] { 108, 176, 122, 132, 131, 187, 50, 191, 203, 157, 84, 29, 82, 100, 20, 205, 178, 236, 195, 17, 10, 254, 253, 222, 226, 226, 79, 8, 10, 222, 76, 178, 106, 230, 208, 8, 134, 162, 1, 133, 164, 232, 96, 109, 193, 226, 132, 138, 33, 252, 15, 86, 23, 228, 232, 54, 86, 186, 130, 7, 179, 208, 217, 217 }, + DQ = new byte[] { 175, 63, 252, 46, 140, 99, 208, 138, 194, 123, 218, 101, 101, 214, 91, 65, 199, 196, 220, 182, 66, 73, 221, 128, 11, 180, 85, 198, 202, 206, 20, 147, 179, 102, 106, 170, 247, 245, 229, 127, 81, 58, 111, 218, 151, 76, 154, 213, 114, 2, 127, 21, 187, 133, 102, 64, 151, 7, 245, 229, 34, 50, 45, 153 }, InverseQ = new byte[] { 137, 156, 11, 248, 118, 201, 135, 145, 134, 121, 14, 162, 149, 14, 98, 84, 108, 160, 27, 91, 230, 116, 216, 181, 200, 49, 34, 254, 119, 153, 179, 52, 231, 234, 36, 148, 71, 161, 182, 171, 35, 182, 46, 164, 179, 100, 226, 71, 119, 23, 0, 16, 240, 4, 30, 57, 76, 109, 89, 131, 56, 219, 71, 206 }, - D = new byte[] { 108, 15, 123, 176, 150, 208, 197, 72, 23, 53, 159, 63, 53, 85, 238, 197, 153, 187, 156, 187, 192, 226, 186, 170, 26, 168, 245, 196, 65, 223, 248, 81, 170, 79, 91, 191, 83, 15, 31, 77, 39, 119, 249, 143, 245, 183, 49, 105, 115, 15, 122, 242, 87, 221, 94, 230, 196, 146, 59, 7, 103, 94, 9, 223, 146, 180, 189, 86, 190, 94, 242, 59, 32, 54, 23, 181, 124, 170, 63, 172, 90, 158, 169, 140, 6, 102, 170, 0, 135, 199, 35, 196, 212, 238, 196, 56, 14, 0, 140, 197, 169, 240, 156, 43, 182, 123, 102, 79, 89, 20, 120, 171, 43, 223, 58, 190, 230, 166, 185, 162, 186, 226, 31, 206, 196, 188, 104, 1 }, + D = new byte[] { 108, 15, 123, 176, 150, 208, 197, 72, 23, 53, 159, 63, 53, 85, 238, 197, 153, 187, 156, 187, 192, 226, 186, 170, 26, 168, 245, 196, 65, 223, 248, 81, 170, 79, 91, 191, 83, 15, 31, 77, 39, 119, 249, 143, 245, 183, 49, 105, 115, 15, 122, 242, 87, 221, 94, 230, 196, 146, 59, 7, 103, 94, 9, 223, 146, 180, 189, 86, 190, 94, 242, 59, 32, 54, 23, 181, 124, 170, 63, 172, 90, 158, 169, 140, 6, 102, 170, 0, 135, 199, 35, 196, 212, 238, 196, 56, 14, 0, 140, 197, 169, 240, 156, 43, 182, 123, 102, 79, 89, 20, 120, 171, 43, 223, 58, 190, 230, 166, 185, 162, 186, 226, 31, 206, 196, 188, 104, 1 }, }; #else // This is how you could generate your own public/private key pair. - var keyPair = new RSACryptoServiceProvider(); + // As we generate a new random key, we need to set the UseMachineKeyStore flag so that this doesn't + // crash on IIS. For more information: + // http://social.msdn.microsoft.com/Forums/en-US/clr/thread/7ea48fd0-8d6b-43ed-b272-1a0249ae490f?prof=required + var cspParameters = new CspParameters(); + cspParameters.Flags = CspProviderFlags.UseArchivableKey | CspProviderFlags.UseMachineKeyStore; + var keyPair = new RSACryptoServiceProvider(cspParameters); // After exporting the private/public key information, read the information out and store it somewhere var privateKey = keyPair.ExportParameters(true); var publicKey = keyPair.ExportParameters(false); // Ultimately the private key information must be what is returned through the AccessTokenSigningPrivateKey property. - AsymmetricTokenSigningPrivateKey = privateKey; + return privateKey; #endif } - /// <summary> - /// Creates the asymmetric token signing service provider. - /// </summary> - /// <returns>An RSA crypto service provider.</returns> - /// <remarks> - /// Since <see cref="RSACryptoServiceProvider"/> are not thread-safe, one must be created for each thread. - /// In this sample we just create one for each incoming request. Be sure to call Dispose on them to release native handles. - /// </remarks> - private static RSACryptoServiceProvider CreateAsymmetricTokenSigningServiceProvider() { - var asymmetricTokenSigningServiceProvider = new RSACryptoServiceProvider(); - asymmetricTokenSigningServiceProvider.ImportParameters(AsymmetricTokenSigningPrivateKey); - return asymmetricTokenSigningServiceProvider; - } - #region Implementation of IAuthorizationServer public byte[] Secret { @@ -77,8 +77,10 @@ get { return this.nonceStore; } } - public RSACryptoServiceProvider AccessTokenSigningPrivateKey { - get { return AsymmetricTokenSigningServiceProvider; } + public RSACryptoServiceProvider CreateAccessTokenSigningCryptoServiceProvider() { + var asymmetricTokenSigningServiceProvider = new RSACryptoServiceProvider(); + asymmetricTokenSigningServiceProvider.ImportParameters(AsymmetricTokenSigningPrivateKey); + return asymmetricTokenSigningServiceProvider; } public IConsumerDescription GetClient(string clientIdentifier) { diff --git a/samples/OAuthAuthorizationServer/Controllers/OAuthController.cs b/samples/OAuthAuthorizationServer/Controllers/OAuthController.cs index b9fbe65..47c1977 100644 --- a/samples/OAuthAuthorizationServer/Controllers/OAuthController.cs +++ b/samples/OAuthAuthorizationServer/Controllers/OAuthController.cs @@ -31,23 +31,14 @@ };
#else
[Obsolete("You must use a real key for a real app.", true)]
- private static readonly RSAParameters ResourceServerEncryptionPublicKey = new RSAParameters();
+ private static readonly RSAParameters ResourceServerEncryptionPublicKey;
#endif
/// <summary>
- /// The resource server's encryption service provider with private key.
- /// </summary>
- /// <remarks>
- /// Since <see cref="RSACryptoServiceProvider"/> are not thread-safe, one must be created for each thread.
- /// </remarks>
- [ThreadStatic]
- private static RSACryptoServiceProvider ResourceServerEncryptionServiceProvider = CreateResourceServerEncryptionServiceProvider();
-
- /// <summary>
/// Creates the resource server's encryption service provider with private key.
/// </summary>
/// <returns>An RSA crypto service provider.</returns>
- private static RSACryptoServiceProvider CreateResourceServerEncryptionServiceProvider() {
+ internal static RSACryptoServiceProvider CreateResourceServerEncryptionServiceProvider() {
var resourceServerEncryptionServiceProvider = new RSACryptoServiceProvider();
resourceServerEncryptionServiceProvider.ImportParameters(ResourceServerEncryptionPublicKey);
return resourceServerEncryptionServiceProvider;
@@ -71,8 +62,10 @@ // TODO: code here
// Prepare the refresh and access tokens.
- var response = this.authorizationServer.PrepareAccessTokenResponse(request, ResourceServerEncryptionServiceProvider, accessTokenLifetime);
- return this.authorizationServer.Channel.PrepareResponse(response).AsActionResult();
+ using (var crypto = CreateResourceServerEncryptionServiceProvider()) {
+ var response = this.authorizationServer.PrepareAccessTokenResponse(request, crypto, accessTokenLifetime);
+ return this.authorizationServer.Channel.PrepareResponse(response).AsActionResult();
+ }
}
throw new HttpException((int)HttpStatusCode.BadRequest, "Missing OAuth 2.0 request message.");
diff --git a/samples/OAuthResourceServer/Code/Global.cs b/samples/OAuthResourceServer/Code/Global.cs index a70930b..a48baff 100644 --- a/samples/OAuthResourceServer/Code/Global.cs +++ b/samples/OAuthResourceServer/Code/Global.cs @@ -32,15 +32,6 @@ #endif /// <summary> - /// The authorization server crypto service provider that contains a public key. - /// </summary> - /// <remarks> - /// Since <see cref="RSACryptoServiceProvider"/> are not thread-safe, one must be created for each thread. - /// </remarks> - [ThreadStatic] - public static readonly RSACryptoServiceProvider AuthorizationServerSigningServiceProvider = CreateAuthorizationServerSigningServiceProvider(); - - /// <summary> /// An application memory cache of recent log messages. /// </summary> public static StringBuilder LogMessages = new StringBuilder(); @@ -74,19 +65,10 @@ #endif /// <summary> - /// The crypto service provider for this resource server that contains the private key used to decrypt an access token. - /// </summary> - /// <remarks> - /// Since <see cref="RSACryptoServiceProvider"/> are not thread-safe, one must be created for each thread. - /// </remarks> - [ThreadStatic] - internal static readonly RSACryptoServiceProvider ResourceServerEncryptionServiceProvider = CreateResourceServerEncryptionServiceProvider(); - - /// <summary> /// Creates the crypto service provider for this resource server that contains the private key used to decrypt an access token. /// </summary> /// <returns>An RSA crypto service provider.</returns> - private static RSACryptoServiceProvider CreateResourceServerEncryptionServiceProvider() { + internal static RSACryptoServiceProvider CreateResourceServerEncryptionServiceProvider() { var resourceServerEncryptionServiceProvider = new RSACryptoServiceProvider(); resourceServerEncryptionServiceProvider.ImportParameters(ResourceServerEncryptionPrivateKey); return resourceServerEncryptionServiceProvider; @@ -96,7 +78,7 @@ /// Creates the crypto service provider for the authorization server that contains the public key used to verify an access token signature. /// </summary> /// <returns>An RSA crypto service provider.</returns> - private static RSACryptoServiceProvider CreateAuthorizationServerSigningServiceProvider() { + internal static RSACryptoServiceProvider CreateAuthorizationServerSigningServiceProvider() { var authorizationServerSigningServiceProvider = new RSACryptoServiceProvider(); authorizationServerSigningServiceProvider.ImportParameters(AuthorizationServerSigningPublicKey); return authorizationServerSigningServiceProvider; diff --git a/samples/OAuthResourceServer/Code/OAuthAuthorizationManager.cs b/samples/OAuthResourceServer/Code/OAuthAuthorizationManager.cs index 4b47dd5..0c1953d 100644 --- a/samples/OAuthResourceServer/Code/OAuthAuthorizationManager.cs +++ b/samples/OAuthResourceServer/Code/OAuthAuthorizationManager.cs @@ -64,16 +64,17 @@ private static IPrincipal VerifyOAuth2(HttpRequestMessageProperty httpDetails, Uri requestUri) { // for this sample where the auth server and resource server are the same site, // we use the same public/private key. - var resourceServer = new ResourceServer( - new StandardAccessTokenAnalyzer( - Global.AuthorizationServerSigningServiceProvider, - Global.ResourceServerEncryptionServiceProvider)); + using (var signing = Global.CreateAuthorizationServerSigningServiceProvider()) { + using (var encrypting = Global.CreateResourceServerEncryptionServiceProvider()) { + var resourceServer = new ResourceServer(new StandardAccessTokenAnalyzer(signing, encrypting)); - IPrincipal result; - var error = resourceServer.VerifyAccess(new HttpRequestInfo(httpDetails, requestUri), out result); + IPrincipal result; + var error = resourceServer.VerifyAccess(new HttpRequestInfo(httpDetails, requestUri), out result); - // TODO: return the prepared error code. - return error != null ? null : result; + // TODO: return the prepared error code. + return error != null ? null : result; + } + } } } } diff --git a/src/DotNetOpenAuth/OAuth2/AuthorizationServer.cs b/src/DotNetOpenAuth/OAuth2/AuthorizationServer.cs index 0883b1e..1c1c88c 100644 --- a/src/DotNetOpenAuth/OAuth2/AuthorizationServer.cs +++ b/src/DotNetOpenAuth/OAuth2/AuthorizationServer.cs @@ -124,8 +124,10 @@ namespace DotNetOpenAuth.OAuth2 { if (request != null) { // This convenience method only encrypts access tokens assuming that this auth server // doubles as the resource server. - var resourceServerPublicKey = this.AuthorizationServerServices.AccessTokenSigningPrivateKey; - response = this.PrepareAccessTokenResponse(request, resourceServerPublicKey); + using (var resourceServerPublicKey = this.AuthorizationServerServices.CreateAccessTokenSigningCryptoServiceProvider()) { + response = this.PrepareAccessTokenResponse(request, resourceServerPublicKey); + } + return true; } @@ -220,22 +222,24 @@ namespace DotNetOpenAuth.OAuth2 { Contract.Requires<ArgumentNullException>(accessTokenEncryptingPublicKey != null, "accessTokenEncryptingPublicKey"); var tokenRequest = (ITokenCarryingRequest)request; - var accessTokenFormatter = AccessToken.CreateFormatter(this.AuthorizationServerServices.AccessTokenSigningPrivateKey, accessTokenEncryptingPublicKey); - var accessToken = new AccessToken(tokenRequest.AuthorizationDescription, accessTokenLifetime); - - var response = new AccessTokenSuccessResponse(request) { - AccessToken = accessTokenFormatter.Serialize(accessToken), - Lifetime = accessToken.Lifetime, - }; - response.Scope.ResetContents(tokenRequest.AuthorizationDescription.Scope); - - if (includeRefreshToken) { - var refreshTokenFormatter = RefreshToken.CreateFormatter(this.AuthorizationServerServices.Secret); - var refreshToken = new RefreshToken(tokenRequest.AuthorizationDescription); - response.RefreshToken = refreshTokenFormatter.Serialize(refreshToken); + using (var crypto = this.AuthorizationServerServices.CreateAccessTokenSigningCryptoServiceProvider()) { + var accessTokenFormatter = AccessToken.CreateFormatter(crypto, accessTokenEncryptingPublicKey); + var accessToken = new AccessToken(tokenRequest.AuthorizationDescription, accessTokenLifetime); + + var response = new AccessTokenSuccessResponse(request) { + AccessToken = accessTokenFormatter.Serialize(accessToken), + Lifetime = accessToken.Lifetime, + }; + response.Scope.ResetContents(tokenRequest.AuthorizationDescription.Scope); + + if (includeRefreshToken) { + var refreshTokenFormatter = RefreshToken.CreateFormatter(this.AuthorizationServerServices.Secret); + var refreshToken = new RefreshToken(tokenRequest.AuthorizationDescription); + response.RefreshToken = refreshTokenFormatter.Serialize(refreshToken); + } + + return response; } - - return response; } /// <summary> diff --git a/src/DotNetOpenAuth/OAuth2/IAuthorizationServer.cs b/src/DotNetOpenAuth/OAuth2/IAuthorizationServer.cs index 2a0c5cc..ccce0ab 100644 --- a/src/DotNetOpenAuth/OAuth2/IAuthorizationServer.cs +++ b/src/DotNetOpenAuth/OAuth2/IAuthorizationServer.cs @@ -30,14 +30,15 @@ namespace DotNetOpenAuth.OAuth2 { byte[] Secret { get; } /// <summary> - /// Gets the crypto service provider with the asymmetric private key to use for signing access tokens. + /// Creates a new instance of the crypto service provider with the asymmetric private key to use for signing access tokens. /// </summary> /// <value>Must not be null, and must contain the private key.</value> /// <remarks> /// The public key in the private/public key pair will be used by the resource /// servers to validate that the access token is minted by a trusted authorization server. + /// The caller is responsible to dispose of the returned instance. /// </remarks> - RSACryptoServiceProvider AccessTokenSigningPrivateKey { get; } + RSACryptoServiceProvider CreateAccessTokenSigningCryptoServiceProvider(); /// <summary> /// Gets the authorization code nonce store to use to ensure that authorization codes can only be used once. @@ -108,17 +109,14 @@ namespace DotNetOpenAuth.OAuth2 { /// <summary> /// Gets the crypto service provider with the asymmetric private key to use for signing access tokens. /// </summary> - /// <value></value> /// <remarks> /// The public key in the private/public key pair will be used by the resource /// servers to validate that the access token is minted by a trusted authorization server. /// </remarks> - RSACryptoServiceProvider IAuthorizationServer.AccessTokenSigningPrivateKey { - get { - Contract.Ensures(Contract.Result<RSACryptoServiceProvider>() != null); - Contract.Ensures(!Contract.Result<RSACryptoServiceProvider>().PublicOnly); - throw new NotImplementedException(); - } + RSACryptoServiceProvider IAuthorizationServer.CreateAccessTokenSigningCryptoServiceProvider() { + Contract.Ensures(Contract.Result<RSACryptoServiceProvider>() != null); + Contract.Ensures(!Contract.Result<RSACryptoServiceProvider>().PublicOnly); + throw new NotImplementedException(); } /// <summary> |