diff options
21 files changed, 288 insertions, 167 deletions
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj b/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj index cdbd2dc..301a5a3 100644 --- a/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj +++ b/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj @@ -18,6 +18,9 @@ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> </PropertyGroup> <ItemGroup> + <Compile Include="OAuth\ChannelElements\OAuthConsumerChannel.cs" /> + <Compile Include="OAuth\ChannelElements\OAuthConsumerMessageFactory.cs" /> + <Compile Include="OAuth\ChannelElements\RsaSha1ConsumerSigningBindingElement.cs" /> <Compile Include="OAuth\ConsumerBase.cs" /> <Compile Include="OAuth\DesktopConsumer.cs" /> <Compile Include="OAuth\WebConsumer.cs" /> diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerChannel.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerChannel.cs new file mode 100644 index 0000000..9d5e74a --- /dev/null +++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerChannel.cs @@ -0,0 +1,61 @@ +namespace DotNetOpenAuth.OAuth.ChannelElements { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Diagnostics.CodeAnalysis; + using System.Diagnostics.Contracts; + using DotNetOpenAuth.Messaging.Bindings; + using DotNetOpenAuth.Messaging; + + internal class OAuthConsumerChannel : OAuthChannel { + /// <summary> + /// Initializes a new instance of the <see cref="OAuthChannel"/> class. + /// </summary> + /// <param name="signingBindingElement">The binding element to use for signing.</param> + /// <param name="store">The web application store to use for nonces.</param> + /// <param name="tokenManager">The token manager instance to use.</param> + /// <param name="securitySettings">The security settings.</param> + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Diagnostics.Contracts.__ContractsRuntime.Requires<System.ArgumentNullException>(System.Boolean,System.String,System.String)", Justification = "Code contracts"), SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "securitySettings", Justification = "Code contracts")] + internal OAuthConsumerChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, IConsumerTokenManager tokenManager, ConsumerSecuritySettings securitySettings) + : base( + signingBindingElement, + store, + tokenManager, + securitySettings, + new OAuthConsumerMessageFactory(), + InitializeBindingElements(signingBindingElement, store, tokenManager, securitySettings)) { + Contract.Requires<ArgumentNullException>(tokenManager != null); + Contract.Requires<ArgumentNullException>(securitySettings != null); + Contract.Requires<ArgumentNullException>(signingBindingElement != null); + Contract.Requires<ArgumentException>(signingBindingElement.SignatureCallback == null, OAuthStrings.SigningElementAlreadyAssociatedWithChannel); + } + + /// <summary> + /// Gets the consumer secret for a given consumer key. + /// </summary> + /// <param name="consumerKey">The consumer key.</param> + /// <returns>The consumer secret.</returns> + protected override string GetConsumerSecret(string consumerKey) { + var consumerTokenManager = (IConsumerTokenManager)this.TokenManager; + ErrorUtilities.VerifyInternal(consumerKey == consumerTokenManager.ConsumerKey, "The token manager consumer key and the consumer key set earlier do not match!"); + return consumerTokenManager.ConsumerSecret; + } + + /// <summary> + /// Initializes the binding elements for the OAuth channel. + /// </summary> + /// <param name="signingBindingElement">The signing binding element.</param> + /// <param name="store">The nonce store.</param> + /// <param name="tokenManager">The token manager.</param> + /// <param name="securitySettings">The security settings.</param> + /// <returns> + /// An array of binding elements used to initialize the channel. + /// </returns> + private static IChannelBindingElement[] InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, SecuritySettings securitySettings) { + Contract.Requires(securitySettings != null); + + return OAuthChannel.InitializeBindingElements(signingBindingElement, store, tokenManager, securitySettings).ToArray(); + } + } +} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs index 327b923..327b923 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs +++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/RsaSha1ConsumerSigningBindingElement.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/RsaSha1ConsumerSigningBindingElement.cs new file mode 100644 index 0000000..ba451e5 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/RsaSha1ConsumerSigningBindingElement.cs @@ -0,0 +1,61 @@ +//----------------------------------------------------------------------- +// <copyright file="RsaSha1SigningBindingElement.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth.ChannelElements { + using System; + using System.Diagnostics.Contracts; + using System.Security.Cryptography; + using System.Security.Cryptography.X509Certificates; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A binding element that signs outgoing messages and verifies the signature on incoming messages. + /// </summary> + public class RsaSha1ConsumerSigningBindingElement : RsaSha1SigningBindingElement { + /// <summary> + /// Initializes a new instance of the <see cref="RsaSha1SigningBindingElement"/> class. + /// </summary> + /// <param name="signingCertificate">The certificate used to sign outgoing messages.</param> + public RsaSha1ConsumerSigningBindingElement(X509Certificate2 signingCertificate) { + Contract.Requires<ArgumentNullException>(signingCertificate != null); + + this.SigningCertificate = signingCertificate; + } + + /// <summary> + /// Gets or sets the certificate used to sign outgoing messages. Used only by Consumers. + /// </summary> + public X509Certificate2 SigningCertificate { get; set; } + + protected override bool IsSignatureValid(ITamperResistantOAuthMessage message) { + throw new NotImplementedException(); + } + + /// <summary> + /// Calculates a signature for a given message. + /// </summary> + /// <param name="message">The message to sign.</param> + /// <returns>The signature for the message.</returns> + /// <remarks> + /// This method signs the message per OAuth 1.0 section 9.3. + /// </remarks> + protected override string GetSignature(ITamperResistantOAuthMessage message) { + ErrorUtilities.VerifyOperation(this.SigningCertificate != null, OAuthStrings.X509CertificateNotProvidedForSigning); + + string signatureBaseString = ConstructSignatureBaseString(message, this.Channel.MessageDescriptions.GetAccessor(message)); + byte[] data = Encoding.ASCII.GetBytes(signatureBaseString); + var provider = (RSACryptoServiceProvider)this.SigningCertificate.PrivateKey; + byte[] binarySignature = provider.SignData(data, "SHA1"); + string base64Signature = Convert.ToBase64String(binarySignature); + return base64Signature; + } + + protected override ITamperProtectionChannelBindingElement Clone() { + return new RsaSha1ConsumerSigningBindingElement(this.SigningCertificate); + } + } +} diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs index c02ca79..82ee92f 100644 --- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs +++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs @@ -33,7 +33,7 @@ namespace DotNetOpenAuth.OAuth { ITamperProtectionChannelBindingElement signingElement = serviceDescription.CreateTamperProtectionElement(); INonceStore store = new NonceMemoryStore(StandardExpirationBindingElement.MaximumMessageAge); this.SecuritySettings = OAuthElement.Configuration.Consumer.SecuritySettings.CreateSecuritySettings(); - this.OAuthChannel = new OAuthChannel(signingElement, store, tokenManager, this.SecuritySettings); + this.OAuthChannel = new OAuthConsumerChannel(signingElement, store, tokenManager, this.SecuritySettings); this.ServiceProvider = serviceDescription; OAuthReporting.RecordFeatureAndDependencyUse(this, serviceDescription, tokenManager, null); diff --git a/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj b/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj index f3ba9f7..fea76f8 100644 --- a/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj @@ -18,7 +18,18 @@ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> </PropertyGroup> <ItemGroup> + <Compile Include="OAuth\ChannelElements\IConsumerDescription.cs" /> + <Compile Include="OAuth\ChannelElements\IServiceProviderAccessToken.cs" /> + <Compile Include="OAuth\ChannelElements\IServiceProviderRequestToken.cs" /> + <Compile Include="OAuth\ChannelElements\IServiceProviderTokenManager.cs" /> + <Compile Include="OAuth\ChannelElements\OAuthServiceProviderChannel.cs" /> + <Compile Include="OAuth\ChannelElements\OAuthServiceProviderMessageFactory.cs" /> + <Compile Include="OAuth\ChannelElements\OAuthIdentity.cs" /> + <Compile Include="OAuth\ChannelElements\OAuthPrincipal.cs" /> + <Compile Include="OAuth\ChannelElements\RsaSha1ServiceProviderSigningBindingElement.cs" /> + <Compile Include="OAuth\ChannelElements\TokenHandlingBindingElement.cs" /> <Compile Include="OAuth\ServiceProvider.cs" /> + <Compile Include="OAuth\VerificationCodeFormat.cs" /> <Compile Include="Properties\AssemblyInfo.cs"> <SubType> </SubType> diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IConsumerDescription.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/IConsumerDescription.cs index db505d5..db505d5 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IConsumerDescription.cs +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/IConsumerDescription.cs diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderAccessToken.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/IServiceProviderAccessToken.cs index 35ba52d..35ba52d 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderAccessToken.cs +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/IServiceProviderAccessToken.cs diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderRequestToken.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/IServiceProviderRequestToken.cs index 6dfa416..6dfa416 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderRequestToken.cs +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/IServiceProviderRequestToken.cs diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/IServiceProviderTokenManager.cs index 7df67ce..7df67ce 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/IServiceProviderTokenManager.cs diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthIdentity.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/OAuthIdentity.cs index 65bde20..65bde20 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthIdentity.cs +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/OAuthIdentity.cs diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthPrincipal.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/OAuthPrincipal.cs index 82ecb0a..82ecb0a 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthPrincipal.cs +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/OAuthPrincipal.cs diff --git a/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/OAuthServiceProviderChannel.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/OAuthServiceProviderChannel.cs new file mode 100644 index 0000000..cc2f169 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/OAuthServiceProviderChannel.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics.CodeAnalysis; +using DotNetOpenAuth.Messaging; +using DotNetOpenAuth.Messaging.Bindings; +using System.Diagnostics.Contracts; + +namespace DotNetOpenAuth.OAuth.ChannelElements { + internal class OAuthServiceProviderChannel : OAuthChannel { + /// <summary> + /// Initializes a new instance of the <see cref="OAuthChannel"/> class. + /// </summary> + /// <param name="signingBindingElement">The binding element to use for signing.</param> + /// <param name="store">The web application store to use for nonces.</param> + /// <param name="tokenManager">The token manager instance to use.</param> + /// <param name="securitySettings">The security settings.</param> + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Diagnostics.Contracts.__ContractsRuntime.Requires<System.ArgumentNullException>(System.Boolean,System.String,System.String)", Justification = "Code contracts"), SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "securitySettings", Justification = "Code contracts")] + internal OAuthServiceProviderChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, IServiceProviderTokenManager tokenManager, ServiceProviderSecuritySettings securitySettings, IMessageFactory messageTypeProvider) + : base( + signingBindingElement, + store, + tokenManager, + securitySettings, + messageTypeProvider ?? new OAuthServiceProviderMessageFactory(tokenManager), + InitializeBindingElements(signingBindingElement, store, tokenManager, securitySettings)) { + Contract.Requires<ArgumentNullException>(tokenManager != null); + Contract.Requires<ArgumentNullException>(securitySettings != null); + Contract.Requires<ArgumentNullException>(signingBindingElement != null); + Contract.Requires<ArgumentException>(signingBindingElement.SignatureCallback == null, OAuthStrings.SigningElementAlreadyAssociatedWithChannel); + } + + /// <summary> + /// Gets the consumer secret for a given consumer key. + /// </summary> + /// <param name="consumerKey">The consumer key.</param> + /// <returns>The consumer secret.</returns> + protected override string GetConsumerSecret(string consumerKey) { + return ((IServiceProviderTokenManager)this.TokenManager).GetConsumer(consumerKey).Secret; + } + + /// <summary> + /// Initializes the binding elements for the OAuth channel. + /// </summary> + /// <param name="signingBindingElement">The signing binding element.</param> + /// <param name="store">The nonce store.</param> + /// <param name="tokenManager">The token manager.</param> + /// <param name="securitySettings">The security settings.</param> + /// <returns> + /// An array of binding elements used to initialize the channel. + /// </returns> + private static IChannelBindingElement[] InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, SecuritySettings securitySettings) { + Contract.Requires(securitySettings != null); + + var bindingElements = OAuthChannel.InitializeBindingElements(signingBindingElement, store, tokenManager, securitySettings); + + var spTokenManager = tokenManager as IServiceProviderTokenManager; + var serviceProviderSecuritySettings = securitySettings as ServiceProviderSecuritySettings; + bindingElements.Insert(0, new TokenHandlingBindingElement(spTokenManager, serviceProviderSecuritySettings)); + + return bindingElements.ToArray(); + } + } +} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs index 5b3c918..5b3c918 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs diff --git a/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/RsaSha1ServiceProviderSigningBindingElement.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/RsaSha1ServiceProviderSigningBindingElement.cs new file mode 100644 index 0000000..c05ba84 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/RsaSha1ServiceProviderSigningBindingElement.cs @@ -0,0 +1,74 @@ +//----------------------------------------------------------------------- +// <copyright file="RsaSha1SigningBindingElement.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth.ChannelElements { + using System; + using System.Diagnostics.Contracts; + using System.Security.Cryptography; + using System.Security.Cryptography.X509Certificates; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A binding element that signs outgoing messages and verifies the signature on incoming messages. + /// </summary> + public class RsaSha1ServiceProviderSigningBindingElement : RsaSha1SigningBindingElement { + /// <summary> + /// The token manager for the service provider. + /// </summary> + private IServiceProviderTokenManager tokenManager; + + /// <summary> + /// Initializes a new instance of the <see cref="RsaSha1ServiceProviderSigningBindingElement"/> class. + /// </summary> + /// <param name="tokenManager">The token manager.</param> + public RsaSha1ServiceProviderSigningBindingElement(IServiceProviderTokenManager tokenManager) { + Contract.Requires<ArgumentNullException>(tokenManager != null); + + this.tokenManager = tokenManager; + } + + /// <summary> + /// Determines whether the signature on some message is valid. + /// </summary> + /// <param name="message">The message to check the signature on.</param> + /// <returns> + /// <c>true</c> if the signature on the message is valid; otherwise, <c>false</c>. + /// </returns> + protected override bool IsSignatureValid(ITamperResistantOAuthMessage message) { + ErrorUtilities.VerifyInternal(this.tokenManager != null, "No token manager available for fetching Consumer public certificates."); + + string signatureBaseString = ConstructSignatureBaseString(message, this.Channel.MessageDescriptions.GetAccessor(message)); + byte[] data = Encoding.ASCII.GetBytes(signatureBaseString); + + byte[] carriedSignature = Convert.FromBase64String(message.Signature); + + X509Certificate2 cert = this.tokenManager.GetConsumer(message.ConsumerKey).Certificate; + if (cert == null) { + Logger.Signatures.WarnFormat("Incoming message from consumer '{0}' could not be matched with an appropriate X.509 certificate for signature verification.", message.ConsumerKey); + return false; + } + + var provider = (RSACryptoServiceProvider)cert.PublicKey.Key; + bool valid = provider.VerifyData(data, "SHA1", carriedSignature); + return valid; + } + + protected override string GetSignature(ITamperResistantOAuthMessage message) { + throw new NotImplementedException(); + } + + /// <summary> + /// Clones this instance. + /// </summary> + /// <returns> + /// A new instance of the binding element. + /// </returns> + protected override ITamperProtectionChannelBindingElement Clone() { + return new RsaSha1ServiceProviderSigningBindingElement(this.tokenManager); + } + } +} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/TokenHandlingBindingElement.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/TokenHandlingBindingElement.cs index f53aa1b..f53aa1b 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/TokenHandlingBindingElement.cs +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/TokenHandlingBindingElement.cs diff --git a/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProvider.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProvider.cs index 78857c1..09f3fad 100644 --- a/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProvider.cs +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProvider.cs @@ -100,7 +100,7 @@ namespace DotNetOpenAuth.OAuth { var signingElement = serviceDescription.CreateTamperProtectionElement(); this.ServiceDescription = serviceDescription; this.SecuritySettings = OAuthElement.Configuration.ServiceProvider.SecuritySettings.CreateSecuritySettings(); - this.OAuthChannel = new OAuthChannel(signingElement, nonceStore, tokenManager, this.SecuritySettings, messageTypeProvider); + this.OAuthChannel = new OAuthServiceProviderChannel(signingElement, nonceStore, tokenManager, this.SecuritySettings, messageTypeProvider); this.TokenGenerator = new StandardTokenGenerator(); OAuthReporting.RecordFeatureAndDependencyUse(this, serviceDescription, tokenManager, nonceStore); diff --git a/src/DotNetOpenAuth.OAuth/OAuth/VerificationCodeFormat.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/VerificationCodeFormat.cs index a6560d8..a6560d8 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/VerificationCodeFormat.cs +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/VerificationCodeFormat.cs diff --git a/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj b/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj index 09cd70e..cdacfac 100644 --- a/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj +++ b/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj @@ -26,26 +26,18 @@ <Compile Include="Messaging\ITamperProtectionChannelBindingElement.cs" /> <Compile Include="OAuthReporting.cs" /> <Compile Include="OAuth\ChannelElements\ICombinedOpenIdProviderTokenManager.cs" /> - <Compile Include="OAuth\ChannelElements\IConsumerDescription.cs" /> <Compile Include="OAuth\ChannelElements\IConsumerTokenManager.cs" /> <Compile Include="OAuth\ChannelElements\IOpenIdOAuthTokenManager.cs" /> - <Compile Include="OAuth\ChannelElements\IServiceProviderAccessToken.cs" /> - <Compile Include="OAuth\ChannelElements\IServiceProviderTokenManager.cs" /> - <Compile Include="OAuth\ChannelElements\OAuthConsumerMessageFactory.cs" /> <Compile Include="OAuth\ChannelElements\ITokenGenerator.cs" /> <Compile Include="OAuth\ChannelElements\ITokenManager.cs" /> <Compile Include="OAuth\ChannelElements\OAuthHttpMethodBindingElement.cs" /> - <Compile Include="OAuth\ChannelElements\OAuthIdentity.cs" /> - <Compile Include="OAuth\ChannelElements\OAuthPrincipal.cs" /> <Compile Include="OAuth\ChannelElements\PlaintextSigningBindingElement.cs" /> <Compile Include="OAuth\ChannelElements\HmacSha1SigningBindingElement.cs" /> - <Compile Include="OAuth\ChannelElements\IServiceProviderRequestToken.cs" /> <Compile Include="OAuth\ChannelElements\SigningBindingElementBaseContract.cs" /> <Compile Include="OAuth\ChannelElements\SigningBindingElementChain.cs" /> <Compile Include="OAuth\ChannelElements\StandardTokenGenerator.cs" /> <Compile Include="OAuth\ChannelElements\TokenType.cs" /> <Compile Include="OAuth\ChannelElements\UriOrOobEncoding.cs" /> - <Compile Include="OAuth\ChannelElements\TokenHandlingBindingElement.cs" /> <Compile Include="OAuth\ConsumerSecuritySettings.cs" /> <Compile Include="OAuth\Messages\ITokenSecretContainingMessage.cs" /> <Compile Include="OAuth\OAuthStrings.Designer.cs"> @@ -59,7 +51,6 @@ <Compile Include="OAuth\Messages\SignedMessageBase.cs" /> <Compile Include="OAuth\ChannelElements\SigningBindingElementBase.cs" /> <Compile Include="OAuth\ServiceProviderSecuritySettings.cs" /> - <Compile Include="OAuth\VerificationCodeFormat.cs" /> <Compile Include="OAuth\ChannelElements\ITamperResistantOAuthMessage.cs" /> <Compile Include="OAuth\Messages\MessageBase.cs" /> <Compile Include="OAuth\Messages\AuthorizedTokenRequest.cs" /> @@ -69,7 +60,6 @@ <Compile Include="OAuth\Messages\UserAuthorizationRequest.cs" /> <Compile Include="OAuth\Messages\UnauthorizedTokenResponse.cs" /> <Compile Include="OAuth\ChannelElements\OAuthChannel.cs" /> - <Compile Include="OAuth\ChannelElements\OAuthServiceProviderMessageFactory.cs" /> <Compile Include="Properties\AssemblyInfo.cs"> <SubType> </SubType> diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthChannel.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthChannel.cs index 76b5149..b6ad28d 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthChannel.cs +++ b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthChannel.cs @@ -25,49 +25,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// <summary> /// An OAuth-specific implementation of the <see cref="Channel"/> class. /// </summary> - internal class OAuthChannel : Channel { - /// <summary> - /// Initializes a new instance of the <see cref="OAuthChannel"/> class. - /// </summary> - /// <param name="signingBindingElement">The binding element to use for signing.</param> - /// <param name="store">The web application store to use for nonces.</param> - /// <param name="tokenManager">The token manager instance to use.</param> - /// <param name="securitySettings">The security settings.</param> - [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Diagnostics.Contracts.__ContractsRuntime.Requires<System.ArgumentNullException>(System.Boolean,System.String,System.String)", Justification = "Code contracts"), SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "securitySettings", Justification = "Code contracts")] - internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, IConsumerTokenManager tokenManager, ConsumerSecuritySettings securitySettings) - : this( - signingBindingElement, - store, - tokenManager, - securitySettings, - new OAuthConsumerMessageFactory()) { - Contract.Requires<ArgumentNullException>(tokenManager != null); - Contract.Requires<ArgumentNullException>(securitySettings != null); - Contract.Requires<ArgumentNullException>(signingBindingElement != null); - Contract.Requires<ArgumentException>(signingBindingElement.SignatureCallback == null, OAuthStrings.SigningElementAlreadyAssociatedWithChannel); - } - - /// <summary> - /// Initializes a new instance of the <see cref="OAuthChannel"/> class. - /// </summary> - /// <param name="signingBindingElement">The binding element to use for signing.</param> - /// <param name="store">The web application store to use for nonces.</param> - /// <param name="tokenManager">The token manager instance to use.</param> - /// <param name="securitySettings">The security settings.</param> - [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Diagnostics.Contracts.__ContractsRuntime.Requires<System.ArgumentNullException>(System.Boolean,System.String,System.String)", Justification = "Code contracts"), SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "securitySettings", Justification = "Code contracts")] - internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, IServiceProviderTokenManager tokenManager, ServiceProviderSecuritySettings securitySettings) - : this( - signingBindingElement, - store, - tokenManager, - securitySettings, - new OAuthServiceProviderMessageFactory(tokenManager)) { - Contract.Requires<ArgumentNullException>(tokenManager != null); - Contract.Requires<ArgumentNullException>(securitySettings != null); - Contract.Requires<ArgumentNullException>(signingBindingElement != null); - Contract.Requires<ArgumentException>(signingBindingElement.SignatureCallback == null, OAuthStrings.SigningElementAlreadyAssociatedWithChannel); - } - + internal abstract class OAuthChannel : Channel { /// <summary> /// Initializes a new instance of the <see cref="OAuthChannel"/> class. /// </summary> @@ -79,12 +37,13 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// Except for mock testing, this should always be one of /// <see cref="OAuthConsumerMessageFactory"/> or <see cref="OAuthServiceProviderMessageFactory"/>.</param> [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Diagnostics.Contracts.__ContractsRuntime.Requires<System.ArgumentNullException>(System.Boolean,System.String,System.String)", Justification = "Code contracts"), SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "securitySettings", Justification = "Code contracts")] - internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, SecuritySettings securitySettings, IMessageFactory messageTypeProvider) - : base(messageTypeProvider, InitializeBindingElements(signingBindingElement, store, tokenManager, securitySettings)) { + protected OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, SecuritySettings securitySettings, IMessageFactory messageTypeProvider, IChannelBindingElement[] bindingElements) + : base(messageTypeProvider, bindingElements) { Contract.Requires<ArgumentNullException>(tokenManager != null); Contract.Requires<ArgumentNullException>(securitySettings != null); Contract.Requires<ArgumentNullException>(signingBindingElement != null); Contract.Requires<ArgumentException>(signingBindingElement.SignatureCallback == null, OAuthStrings.SigningElementAlreadyAssociatedWithChannel); + Contract.Requires<ArgumentNullException>(bindingElements != null, "bindingElements"); this.TokenManager = tokenManager; signingBindingElement.SignatureCallback = this.SignatureCallback; @@ -263,7 +222,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// <returns> /// An array of binding elements used to initialize the channel. /// </returns> - private static IChannelBindingElement[] InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, SecuritySettings securitySettings) { + protected static List<IChannelBindingElement> InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, SecuritySettings securitySettings) { Contract.Requires(securitySettings != null); var bindingElements = new List<IChannelBindingElement> { @@ -273,13 +232,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { new StandardReplayProtectionBindingElement(store), }; - var spTokenManager = tokenManager as IServiceProviderTokenManager; - var serviceProviderSecuritySettings = securitySettings as ServiceProviderSecuritySettings; - if (spTokenManager != null && serviceProviderSecuritySettings != null) { - bindingElements.Insert(0, new TokenHandlingBindingElement(spTokenManager, serviceProviderSecuritySettings)); - } - - return bindingElements.ToArray(); + return bindingElements; } /// <summary> @@ -392,19 +345,6 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { } } - /// <summary> - /// Gets the consumer secret for a given consumer key. - /// </summary> - /// <param name="consumerKey">The consumer key.</param> - /// <returns>The consumer secret.</returns> - private string GetConsumerSecret(string consumerKey) { - var consumerTokenManager = this.TokenManager as IConsumerTokenManager; - if (consumerTokenManager != null) { - ErrorUtilities.VerifyInternal(consumerKey == consumerTokenManager.ConsumerKey, "The token manager consumer key and the consumer key set earlier do not match!"); - return consumerTokenManager.ConsumerSecret; - } else { - return ((IServiceProviderTokenManager)this.TokenManager).GetConsumer(consumerKey).Secret; - } - } + protected abstract string GetConsumerSecret(string consumerKey); } } diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/RsaSha1SigningBindingElement.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/RsaSha1SigningBindingElement.cs index f7b8370..83be094 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/RsaSha1SigningBindingElement.cs +++ b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/RsaSha1SigningBindingElement.cs @@ -15,101 +15,17 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// <summary> /// A binding element that signs outgoing messages and verifies the signature on incoming messages. /// </summary> - public class RsaSha1SigningBindingElement : SigningBindingElementBase { + public abstract class RsaSha1SigningBindingElement : SigningBindingElementBase { /// <summary> /// The name of the hash algorithm to use. /// </summary> - private const string HashAlgorithmName = "RSA-SHA1"; + protected const string HashAlgorithmName = "RSA-SHA1"; /// <summary> - /// The token manager for the service provider. + /// Initializes a new instance of the <see cref="RsaSha1SigningBindingElement"/> class. /// </summary> - private IServiceProviderTokenManager tokenManager; - - /// <summary> - /// Initializes a new instance of the <see cref="RsaSha1SigningBindingElement"/> class - /// for use by Consumers. - /// </summary> - /// <param name="signingCertificate">The certificate used to sign outgoing messages.</param> - public RsaSha1SigningBindingElement(X509Certificate2 signingCertificate) + protected RsaSha1SigningBindingElement() : base(HashAlgorithmName) { - Contract.Requires<ArgumentNullException>(signingCertificate != null); - - this.SigningCertificate = signingCertificate; - } - - /// <summary> - /// Initializes a new instance of the <see cref="RsaSha1SigningBindingElement"/> class - /// for use by Service Providers. - /// </summary> - /// <param name="tokenManager">The token manager.</param> - public RsaSha1SigningBindingElement(IServiceProviderTokenManager tokenManager) - : base(HashAlgorithmName) { - Contract.Requires<ArgumentNullException>(tokenManager != null); - - this.tokenManager = tokenManager; - } - - /// <summary> - /// Gets or sets the certificate used to sign outgoing messages. Used only by Consumers. - /// </summary> - public X509Certificate2 SigningCertificate { get; set; } - - /// <summary> - /// Calculates a signature for a given message. - /// </summary> - /// <param name="message">The message to sign.</param> - /// <returns>The signature for the message.</returns> - /// <remarks> - /// This method signs the message per OAuth 1.0 section 9.3. - /// </remarks> - protected override string GetSignature(ITamperResistantOAuthMessage message) { - ErrorUtilities.VerifyOperation(this.SigningCertificate != null, OAuthStrings.X509CertificateNotProvidedForSigning); - - string signatureBaseString = ConstructSignatureBaseString(message, this.Channel.MessageDescriptions.GetAccessor(message)); - byte[] data = Encoding.ASCII.GetBytes(signatureBaseString); - var provider = (RSACryptoServiceProvider)this.SigningCertificate.PrivateKey; - byte[] binarySignature = provider.SignData(data, "SHA1"); - string base64Signature = Convert.ToBase64String(binarySignature); - return base64Signature; - } - - /// <summary> - /// Determines whether the signature on some message is valid. - /// </summary> - /// <param name="message">The message to check the signature on.</param> - /// <returns> - /// <c>true</c> if the signature on the message is valid; otherwise, <c>false</c>. - /// </returns> - protected override bool IsSignatureValid(ITamperResistantOAuthMessage message) { - ErrorUtilities.VerifyInternal(this.tokenManager != null, "No token manager available for fetching Consumer public certificates."); - - string signatureBaseString = ConstructSignatureBaseString(message, this.Channel.MessageDescriptions.GetAccessor(message)); - byte[] data = Encoding.ASCII.GetBytes(signatureBaseString); - - byte[] carriedSignature = Convert.FromBase64String(message.Signature); - - X509Certificate2 cert = this.tokenManager.GetConsumer(message.ConsumerKey).Certificate; - if (cert == null) { - Logger.Signatures.WarnFormat("Incoming message from consumer '{0}' could not be matched with an appropriate X.509 certificate for signature verification.", message.ConsumerKey); - return false; - } - - var provider = (RSACryptoServiceProvider)cert.PublicKey.Key; - bool valid = provider.VerifyData(data, "SHA1", carriedSignature); - return valid; - } - - /// <summary> - /// Clones this instance. - /// </summary> - /// <returns>A new instance of the binding element.</returns> - protected override ITamperProtectionChannelBindingElement Clone() { - if (this.tokenManager != null) { - return new RsaSha1SigningBindingElement(this.tokenManager); - } else { - return new RsaSha1SigningBindingElement(this.SigningCertificate); - } } } } |