summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OAuth.Consumer
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth.OAuth.Consumer')
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj3
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerChannel.cs61
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs109
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/RsaSha1ConsumerSigningBindingElement.cs61
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs2
5 files changed, 235 insertions, 1 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.Consumer/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs
new file mode 100644
index 0000000..327b923
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs
@@ -0,0 +1,109 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthConsumerMessageFactory.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth.Messages;
+
+ /// <summary>
+ /// An OAuth-protocol specific implementation of the <see cref="IMessageFactory"/>
+ /// interface.
+ /// </summary>
+ public class OAuthConsumerMessageFactory : IMessageFactory {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuthConsumerMessageFactory"/> class.
+ /// </summary>
+ protected internal OAuthConsumerMessageFactory() {
+ }
+
+ #region IMessageFactory Members
+
+ /// <summary>
+ /// Analyzes an incoming request message payload to discover what kind of
+ /// message is embedded in it and returns the type, or null if no match is found.
+ /// </summary>
+ /// <param name="recipient">The intended or actual recipient of the request message.</param>
+ /// <param name="fields">The name/value pairs that make up the message payload.</param>
+ /// <returns>
+ /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can
+ /// deserialize to. Null if the request isn't recognized as a valid protocol message.
+ /// </returns>
+ /// <remarks>
+ /// The request messages are:
+ /// UserAuthorizationResponse
+ /// </remarks>
+ public virtual IDirectedProtocolMessage GetNewRequestMessage(MessageReceivingEndpoint recipient, IDictionary<string, string> fields) {
+ MessageBase message = null;
+
+ if (fields.ContainsKey("oauth_token")) {
+ Protocol protocol = fields.ContainsKey("oauth_verifier") ? Protocol.V10a : Protocol.V10;
+ message = new UserAuthorizationResponse(recipient.Location, protocol.Version);
+ }
+
+ if (message != null) {
+ message.SetAsIncoming();
+ }
+
+ return message;
+ }
+
+ /// <summary>
+ /// Analyzes an incoming request message payload to discover what kind of
+ /// message is embedded in it and returns the type, or null if no match is found.
+ /// </summary>
+ /// <param name="request">
+ /// The message that was sent as a request that resulted in the response.
+ /// Null on a Consumer site that is receiving an indirect message from the Service Provider.
+ /// </param>
+ /// <param name="fields">The name/value pairs that make up the message payload.</param>
+ /// <returns>
+ /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can
+ /// deserialize to. Null if the request isn't recognized as a valid protocol message.
+ /// </returns>
+ /// <remarks>
+ /// The response messages are:
+ /// UnauthorizedTokenResponse
+ /// AuthorizedTokenResponse
+ /// </remarks>
+ public virtual IDirectResponseProtocolMessage GetNewResponseMessage(IDirectedProtocolMessage request, IDictionary<string, string> fields) {
+ MessageBase message = null;
+
+ // All response messages have the oauth_token field.
+ if (!fields.ContainsKey("oauth_token")) {
+ return null;
+ }
+
+ // All direct message responses should have the oauth_token_secret field.
+ if (!fields.ContainsKey("oauth_token_secret")) {
+ Logger.OAuth.Error("An OAuth message was expected to contain an oauth_token_secret but didn't.");
+ return null;
+ }
+
+ var unauthorizedTokenRequest = request as UnauthorizedTokenRequest;
+ var authorizedTokenRequest = request as AuthorizedTokenRequest;
+ if (unauthorizedTokenRequest != null) {
+ Protocol protocol = fields.ContainsKey("oauth_callback_confirmed") ? Protocol.V10a : Protocol.V10;
+ message = new UnauthorizedTokenResponse(unauthorizedTokenRequest, protocol.Version);
+ } else if (authorizedTokenRequest != null) {
+ message = new AuthorizedTokenResponse(authorizedTokenRequest);
+ } else {
+ Logger.OAuth.ErrorFormat("Unexpected response message given the request type {0}", request.GetType().Name);
+ throw new ProtocolException(OAuthStrings.InvalidIncomingMessage);
+ }
+
+ if (message != null) {
+ message.SetAsIncoming();
+ }
+
+ return message;
+ }
+
+ #endregion
+ }
+}
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);