summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/SimpleConsumerTokenManager.cs104
-rw-r--r--src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj2
-rw-r--r--src/DotNetOpenAuth.AspNet/WebResources.Designer.cs11
-rw-r--r--src/DotNetOpenAuth.AspNet/WebResources.resx3
-rw-r--r--src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj1
-rw-r--r--src/DotNetOpenAuth.Core/MachineKeyUtil.cs (renamed from src/DotNetOpenAuth.AspNet/MachineKeyUtil.cs)4
-rw-r--r--src/DotNetOpenAuth.Core/Strings.Designer.cs11
-rw-r--r--src/DotNetOpenAuth.Core/Strings.resx3
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj13
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessToken.cs39
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessTokenResponse.cs19
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/IConsumerTokenManager.cs25
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerChannel.cs67
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs108
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/RsaSha1ConsumerSigningBindingElement.cs76
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/Consumer.cs336
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs258
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/CookieTemporaryCredentialStorage.cs130
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/DesktopConsumer.cs79
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ITemporaryCredentialStorage.cs40
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/MemoryTemporaryCredentialStorage.cs65
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1HttpMessageHandlerBase.cs42
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1RsaSha1HttpMessageHandler.cs15
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/WebConsumer.cs87
-rw-r--r--src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj1
-rw-r--r--src/DotNetOpenAuth.OAuth.ServiceProvider/OAuthReporting.cs (renamed from src/DotNetOpenAuth.OAuth/OAuthReporting.cs)4
-rw-r--r--src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj4
-rw-r--r--src/DotNetOpenAuth.OAuth/OAuth/Messages/MessageBaseSimple.cs10
-rw-r--r--src/DotNetOpenAuth.OAuth/OAuth/Protocol.cs25
-rw-r--r--src/DotNetOpenAuth.OAuth/OAuth/ServiceProviderDescription.cs105
-rw-r--r--src/DotNetOpenAuth.OpenIdOAuth/OAuth/WebConsumerOpenIdRelyingParty.cs41
31 files changed, 807 insertions, 921 deletions
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/SimpleConsumerTokenManager.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/SimpleConsumerTokenManager.cs
deleted file mode 100644
index 899204c..0000000
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/SimpleConsumerTokenManager.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="SimpleConsumerTokenManager.cs" company="Microsoft">
-// Copyright (c) Microsoft. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.AspNet.Clients {
- using System;
- using DotNetOpenAuth.OAuth.ChannelElements;
- using Validation;
-
- /// <summary>
- /// Simple wrapper around IConsumerTokenManager
- /// </summary>
- public class SimpleConsumerTokenManager : IConsumerTokenManager {
- /// <summary>
- /// Store the token manager.
- /// </summary>
- private readonly IOAuthTokenManager tokenManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="SimpleConsumerTokenManager"/> class.
- /// </summary>
- /// <param name="consumerKey">The consumer key.</param>
- /// <param name="consumerSecret">The consumer secret.</param>
- /// <param name="tokenManager">The OAuth token manager.</param>
- public SimpleConsumerTokenManager(string consumerKey, string consumerSecret, IOAuthTokenManager tokenManager) {
- Requires.NotNullOrEmpty(consumerKey, "consumerKey");
- Requires.NotNullOrEmpty(consumerSecret, "consumerSecret");
- Requires.NotNull(tokenManager, "oAuthTokenManager");
-
- this.ConsumerKey = consumerKey;
- this.ConsumerSecret = consumerSecret;
- this.tokenManager = tokenManager;
- }
-
- /// <summary>
- /// Gets the consumer key.
- /// </summary>
- /// <value>
- /// The consumer key.
- /// </value>
- public string ConsumerKey {
- get;
- private set;
- }
-
- /// <summary>
- /// Gets the consumer secret.
- /// </summary>
- /// <value>
- /// The consumer secret.
- /// </value>
- public string ConsumerSecret {
- get;
- private set;
- }
-
- /// <summary>
- /// Gets the Token Secret given a request or access token.
- /// </summary>
- /// <param name="token">The request or access token.</param>
- /// <returns>
- /// The secret associated with the given token.
- /// </returns>
- /// <exception cref="ArgumentException">Thrown if the secret cannot be found for the given token.</exception>
- public string GetTokenSecret(string token) {
- return this.tokenManager.GetTokenSecret(token);
- }
-
- /// <summary>
- /// Stores a newly generated unauthorized request token, secret, and optional
- /// application-specific parameters for later recall.
- /// </summary>
- /// <param name="request">The request message that resulted in the generation of a new unauthorized request token.</param>
- /// <param name="response">The response message that includes the unauthorized request token.</param>
- /// <exception cref="ArgumentException">Thrown if the consumer key is not registered, or a required parameter was not found in the parameters collection.</exception>
- public void StoreNewRequestToken(DotNetOpenAuth.OAuth.Messages.UnauthorizedTokenRequest request, DotNetOpenAuth.OAuth.Messages.ITokenSecretContainingMessage response) {
- this.tokenManager.StoreRequestToken(response.Token, response.TokenSecret);
- }
-
- /// <summary>
- /// Deletes a request token and its associated secret and stores a new access token and secret.
- /// </summary>
- /// <param name="consumerKey">The Consumer that is exchanging its request token for an access token.</param>
- /// <param name="requestToken">The Consumer's request token that should be deleted/expired.</param>
- /// <param name="accessToken">The new access token that is being issued to the Consumer.</param>
- /// <param name="accessTokenSecret">The secret associated with the newly issued access token.</param>
- public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) {
- this.tokenManager.ReplaceRequestTokenWithAccessToken(requestToken, accessToken, accessTokenSecret);
- }
-
- /// <summary>
- /// Classifies a token as a request token or an access token.
- /// </summary>
- /// <param name="token">The token to classify.</param>
- /// <returns>
- /// Request or Access token, or invalid if the token is not recognized.
- /// </returns>
- public TokenType GetTokenType(string token) {
- throw new NotSupportedException();
- }
- }
-} \ No newline at end of file
diff --git a/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj b/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj
index 7a9d49b..7c64203 100644
--- a/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj
+++ b/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj
@@ -55,7 +55,6 @@
</Compile>
<Compile Include="Clients\OAuth\CookieOAuthTokenManager.cs" />
<Compile Include="Clients\OAuth\IOAuthTokenManager.cs" />
- <Compile Include="Clients\OAuth\SimpleConsumerTokenManager.cs" />
<Compile Include="IAuthenticationClient.cs" />
<Compile Include="Clients\OAuth2\FacebookClient.cs" />
<Compile Include="Clients\OAuth2\FacebookGraphData.cs" />
@@ -73,7 +72,6 @@
<Compile Include="Clients\OpenID\GoogleOpenIdClient.cs" />
<Compile Include="Clients\OpenID\OpenIdClient.cs" />
<Compile Include="Clients\OpenID\YahooOpenIdClient.cs" />
- <Compile Include="MachineKeyUtil.cs" />
<Compile Include="UriHelper.cs" />
<Compile Include="IOpenAuthDataProvider.cs" />
<Compile Include="OpenAuthAuthenticationTicketHelper.cs" />
diff --git a/src/DotNetOpenAuth.AspNet/WebResources.Designer.cs b/src/DotNetOpenAuth.AspNet/WebResources.Designer.cs
index fd79a73..da1d1ca 100644
--- a/src/DotNetOpenAuth.AspNet/WebResources.Designer.cs
+++ b/src/DotNetOpenAuth.AspNet/WebResources.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:4.0.30319.544
+// Runtime Version:4.0.30319.18033
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -79,15 +79,6 @@ namespace DotNetOpenAuth.AspNet {
}
/// <summary>
- /// Looks up a localized string similar to The provided data could not be decrypted. If the current application is deployed in a web farm configuration, ensure that the &apos;decryptionKey&apos; and &apos;validationKey&apos; attributes are explicitly specified in the &lt;machineKey&gt; configuration section..
- /// </summary>
- internal static string Generic_CryptoFailure {
- get {
- return ResourceManager.GetString("Generic_CryptoFailure", resourceCulture);
- }
- }
-
- /// <summary>
/// Looks up a localized string similar to An OAuth data provider has already been registered for this application..
/// </summary>
internal static string OAuthDataProviderRegistered {
diff --git a/src/DotNetOpenAuth.AspNet/WebResources.resx b/src/DotNetOpenAuth.AspNet/WebResources.resx
index c1552e9..a491579 100644
--- a/src/DotNetOpenAuth.AspNet/WebResources.resx
+++ b/src/DotNetOpenAuth.AspNet/WebResources.resx
@@ -123,9 +123,6 @@
<data name="FailedToEncryptTicket" xml:space="preserve">
<value>Unable to encrypt the authentication ticket.</value>
</data>
- <data name="Generic_CryptoFailure" xml:space="preserve">
- <value>The provided data could not be decrypted. If the current application is deployed in a web farm configuration, ensure that the 'decryptionKey' and 'validationKey' attributes are explicitly specified in the &lt;machineKey&gt; configuration section.</value>
- </data>
<data name="OAuthDataProviderRegistered" xml:space="preserve">
<value>An OAuth data provider has already been registered for this application.</value>
</data>
diff --git a/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj b/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
index 7877cf0..88513af 100644
--- a/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
+++ b/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
@@ -22,6 +22,7 @@
<Compile Include="Assumes.cs" />
<Compile Include="IHostFactories.cs" />
<Compile Include="IRequireHostFactories.cs" />
+ <Compile Include="MachineKeyUtil.cs" />
<Compile Include="Messaging\Base64WebEncoder.cs" />
<Compile Include="Messaging\Bindings\AsymmetricCryptoKeyStoreWrapper.cs" />
<Compile Include="Messaging\Bindings\CryptoKey.cs" />
diff --git a/src/DotNetOpenAuth.AspNet/MachineKeyUtil.cs b/src/DotNetOpenAuth.Core/MachineKeyUtil.cs
index eb2020b..eceb38c 100644
--- a/src/DotNetOpenAuth.AspNet/MachineKeyUtil.cs
+++ b/src/DotNetOpenAuth.Core/MachineKeyUtil.cs
@@ -4,7 +4,7 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.AspNet {
+namespace DotNetOpenAuth {
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
@@ -183,7 +183,7 @@ namespace DotNetOpenAuth.AspNet {
}
// if we reached this point, some cryptographic operation failed
- throw new CryptographicException(WebResources.Generic_CryptoFailure);
+ throw new CryptographicException(Strings.Generic_CryptoFailure);
}
/// <summary>
diff --git a/src/DotNetOpenAuth.Core/Strings.Designer.cs b/src/DotNetOpenAuth.Core/Strings.Designer.cs
index 9eefd62..b96f68a 100644
--- a/src/DotNetOpenAuth.Core/Strings.Designer.cs
+++ b/src/DotNetOpenAuth.Core/Strings.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:4.0.30319.18010
+// Runtime Version:4.0.30319.18033
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -97,6 +97,15 @@ namespace DotNetOpenAuth {
}
/// <summary>
+ /// Looks up a localized string similar to The provided data could not be decrypted. If the current application is deployed in a web farm configuration, ensure that the &apos;decryptionKey&apos; and &apos;validationKey&apos; attributes are explicitly specified in the &lt;machineKey&gt; configuration section..
+ /// </summary>
+ internal static string Generic_CryptoFailure {
+ get {
+ return ResourceManager.GetString("Generic_CryptoFailure", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to The HostFactories property must be set first..
/// </summary>
internal static string HostFactoriesRequired {
diff --git a/src/DotNetOpenAuth.Core/Strings.resx b/src/DotNetOpenAuth.Core/Strings.resx
index 133fe6f..1c2aee2 100644
--- a/src/DotNetOpenAuth.Core/Strings.resx
+++ b/src/DotNetOpenAuth.Core/Strings.resx
@@ -144,4 +144,7 @@
<data name="HostFactoriesRequired" xml:space="preserve">
<value>The HostFactories property must be set first.</value>
</data>
+ <data name="Generic_CryptoFailure" xml:space="preserve">
+ <value>The provided data could not be decrypted. If the current application is deployed in a web farm configuration, ensure that the 'decryptionKey' and 'validationKey' attributes are explicitly specified in the &lt;machineKey&gt; configuration section.</value>
+ </data>
</root> \ No newline at end of file
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj b/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj
index 922b860..fe14abc 100644
--- a/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj
+++ b/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj
@@ -19,17 +19,16 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
</PropertyGroup>
<ItemGroup>
- <Compile Include="OAuth\ChannelElements\IConsumerTokenManager.cs" />
- <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\AccessToken.cs" />
+ <Compile Include="OAuth\AccessTokenResponse.cs" />
+ <Compile Include="OAuth\ITemporaryCredentialStorage.cs" />
+ <Compile Include="OAuth\Consumer.cs" />
+ <Compile Include="OAuth\CookieTemporaryCredentialStorage.cs" />
+ <Compile Include="OAuth\MemoryTemporaryCredentialStorage.cs" />
<Compile Include="OAuth\OAuth1HmacSha1HttpMessageHandler.cs" />
<Compile Include="OAuth\OAuth1HttpMessageHandlerBase.cs" />
<Compile Include="OAuth\OAuth1PlainTextMessageHandler.cs" />
<Compile Include="OAuth\OAuth1RsaSha1HttpMessageHandler.cs" />
- <Compile Include="OAuth\WebConsumer.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>
</SubType>
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessToken.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessToken.cs
new file mode 100644
index 0000000..20e3ec4
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessToken.cs
@@ -0,0 +1,39 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessToken.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth {
+ /// <summary>
+ /// An OAuth 1.0 access token and secret.
+ /// </summary>
+ public struct AccessToken {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessToken"/> struct.
+ /// </summary>
+ /// <param name="token">The token.</param>
+ /// <param name="secret">The secret.</param>
+ public AccessToken(string token, string secret)
+ : this() {
+ this.Token = token;
+ this.Secret = secret;
+ }
+
+ /// <summary>
+ /// Gets or sets the token.
+ /// </summary>
+ /// <value>
+ /// The token.
+ /// </value>
+ public string Token { get; set; }
+
+ /// <summary>
+ /// Gets or sets the token secret.
+ /// </summary>
+ /// <value>
+ /// The secret.
+ /// </value>
+ public string Secret { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessTokenResponse.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessTokenResponse.cs
new file mode 100644
index 0000000..dd35400
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessTokenResponse.cs
@@ -0,0 +1,19 @@
+namespace DotNetOpenAuth.OAuth {
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.Specialized;
+ using System.Linq;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ public class AccessTokenResponse {
+ public AccessTokenResponse(string accessToken, string tokenSecret, NameValueCollection extraData) {
+ this.AccessToken = new AccessToken(accessToken, tokenSecret);
+ this.ExtraData = extraData;
+ }
+
+ public AccessToken AccessToken { get; set; }
+
+ public NameValueCollection ExtraData { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/IConsumerTokenManager.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/IConsumerTokenManager.cs
deleted file mode 100644
index 74ec3be..0000000
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/IConsumerTokenManager.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="IConsumerTokenManager.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth.ChannelElements {
- /// <summary>
- /// A token manager for use by a web site in its role as a consumer of
- /// an individual ServiceProvider.
- /// </summary>
- public interface IConsumerTokenManager : ITokenManager {
- /// <summary>
- /// Gets the consumer key.
- /// </summary>
- /// <value>The consumer key.</value>
- string ConsumerKey { get; }
-
- /// <summary>
- /// Gets the consumer secret.
- /// </summary>
- /// <value>The consumer secret.</value>
- string ConsumerSecret { get; }
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerChannel.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerChannel.cs
deleted file mode 100644
index a10ff09..0000000
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerChannel.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="OAuthConsumerChannel.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth.ChannelElements {
- using System;
- using System.Collections.Generic;
- using System.Diagnostics.CodeAnalysis;
- using System.Linq;
- using System.Text;
- using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.Messaging.Bindings;
- using Validation;
-
- /// <summary>
- /// The messaging channel for OAuth 1.0(a) Consumers.
- /// </summary>
- internal class OAuthConsumerChannel : OAuthChannel {
- /// <summary>
- /// Initializes a new instance of the <see cref="OAuthConsumerChannel" /> 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>
- /// <param name="messageFactory">The message factory.</param>
- /// <param name="hostFactories">The host factories.</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, IMessageFactory messageFactory = null, IHostFactories hostFactories = null)
- : base(
- signingBindingElement,
- tokenManager,
- securitySettings,
- messageFactory ?? new OAuthConsumerMessageFactory(),
- InitializeBindingElements(signingBindingElement, store),
- hostFactories) {
- Requires.NotNull(tokenManager, "tokenManager");
- Requires.NotNull(securitySettings, "securitySettings");
- Requires.NotNull(signingBindingElement, "signingBindingElement");
- }
-
- /// <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>
- /// <returns>
- /// An array of binding elements used to initialize the channel.
- /// </returns>
- private static new IChannelBindingElement[] InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store) {
- return OAuthChannel.InitializeBindingElements(signingBindingElement, store).ToArray();
- }
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs
deleted file mode 100644
index e79749f..0000000
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs
+++ /dev/null
@@ -1,108 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="OAuthConsumerMessageFactory.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth.ChannelElements {
- using System;
- using System.Collections.Generic;
- 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
deleted file mode 100644
index d492e33..0000000
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/RsaSha1ConsumerSigningBindingElement.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="RsaSha1ConsumerSigningBindingElement.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth.ChannelElements {
- using System;
- using System.Diagnostics.CodeAnalysis;
- using System.Security.Cryptography;
- using System.Security.Cryptography.X509Certificates;
- using System.Text;
- using DotNetOpenAuth.Messaging;
- using Validation;
-
- /// <summary>
- /// A binding element that signs outgoing messages and verifies the signature on incoming messages.
- /// </summary>
- [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Sha", Justification = "Acronym")]
- public class RsaSha1ConsumerSigningBindingElement : RsaSha1SigningBindingElement {
- /// <summary>
- /// Initializes a new instance of the <see cref="RsaSha1ConsumerSigningBindingElement"/> class.
- /// </summary>
- /// <param name="signingCertificate">The certificate used to sign outgoing messages.</param>
- public RsaSha1ConsumerSigningBindingElement(X509Certificate2 signingCertificate) {
- Requires.NotNull(signingCertificate, "signingCertificate");
-
- this.SigningCertificate = signingCertificate;
- }
-
- /// <summary>
- /// Gets or sets the certificate used to sign outgoing messages. Used only by Consumers.
- /// </summary>
- public X509Certificate2 SigningCertificate { get; set; }
-
- /// <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) {
- 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;
- }
-
- /// <summary>
- /// Creates a new object that is a copy of the current instance.
- /// </summary>
- /// <returns>
- /// A new object that is a copy of this instance.
- /// </returns>
- protected override ITamperProtectionChannelBindingElement Clone() {
- return new RsaSha1ConsumerSigningBindingElement(this.SigningCertificate);
- }
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/Consumer.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/Consumer.cs
new file mode 100644
index 0000000..578902c
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/Consumer.cs
@@ -0,0 +1,336 @@
+//-----------------------------------------------------------------------
+// <copyright file="Consumer.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Linq;
+ using System.Net;
+ using System.Net.Http;
+ using System.Security.Cryptography.X509Certificates;
+ using System.Threading;
+ using System.Threading.Tasks;
+ using System.Web;
+ using DotNetOpenAuth.Configuration;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Bindings;
+ using DotNetOpenAuth.OAuth.ChannelElements;
+ using DotNetOpenAuth.OAuth.Messages;
+ using Validation;
+
+ /// <summary>
+ /// Base class for <see cref="WebConsumer"/> and <see cref="DesktopConsumer"/> types.
+ /// </summary>
+ public class Consumer {
+ /// <summary>
+ /// The host factories.
+ /// </summary>
+ private IHostFactories hostFactories;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Consumer"/> class.
+ /// </summary>
+ public Consumer() {
+ this.HostFactories = new DefaultOAuthHostFactories();
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Consumer"/> class.
+ /// </summary>
+ /// <param name="consumerKey">The consumer key.</param>
+ /// <param name="consumerSecret">The consumer secret.</param>
+ /// <param name="serviceProvider">The service provider.</param>
+ /// <param name="temporaryCredentialStorage">The temporary credential storage.</param>
+ public Consumer(
+ string consumerKey,
+ string consumerSecret,
+ ServiceProviderDescription serviceProvider,
+ ITemporaryCredentialStorage temporaryCredentialStorage) {
+ this.ConsumerKey = consumerKey;
+ this.ConsumerSecret = consumerSecret;
+ this.ServiceProvider = serviceProvider;
+ this.TemporaryCredentialStorage = temporaryCredentialStorage;
+ }
+
+ /// <summary>
+ /// Gets or sets the object with factories for host-customizable services.
+ /// </summary>
+ public IHostFactories HostFactories {
+ get {
+ return this.hostFactories;
+ }
+
+ set {
+ Requires.NotNull(value, "value");
+ this.hostFactories = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets the Consumer Key used to communicate with the Service Provider.
+ /// </summary>
+ public string ConsumerKey { get; set; }
+
+ /// <summary>
+ /// Gets or sets the consumer secret.
+ /// </summary>
+ /// <value>
+ /// The consumer secret.
+ /// </value>
+ public string ConsumerSecret { get; set; }
+
+ /// <summary>
+ /// Gets or sets the consumer certificate.
+ /// </summary>
+ /// <value>
+ /// The consumer certificate.
+ /// </value>
+ /// <remarks>
+ /// If set, this causes all outgoing messages to be signed with the certificate instead of the consumer secret.
+ /// </remarks>
+ public X509Certificate2 ConsumerCertificate { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Service Provider that will be accessed.
+ /// </summary>
+ public ServiceProviderDescription ServiceProvider { get; set; }
+
+ /// <summary>
+ /// Gets the persistence store for tokens and secrets.
+ /// </summary>
+ public ITemporaryCredentialStorage TemporaryCredentialStorage { get; set; }
+
+ /// <summary>
+ /// Obtains an access token for a new account at the Service Provider via 2-legged OAuth.
+ /// </summary>
+ /// <param name="requestParameters">Any applicable parameters to include in the query string of the token request.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>The access token.</returns>
+ public async Task<AccessTokenResponse> RequestNewClientAccountAsync(IEnumerable<KeyValuePair<string, string>> requestParameters = null, CancellationToken cancellationToken = default(CancellationToken)) {
+ Verify.Operation(this.ConsumerKey != null, Strings.RequiredPropertyNotYetPreset, "ConsumerKey");
+ Verify.Operation(this.ServiceProvider != null, Strings.RequiredPropertyNotYetPreset, "ServiceProvider");
+
+ using (var handler = this.CreateMessageHandler()) {
+ using (var client = this.CreateHttpClient(handler)) {
+ string identifier, secret;
+
+ var requestUri = new UriBuilder(this.ServiceProvider.TemporaryCredentialsRequestEndpoint);
+ requestUri.AppendQueryArgument(Protocol.CallbackParameter, "oob");
+ requestUri.AppendQueryArgs(requestParameters);
+ var request = new HttpRequestMessage(this.ServiceProvider.TemporaryCredentialsRequestEndpointMethod, requestUri.Uri);
+ using (var response = await client.SendAsync(request, cancellationToken)) {
+ response.EnsureSuccessStatusCode();
+ cancellationToken.ThrowIfCancellationRequested();
+
+ // Parse the response and ensure that it meets the requirements of the OAuth 1.0 spec.
+ string content = await response.Content.ReadAsStringAsync();
+ var responseData = HttpUtility.ParseQueryString(content);
+ identifier = responseData[Protocol.TokenParameter];
+ secret = responseData[Protocol.TokenSecretParameter];
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(identifier), MessagingStrings.RequiredParametersMissing, typeof(UnauthorizedTokenResponse).Name, Protocol.TokenParameter);
+ ErrorUtilities.VerifyProtocol(secret != null, MessagingStrings.RequiredParametersMissing, typeof(UnauthorizedTokenResponse).Name, Protocol.TokenSecretParameter);
+ }
+
+ // Immediately exchange the temporary credential for an access token.
+ handler.AccessToken = identifier;
+ handler.AccessTokenSecret = secret;
+ request = new HttpRequestMessage(this.ServiceProvider.TokenRequestEndpointMethod, this.ServiceProvider.TokenRequestEndpoint);
+ using (var response = await client.SendAsync(request, cancellationToken)) {
+ response.EnsureSuccessStatusCode();
+
+ // Parse the response and ensure that it meets the requirements of the OAuth 1.0 spec.
+ string content = await response.Content.ReadAsStringAsync();
+ var responseData = HttpUtility.ParseQueryString(content);
+ string accessToken = responseData[Protocol.TokenParameter];
+ string tokenSecret = responseData[Protocol.TokenSecretParameter];
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(accessToken), MessagingStrings.RequiredParametersMissing, typeof(AuthorizedTokenResponse).Name, Protocol.TokenParameter);
+ ErrorUtilities.VerifyProtocol(tokenSecret != null, MessagingStrings.RequiredParametersMissing, typeof(AuthorizedTokenResponse).Name, Protocol.TokenSecretParameter);
+
+ responseData.Remove(Protocol.TokenParameter);
+ responseData.Remove(Protocol.TokenSecretParameter);
+ return new AccessTokenResponse(accessToken, tokenSecret, responseData);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Prepares an OAuth message that begins an authorization request that will
+ /// redirect the user to the Service Provider to provide that authorization.
+ /// </summary>
+ /// <param name="callback">The absolute URI that the Service Provider should redirect the
+ /// User Agent to upon successful authorization, or <c>null</c> to signify an out of band return.</param>
+ /// <param name="requestParameters">Extra parameters to add to the request token message. Optional.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// The URL to direct the user agent to for user authorization.
+ /// </returns>
+ public async Task<Uri> RequestUserAuthorizationAsync(Uri callback = null, IEnumerable<KeyValuePair<string, string>> requestParameters = null, CancellationToken cancellationToken = default(CancellationToken)) {
+ Requires.NotNull(callback, "callback");
+ Verify.Operation(this.ConsumerKey != null, Strings.RequiredPropertyNotYetPreset, "ConsumerKey");
+ Verify.Operation(this.TemporaryCredentialStorage != null, Strings.RequiredPropertyNotYetPreset, "TemporaryCredentialStorage");
+ Verify.Operation(this.ServiceProvider != null, Strings.RequiredPropertyNotYetPreset, "ServiceProvider");
+
+ // Obtain temporary credentials before the redirect.
+ using (var client = this.CreateHttpClient(new AccessToken())) {
+ var requestUri = new UriBuilder(this.ServiceProvider.TemporaryCredentialsRequestEndpoint);
+ requestUri.AppendQueryArgument(Protocol.CallbackParameter, callback != null ? callback.AbsoluteUri : "oob");
+ requestUri.AppendQueryArgs(requestParameters);
+ var request = new HttpRequestMessage(this.ServiceProvider.TemporaryCredentialsRequestEndpointMethod, requestUri.Uri);
+ using (var response = await client.SendAsync(request, cancellationToken)) {
+ response.EnsureSuccessStatusCode();
+ cancellationToken.ThrowIfCancellationRequested();
+
+ // Parse the response and ensure that it meets the requirements of the OAuth 1.0 spec.
+ string content = await response.Content.ReadAsStringAsync();
+ var responseData = HttpUtility.ParseQueryString(content);
+ ErrorUtilities.VerifyProtocol(string.Equals(responseData[Protocol.CallbackConfirmedParameter], "true", StringComparison.Ordinal), MessagingStrings.RequiredParametersMissing, typeof(UnauthorizedTokenResponse).Name, Protocol.CallbackConfirmedParameter);
+ string identifier = responseData[Protocol.TokenParameter];
+ string secret = responseData[Protocol.TokenSecretParameter];
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(identifier), MessagingStrings.RequiredParametersMissing, typeof(UnauthorizedTokenResponse).Name, Protocol.TokenParameter);
+ ErrorUtilities.VerifyProtocol(secret != null, MessagingStrings.RequiredParametersMissing, typeof(UnauthorizedTokenResponse).Name, Protocol.TokenSecretParameter);
+
+ // Save the temporary credential we received so that after user authorization
+ // we can use it to obtain the access token.
+ cancellationToken.ThrowIfCancellationRequested();
+ this.TemporaryCredentialStorage.SaveTemporaryCredential(identifier, secret);
+
+ // Construct the user authorization URL so our caller can direct a browser to it.
+ var authorizationEndpoint = new UriBuilder(this.ServiceProvider.ResourceOwnerAuthorizationEndpoint);
+ authorizationEndpoint.AppendQueryArgument(Protocol.TokenParameter, identifier);
+ return authorizationEndpoint.Uri;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Obtains an access token after a successful user authorization.
+ /// </summary>
+ /// <param name="authorizationCompleteUri">The URI used to redirect back to the consumer that contains a message from the service provider.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// The access token assigned by the Service Provider, or <c>null</c> if no response was detected in the specified URL.
+ /// </returns>
+ public Task<AccessTokenResponse> ProcessUserAuthorizationAsync(Uri authorizationCompleteUri, CancellationToken cancellationToken = default(CancellationToken)) {
+ Requires.NotNull(authorizationCompleteUri, "authorizationCompleteUri");
+ Verify.Operation(this.TemporaryCredentialStorage != null, Strings.RequiredPropertyNotYetPreset, "TemporaryCredentialStorage");
+
+ // Parse the response and verify that it meets spec requirements.
+ var queryString = HttpUtility.ParseQueryString(authorizationCompleteUri.Query);
+ string identifier = queryString[Protocol.TokenParameter];
+ string verifier = queryString[Protocol.VerifierParameter];
+
+ if (identifier == null) {
+ // We assume there is no response message here at all, and return null to indicate that.
+ return null;
+ }
+
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(identifier), MessagingStrings.RequiredNonEmptyParameterWasEmpty, typeof(UserAuthorizationResponse).Name, Protocol.TokenParameter);
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(verifier), MessagingStrings.RequiredNonEmptyParameterWasEmpty, typeof(UserAuthorizationResponse).Name, Protocol.VerifierParameter);
+
+ var temporaryCredential = this.TemporaryCredentialStorage.RetrieveTemporaryCredential();
+ Verify.Operation(string.Equals(temporaryCredential.Key, identifier, StringComparison.Ordinal), "Temporary credential identifiers do not match.");
+
+ return this.ProcessUserAuthorizationAsync(verifier, cancellationToken);
+ }
+
+ /// <summary>
+ /// Obtains an access token after a successful user authorization.
+ /// </summary>
+ /// <param name="verifier">The verifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// The access token assigned by the Service Provider.
+ /// </returns>
+ public async Task<AccessTokenResponse> ProcessUserAuthorizationAsync(string verifier, CancellationToken cancellationToken = default(CancellationToken)) {
+ Requires.NotNull(verifier, "verifier");
+ Verify.Operation(this.ConsumerKey != null, Strings.RequiredPropertyNotYetPreset, "ConsumerKey");
+ Verify.Operation(this.TemporaryCredentialStorage != null, Strings.RequiredPropertyNotYetPreset, "TemporaryCredentialStorage");
+ Verify.Operation(this.ServiceProvider != null, Strings.RequiredPropertyNotYetPreset, "ServiceProvider");
+
+ var temporaryCredential = this.TemporaryCredentialStorage.RetrieveTemporaryCredential();
+
+ using (var client = this.CreateHttpClient(new AccessToken(temporaryCredential.Key, temporaryCredential.Value))) {
+ var requestUri = new UriBuilder(this.ServiceProvider.TokenRequestEndpoint);
+ requestUri.AppendQueryArgument(Protocol.VerifierParameter, verifier);
+ var request = new HttpRequestMessage(this.ServiceProvider.TokenRequestEndpointMethod, requestUri.Uri);
+ using (var response = await client.SendAsync(request, cancellationToken)) {
+ response.EnsureSuccessStatusCode();
+
+ // Parse the response and ensure that it meets the requirements of the OAuth 1.0 spec.
+ string content = await response.Content.ReadAsStringAsync();
+ var responseData = HttpUtility.ParseQueryString(content);
+ string accessToken = responseData[Protocol.TokenParameter];
+ string tokenSecret = responseData[Protocol.TokenSecretParameter];
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(accessToken), MessagingStrings.RequiredParametersMissing, typeof(AuthorizedTokenResponse).Name, Protocol.TokenParameter);
+ ErrorUtilities.VerifyProtocol(tokenSecret != null, MessagingStrings.RequiredParametersMissing, typeof(AuthorizedTokenResponse).Name, Protocol.TokenSecretParameter);
+
+ responseData.Remove(Protocol.TokenParameter);
+ responseData.Remove(Protocol.TokenSecretParameter);
+ return new AccessTokenResponse(accessToken, tokenSecret, responseData);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Creates a message handler that signs outbound requests with a previously obtained authorization.
+ /// </summary>
+ /// <param name="accessToken">The access token to authorize outbound HTTP requests with.</param>
+ /// <param name="innerHandler">The inner handler that actually sends the HTTP message on the network.</param>
+ /// <returns>
+ /// A message handler.
+ /// </returns>
+ /// <remarks>
+ /// Overrides of this method may allow various derived types of handlers to be returned,
+ /// enabling consumers that use RSA or other signing methods.
+ /// </remarks>
+ public virtual OAuth1HttpMessageHandlerBase CreateMessageHandler(AccessToken accessToken = default(AccessToken), HttpMessageHandler innerHandler = null) {
+ Verify.Operation(this.ConsumerKey != null, Strings.RequiredPropertyNotYetPreset, "ConsumerKey");
+
+ innerHandler = innerHandler ?? this.HostFactories.CreateHttpMessageHandler();
+ OAuth1HttpMessageHandlerBase handler;
+ if (this.ConsumerCertificate != null) {
+ handler = new OAuth1RsaSha1HttpMessageHandler(innerHandler) {
+ SigningCertificate = this.ConsumerCertificate,
+ };
+ } else {
+ handler = new OAuth1HmacSha1HttpMessageHandler(innerHandler);
+ }
+
+ handler.ConsumerKey = this.ConsumerKey;
+ handler.ConsumerSecret = this.ConsumerSecret;
+ handler.AccessToken = accessToken.Token;
+ handler.AccessTokenSecret = accessToken.Secret;
+
+ return handler;
+ }
+
+ /// <summary>
+ /// Creates the HTTP client.
+ /// </summary>
+ /// <param name="accessToken">The access token to authorize outbound HTTP requests with.</param>
+ /// <param name="innerHandler">The inner handler that actually sends the HTTP message on the network.</param>
+ /// <returns>The HttpClient to use.</returns>
+ public HttpClient CreateHttpClient(AccessToken accessToken, HttpMessageHandler innerHandler = null) {
+ var handler = this.CreateMessageHandler(accessToken, innerHandler);
+ var client = this.HostFactories.CreateHttpClient(handler);
+ return client;
+ }
+
+ /// <summary>
+ /// Creates the HTTP client.
+ /// </summary>
+ /// <param name="innerHandler">The inner handler that actually sends the HTTP message on the network.</param>
+ /// <returns>The HttpClient to use.</returns>
+ public HttpClient CreateHttpClient(OAuth1HttpMessageHandlerBase innerHandler) {
+ Requires.NotNull(innerHandler, "innerHandler");
+
+ var client = this.HostFactories.CreateHttpClient(innerHandler);
+ return client;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs
deleted file mode 100644
index 1bea2c5..0000000
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs
+++ /dev/null
@@ -1,258 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="ConsumerBase.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth {
- using System;
- using System.Collections.Generic;
- using System.Diagnostics.CodeAnalysis;
- using System.Linq;
- using System.Net;
- using System.Net.Http;
- using System.Threading;
- using System.Threading.Tasks;
- using DotNetOpenAuth.Configuration;
- using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.Messaging.Bindings;
- using DotNetOpenAuth.OAuth.ChannelElements;
- using DotNetOpenAuth.OAuth.Messages;
- using Validation;
-
- /// <summary>
- /// Base class for <see cref="WebConsumer"/> and <see cref="DesktopConsumer"/> types.
- /// </summary>
- public class ConsumerBase : IDisposable {
- /// <summary>
- /// Initializes a new instance of the <see cref="ConsumerBase"/> class.
- /// </summary>
- /// <param name="serviceDescription">The endpoints and behavior of the Service Provider.</param>
- /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
- protected ConsumerBase(ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager) {
- Requires.NotNull(serviceDescription, "serviceDescription");
- Requires.NotNull(tokenManager, "tokenManager");
-
- ITamperProtectionChannelBindingElement signingElement = serviceDescription.CreateTamperProtectionElement();
- INonceStore store = new NonceMemoryStore(StandardExpirationBindingElement.MaximumMessageAge);
- this.SecuritySettings = OAuthElement.Configuration.Consumer.SecuritySettings.CreateSecuritySettings();
- this.OAuthChannel = new OAuthConsumerChannel(signingElement, store, tokenManager, this.SecuritySettings);
- this.ServiceProvider = serviceDescription;
-
- OAuthReporting.RecordFeatureAndDependencyUse(this, serviceDescription, tokenManager, null);
- }
-
- /// <summary>
- /// Gets the Consumer Key used to communicate with the Service Provider.
- /// </summary>
- public string ConsumerKey {
- get { return this.TokenManager.ConsumerKey; }
- }
-
- /// <summary>
- /// Gets the Service Provider that will be accessed.
- /// </summary>
- public ServiceProviderDescription ServiceProvider { get; private set; }
-
- /// <summary>
- /// Gets the persistence store for tokens and secrets.
- /// </summary>
- public IConsumerTokenManager TokenManager {
- get { return (IConsumerTokenManager)this.OAuthChannel.TokenManager; }
- }
-
- /// <summary>
- /// Gets the channel to use for sending/receiving messages.
- /// </summary>
- public Channel Channel {
- get { return this.OAuthChannel; }
- }
-
- /// <summary>
- /// Gets the security settings for this consumer.
- /// </summary>
- internal ConsumerSecuritySettings SecuritySettings { get; private set; }
-
- /// <summary>
- /// Gets or sets the channel to use for sending/receiving messages.
- /// </summary>
- internal OAuthChannel OAuthChannel { get; set; }
-
- /// <summary>
- /// Creates a message handler that signs outbound requests with a previously obtained authorization.
- /// </summary>
- /// <param name="accessToken">The access token to authorize outbound HTTP requests with.</param>
- /// <param name="innerHandler">The inner handler that actually sends the HTTP message on the network.</param>
- /// <returns>
- /// A message handler.
- /// </returns>
- public OAuth1HttpMessageHandlerBase CreateMessageHandler(string accessToken = null, HttpMessageHandler innerHandler = null) {
- return new OAuth1HmacSha1HttpMessageHandler() {
- ConsumerKey = this.ConsumerKey,
- ConsumerSecret = this.TokenManager.ConsumerSecret,
- AccessToken = accessToken,
- AccessTokenSecret = accessToken != null ? this.TokenManager.GetTokenSecret(accessToken) : null,
- InnerHandler = innerHandler ?? this.Channel.HostFactories.CreateHttpMessageHandler(),
- };
- }
-
- /// <summary>
- /// Creates the HTTP client.
- /// </summary>
- /// <param name="accessToken">The access token to authorize outbound HTTP requests with.</param>
- /// <param name="innerHandler">The inner handler that actually sends the HTTP message on the network.</param>
- /// <returns>The HttpClient to use.</returns>
- public HttpClient CreateHttpClient(string accessToken, HttpMessageHandler innerHandler = null) {
- Requires.NotNullOrEmpty(accessToken, "accessToken");
-
- var handler = this.CreateMessageHandler(accessToken, innerHandler);
- var client = this.Channel.HostFactories.CreateHttpClient(handler);
- return client;
- }
-
- /// <summary>
- /// Creates the HTTP client.
- /// </summary>
- /// <param name="innerHandler">The inner handler that actually sends the HTTP message on the network.</param>
- /// <returns>The HttpClient to use.</returns>
- public HttpClient CreateHttpClient(OAuth1HttpMessageHandlerBase innerHandler) {
- Requires.NotNull(innerHandler, "innerHandler");
-
- var client = this.Channel.HostFactories.CreateHttpClient(innerHandler);
- return client;
- }
-
- /// <summary>
- /// Obtains an access token for a new account at the Service Provider via 2-legged OAuth.
- /// </summary>
- /// <param name="requestParameters">Any applicable parameters to include in the query string of the token request.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>The access token.</returns>
- /// <remarks>
- /// The token secret is stored in the <see cref="TokenManager"/>.
- /// </remarks>
- public async Task<string> RequestNewClientAccountAsync(IDictionary<string, string> requestParameters = null, CancellationToken cancellationToken = default(CancellationToken)) {
- // Obtain an unauthorized request token. Force use of OAuth 1.0 (not 1.0a) so that
- // we are not expected to provide an oauth_verifier which doesn't apply in 2-legged OAuth.
- var token = new UnauthorizedTokenRequest(this.ServiceProvider.RequestTokenEndpoint, Protocol.V10.Version) {
- ConsumerKey = this.ConsumerKey,
- };
- var tokenAccessor = this.Channel.MessageDescriptions.GetAccessor(token);
- tokenAccessor.AddExtraParameters(requestParameters);
- var requestTokenResponse = await this.Channel.RequestAsync<UnauthorizedTokenResponse>(token, cancellationToken);
- this.TokenManager.StoreNewRequestToken(token, requestTokenResponse);
-
- var requestAccess = new AuthorizedTokenRequest(this.ServiceProvider.AccessTokenEndpoint, Protocol.V10.Version) {
- RequestToken = requestTokenResponse.RequestToken,
- ConsumerKey = this.ConsumerKey,
- };
- var grantAccess = await this.Channel.RequestAsync<AuthorizedTokenResponse>(requestAccess, cancellationToken);
- this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, requestTokenResponse.RequestToken, grantAccess.AccessToken, grantAccess.TokenSecret);
- return grantAccess.AccessToken;
- }
-
- #region IDisposable Members
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose() {
- this.Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- #endregion
-
- /// <summary>
- /// Creates a web request prepared with OAuth authorization
- /// that may be further tailored by adding parameters by the caller.
- /// </summary>
- /// <param name="endpoint">The URL and method on the Service Provider to send the request to.</param>
- /// <param name="accessToken">The access token that permits access to the protected resource.</param>
- /// <returns>The initialized WebRequest object.</returns>
- protected internal AccessProtectedResourceRequest CreateAuthorizingMessage(MessageReceivingEndpoint endpoint, string accessToken) {
- Requires.NotNull(endpoint, "endpoint");
- Requires.NotNullOrEmpty(accessToken, "accessToken");
-
- AccessProtectedResourceRequest message = new AccessProtectedResourceRequest(endpoint, this.ServiceProvider.Version) {
- AccessToken = accessToken,
- ConsumerKey = this.ConsumerKey,
- };
-
- return message;
- }
-
- /// <summary>
- /// Prepares an OAuth message that begins an authorization request that will
- /// redirect the user to the Service Provider to provide that authorization.
- /// </summary>
- /// <param name="callback">An optional Consumer URL that the Service Provider should redirect the
- /// User Agent to upon successful authorization.</param>
- /// <param name="requestParameters">Extra parameters to add to the request token message. Optional.</param>
- /// <param name="redirectParameters">Extra parameters to add to the redirect to Service Provider message. Optional.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>
- /// The pending user agent redirect based message to be sent as an HttpResponse.
- /// </returns>
- [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "3#", Justification = "Two results")]
- protected internal async Task<UserAuthorizationRequest> PrepareRequestUserAuthorizationAsync(Uri callback, IDictionary<string, string> requestParameters, IDictionary<string, string> redirectParameters, CancellationToken cancellationToken = default(CancellationToken)) {
- // Obtain an unauthorized request token. Assume the OAuth version given in the service description.
- var token = new UnauthorizedTokenRequest(this.ServiceProvider.RequestTokenEndpoint, this.ServiceProvider.Version) {
- ConsumerKey = this.ConsumerKey,
- Callback = callback,
- };
- var tokenAccessor = this.Channel.MessageDescriptions.GetAccessor(token);
- tokenAccessor.AddExtraParameters(requestParameters);
- var requestTokenResponse = await this.Channel.RequestAsync<UnauthorizedTokenResponse>(token, cancellationToken);
- this.TokenManager.StoreNewRequestToken(token, requestTokenResponse);
-
- // Fine-tune our understanding of the SP's supported OAuth version if it's wrong.
- if (this.ServiceProvider.Version != requestTokenResponse.Version) {
- Logger.OAuth.WarnFormat("Expected OAuth service provider at endpoint {0} to use OAuth {1} but {2} was detected. Adjusting service description to new version.", this.ServiceProvider.RequestTokenEndpoint.Location, this.ServiceProvider.Version, requestTokenResponse.Version);
- this.ServiceProvider.ProtocolVersion = Protocol.Lookup(requestTokenResponse.Version).ProtocolVersion;
- }
-
- // Request user authorization. The OAuth version will automatically include
- // or drop the callback that we're setting here.
- ITokenContainingMessage assignedRequestToken = requestTokenResponse;
- var requestAuthorization = new UserAuthorizationRequest(this.ServiceProvider.UserAuthorizationEndpoint, assignedRequestToken.Token, requestTokenResponse.Version) {
- Callback = callback,
- };
- var requestAuthorizationAccessor = this.Channel.MessageDescriptions.GetAccessor(requestAuthorization);
- requestAuthorizationAccessor.AddExtraParameters(redirectParameters);
- return requestAuthorization;
- }
-
- /// <summary>
- /// Exchanges a given request token for access token.
- /// </summary>
- /// <param name="requestToken">The request token that the user has authorized.</param>
- /// <param name="verifier">The verifier code.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>
- /// The access token assigned by the Service Provider.
- /// </returns>
- protected async Task<AuthorizedTokenResponse> ProcessUserAuthorizationAsync(string requestToken, string verifier, CancellationToken cancellationToken = default(CancellationToken)) {
- Requires.NotNullOrEmpty(requestToken, "requestToken");
-
- var requestAccess = new AuthorizedTokenRequest(this.ServiceProvider.AccessTokenEndpoint, this.ServiceProvider.Version) {
- RequestToken = requestToken,
- VerificationCode = verifier,
- ConsumerKey = this.ConsumerKey,
- };
- var grantAccess = await this.Channel.RequestAsync<AuthorizedTokenResponse>(requestAccess, cancellationToken);
- this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, requestToken, grantAccess.AccessToken, grantAccess.TokenSecret);
- return grantAccess;
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources
- /// </summary>
- /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool disposing) {
- if (disposing) {
- this.Channel.Dispose();
- }
- }
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/CookieTemporaryCredentialStorage.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/CookieTemporaryCredentialStorage.cs
new file mode 100644
index 0000000..25941e6
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/CookieTemporaryCredentialStorage.cs
@@ -0,0 +1,130 @@
+//-----------------------------------------------------------------------
+// <copyright file="CookieTemporaryCredentialStorage.cs" company="Microsoft">
+// Copyright (c) Microsoft. All rights reserved.
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Threading.Tasks;
+ using System.Web;
+ using System.Web.Security;
+ using Validation;
+
+ /// <summary>
+ /// Provides temporary credential storage by persisting them in a protected cookie on the
+ /// user agent (i.e. browser).
+ /// </summary>
+ public class CookieTemporaryCredentialStorage : ITemporaryCredentialStorage {
+ /// <summary>
+ /// Key used for token cookie
+ /// </summary>
+ protected const string TokenCookieKey = "DNOAOAuth1TempCredential";
+
+ /// <summary>
+ /// Primary request context.
+ /// </summary>
+ private readonly HttpContextBase httpContext;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CookieTemporaryCredentialsStorage"/> class
+ /// using <see cref="HttpContext.Current"/> as the source for the context to read and write cookies to.
+ /// </summary>
+ public CookieTemporaryCredentialStorage()
+ : this(new HttpContextWrapper(HttpContext.Current)) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CookieTemporaryCredentialsStorage"/> class.
+ /// </summary>
+ /// <param name="httpContext">The HTTP context from and to which to access cookies.</param>
+ public CookieTemporaryCredentialStorage(HttpContextBase httpContext) {
+ Requires.NotNull(httpContext, "httpContext");
+ this.httpContext = httpContext;
+ }
+
+ #region ITemporaryCredentialsStorage Members
+
+ /// <summary>
+ /// Saves the temporary credential.
+ /// </summary>
+ /// <param name="identifier">The identifier.</param>
+ /// <param name="secret">The secret.</param>
+ public void SaveTemporaryCredential(string identifier, string secret) {
+ var cookie = new HttpCookie(TokenCookieKey) {
+ HttpOnly = true
+ };
+
+ if (FormsAuthentication.RequireSSL) {
+ cookie.Secure = true;
+ }
+
+ var encryptedToken = ProtectAndEncodeToken(identifier, secret);
+ cookie.Values[identifier] = encryptedToken;
+
+ this.httpContext.Response.Cookies.Set(cookie);
+ }
+
+ /// <summary>
+ /// Obtains the temporary credential identifier and secret, if available.
+ /// </summary>
+ /// <returns>
+ /// An initialized key value pair if credentials are available; otherwise both key and value are <c>null</c>.
+ /// </returns>
+ /// <exception cref="System.NotImplementedException"></exception>
+ public KeyValuePair<string, string> RetrieveTemporaryCredential() {
+ HttpCookie cookie = this.httpContext.Request.Cookies[TokenCookieKey];
+ if (cookie == null || cookie.Values.Count == 0) {
+ return new KeyValuePair<string, string>();
+ }
+
+ string identifier = cookie.Values.GetKey(0);
+ string secret = DecodeAndUnprotectToken(identifier, cookie.Values[identifier]);
+ return new KeyValuePair<string, string>(identifier, secret);
+ }
+
+ /// <summary>
+ /// Clears the temporary credentials from storage.
+ /// </summary>
+ /// <remarks>
+ /// DotNetOpenAuth calls this when the credentials are no longer needed.
+ /// </remarks>
+ public void ClearTemporaryCredential() {
+ var cookie = new HttpCookie(TokenCookieKey) {
+ Value = string.Empty,
+ Expires = DateTime.UtcNow.AddDays(-5),
+ };
+ this.httpContext.Response.Cookies.Set(cookie);
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Protect and url-encode the specified token secret.
+ /// </summary>
+ /// <param name="token">The token to be used as a key.</param>
+ /// <param name="tokenSecret">The token secret to be protected</param>
+ /// <returns>The encrypted and protected string.</returns>
+ protected static string ProtectAndEncodeToken(string token, string tokenSecret) {
+ byte[] cookieBytes = Encoding.UTF8.GetBytes(tokenSecret);
+ var secretBytes = MachineKeyUtil.Protect(cookieBytes, TokenCookieKey, "Token:" + token);
+ return HttpServerUtility.UrlTokenEncode(secretBytes);
+ }
+
+ /// <summary>
+ /// Url-decode and unprotect the specified encrypted token string.
+ /// </summary>
+ /// <param name="token">The token to be used as a key.</param>
+ /// <param name="encryptedToken">The encrypted token to be decrypted</param>
+ /// <returns>The original token secret</returns>
+ protected static string DecodeAndUnprotectToken(string token, string encryptedToken) {
+ byte[] cookieBytes = HttpServerUtility.UrlTokenDecode(encryptedToken);
+ byte[] clearBytes = MachineKeyUtil.Unprotect(cookieBytes, TokenCookieKey, "Token:" + token);
+ return Encoding.UTF8.GetString(clearBytes);
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/DesktopConsumer.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/DesktopConsumer.cs
deleted file mode 100644
index a1bfd2d..0000000
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/DesktopConsumer.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="DesktopConsumer.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth {
- using System;
- using System.Collections.Generic;
- using System.Diagnostics.CodeAnalysis;
- using System.Threading;
- using System.Threading.Tasks;
- using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.OAuth;
- using DotNetOpenAuth.OAuth.ChannelElements;
- using DotNetOpenAuth.OAuth.Messages;
-
- /// <summary>
- /// Used by a desktop application to use OAuth to access the Service Provider on behalf of the User.
- /// </summary>
- /// <remarks>
- /// The methods on this class are thread-safe. Provided the properties are set and not changed
- /// afterward, a single instance of this class may be used by an entire desktop application safely.
- /// </remarks>
- public class DesktopConsumer : ConsumerBase {
- /// <summary>
- /// Initializes a new instance of the <see cref="DesktopConsumer"/> class.
- /// </summary>
- /// <param name="serviceDescription">The endpoints and behavior of the Service Provider.</param>
- /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
- public DesktopConsumer(ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager)
- : base(serviceDescription, tokenManager) {
- }
-
- /// <summary>
- /// Begins an OAuth authorization request.
- /// </summary>
- /// <param name="requestParameters">Extra parameters to add to the request token message. Optional.</param>
- /// <param name="redirectParameters">Extra parameters to add to the redirect to Service Provider message. Optional.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>
- /// The URL to open a browser window to allow the user to provide authorization and the request token.
- /// </returns>
- [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#", Justification = "Two results")]
- public async Task<Tuple<Uri, string>> RequestUserAuthorizationAsync(IDictionary<string, string> requestParameters, IDictionary<string, string> redirectParameters, CancellationToken cancellationToken = default(CancellationToken)) {
- var message = await this.PrepareRequestUserAuthorizationAsync(null, requestParameters, redirectParameters, cancellationToken);
- var response = await this.Channel.PrepareResponseAsync(message, cancellationToken);
- return Tuple.Create(response.GetDirectUriRequest(), message.RequestToken);
- }
-
- /// <summary>
- /// Exchanges a given request token for access token.
- /// </summary>
- /// <param name="requestToken">The request token that the user has authorized.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>The access token assigned by the Service Provider.</returns>
- [Obsolete("Use the ProcessUserAuthorization method that takes a verifier parameter instead.")]
- public Task<AuthorizedTokenResponse> ProcessUserAuthorizationAsync(string requestToken, CancellationToken cancellationToken = default(CancellationToken)) {
- return this.ProcessUserAuthorizationAsync(requestToken, null, cancellationToken);
- }
-
- /// <summary>
- /// Exchanges a given request token for access token.
- /// </summary>
- /// <param name="requestToken">The request token that the user has authorized.</param>
- /// <param name="verifier">The verifier code typed in by the user. Must not be <c>Null</c> for OAuth 1.0a service providers and later.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>
- /// The access token assigned by the Service Provider.
- /// </returns>
- public new Task<AuthorizedTokenResponse> ProcessUserAuthorizationAsync(string requestToken, string verifier, CancellationToken cancellationToken = default(CancellationToken)) {
- if (this.ServiceProvider.Version >= Protocol.V10a.Version) {
- ErrorUtilities.VerifyNonZeroLength(verifier, "verifier");
- }
-
- return base.ProcessUserAuthorizationAsync(requestToken, verifier, cancellationToken);
- }
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ITemporaryCredentialStorage.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ITemporaryCredentialStorage.cs
new file mode 100644
index 0000000..428749a
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ITemporaryCredentialStorage.cs
@@ -0,0 +1,40 @@
+//-----------------------------------------------------------------------
+// <copyright file="ITemporaryCredentialStorage.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth {
+ using System.Collections.Generic;
+
+ /// <summary>
+ /// A token manager for use by an OAuth Consumer to store a temporary credential
+ /// (previously known as "unauthorized request token and secret").
+ /// </summary>
+ /// <remarks>
+ /// The credentials stored here are obtained as described in:
+ /// http://tools.ietf.org/html/rfc5849#section-2.1
+ /// </remarks>
+ public interface ITemporaryCredentialStorage {
+ /// <summary>
+ /// Saves the specified temporary credential for later retrieval.
+ /// </summary>
+ /// <param name="identifier">The identifier.</param>
+ /// <param name="secret">The secret.</param>
+ void SaveTemporaryCredential(string identifier, string secret);
+
+ /// <summary>
+ /// Obtains a temporary credential secret, if available.
+ /// </summary>
+ /// <returns>The temporary credential identifier secret if available; otherwise a key value pair whose strings are left in their uninitialized <c>null</c> state.</returns>
+ KeyValuePair<string, string> RetrieveTemporaryCredential();
+
+ /// <summary>
+ /// Clears the temporary credentials from storage.
+ /// </summary>
+ /// <remarks>
+ /// DotNetOpenAuth calls this when the credentials are no longer needed.
+ /// </remarks>
+ void ClearTemporaryCredential();
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/MemoryTemporaryCredentialStorage.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/MemoryTemporaryCredentialStorage.cs
new file mode 100644
index 0000000..832084d
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/MemoryTemporaryCredentialStorage.cs
@@ -0,0 +1,65 @@
+//-----------------------------------------------------------------------
+// <copyright file="MemoryTemporaryCredentialStorage.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ /// <summary>
+ /// Non-persistent memory storage for temporary credentials.
+ /// Useful for installed apps (not redirection based web apps).
+ /// </summary>
+ public class MemoryTemporaryCredentialStorage : ITemporaryCredentialStorage {
+ /// <summary>
+ /// The identifier.
+ /// </summary>
+ private string identifier;
+
+ /// <summary>
+ /// The secret.
+ /// </summary>
+ private string secret;
+
+ #region ITemporaryCredentialStorage Members
+
+ /// <summary>
+ /// Saves the specified temporary credential for later retrieval.
+ /// </summary>
+ /// <param name="identifier">The identifier.</param>
+ /// <param name="secret">The secret.</param>
+ public void SaveTemporaryCredential(string identifier, string secret) {
+ this.identifier = identifier;
+ this.secret = secret;
+ }
+
+ /// <summary>
+ /// Obtains a temporary credential secret, if available.
+ /// </summary>
+ /// <returns>
+ /// The temporary credential secret if available; otherwise <c>null</c>.
+ /// </returns>
+ public KeyValuePair<string, string> RetrieveTemporaryCredential() {
+ return new KeyValuePair<string, string>(this.identifier, this.secret);
+ }
+
+ /// <summary>
+ /// Clears the temporary credentials from storage.
+ /// </summary>
+ /// <param name="identifier">The identifier of the credentials to clear.</param>
+ /// <remarks>
+ /// DotNetOpenAuth calls this when the credentials are no longer needed.
+ /// </remarks>
+ public void ClearTemporaryCredential() {
+ this.identifier = null;
+ this.secret = null;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1HttpMessageHandlerBase.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1HttpMessageHandlerBase.cs
index 17d7b7a..aa462f3 100644
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1HttpMessageHandlerBase.cs
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1HttpMessageHandlerBase.cs
@@ -154,6 +154,10 @@ namespace DotNetOpenAuth.OAuth {
// Add parameters and signature to request.
switch (this.Location) {
case OAuthParametersLocation.AuthorizationHttpHeader:
+ // Some oauth parameters may have been put in the query string of the original message.
+ // We want to move any that we find into the authorization header.
+ oauthParameters.Add(ExtractOAuthParametersFromQueryString(request));
+
request.Headers.Authorization = new AuthenticationHeaderValue(Protocol.AuthorizationHeaderScheme, MessagingUtilities.AssembleAuthorizationHeader(oauthParameters.AsKeyValuePairs()));
break;
case OAuthParametersLocation.QueryString:
@@ -258,6 +262,38 @@ namespace DotNetOpenAuth.OAuth {
}
/// <summary>
+ /// Collects and removes all query string parameters beginning with "oauth_" from the specified request,
+ /// and returns them as a collection.
+ /// </summary>
+ /// <param name="request">The request whose query string should be searched for "oauth_" parameters.</param>
+ /// <returns>The collection of parameters that were removed from the query string.</returns>
+ private static NameValueCollection ExtractOAuthParametersFromQueryString(HttpRequestMessage request) {
+ Requires.NotNull(request, "request");
+
+ var extracted = new NameValueCollection();
+ if (!string.IsNullOrEmpty(request.RequestUri.Query)) {
+ var queryString = HttpUtility.ParseQueryString(request.RequestUri.Query);
+ foreach (var pair in queryString.AsKeyValuePairs()) {
+ if (pair.Key.StartsWith(Protocol.ParameterPrefix, StringComparison.Ordinal)) {
+ extracted.Add(pair.Key, pair.Value);
+ }
+ }
+
+ if (extracted.Count > 0) {
+ foreach (string key in extracted) {
+ queryString.Remove(key);
+ }
+
+ var modifiedRequestUri = new UriBuilder(request.RequestUri);
+ modifiedRequestUri.Query = MessagingUtilities.CreateQueryString(queryString.AsKeyValuePairs());
+ request.RequestUri = modifiedRequestUri.Uri;
+ }
+ }
+
+ return extracted;
+ }
+
+ /// <summary>
/// Constructs the "Signature Base String" as described in http://tools.ietf.org/html/rfc5849#section-3.4.1
/// </summary>
/// <param name="request">The HTTP request message.</param>
@@ -319,12 +355,6 @@ namespace DotNetOpenAuth.OAuth {
if (request.RequestUri.Query != null) {
// NameValueCollection does support non-unique keys, as long as you use it carefully.
nvc = HttpUtility.ParseQueryString(request.RequestUri.Query);
-
- // Remove any parameters beginning with "oauth_"
- var keysToRemove = nvc.Cast<string>().Where(k => k.StartsWith(Protocol.ParameterPrefix, StringComparison.Ordinal)).ToList();
- foreach (string key in keysToRemove) {
- nvc.Remove(key);
- }
} else {
nvc = new NameValueCollection(8);
}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1RsaSha1HttpMessageHandler.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1RsaSha1HttpMessageHandler.cs
index fd2ad65..129ebc2 100644
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1RsaSha1HttpMessageHandler.cs
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1RsaSha1HttpMessageHandler.cs
@@ -8,6 +8,7 @@ namespace DotNetOpenAuth.OAuth {
using System;
using System.Collections.Generic;
using System.Linq;
+ using System.Net.Http;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
@@ -20,6 +21,20 @@ namespace DotNetOpenAuth.OAuth {
/// </summary>
public class OAuth1RsaSha1HttpMessageHandler : OAuth1HttpMessageHandlerBase {
/// <summary>
+ /// Initializes a new instance of the <see cref="OAuth1RsaSha1HttpMessageHandler"/> class.
+ /// </summary>
+ public OAuth1RsaSha1HttpMessageHandler() {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuth1RsaSha1HttpMessageHandler"/> class.
+ /// </summary>
+ /// <param name="innerHandler">The inner handler which is responsible for processing the HTTP response messages.</param>
+ public OAuth1RsaSha1HttpMessageHandler(HttpMessageHandler innerHandler)
+ : base(innerHandler) {
+ }
+
+ /// <summary>
/// Gets or sets the certificate used to sign outgoing messages. Used only by Consumers.
/// </summary>
public X509Certificate2 SigningCertificate { get; set; }
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/WebConsumer.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/WebConsumer.cs
deleted file mode 100644
index 49a54a0..0000000
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/WebConsumer.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="WebConsumer.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth {
- using System;
- using System.Collections.Generic;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Web;
- using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.OAuth.ChannelElements;
- using DotNetOpenAuth.OAuth.Messages;
- using Validation;
-
- /// <summary>
- /// A website or application that uses OAuth to access the Service Provider on behalf of the User.
- /// </summary>
- /// <remarks>
- /// The methods on this class are thread-safe. Provided the properties are set and not changed
- /// afterward, a single instance of this class may be used by an entire web application safely.
- /// </remarks>
- public class WebConsumer : ConsumerBase {
- /// <summary>
- /// Initializes a new instance of the <see cref="WebConsumer"/> class.
- /// </summary>
- /// <param name="serviceDescription">The endpoints and behavior of the Service Provider.</param>
- /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
- public WebConsumer(ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager)
- : base(serviceDescription, tokenManager) {
- }
-
- /// <summary>
- /// Begins an OAuth authorization request and redirects the user to the Service Provider
- /// to provide that authorization. Upon successful authorization, the user is redirected
- /// back to the current page.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>The pending user agent redirect based message to be sent as an HttpResponse.</returns>
- /// <remarks>
- /// Requires HttpContext.Current.
- /// </remarks>
- public Task<UserAuthorizationRequest> PrepareRequestUserAuthorizationAsync(CancellationToken cancellationToken = default(CancellationToken)) {
- Uri callback = this.Channel.GetRequestFromContext().GetPublicFacingUrl().StripQueryArgumentsWithPrefix(Protocol.ParameterPrefix);
- return this.PrepareRequestUserAuthorizationAsync(callback, null, null, cancellationToken);
- }
-
- /// <summary>
- /// Prepares an OAuth message that begins an authorization request that will
- /// redirect the user to the Service Provider to provide that authorization.
- /// </summary>
- /// <param name="callback">
- /// An optional Consumer URL that the Service Provider should redirect the
- /// User Agent to upon successful authorization.
- /// </param>
- /// <param name="requestParameters">Extra parameters to add to the request token message. Optional.</param>
- /// <param name="redirectParameters">Extra parameters to add to the redirect to Service Provider message. Optional.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>The pending user agent redirect based message to be sent as an HttpResponse.</returns>
- public new Task<UserAuthorizationRequest> PrepareRequestUserAuthorizationAsync(Uri callback, IDictionary<string, string> requestParameters, IDictionary<string, string> redirectParameters, CancellationToken cancellationToken = default(CancellationToken)) {
- return base.PrepareRequestUserAuthorizationAsync(callback, requestParameters, redirectParameters, cancellationToken);
- }
-
- /// <summary>
- /// Processes an incoming authorization-granted message from an SP and obtains an access token.
- /// </summary>
- /// <param name="request">The incoming HTTP request.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>
- /// The access token, or null if no incoming authorization message was recognized.
- /// </returns>
- public async Task<AuthorizedTokenResponse> ProcessUserAuthorizationAsync(HttpRequestBase request = null, CancellationToken cancellationToken = default(CancellationToken)) {
- request = request ?? this.Channel.GetRequestFromContext();
-
- var authorizationMessage = await this.Channel.TryReadFromRequestAsync<UserAuthorizationResponse>(cancellationToken, request);
- if (authorizationMessage != null) {
- string requestToken = authorizationMessage.RequestToken;
- string verifier = authorizationMessage.VerificationCode;
- return await this.ProcessUserAuthorizationAsync(requestToken, verifier, cancellationToken);
- } else {
- return null;
- }
- }
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj b/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj
index 815a341..059f025 100644
--- a/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj
+++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj
@@ -19,6 +19,7 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
</PropertyGroup>
<ItemGroup>
+ <Compile Include="OAuthReporting.cs" />
<Compile Include="OAuth\ChannelElements\IConsumerDescription.cs" />
<Compile Include="OAuth\ChannelElements\IServiceProviderAccessToken.cs" />
<Compile Include="OAuth\ChannelElements\IServiceProviderRequestToken.cs" />
diff --git a/src/DotNetOpenAuth.OAuth/OAuthReporting.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuthReporting.cs
index e2c0aab..aa3f934 100644
--- a/src/DotNetOpenAuth.OAuth/OAuthReporting.cs
+++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuthReporting.cs
@@ -45,9 +45,7 @@ namespace DotNetOpenAuth {
builder.Append(nonceStore.GetType().Name);
}
builder.Append(" ");
- builder.Append(service.Version);
- builder.Append(" ");
- builder.Append(service.UserAuthorizationEndpoint);
+ builder.Append(service.ResourceOwnerAuthorizationEndpoint);
Reporting.ObservedFeatures.Add(builder.ToString());
Reporting.Touch();
}
diff --git a/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj b/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj
index 58e09b0..8524a78 100644
--- a/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj
+++ b/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj
@@ -25,7 +25,6 @@
<Compile Include="Configuration\OAuthServiceProviderElement.cs" />
<Compile Include="Configuration\OAuthServiceProviderSecuritySettingsElement.cs" />
<Compile Include="Messaging\ITamperProtectionChannelBindingElement.cs" />
- <Compile Include="OAuthReporting.cs" />
<Compile Include="OAuth\ChannelElements\ITokenManager.cs" />
<Compile Include="OAuth\ChannelElements\OAuthHttpMethodBindingElement.cs" />
<Compile Include="OAuth\ChannelElements\PlaintextSigningBindingElement.cs" />
@@ -35,16 +34,17 @@
<Compile Include="OAuth\ChannelElements\UriOrOobEncoding.cs" />
<Compile Include="OAuth\ConsumerSecuritySettings.cs" />
<Compile Include="OAuth\Messages\ITokenSecretContainingMessage.cs" />
+ <Compile Include="OAuth\Messages\MessageBaseSimple.cs" />
<Compile Include="OAuth\OAuthStrings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>OAuthStrings.resx</DependentUpon>
</Compile>
<Compile Include="OAuth\SecuritySettings.cs" />
- <Compile Include="OAuth\ServiceProviderDescription.cs" />
<Compile Include="OAuth\Messages\ITokenContainingMessage.cs" />
<Compile Include="OAuth\Messages\SignedMessageBase.cs" />
<Compile Include="OAuth\ChannelElements\SigningBindingElementBase.cs" />
+ <Compile Include="OAuth\ServiceProviderDescription.cs" />
<Compile Include="OAuth\ServiceProviderSecuritySettings.cs" />
<Compile Include="OAuth\ChannelElements\ITamperResistantOAuthMessage.cs" />
<Compile Include="OAuth\Messages\MessageBase.cs" />
diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/MessageBaseSimple.cs b/src/DotNetOpenAuth.OAuth/OAuth/Messages/MessageBaseSimple.cs
new file mode 100644
index 0000000..23822d3
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/MessageBaseSimple.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DotNetOpenAuth.OAuth.Messages {
+ class MessageBaseSimple {
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Protocol.cs b/src/DotNetOpenAuth.OAuth/OAuth/Protocol.cs
index 72f0ff4..049fd58 100644
--- a/src/DotNetOpenAuth.OAuth/OAuth/Protocol.cs
+++ b/src/DotNetOpenAuth.OAuth/OAuth/Protocol.cs
@@ -60,6 +60,31 @@ namespace DotNetOpenAuth.OAuth {
internal const string AuthorizationHeaderScheme = "OAuth";
/// <summary>
+ /// The name of the 'oauth_callback' parameter.
+ /// </summary>
+ internal const string CallbackParameter = "oauth_callback";
+
+ /// <summary>
+ /// The name of the 'oauth_callback_confirmed' parameter.
+ /// </summary>
+ internal const string CallbackConfirmedParameter = "oauth_callback_confirmed";
+
+ /// <summary>
+ /// The name of the 'oauth_token' parameter.
+ /// </summary>
+ internal const string TokenParameter = "oauth_token";
+
+ /// <summary>
+ /// The name of the 'oauth_token_secret' parameter.
+ /// </summary>
+ internal const string TokenSecretParameter = "oauth_token_secret";
+
+ /// <summary>
+ /// The name of the 'oauth_verifier' parameter.
+ /// </summary>
+ internal const string VerifierParameter = "oauth_verifier";
+
+ /// <summary>
/// Gets the <see cref="Protocol"/> instance with values initialized for V1.0 of the protocol.
/// </summary>
internal static readonly Protocol V10 = new Protocol {
diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ServiceProviderDescription.cs b/src/DotNetOpenAuth.OAuth/OAuth/ServiceProviderDescription.cs
index 6dbe6ea..e6a2b32 100644
--- a/src/DotNetOpenAuth.OAuth/OAuth/ServiceProviderDescription.cs
+++ b/src/DotNetOpenAuth.OAuth/OAuth/ServiceProviderDescription.cs
@@ -1,101 +1,84 @@
//-----------------------------------------------------------------------
-// <copyright file="ServiceProviderDescription.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
+// <copyright file="ServiceProviderDescription.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.OAuth {
using System;
- using System.Diagnostics;
- using System.Diagnostics.CodeAnalysis;
+ using System.Collections.Generic;
using System.Linq;
- using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.OAuth.ChannelElements;
+ using System.Net.Http;
+ using System.Text;
+ using System.Threading.Tasks;
+ using Validation;
/// <summary>
- /// A description of the endpoints on a Service Provider.
+ /// Describes an OAuth 1.0 service provider.
/// </summary>
public class ServiceProviderDescription {
/// <summary>
- /// The field used to store the value of the <see cref="RequestTokenEndpoint"/> property.
- /// </summary>
- [DebuggerBrowsable(DebuggerBrowsableState.Never)]
- private MessageReceivingEndpoint requestTokenEndpoint;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ServiceProviderDescription"/> class.
+ /// Initializes a new instance of the <see cref="ServiceProviderDescription" /> class.
/// </summary>
public ServiceProviderDescription() {
- this.ProtocolVersion = Protocol.Default.ProtocolVersion;
+ this.TemporaryCredentialsRequestEndpointMethod = HttpMethod.Post;
+ this.TokenRequestEndpointMethod = HttpMethod.Post;
}
/// <summary>
- /// Gets or sets the OAuth version supported by the Service Provider.
- /// </summary>
- public ProtocolVersion ProtocolVersion { get; set; }
-
- /// <summary>
- /// Gets or sets the URL used to obtain an unauthorized Request Token,
- /// described in Section 6.1 (Obtaining an Unauthorized Request Token).
+ /// Initializes a new instance of the <see cref="ServiceProviderDescription"/> class.
/// </summary>
- /// <remarks>
- /// The request URL query MUST NOT contain any OAuth Protocol Parameters.
- /// This is the URL that <see cref="OAuth.Messages.UnauthorizedTokenRequest"/> messages are directed to.
- /// </remarks>
- /// <exception cref="ArgumentException">Thrown if this property is set to a URI with OAuth protocol parameters.</exception>
- public MessageReceivingEndpoint RequestTokenEndpoint {
- get {
- return this.requestTokenEndpoint;
+ /// <param name="temporaryCredentialsRequestEndpoint">The temporary credentials request endpoint.</param>
+ /// <param name="resourceOwnerAuthorizationEndpoint">The resource owner authorization endpoint.</param>
+ /// <param name="tokenRequestEndpoint">The token request endpoint.</param>
+ public ServiceProviderDescription(
+ string temporaryCredentialsRequestEndpoint, string resourceOwnerAuthorizationEndpoint, string tokenRequestEndpoint) {
+ if (temporaryCredentialsRequestEndpoint != null) {
+ this.TemporaryCredentialsRequestEndpoint = new Uri(temporaryCredentialsRequestEndpoint, UriKind.Absolute);
}
- set {
- if (value != null && UriUtil.QueryStringContainPrefixedParameters(value.Location, OAuth.Protocol.ParameterPrefix)) {
- throw new ArgumentException(OAuthStrings.RequestUrlMustNotHaveOAuthParameters);
- }
+ if (resourceOwnerAuthorizationEndpoint != null) {
+ this.ResourceOwnerAuthorizationEndpoint = new Uri(resourceOwnerAuthorizationEndpoint, UriKind.Absolute);
+ }
- this.requestTokenEndpoint = value;
+ if (tokenRequestEndpoint != null) {
+ this.TokenRequestEndpoint = new Uri(tokenRequestEndpoint, UriKind.Absolute);
}
}
/// <summary>
- /// Gets or sets the URL used to obtain User authorization for Consumer access,
- /// described in Section 6.2 (Obtaining User Authorization).
+ /// Gets or sets the temporary credentials request endpoint.
/// </summary>
- /// <remarks>
- /// This is the URL that <see cref="OAuth.Messages.UserAuthorizationRequest"/> messages are
- /// indirectly (via the user agent) sent to.
- /// </remarks>
- public MessageReceivingEndpoint UserAuthorizationEndpoint { get; set; }
+ /// <value>
+ /// The temporary credentials request endpoint.
+ /// </value>
+ public Uri TemporaryCredentialsRequestEndpoint { get; set; }
/// <summary>
- /// Gets or sets the URL used to exchange the User-authorized Request Token
- /// for an Access Token, described in Section 6.3 (Obtaining an Access Token).
+ /// Gets or sets the HTTP method to use with the temporary credentials request endpoint.
/// </summary>
- /// <remarks>
- /// This is the URL that <see cref="OAuth.Messages.AuthorizedTokenRequest"/> messages are directed to.
- /// </remarks>
- public MessageReceivingEndpoint AccessTokenEndpoint { get; set; }
+ public HttpMethod TemporaryCredentialsRequestEndpointMethod { get; set; }
/// <summary>
- /// Gets or sets the signing policies that apply to this Service Provider.
+ /// Gets the resource owner authorization endpoint.
/// </summary>
- [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Type initializers require this format.")]
- public ITamperProtectionChannelBindingElement[] TamperProtectionElements { get; set; }
+ /// <value>
+ /// The resource owner authorization endpoint.
+ /// May be <c>null</c> for 2-legged OAuth.
+ /// </value>
+ public Uri ResourceOwnerAuthorizationEndpoint { get; set; }
/// <summary>
- /// Gets the OAuth version supported by the Service Provider.
+ /// Gets the token request endpoint.
/// </summary>
- internal Version Version {
- get { return Protocol.Lookup(this.ProtocolVersion).Version; }
- }
+ /// <value>
+ /// The token request endpoint.
+ /// </value>
+ public Uri TokenRequestEndpoint { get; set; }
/// <summary>
- /// Creates a signing element that includes all the signing elements this service provider supports.
+ /// Gets or sets the HTTP method to use with the token request endpoint.
/// </summary>
- /// <returns>The created signing element.</returns>
- internal ITamperProtectionChannelBindingElement CreateTamperProtectionElement() {
- RequiresEx.ValidState(this.TamperProtectionElements != null);
- return new SigningBindingElementChain(this.TamperProtectionElements.Select(el => (ITamperProtectionChannelBindingElement)el.Clone()).ToArray());
- }
+ public HttpMethod TokenRequestEndpointMethod { get; set; }
}
}
diff --git a/src/DotNetOpenAuth.OpenIdOAuth/OAuth/WebConsumerOpenIdRelyingParty.cs b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/WebConsumerOpenIdRelyingParty.cs
index a19d505..dce51c2 100644
--- a/src/DotNetOpenAuth.OpenIdOAuth/OAuth/WebConsumerOpenIdRelyingParty.cs
+++ b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/WebConsumerOpenIdRelyingParty.cs
@@ -8,9 +8,11 @@ namespace DotNetOpenAuth.OAuth {
using System;
using System.Collections.Generic;
using System.Linq;
+ using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+ using System.Web;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth.ChannelElements;
using DotNetOpenAuth.OAuth.Messages;
@@ -26,14 +28,13 @@ namespace DotNetOpenAuth.OAuth {
/// The methods on this class are thread-safe. Provided the properties are set and not changed
/// afterward, a single instance of this class may be used by an entire web application safely.
/// </remarks>
- public class WebConsumerOpenIdRelyingParty : WebConsumer {
+ public class WebConsumerOpenIdRelyingParty : Consumer {
/// <summary>
/// Initializes a new instance of the <see cref="WebConsumerOpenIdRelyingParty"/> class.
/// </summary>
/// <param name="serviceDescription">The endpoints and behavior of the Service Provider.</param>
/// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
- public WebConsumerOpenIdRelyingParty(ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager)
- : base(serviceDescription, tokenManager) {
+ public WebConsumerOpenIdRelyingParty() {
}
/// <summary>
@@ -64,11 +65,8 @@ namespace DotNetOpenAuth.OAuth {
/// The access token, if granted, is automatically stored in the <see cref="ConsumerBase.TokenManager" />.
/// The token manager instance must implement <see cref="IOpenIdOAuthTokenManager" />.
/// </remarks>
- public async Task<AuthorizedTokenResponse> ProcessUserAuthorizationAsync(IAuthenticationResponse openIdAuthenticationResponse, CancellationToken cancellationToken = default(CancellationToken)) {
+ public async Task<AccessTokenResponse> ProcessUserAuthorizationAsync(IAuthenticationResponse openIdAuthenticationResponse, CancellationToken cancellationToken = default(CancellationToken)) {
Requires.NotNull(openIdAuthenticationResponse, "openIdAuthenticationResponse");
- RequiresEx.ValidState(this.TokenManager is IOpenIdOAuthTokenManager);
- var openidTokenManager = this.TokenManager as IOpenIdOAuthTokenManager;
- ErrorUtilities.VerifyOperation(openidTokenManager != null, OAuthStrings.OpenIdOAuthExtensionRequiresSpecialTokenManagerInterface, typeof(IOpenIdOAuthTokenManager).FullName);
// The OAuth extension is only expected in positive assertion responses.
if (openIdAuthenticationResponse.Status != AuthenticationStatus.Authenticated) {
@@ -81,21 +79,24 @@ namespace DotNetOpenAuth.OAuth {
return null;
}
- // Prepare a message to exchange the request token for an access token.
- // We are careful to use a v1.0 message version so that the oauth_verifier is not required.
- var requestAccess = new AuthorizedTokenRequest(this.ServiceProvider.AccessTokenEndpoint, Protocol.V10.Version) {
- RequestToken = positiveAuthorization.RequestToken,
- ConsumerKey = this.ConsumerKey,
- };
+ using (var client = this.CreateHttpClient(new AccessToken(positiveAuthorization.RequestToken, string.Empty))) {
+ var request = new HttpRequestMessage(this.ServiceProvider.TokenRequestEndpointMethod, this.ServiceProvider.TokenRequestEndpoint);
+ using (var response = await client.SendAsync(request, cancellationToken)) {
+ response.EnsureSuccessStatusCode();
- // Retrieve the access token and store it in the token manager.
- openidTokenManager.StoreOpenIdAuthorizedRequestToken(this.ConsumerKey, positiveAuthorization);
- var grantAccess = await this.Channel.RequestAsync<AuthorizedTokenResponse>(requestAccess, cancellationToken);
- this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, positiveAuthorization.RequestToken, grantAccess.AccessToken, grantAccess.TokenSecret);
+ // Parse the response and ensure that it meets the requirements of the OAuth 1.0 spec.
+ string content = await response.Content.ReadAsStringAsync();
+ var responseData = HttpUtility.ParseQueryString(content);
+ string accessToken = responseData[Protocol.TokenParameter];
+ string tokenSecret = responseData[Protocol.TokenSecretParameter];
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(accessToken), MessagingStrings.RequiredParametersMissing, typeof(AuthorizedTokenResponse).Name, Protocol.TokenParameter);
+ ErrorUtilities.VerifyProtocol(tokenSecret != null, MessagingStrings.RequiredParametersMissing, typeof(AuthorizedTokenResponse).Name, Protocol.TokenSecretParameter);
- // Provide the caller with the access token so it may be associated with the user
- // that is logging in.
- return grantAccess;
+ responseData.Remove(Protocol.TokenParameter);
+ responseData.Remove(Protocol.TokenSecretParameter);
+ return new AccessTokenResponse(accessToken, tokenSecret, responseData);
+ }
+ }
}
}
}