summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs9
-rw-r--r--src/DotNetOpenAuth.Test/OAuth/ChannelElements/PlaintextSigningBindingElementTest.cs14
-rw-r--r--src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs3
-rw-r--r--src/DotNetOpenAuth.Test/OAuth/ProtocolTests.cs4
-rw-r--r--src/DotNetOpenAuth.sln1
-rw-r--r--src/DotNetOpenAuth/DotNetOpenAuth.csproj2
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs14
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs29
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs7
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs12
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/UriOrOobEncoder.cs62
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/VerificationCodeBindingElement.cs119
-rw-r--r--src/DotNetOpenAuth/OAuth/ConsumerBase.cs8
-rw-r--r--src/DotNetOpenAuth/OAuth/Messages/AccessProtectedResourceRequest.cs6
-rw-r--r--src/DotNetOpenAuth/OAuth/Messages/AuthorizedTokenRequest.cs13
-rw-r--r--src/DotNetOpenAuth/OAuth/Messages/AuthorizedTokenResponse.cs6
-rw-r--r--src/DotNetOpenAuth/OAuth/Messages/MessageBase.cs18
-rw-r--r--src/DotNetOpenAuth/OAuth/Messages/SignedMessageBase.cs5
-rw-r--r--src/DotNetOpenAuth/OAuth/Messages/UnauthorizedTokenRequest.cs18
-rw-r--r--src/DotNetOpenAuth/OAuth/Messages/UnauthorizedTokenResponse.cs18
-rw-r--r--src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationRequest.cs12
-rw-r--r--src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationResponse.cs19
-rw-r--r--src/DotNetOpenAuth/OAuth/OAuthStrings.Designer.cs11
-rw-r--r--src/DotNetOpenAuth/OAuth/OAuthStrings.resx3
-rw-r--r--src/DotNetOpenAuth/OAuth/Protocol.cs92
-rw-r--r--src/DotNetOpenAuth/OAuth/ServiceProvider.cs12
-rw-r--r--src/DotNetOpenAuth/OAuth/ServiceProviderDescription.cs8
-rw-r--r--src/DotNetOpenAuth/OAuth/WebConsumer.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs2
29 files changed, 439 insertions, 90 deletions
diff --git a/src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs b/src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs
index be3c563..bf9dc2b 100644
--- a/src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs
+++ b/src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs
@@ -15,6 +15,7 @@ namespace DotNetOpenAuth.Test.Mocks {
internal class InMemoryTokenManager : IConsumerTokenManager, IServiceProviderTokenManager {
private Dictionary<string, string> consumersAndSecrets = new Dictionary<string, string>();
private Dictionary<string, string> tokensAndSecrets = new Dictionary<string, string>();
+ private Dictionary<string, string> tokensAndVerifiers = new Dictionary<string, string>();
/// <summary>
/// Request tokens that have been issued, and whether they have been authorized yet.
@@ -97,6 +98,14 @@ namespace DotNetOpenAuth.Test.Mocks {
return this.consumersAndSecrets[consumerKey];
}
+ public void SetRequestTokenVerifier(string requestToken, string verifier) {
+ this.tokensAndVerifiers[requestToken] = verifier;
+ }
+
+ public string GetRequestTokenVerifier(string requestToken) {
+ return this.tokensAndVerifiers[requestToken];
+ }
+
#endregion
/// <summary>
diff --git a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/PlaintextSigningBindingElementTest.cs b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/PlaintextSigningBindingElementTest.cs
index ca63b50..627db8f 100644
--- a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/PlaintextSigningBindingElementTest.cs
+++ b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/PlaintextSigningBindingElementTest.cs
@@ -4,9 +4,9 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.Test.ChannelElements
-{
+namespace DotNetOpenAuth.Test.ChannelElements {
using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.ChannelElements;
using DotNetOpenAuth.OAuth.Messages;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -17,7 +17,7 @@ namespace DotNetOpenAuth.Test.ChannelElements
public void HttpsSignatureGeneration() {
SigningBindingElementBase target = new PlaintextSigningBindingElement();
MessageReceivingEndpoint endpoint = new MessageReceivingEndpoint("https://localtest", HttpDeliveryMethods.GetRequest);
- ITamperResistantOAuthMessage message = new UnauthorizedTokenRequest(endpoint);
+ ITamperResistantOAuthMessage message = new UnauthorizedTokenRequest(endpoint, Protocol.Default.Version);
message.ConsumerSecret = "cs";
message.TokenSecret = "ts";
Assert.IsNotNull(target.ProcessOutgoingMessage(message));
@@ -29,7 +29,7 @@ namespace DotNetOpenAuth.Test.ChannelElements
public void HttpsSignatureVerification() {
MessageReceivingEndpoint endpoint = new MessageReceivingEndpoint("https://localtest", HttpDeliveryMethods.GetRequest);
ITamperProtectionChannelBindingElement target = new PlaintextSigningBindingElement();
- ITamperResistantOAuthMessage message = new UnauthorizedTokenRequest(endpoint);
+ ITamperResistantOAuthMessage message = new UnauthorizedTokenRequest(endpoint, Protocol.Default.Version);
message.ConsumerSecret = "cs";
message.TokenSecret = "ts";
message.SignatureMethod = "PLAINTEXT";
@@ -41,7 +41,7 @@ namespace DotNetOpenAuth.Test.ChannelElements
public void HttpsSignatureVerificationNotApplicable() {
SigningBindingElementBase target = new PlaintextSigningBindingElement();
MessageReceivingEndpoint endpoint = new MessageReceivingEndpoint("https://localtest", HttpDeliveryMethods.GetRequest);
- ITamperResistantOAuthMessage message = new UnauthorizedTokenRequest(endpoint);
+ ITamperResistantOAuthMessage message = new UnauthorizedTokenRequest(endpoint, Protocol.Default.Version);
message.ConsumerSecret = "cs";
message.TokenSecret = "ts";
message.SignatureMethod = "ANOTHERALGORITHM";
@@ -53,7 +53,7 @@ namespace DotNetOpenAuth.Test.ChannelElements
public void HttpSignatureGeneration() {
SigningBindingElementBase target = new PlaintextSigningBindingElement();
MessageReceivingEndpoint endpoint = new MessageReceivingEndpoint("http://localtest", HttpDeliveryMethods.GetRequest);
- ITamperResistantOAuthMessage message = new UnauthorizedTokenRequest(endpoint);
+ ITamperResistantOAuthMessage message = new UnauthorizedTokenRequest(endpoint, Protocol.Default.Version);
message.ConsumerSecret = "cs";
message.TokenSecret = "ts";
@@ -67,7 +67,7 @@ namespace DotNetOpenAuth.Test.ChannelElements
public void HttpSignatureVerification() {
SigningBindingElementBase target = new PlaintextSigningBindingElement();
MessageReceivingEndpoint endpoint = new MessageReceivingEndpoint("http://localtest", HttpDeliveryMethods.GetRequest);
- ITamperResistantOAuthMessage message = new UnauthorizedTokenRequest(endpoint);
+ ITamperResistantOAuthMessage message = new UnauthorizedTokenRequest(endpoint, Protocol.Default.Version);
message.ConsumerSecret = "cs";
message.TokenSecret = "ts";
message.SignatureMethod = "PLAINTEXT";
diff --git a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs
index 93c0b3f..32ccf9e 100644
--- a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs
+++ b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs
@@ -7,6 +7,7 @@
namespace DotNetOpenAuth.Test.ChannelElements {
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.Messaging.Reflection;
+ using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.ChannelElements;
using DotNetOpenAuth.OAuth.Messages;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -63,7 +64,7 @@ namespace DotNetOpenAuth.Test.ChannelElements {
internal static UnauthorizedTokenRequest CreateTestRequestTokenMessage(MessageDescriptionCollection messageDescriptions, MessageReceivingEndpoint endpoint) {
endpoint = endpoint ?? new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetRequestToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest);
- UnauthorizedTokenRequest message = new UnauthorizedTokenRequest(endpoint);
+ UnauthorizedTokenRequest message = new UnauthorizedTokenRequest(endpoint, Protocol.Default.Version);
message.ConsumerKey = "nerdbank.org";
((ITamperResistantOAuthMessage)message).ConsumerSecret = "nerdbanksecret";
var signedMessage = (ITamperResistantOAuthMessage)message;
diff --git a/src/DotNetOpenAuth.Test/OAuth/ProtocolTests.cs b/src/DotNetOpenAuth.Test/OAuth/ProtocolTests.cs
index 6a2551a..a6c7306 100644
--- a/src/DotNetOpenAuth.Test/OAuth/ProtocolTests.cs
+++ b/src/DotNetOpenAuth.Test/OAuth/ProtocolTests.cs
@@ -23,12 +23,12 @@ namespace DotNetOpenAuth.Test {
[TestMethod]
public void AuthorizationHeaderScheme() {
- Assert.AreEqual("OAuth", Protocol.V10.AuthorizationHeaderScheme);
+ Assert.AreEqual("OAuth", Protocol.AuthorizationHeaderScheme);
}
[TestMethod]
public void ParameterPrefix() {
- Assert.AreEqual("oauth_", Protocol.V10.ParameterPrefix);
+ Assert.AreEqual("oauth_", Protocol.ParameterPrefix);
}
}
}
diff --git a/src/DotNetOpenAuth.sln b/src/DotNetOpenAuth.sln
index 171ab07..336f138 100644
--- a/src/DotNetOpenAuth.sln
+++ b/src/DotNetOpenAuth.sln
@@ -17,6 +17,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Specs", "Specs", "{CD57219F-24F4-4136-8741-6063D0D7A031}"
ProjectSection(SolutionItems) = preProject
..\doc\specs\OAuth Core 1.0.htm = ..\doc\specs\OAuth Core 1.0.htm
+ ..\doc\specs\OAuth Core 1.0a (Draft 3).htm = ..\doc\specs\OAuth Core 1.0a (Draft 3).htm
..\doc\specs\openid-attribute-exchange-1_0.html = ..\doc\specs\openid-attribute-exchange-1_0.html
..\doc\specs\openid-authentication-1_1.html = ..\doc\specs\openid-authentication-1_1.html
..\doc\specs\openid-authentication-2_0.html = ..\doc\specs\openid-authentication-2_0.html
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
index 441c714..6f66c7c 100644
--- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj
+++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
@@ -236,6 +236,8 @@
<Compile Include="OAuth\ChannelElements\SigningBindingElementChain.cs" />
<Compile Include="OAuth\ChannelElements\StandardTokenGenerator.cs" />
<Compile Include="OAuth\ChannelElements\TokenType.cs" />
+ <Compile Include="OAuth\ChannelElements\UriOrOobEncoder.cs" />
+ <Compile Include="OAuth\ChannelElements\VerificationCodeBindingElement.cs" />
<Compile Include="OAuth\ConsumerBase.cs" />
<Compile Include="OAuth\DesktopConsumer.cs" />
<Compile Include="GlobalSuppressions.cs" />
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs
index e1c1e3f..bc4a03d 100644
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs
@@ -23,5 +23,19 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
/// <exception cref="ArgumentException">Thrown if the consumer key cannot be found.</exception>
/// <exception cref="InvalidOperationException">May be thrown if called when the signature algorithm does not require a consumer secret, such as when RSA-SHA1 is used.</exception>
string GetConsumerSecret(string consumerKey);
+
+ /// <summary>
+ /// Sets the verifier code associated with an authorized request token.
+ /// </summary>
+ /// <param name="requestToken">The request token.</param>
+ /// <param name="verifier">The verification code.</param>
+ void SetRequestTokenVerifier(string requestToken, string verifier);
+
+ /// <summary>
+ /// Gets the verifier code associated with an authorized request token.
+ /// </summary>
+ /// <param name="requestToken">The request token that the Consumer is exchanging for an access token.</param>
+ /// <returns>The verifier code that was generated when previously authorizing the request token.</returns>
+ string GetRequestTokenVerifier(string requestToken);
}
}
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs
index 5ac1aa8..f0aa64a 100644
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs
@@ -63,7 +63,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
/// <see cref="OAuthConsumerMessageFactory"/> or <see cref="OAuthServiceProviderMessageFactory"/>.
/// </param>
internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, IMessageFactory messageTypeProvider)
- : base(messageTypeProvider, new OAuthHttpMethodBindingElement(), signingBindingElement, new StandardExpirationBindingElement(), new StandardReplayProtectionBindingElement(store)) {
+ : base(messageTypeProvider, InitializeBindingElements(signingBindingElement, store, tokenManager)) {
ErrorUtilities.VerifyArgumentNotNull(tokenManager, "tokenManager");
this.TokenManager = tokenManager;
@@ -122,7 +122,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
string authorization = request.Headers[HttpRequestHeader.Authorization];
if (authorization != null) {
string[] authorizationSections = authorization.Split(';'); // TODO: is this the right delimiter?
- string oauthPrefix = Protocol.Default.AuthorizationHeaderScheme + " ";
+ string oauthPrefix = Protocol.AuthorizationHeaderScheme + " ";
// The Authorization header may have multiple uses, and OAuth may be just one of them.
// Go through each one looking for an OAuth one.
@@ -241,6 +241,29 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
}
/// <summary>
+ /// Initializes the binding elements for the OAuth channel.
+ /// </summary>
+ /// <param name="signingBindingElement">The signing binding element.</param>
+ /// <param name="store">The nonce store.</param>
+ /// <param name="tokenManager">The token manager.</param>
+ /// <returns>An array of binding elements used to initialize the channel.</returns>
+ private static IChannelBindingElement[] InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager) {
+ var bindingElements = new List<IChannelBindingElement> {
+ new OAuthHttpMethodBindingElement(),
+ signingBindingElement,
+ new StandardExpirationBindingElement(),
+ new StandardReplayProtectionBindingElement(store),
+ };
+
+ var spTokenManager = tokenManager as IServiceProviderTokenManager;
+ if (spTokenManager != null) {
+ bindingElements.Insert(0, new VerificationCodeBindingElement(spTokenManager));
+ }
+
+ return bindingElements.ToArray();
+ }
+
+ /// <summary>
/// Uri-escapes the names and values in a dictionary per OAuth 1.0 section 5.1.
/// </summary>
/// <param name="source">The dictionary with names and values to encode.</param>
@@ -307,7 +330,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
httpRequest.Method = GetHttpMethod(requestMessage);
StringBuilder authorization = new StringBuilder();
- authorization.Append(protocol.AuthorizationHeaderScheme);
+ authorization.Append(Protocol.AuthorizationHeaderScheme);
authorization.Append(" ");
foreach (var pair in fields) {
string key = MessagingUtilities.EscapeUriDataStringRfc3986(pair.Key);
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs
index fce351b..3f18d82 100644
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs
@@ -44,7 +44,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
MessageBase message = null;
if (fields.ContainsKey("oauth_token")) {
- message = new UserAuthorizationResponse(recipient.Location);
+ message = new UserAuthorizationResponse(recipient.Location, Protocol.Default.Version);
}
if (message != null) {
@@ -92,9 +92,10 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
var unauthorizedTokenRequest = request as UnauthorizedTokenRequest;
var authorizedTokenRequest = request as AuthorizedTokenRequest;
if (unauthorizedTokenRequest != null) {
- message = new UnauthorizedTokenResponse(unauthorizedTokenRequest);
+ 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);
+ message = new AuthorizedTokenResponse(authorizedTokenRequest, Protocol.Default.Version);
} else {
Logger.OAuth.ErrorFormat("Unexpected response message given the request type {0}", request.GetType().Name);
throw new ProtocolException(OAuthStrings.InvalidIncomingMessage);
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs
index 1aaea7f..b3f750e 100644
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs
@@ -55,9 +55,9 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
MessageBase message = null;
- if (fields.ContainsKey("oauth_consumer_key") &&
- !fields.ContainsKey("oauth_token")) {
- message = new UnauthorizedTokenRequest(recipient);
+ if (fields.ContainsKey("oauth_consumer_key") && !fields.ContainsKey("oauth_token")) {
+ Protocol protocol = fields.ContainsKey("oauth_callback") ? Protocol.V10a : Protocol.V10;
+ message = new UnauthorizedTokenRequest(recipient, protocol.Version);
} else if (fields.ContainsKey("oauth_consumer_key") &&
fields.ContainsKey("oauth_token")) {
// Discern between RequestAccessToken and AccessProtectedResources,
@@ -65,11 +65,11 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
// is in the token parameter.
bool tokenTypeIsAccessToken = this.tokenManager.GetTokenType(fields["oauth_token"]) == TokenType.AccessToken;
- message = tokenTypeIsAccessToken ? (MessageBase)new AccessProtectedResourceRequest(recipient) :
- new AuthorizedTokenRequest(recipient);
+ message = tokenTypeIsAccessToken ? (MessageBase)new AccessProtectedResourceRequest(recipient, Protocol.Default.Version) :
+ new AuthorizedTokenRequest(recipient, Protocol.Default.Version);
} else {
// fail over to the message with no required fields at all.
- message = new UserAuthorizationRequest(recipient);
+ message = new UserAuthorizationRequest(recipient, Protocol.Default.Version);
}
if (message != null) {
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/UriOrOobEncoder.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/UriOrOobEncoder.cs
new file mode 100644
index 0000000..9652e24
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/UriOrOobEncoder.cs
@@ -0,0 +1,62 @@
+//-----------------------------------------------------------------------
+// <copyright file="UriOrOobEncoder.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging.Reflection;
+
+ /// <summary>
+ /// An URI encoder that translates null <see cref="Uri"/> references as "oob"
+ /// instead of an empty/missing argument.
+ /// </summary>
+ internal class UriOrOobEncoder : IMessagePartEncoder {
+ /// <summary>
+ /// The string constant "oob", used to indicate an out-of-band configuration.
+ /// </summary>
+ private const string OutOfBandConfiguration = "oob";
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="UriOrOobEncoder"/> class.
+ /// </summary>
+ internal UriOrOobEncoder() {
+ }
+
+ #region IMessagePartEncoder Members
+
+ /// <summary>
+ /// Encodes the specified value.
+ /// </summary>
+ /// <param name="value">The value. Guaranteed to never be null.</param>
+ /// <returns>
+ /// The <paramref name="value"/> in string form, ready for message transport.
+ /// </returns>
+ public string Encode(object value) {
+ Uri uriValue = (Uri)value;
+ return uriValue != null ? uriValue.AbsoluteUri : OutOfBandConfiguration;
+ }
+
+ /// <summary>
+ /// Decodes the specified value.
+ /// </summary>
+ /// <param name="value">The string value carried by the transport. Guaranteed to never be null, although it may be empty.</param>
+ /// <returns>
+ /// The deserialized form of the given string.
+ /// </returns>
+ /// <exception cref="FormatException">Thrown when the string value given cannot be decoded into the required object type.</exception>
+ public object Decode(string value) {
+ if (string.Equals(value, OutOfBandConfiguration, StringComparison.Ordinal)) {
+ return null;
+ } else {
+ return new Uri(value, UriKind.Absolute);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/VerificationCodeBindingElement.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/VerificationCodeBindingElement.cs
new file mode 100644
index 0000000..f1e14f4
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/VerificationCodeBindingElement.cs
@@ -0,0 +1,119 @@
+//-----------------------------------------------------------------------
+// <copyright file="VerificationCodeBindingElement.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth.Messages;
+
+ /// <summary>
+ /// A binding element for Service Providers to manage the verification code on applicable messages.
+ /// </summary>
+ internal class VerificationCodeBindingElement : IChannelBindingElement {
+ /// <summary>
+ /// The length of the verifier code (in raw bytes before base64 encoding) to generate.
+ /// </summary>
+ private const int VerifierCodeLength = 5;
+
+ /// <summary>
+ /// The token manager offered by the service provider.
+ /// </summary>
+ private IServiceProviderTokenManager tokenManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="VerificationCodeBindingElement"/> class.
+ /// </summary>
+ /// <param name="tokenManager">The token manager.</param>
+ internal VerificationCodeBindingElement(IServiceProviderTokenManager tokenManager) {
+ Contract.Requires(tokenManager != null);
+ ErrorUtilities.VerifyArgumentNotNull(tokenManager, "tokenManager");
+
+ this.tokenManager = tokenManager;
+ }
+
+ #region IChannelBindingElement Members
+
+ /// <summary>
+ /// Gets or sets the channel that this binding element belongs to.
+ /// </summary>
+ /// <remarks>
+ /// This property is set by the channel when it is first constructed.
+ /// </remarks>
+ public Channel Channel { get; set; }
+
+ /// <summary>
+ /// Gets the protection commonly offered (if any) by this binding element.
+ /// </summary>
+ /// <remarks>
+ /// This value is used to assist in sorting binding elements in the channel stack.
+ /// </remarks>
+ public MessageProtections Protection {
+ get { return MessageProtections.None; }
+ }
+
+ /// <summary>
+ /// Prepares a message for sending based on the rules of this channel binding element.
+ /// </summary>
+ /// <param name="message">The message to prepare for sending.</param>
+ /// <returns>
+ /// The protections (if any) that this binding element applied to the message.
+ /// Null if this binding element did not even apply to this binding element.
+ /// </returns>
+ /// <remarks>
+ /// Implementations that provide message protection must honor the
+ /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
+ /// </remarks>
+ public MessageProtections? ProcessOutgoingMessage(IProtocolMessage message) {
+ ErrorUtilities.VerifyArgumentNotNull(message, "message");
+
+ var response = message as UserAuthorizationResponse;
+ if (response != null && response.Version >= Protocol.V10a.Version) {
+ ErrorUtilities.VerifyInternal(response.VerificationCode == null, "VerificationCode was unexpectedly already set.");
+ response.VerificationCode = MessagingUtilities.GetCryptoRandomDataAsBase64(VerifierCodeLength);
+ this.tokenManager.SetRequestTokenVerifier(response.RequestToken, response.VerificationCode);
+ return MessageProtections.None;
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Performs any transformation on an incoming message that may be necessary and/or
+ /// validates an incoming message based on the rules of this channel binding element.
+ /// </summary>
+ /// <param name="message">The incoming message to process.</param>
+ /// <returns>
+ /// The protections (if any) that this binding element applied to the message.
+ /// Null if this binding element did not even apply to this binding element.
+ /// </returns>
+ /// <exception cref="ProtocolException">
+ /// Thrown when the binding element rules indicate that this message is invalid and should
+ /// NOT be processed.
+ /// </exception>
+ /// <remarks>
+ /// Implementations that provide message protection must honor the
+ /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
+ /// </remarks>
+ public MessageProtections? ProcessIncomingMessage(IProtocolMessage message) {
+ ErrorUtilities.VerifyArgumentNotNull(message, "message");
+
+ var request = message as AuthorizedTokenRequest;
+ if (request != null && request.Version >= Protocol.V10a.Version) {
+ string expectedVerifier = this.tokenManager.GetRequestTokenVerifier(request.RequestToken);
+ ErrorUtilities.VerifyProtocol(string.Equals(request.VerificationCode, expectedVerifier, StringComparison.Ordinal), OAuthStrings.IncorrectVerifier);
+ return MessageProtections.None;
+ }
+
+ return null;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuth/ConsumerBase.cs b/src/DotNetOpenAuth/OAuth/ConsumerBase.cs
index 2392172..81da0ac 100644
--- a/src/DotNetOpenAuth/OAuth/ConsumerBase.cs
+++ b/src/DotNetOpenAuth/OAuth/ConsumerBase.cs
@@ -167,7 +167,7 @@ namespace DotNetOpenAuth.OAuth {
ErrorUtilities.VerifyArgumentNotNull(endpoint, "endpoint");
ErrorUtilities.VerifyNonZeroLength(accessToken, "accessToken");
- AccessProtectedResourceRequest message = new AccessProtectedResourceRequest(endpoint) {
+ AccessProtectedResourceRequest message = new AccessProtectedResourceRequest(endpoint, Protocol.Default.Version) {
AccessToken = accessToken,
ConsumerKey = this.ConsumerKey,
};
@@ -190,7 +190,7 @@ namespace DotNetOpenAuth.OAuth {
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "3#", Justification = "Two results")]
protected internal UserAuthorizationRequest PrepareRequestUserAuthorization(Uri callback, IDictionary<string, string> requestParameters, IDictionary<string, string> redirectParameters, out string requestToken) {
// Obtain an unauthorized request token.
- var token = new UnauthorizedTokenRequest(this.ServiceProvider.RequestTokenEndpoint) {
+ var token = new UnauthorizedTokenRequest(this.ServiceProvider.RequestTokenEndpoint, Protocol.Default.Version) {
ConsumerKey = this.ConsumerKey,
};
var tokenAccessor = this.Channel.MessageDescriptions.GetAccessor(token);
@@ -200,7 +200,7 @@ namespace DotNetOpenAuth.OAuth {
// Request user authorization.
ITokenContainingMessage assignedRequestToken = requestTokenResponse;
- var requestAuthorization = new UserAuthorizationRequest(this.ServiceProvider.UserAuthorizationEndpoint, assignedRequestToken.Token) {
+ var requestAuthorization = new UserAuthorizationRequest(this.ServiceProvider.UserAuthorizationEndpoint, assignedRequestToken.Token, Protocol.Default.Version) {
Callback = callback,
};
var requestAuthorizationAccessor = this.Channel.MessageDescriptions.GetAccessor(requestAuthorization);
@@ -215,7 +215,7 @@ namespace DotNetOpenAuth.OAuth {
/// <param name="requestToken">The request token that the user has authorized.</param>
/// <returns>The access token assigned by the Service Provider.</returns>
protected AuthorizedTokenResponse ProcessUserAuthorization(string requestToken) {
- var requestAccess = new AuthorizedTokenRequest(this.ServiceProvider.AccessTokenEndpoint) {
+ var requestAccess = new AuthorizedTokenRequest(this.ServiceProvider.AccessTokenEndpoint, Protocol.Default.Version) {
RequestToken = requestToken,
ConsumerKey = this.ConsumerKey,
};
diff --git a/src/DotNetOpenAuth/OAuth/Messages/AccessProtectedResourceRequest.cs b/src/DotNetOpenAuth/OAuth/Messages/AccessProtectedResourceRequest.cs
index 62e02de..b60fda4 100644
--- a/src/DotNetOpenAuth/OAuth/Messages/AccessProtectedResourceRequest.cs
+++ b/src/DotNetOpenAuth/OAuth/Messages/AccessProtectedResourceRequest.cs
@@ -5,6 +5,7 @@
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.OAuth.Messages {
+ using System;
using System.Diagnostics.CodeAnalysis;
using DotNetOpenAuth.Messaging;
@@ -17,8 +18,9 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// Initializes a new instance of the <see cref="AccessProtectedResourceRequest"/> class.
/// </summary>
/// <param name="serviceProvider">The URI of the Service Provider endpoint to send this message to.</param>
- protected internal AccessProtectedResourceRequest(MessageReceivingEndpoint serviceProvider)
- : base(MessageTransport.Direct, serviceProvider) {
+ /// <param name="version">The OAuth version.</param>
+ protected internal AccessProtectedResourceRequest(MessageReceivingEndpoint serviceProvider, Version version)
+ : base(MessageTransport.Direct, serviceProvider, version) {
}
/// <summary>
diff --git a/src/DotNetOpenAuth/OAuth/Messages/AuthorizedTokenRequest.cs b/src/DotNetOpenAuth/OAuth/Messages/AuthorizedTokenRequest.cs
index 2d4793c..c96e82b 100644
--- a/src/DotNetOpenAuth/OAuth/Messages/AuthorizedTokenRequest.cs
+++ b/src/DotNetOpenAuth/OAuth/Messages/AuthorizedTokenRequest.cs
@@ -5,6 +5,7 @@
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.OAuth.Messages {
+ using System;
using System.Globalization;
using DotNetOpenAuth.Messaging;
@@ -20,8 +21,9 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// Initializes a new instance of the <see cref="AuthorizedTokenRequest"/> class.
/// </summary>
/// <param name="serviceProvider">The URI of the Service Provider endpoint to send this message to.</param>
- internal AuthorizedTokenRequest(MessageReceivingEndpoint serviceProvider)
- : base(MessageTransport.Direct, serviceProvider) {
+ /// <param name="version">The OAuth version.</param>
+ internal AuthorizedTokenRequest(MessageReceivingEndpoint serviceProvider, Version version)
+ : base(MessageTransport.Direct, serviceProvider, version) {
}
/// <summary>
@@ -39,6 +41,13 @@ namespace DotNetOpenAuth.OAuth.Messages {
internal string RequestToken { get; set; }
/// <summary>
+ /// Gets or sets the verification code received by the Consumer from the Service Provider
+ /// in the <see cref="UserAuthorizationResponse.VerificationCode"/> property.
+ /// </summary>
+ [MessagePart("oauth_verifier", IsRequired = true, AllowEmpty = false, MinVersion = Protocol.V10aVersion)]
+ internal string VerificationCode { get; set; }
+
+ /// <summary>
/// Checks the message state for conformity to the protocol specification
/// and throws an exception if the message is invalid.
/// </summary>
diff --git a/src/DotNetOpenAuth/OAuth/Messages/AuthorizedTokenResponse.cs b/src/DotNetOpenAuth/OAuth/Messages/AuthorizedTokenResponse.cs
index 14413a5..d87c381 100644
--- a/src/DotNetOpenAuth/OAuth/Messages/AuthorizedTokenResponse.cs
+++ b/src/DotNetOpenAuth/OAuth/Messages/AuthorizedTokenResponse.cs
@@ -5,6 +5,7 @@
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.OAuth.Messages {
+ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using DotNetOpenAuth.Messaging;
@@ -18,8 +19,9 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// Initializes a new instance of the <see cref="AuthorizedTokenResponse"/> class.
/// </summary>
/// <param name="originatingRequest">The originating request.</param>
- protected internal AuthorizedTokenResponse(AuthorizedTokenRequest originatingRequest)
- : base(MessageProtections.None, originatingRequest) {
+ /// <param name="version">The OAuth version.</param>
+ protected internal AuthorizedTokenResponse(AuthorizedTokenRequest originatingRequest, Version version)
+ : base(MessageProtections.None, originatingRequest, version) {
}
/// <summary>
diff --git a/src/DotNetOpenAuth/OAuth/Messages/MessageBase.cs b/src/DotNetOpenAuth/OAuth/Messages/MessageBase.cs
index e0269db..89e0276 100644
--- a/src/DotNetOpenAuth/OAuth/Messages/MessageBase.cs
+++ b/src/DotNetOpenAuth/OAuth/Messages/MessageBase.cs
@@ -62,12 +62,15 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// </summary>
/// <param name="protectionRequired">The level of protection the message requires.</param>
/// <param name="originatingRequest">The request that asked for this direct response.</param>
- protected MessageBase(MessageProtections protectionRequired, IDirectedProtocolMessage originatingRequest) {
+ /// <param name="version">The OAuth version.</param>
+ protected MessageBase(MessageProtections protectionRequired, IDirectedProtocolMessage originatingRequest, Version version) {
ErrorUtilities.VerifyArgumentNotNull(originatingRequest, "originatingRequest");
+ ErrorUtilities.VerifyArgumentNotNull(version, "version");
this.protectionRequired = protectionRequired;
this.transport = MessageTransport.Direct;
this.originatingRequest = originatingRequest;
+ this.Version = version;
}
/// <summary>
@@ -76,14 +79,15 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// <param name="protectionRequired">The level of protection the message requires.</param>
/// <param name="transport">A value indicating whether this message requires a direct or indirect transport.</param>
/// <param name="recipient">The URI that a directed message will be delivered to.</param>
- protected MessageBase(MessageProtections protectionRequired, MessageTransport transport, MessageReceivingEndpoint recipient) {
- if (recipient == null) {
- throw new ArgumentNullException("recipient");
- }
+ /// <param name="version">The OAuth version.</param>
+ protected MessageBase(MessageProtections protectionRequired, MessageTransport transport, MessageReceivingEndpoint recipient, Version version) {
+ ErrorUtilities.VerifyArgumentNotNull(recipient, "recipient");
+ ErrorUtilities.VerifyArgumentNotNull(version, "version");
this.protectionRequired = protectionRequired;
this.transport = transport;
this.recipient = recipient;
+ this.Version = version;
}
#region IProtocolMessage Properties
@@ -163,9 +167,7 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// <summary>
/// Gets the version of the protocol this message is prepared to implement.
/// </summary>
- protected virtual Version Version {
- get { return new Version(1, 0); }
- }
+ protected internal Version Version { get; private set; }
/// <summary>
/// Gets the level of protection this message requires.
diff --git a/src/DotNetOpenAuth/OAuth/Messages/SignedMessageBase.cs b/src/DotNetOpenAuth/OAuth/Messages/SignedMessageBase.cs
index d1abb58..eb85cb5 100644
--- a/src/DotNetOpenAuth/OAuth/Messages/SignedMessageBase.cs
+++ b/src/DotNetOpenAuth/OAuth/Messages/SignedMessageBase.cs
@@ -31,8 +31,9 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// </summary>
/// <param name="transport">A value indicating whether this message requires a direct or indirect transport.</param>
/// <param name="recipient">The URI that a directed message will be delivered to.</param>
- internal SignedMessageBase(MessageTransport transport, MessageReceivingEndpoint recipient)
- : base(MessageProtections.All, transport, recipient) {
+ /// <param name="version">The OAuth version.</param>
+ internal SignedMessageBase(MessageTransport transport, MessageReceivingEndpoint recipient, Version version)
+ : base(MessageProtections.All, transport, recipient, version) {
ITamperResistantOAuthMessage self = (ITamperResistantOAuthMessage)this;
HttpDeliveryMethods methods = ((IDirectedProtocolMessage)this).HttpMethods;
self.HttpMethod = (methods & HttpDeliveryMethods.PostRequest) != 0 ? "POST" : "GET";
diff --git a/src/DotNetOpenAuth/OAuth/Messages/UnauthorizedTokenRequest.cs b/src/DotNetOpenAuth/OAuth/Messages/UnauthorizedTokenRequest.cs
index e491bad..fceac01 100644
--- a/src/DotNetOpenAuth/OAuth/Messages/UnauthorizedTokenRequest.cs
+++ b/src/DotNetOpenAuth/OAuth/Messages/UnauthorizedTokenRequest.cs
@@ -5,8 +5,10 @@
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.OAuth.Messages {
+ using System;
using System.Collections.Generic;
using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth.ChannelElements;
/// <summary>
/// A direct message sent from Consumer to Service Provider to request a Request Token.
@@ -16,11 +18,23 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// Initializes a new instance of the <see cref="UnauthorizedTokenRequest"/> class.
/// </summary>
/// <param name="serviceProvider">The URI of the Service Provider endpoint to send this message to.</param>
- protected internal UnauthorizedTokenRequest(MessageReceivingEndpoint serviceProvider)
- : base(MessageTransport.Direct, serviceProvider) {
+ /// <param name="version">The OAuth version.</param>
+ protected internal UnauthorizedTokenRequest(MessageReceivingEndpoint serviceProvider, Version version)
+ : base(MessageTransport.Direct, serviceProvider, version) {
}
/// <summary>
+ /// Gets or sets the absolute URL to which the Service Provider will redirect the
+ /// User back when the Obtaining User Authorization step is completed.
+ /// </summary>
+ /// <value>
+ /// The callback URL; or <c>null</c> if the Consumer is unable to receive
+ /// callbacks or a callback URL has been established via other means.
+ /// </value>
+ [MessagePart("oauth_callback", IsRequired = true, AllowEmpty = false, MinVersion = Protocol.V10aVersion, Encoder = typeof(UriOrOobEncoder))]
+ public Uri Callback { get; set; }
+
+ /// <summary>
/// Gets the extra, non-OAuth parameters that will be included in the message.
/// </summary>
public new IDictionary<string, string> ExtraData {
diff --git a/src/DotNetOpenAuth/OAuth/Messages/UnauthorizedTokenResponse.cs b/src/DotNetOpenAuth/OAuth/Messages/UnauthorizedTokenResponse.cs
index 285dec7..23a138c 100644
--- a/src/DotNetOpenAuth/OAuth/Messages/UnauthorizedTokenResponse.cs
+++ b/src/DotNetOpenAuth/OAuth/Messages/UnauthorizedTokenResponse.cs
@@ -21,11 +21,12 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// <param name="requestMessage">The unauthorized request token message that this message is being generated in response to.</param>
/// <param name="requestToken">The request token.</param>
/// <param name="tokenSecret">The token secret.</param>
+ /// <param name="version">The OAuth version.</param>
/// <remarks>
/// This constructor is used by the Service Provider to send the message.
/// </remarks>
- protected internal UnauthorizedTokenResponse(UnauthorizedTokenRequest requestMessage, string requestToken, string tokenSecret)
- : this(requestMessage) {
+ protected internal UnauthorizedTokenResponse(UnauthorizedTokenRequest requestMessage, string requestToken, string tokenSecret, Version version)
+ : this(requestMessage, version) {
ErrorUtilities.VerifyArgumentNotNull(requestToken, "requestToken");
ErrorUtilities.VerifyArgumentNotNull(tokenSecret, "tokenSecret");
@@ -37,9 +38,10 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// Initializes a new instance of the <see cref="UnauthorizedTokenResponse"/> class.
/// </summary>
/// <param name="originatingRequest">The originating request.</param>
+ /// <param name="version">The OAuth version.</param>
/// <remarks>This constructor is used by the consumer to deserialize the message.</remarks>
- protected internal UnauthorizedTokenResponse(UnauthorizedTokenRequest originatingRequest)
- : base(MessageProtections.None, originatingRequest) {
+ protected internal UnauthorizedTokenResponse(UnauthorizedTokenRequest originatingRequest, Version version)
+ : base(MessageProtections.None, originatingRequest, version) {
}
/// <summary>
@@ -84,5 +86,13 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// </summary>
[MessagePart("oauth_token_secret", IsRequired = true)]
protected internal string TokenSecret { get; set; }
+
+ /// <summary>
+ /// Gets a value indicating whether the Service Provider recognized the callback parameter in the request.
+ /// </summary>
+ [MessagePart("oauth_callback_confirmed", IsRequired = true, MinVersion = Protocol.V10aVersion)]
+ private bool CallbackConfirmed {
+ get { return true; }
+ }
}
}
diff --git a/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationRequest.cs b/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationRequest.cs
index f1af0bc..0924ac6 100644
--- a/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationRequest.cs
+++ b/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationRequest.cs
@@ -21,8 +21,9 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// </summary>
/// <param name="serviceProvider">The URI of the Service Provider endpoint to send this message to.</param>
/// <param name="requestToken">The request token.</param>
- internal UserAuthorizationRequest(MessageReceivingEndpoint serviceProvider, string requestToken)
- : this(serviceProvider) {
+ /// <param name="version">The OAuth version.</param>
+ internal UserAuthorizationRequest(MessageReceivingEndpoint serviceProvider, string requestToken, Version version)
+ : this(serviceProvider, version) {
this.RequestToken = requestToken;
}
@@ -30,8 +31,9 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// Initializes a new instance of the <see cref="UserAuthorizationRequest"/> class.
/// </summary>
/// <param name="serviceProvider">The URI of the Service Provider endpoint to send this message to.</param>
- internal UserAuthorizationRequest(MessageReceivingEndpoint serviceProvider)
- : base(MessageProtections.None, MessageTransport.Indirect, serviceProvider) {
+ /// <param name="version">The OAuth version.</param>
+ internal UserAuthorizationRequest(MessageReceivingEndpoint serviceProvider, Version version)
+ : base(MessageProtections.None, MessageTransport.Indirect, serviceProvider, version) {
}
/// <summary>
@@ -65,7 +67,7 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// Gets or sets a URL the Service Provider will use to redirect the User back
/// to the Consumer when Obtaining User Authorization is complete. Optional.
/// </summary>
- [MessagePart("oauth_callback", IsRequired = false)]
+ [MessagePart("oauth_callback", IsRequired = false, MaxVersion = "1.0")]
internal Uri Callback { get; set; }
}
}
diff --git a/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationResponse.cs b/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationResponse.cs
index da6a909..a9a43fb 100644
--- a/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationResponse.cs
+++ b/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationResponse.cs
@@ -19,8 +19,9 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// Initializes a new instance of the <see cref="UserAuthorizationResponse"/> class.
/// </summary>
/// <param name="consumer">The URI of the Consumer endpoint to send this message to.</param>
- internal UserAuthorizationResponse(Uri consumer)
- : base(MessageProtections.None, MessageTransport.Indirect, new MessageReceivingEndpoint(consumer, HttpDeliveryMethods.GetRequest)) {
+ /// <param name="version">The OAuth version.</param>
+ internal UserAuthorizationResponse(Uri consumer, Version version)
+ : base(MessageProtections.None, MessageTransport.Indirect, new MessageReceivingEndpoint(consumer, HttpDeliveryMethods.GetRequest), version) {
}
/// <summary>
@@ -36,5 +37,19 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// </summary>
[MessagePart("oauth_token", IsRequired = true)]
internal string RequestToken { get; set; }
+
+ /// <summary>
+ /// Gets or sets the verification code that must accompany the request to exchange the
+ /// authorized request token for an access token.
+ /// </summary>
+ /// <value>An unguessable value passed to the Consumer via the User and REQUIRED to complete the process.</value>
+ /// <remarks>
+ /// If the Consumer did not provide a callback URL, the Service Provider SHOULD display the value of the
+ /// verification code, and instruct the User to manually inform the Consumer that authorization is
+ /// completed. If the Service Provider knows a Consumer to be running on a mobile device or set-top box,
+ /// the Service Provider SHOULD ensure that the verifier value is suitable for manual entry.
+ /// </remarks>
+ [MessagePart("oauth_verifier", IsRequired = true, AllowEmpty = false, MinVersion = Protocol.V10aVersion)]
+ internal string VerificationCode { get; set; }
}
}
diff --git a/src/DotNetOpenAuth/OAuth/OAuthStrings.Designer.cs b/src/DotNetOpenAuth/OAuth/OAuthStrings.Designer.cs
index 63e348a..d1811c4 100644
--- a/src/DotNetOpenAuth/OAuth/OAuthStrings.Designer.cs
+++ b/src/DotNetOpenAuth/OAuth/OAuthStrings.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:2.0.50727.3521
+// Runtime Version:2.0.50727.4918
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -97,6 +97,15 @@ namespace DotNetOpenAuth.OAuth {
}
/// <summary>
+ /// Looks up a localized string similar to oauth_verifier argument was incorrect..
+ /// </summary>
+ internal static string IncorrectVerifier {
+ get {
+ return ResourceManager.GetString("IncorrectVerifier", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to An invalid OAuth message received and discarded..
/// </summary>
internal static string InvalidIncomingMessage {
diff --git a/src/DotNetOpenAuth/OAuth/OAuthStrings.resx b/src/DotNetOpenAuth/OAuth/OAuthStrings.resx
index 3ba4da1..2e82bdb 100644
--- a/src/DotNetOpenAuth/OAuth/OAuthStrings.resx
+++ b/src/DotNetOpenAuth/OAuth/OAuthStrings.resx
@@ -129,6 +129,9 @@
<data name="ConsumerOrTokenSecretNotFound" xml:space="preserve">
<value>Failure looking up secret for consumer or token.</value>
</data>
+ <data name="IncorrectVerifier" xml:space="preserve">
+ <value>oauth_verifier argument was incorrect.</value>
+ </data>
<data name="InvalidIncomingMessage" xml:space="preserve">
<value>An invalid OAuth message received and discarded.</value>
</data>
diff --git a/src/DotNetOpenAuth/OAuth/Protocol.cs b/src/DotNetOpenAuth/OAuth/Protocol.cs
index 88615ff..9417efa 100644
--- a/src/DotNetOpenAuth/OAuth/Protocol.cs
+++ b/src/DotNetOpenAuth/OAuth/Protocol.cs
@@ -12,6 +12,21 @@ namespace DotNetOpenAuth.OAuth {
using DotNetOpenAuth.Messaging;
/// <summary>
+ /// An enumeration of the OAuth protocol versions supported by this library.
+ /// </summary>
+ public enum ProtocolVersion {
+ /// <summary>
+ /// OAuth 1.0 specification
+ /// </summary>
+ V10,
+
+ /// <summary>
+ /// OAuth 1.0a specification
+ /// </summary>
+ V10a,
+ }
+
+ /// <summary>
/// Constants used in the OAuth protocol.
/// </summary>
/// <remarks>
@@ -25,63 +40,92 @@ namespace DotNetOpenAuth.OAuth {
internal const string DataContractNamespaceV10 = "http://oauth.net/core/1.0/";
/// <summary>
+ /// The prefix used for all key names in the protocol.
+ /// </summary>
+ internal const string ParameterPrefix = "oauth_";
+
+ /// <summary>
+ /// The string representation of a <see cref="Version"/> instance to be used to represent OAuth 1.0a.
+ /// </summary>
+ internal const string V10aVersion = "1.0.1";
+
+ /// <summary>
+ /// The scheme to use in Authorization header message requests.
+ /// </summary>
+ internal const string AuthorizationHeaderScheme = "OAuth";
+
+ /// <summary>
/// Gets the <see cref="Protocol"/> instance with values initialized for V1.0 of the protocol.
/// </summary>
internal static readonly Protocol V10 = new Protocol {
dataContractNamespace = DataContractNamespaceV10,
+ Version = new Version(1, 0),
};
/// <summary>
- /// The namespace to use for this version of the protocol.
+ /// Gets the <see cref="Protocol"/> instance with values initialized for V1.0a of the protocol.
/// </summary>
- private string dataContractNamespace;
+ internal static readonly Protocol V10a = new Protocol {
+ dataContractNamespace = DataContractNamespaceV10,
+ Version = new Version(V10aVersion),
+ };
/// <summary>
- /// The prefix used for all key names in the protocol.
+ /// A list of all supported OAuth versions, in order starting from newest version.
/// </summary>
- private string parameterPrefix = "oauth_";
+ internal static readonly List<Protocol> AllVersions = new List<Protocol>() { V10a, V10 };
/// <summary>
- /// The scheme to use in Authorization header message requests.
+ /// The default (or most recent) supported version of the OpenID protocol.
/// </summary>
- private string authorizationHeaderScheme = "OAuth";
+ internal static readonly Protocol Default = AllVersions[0];
/// <summary>
- /// Gets the default <see cref="Protocol"/> instance.
+ /// The namespace to use for this version of the protocol.
/// </summary>
- internal static Protocol Default { get { return V10; } }
+ private string dataContractNamespace;
/// <summary>
- /// Gets the namespace to use for this version of the protocol.
+ /// Initializes a new instance of the <see cref="Protocol"/> class.
/// </summary>
- internal string DataContractNamespace {
- get { return this.dataContractNamespace; }
+ internal Protocol() {
}
/// <summary>
- /// Gets the prefix used for all key names in the protocol.
+ /// Gets the version used to represent OAuth 1.0a.
/// </summary>
- internal string ParameterPrefix {
- get { return this.parameterPrefix; }
- }
+ internal Version Version { get; private set; }
/// <summary>
- /// Gets the scheme to use in Authorization header message requests.
+ /// Gets the namespace to use for this version of the protocol.
/// </summary>
- internal string AuthorizationHeaderScheme {
- get { return this.authorizationHeaderScheme; }
+ internal string DataContractNamespace {
+ get { return this.dataContractNamespace; }
}
/// <summary>
- /// Gets an instance of <see cref="Protocol"/> given a <see cref="Version"/>.
+ /// Gets the OAuth Protocol instance to use for the given version.
/// </summary>
- /// <param name="version">The version of the protocol that is desired.</param>
- /// <returns>The <see cref="Protocol"/> instance representing the requested version.</returns>
- internal static Protocol Lookup(Version version) {
- switch (version.Major) {
- case 1: return Protocol.V10;
+ /// <param name="version">The OAuth version to get.</param>
+ /// <returns>A matching <see cref="Protocol"/> instance.</returns>
+ public static Protocol Lookup(ProtocolVersion version) {
+ switch (version) {
+ case ProtocolVersion.V10: return Protocol.V10;
+ case ProtocolVersion.V10a: return Protocol.V10a;
default: throw new ArgumentOutOfRangeException("version");
}
}
+
+ /// <summary>
+ /// Gets the OAuth Protocol instance to use for the given version.
+ /// </summary>
+ /// <param name="version">The OAuth version to get.</param>
+ /// <returns>A matching <see cref="Protocol"/> instance.</returns>
+ internal static Protocol Lookup(Version version) {
+ ErrorUtilities.VerifyArgumentNotNull(version, "version");
+ Protocol protocol = AllVersions.FirstOrDefault(p => p.Version == version);
+ ErrorUtilities.VerifyArgumentInRange(protocol != null, "version");
+ return protocol;
+ }
}
}
diff --git a/src/DotNetOpenAuth/OAuth/ServiceProvider.cs b/src/DotNetOpenAuth/OAuth/ServiceProvider.cs
index 345c6a2..38b7a60 100644
--- a/src/DotNetOpenAuth/OAuth/ServiceProvider.cs
+++ b/src/DotNetOpenAuth/OAuth/ServiceProvider.cs
@@ -48,7 +48,7 @@ namespace DotNetOpenAuth.OAuth {
/// <param name="serviceDescription">The endpoints and behavior on the Service Provider.</param>
/// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
/// <param name="messageTypeProvider">An object that can figure out what type of message is being received for deserialization.</param>
- public ServiceProvider(ServiceProviderDescription serviceDescription, ITokenManager tokenManager, OAuthServiceProviderMessageFactory messageTypeProvider) {
+ public ServiceProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager, OAuthServiceProviderMessageFactory messageTypeProvider) {
ErrorUtilities.VerifyArgumentNotNull(serviceDescription, "serviceDescription");
ErrorUtilities.VerifyArgumentNotNull(tokenManager, "tokenManager");
ErrorUtilities.VerifyArgumentNotNull(messageTypeProvider, "messageTypeProvider");
@@ -156,13 +156,11 @@ namespace DotNetOpenAuth.OAuth {
/// <param name="request">The token request message the Consumer sent that the Service Provider is now responding to.</param>
/// <returns>The response message to send using the <see cref="Channel"/>, after optionally adding extra data to it.</returns>
public UnauthorizedTokenResponse PrepareUnauthorizedTokenMessage(UnauthorizedTokenRequest request) {
- if (request == null) {
- throw new ArgumentNullException("request");
- }
+ ErrorUtilities.VerifyArgumentNotNull(request, "request");
string token = this.TokenGenerator.GenerateRequestToken(request.ConsumerKey);
string secret = this.TokenGenerator.GenerateSecret();
- UnauthorizedTokenResponse response = new UnauthorizedTokenResponse(request, token, secret);
+ UnauthorizedTokenResponse response = new UnauthorizedTokenResponse(request, token, secret, Protocol.Default.Version);
return response;
}
@@ -231,7 +229,7 @@ namespace DotNetOpenAuth.OAuth {
ErrorUtilities.VerifyArgumentNotNull(request, "request");
ErrorUtilities.VerifyArgumentNotNull(callback, "callback");
- var authorization = new UserAuthorizationResponse(request.Callback) {
+ var authorization = new UserAuthorizationResponse(request.Callback, Protocol.Default.Version) {
RequestToken = request.RequestToken,
};
return authorization;
@@ -282,7 +280,7 @@ namespace DotNetOpenAuth.OAuth {
string accessToken = this.TokenGenerator.GenerateAccessToken(request.ConsumerKey);
string tokenSecret = this.TokenGenerator.GenerateSecret();
this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(request.ConsumerKey, request.RequestToken, accessToken, tokenSecret);
- var grantAccess = new AuthorizedTokenResponse(request) {
+ var grantAccess = new AuthorizedTokenResponse(request, Protocol.Default.Version) {
AccessToken = accessToken,
TokenSecret = tokenSecret,
};
diff --git a/src/DotNetOpenAuth/OAuth/ServiceProviderDescription.cs b/src/DotNetOpenAuth/OAuth/ServiceProviderDescription.cs
index 4636829..bdfd10d 100644
--- a/src/DotNetOpenAuth/OAuth/ServiceProviderDescription.cs
+++ b/src/DotNetOpenAuth/OAuth/ServiceProviderDescription.cs
@@ -26,9 +26,15 @@ namespace DotNetOpenAuth.OAuth {
/// Initializes a new instance of the <see cref="ServiceProviderDescription"/> class.
/// </summary>
public ServiceProviderDescription() {
+ this.Version = Protocol.Default.Version;
}
/// <summary>
+ /// Gets or sets the OAuth version supported by the Service Provider.
+ /// </summary>
+ public Version Version { 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).
/// </summary>
@@ -43,7 +49,7 @@ namespace DotNetOpenAuth.OAuth {
}
set {
- if (value != null && UriUtil.QueryStringContainPrefixedParameters(value.Location, OAuth.Protocol.V10.ParameterPrefix)) {
+ if (value != null && UriUtil.QueryStringContainPrefixedParameters(value.Location, OAuth.Protocol.ParameterPrefix)) {
throw new ArgumentException(OAuthStrings.RequestUrlMustNotHaveOAuthParameters);
}
diff --git a/src/DotNetOpenAuth/OAuth/WebConsumer.cs b/src/DotNetOpenAuth/OAuth/WebConsumer.cs
index bbf6115..7de73c7 100644
--- a/src/DotNetOpenAuth/OAuth/WebConsumer.cs
+++ b/src/DotNetOpenAuth/OAuth/WebConsumer.cs
@@ -39,7 +39,7 @@ namespace DotNetOpenAuth.OAuth {
/// Requires HttpContext.Current.
/// </remarks>
public UserAuthorizationRequest PrepareRequestUserAuthorization() {
- Uri callback = this.Channel.GetRequestFromContext().UrlBeforeRewriting.StripQueryArgumentsWithPrefix(Protocol.Default.ParameterPrefix);
+ Uri callback = this.Channel.GetRequestFromContext().UrlBeforeRewriting.StripQueryArgumentsWithPrefix(Protocol.ParameterPrefix);
return this.PrepareRequestUserAuthorization(callback, null, null);
}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs b/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs
index 37da8a3..635a3c0 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs
@@ -102,7 +102,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
public static void SendResponse() {
var pendingRequest = PendingAuthenticationRequest;
PendingAuthenticationRequest = null;
- Provider.SendResponse(pendingRequest);
+ Provider.SendResponse(pendingRequest);
}
/// <summary>