diff options
-rw-r--r-- | src/DotNetOAuth.Test/Mocks/InMemoryTokenManager.cs | 24 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs | 24 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs | 29 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/Scenarios/Coordinator.cs | 18 | ||||
-rw-r--r-- | src/DotNetOAuth/ChannelElements/ITokenGenerator.cs | 32 | ||||
-rw-r--r-- | src/DotNetOAuth/ChannelElements/ITokenManager.cs | 42 | ||||
-rw-r--r-- | src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs | 10 | ||||
-rw-r--r-- | src/DotNetOAuth/ChannelElements/StandardTokenGenerator.cs | 45 | ||||
-rw-r--r-- | src/DotNetOAuth/Consumer.cs | 49 | ||||
-rw-r--r-- | src/DotNetOAuth/Messages/ITokenContainingMessage.cs | 5 | ||||
-rw-r--r-- | src/DotNetOAuth/Messages/MessageBase.cs | 16 | ||||
-rw-r--r-- | src/DotNetOAuth/Messages/RequestTokenMessage.cs | 2 | ||||
-rw-r--r-- | src/DotNetOAuth/Messaging/Channel.cs | 33 | ||||
-rw-r--r-- | src/DotNetOAuth/ServiceProvider.cs | 39 | ||||
-rw-r--r-- | src/DotNetOAuth/ServiceProviderEndpoints.cs | 2 |
15 files changed, 249 insertions, 121 deletions
diff --git a/src/DotNetOAuth.Test/Mocks/InMemoryTokenManager.cs b/src/DotNetOAuth.Test/Mocks/InMemoryTokenManager.cs index 002eee1..0454fb8 100644 --- a/src/DotNetOAuth.Test/Mocks/InMemoryTokenManager.cs +++ b/src/DotNetOAuth.Test/Mocks/InMemoryTokenManager.cs @@ -1,4 +1,10 @@ -namespace DotNetOAuth.Test.Mocks {
+//-----------------------------------------------------------------------
+// <copyright file="InMemoryTokenManager.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Test.Mocks {
using System;
using System.Collections.Generic;
using System.Linq;
@@ -6,32 +12,32 @@ using DotNetOAuth.ChannelElements;
internal class InMemoryTokenManager : ITokenManager {
- Dictionary<string, string> consumersAndSecrets = new Dictionary<string, string>();
- Dictionary<string, string> tokensAndSecrets = new Dictionary<string, string>();
+ private Dictionary<string, string> consumersAndSecrets = new Dictionary<string, string>();
+ private Dictionary<string, string> tokensAndSecrets = new Dictionary<string, string>();
#region ITokenManager Members
public string GetConsumerSecret(string consumerKey) {
- return consumersAndSecrets[consumerKey];
+ return this.consumersAndSecrets[consumerKey];
}
public string GetTokenSecret(string token) {
- return tokensAndSecrets[token];
+ return this.tokensAndSecrets[token];
}
public void StoreNewRequestToken(string consumerKey, string requestToken, string requestTokenSecret, IDictionary<string, string> parameters) {
- tokensAndSecrets[requestToken] = requestTokenSecret;
+ this.tokensAndSecrets[requestToken] = requestTokenSecret;
}
public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) {
- tokensAndSecrets.Remove(requestToken);
- tokensAndSecrets[accessToken] = accessTokenSecret;
+ this.tokensAndSecrets.Remove(requestToken);
+ this.tokensAndSecrets[accessToken] = accessTokenSecret;
}
#endregion
internal void AddConsumer(string key, string secret) {
- consumersAndSecrets.Add(key, secret);
+ this.consumersAndSecrets.Add(key, secret);
}
}
}
diff --git a/src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs b/src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs index 563fac3..aefa0ea 100644 --- a/src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs +++ b/src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs @@ -1,45 +1,39 @@ //-----------------------------------------------------------------------
-// <copyright file="Scenarios.cs" company="Andrew Arnott">
+// <copyright file="AppendixScenarios.cs" company="Andrew Arnott">
// Copyright (c) Andrew Arnott. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace DotNetOAuth.Test {
using System;
- using System.Collections.Specialized;
- using System.IO;
using System.Linq;
- using System.Net;
- using System.Web;
- using DotNetOAuth.Messaging;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
- using DotNetOAuth.Test.Scenarios;
using DotNetOAuth.ChannelElements;
- using System.Collections.Generic;
+ using DotNetOAuth.Messaging;
using DotNetOAuth.Test.Mocks;
+ using DotNetOAuth.Test.Scenarios;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
public class AppendixScenarios : TestBase {
[TestMethod]
public void SpecAppendixAExample() {
- ServiceProviderEndpoints spEndpoints = new ServiceProviderEndpoints() {
+ ServiceProviderEndpoints endpoints = new ServiceProviderEndpoints() {
RequestTokenEndpoint = new ServiceProviderEndpoint("https://photos.example.net/request_token", HttpDeliveryMethod.PostRequest),
UserAuthorizationEndpoint = new ServiceProviderEndpoint("http://photos.example.net/authorize", HttpDeliveryMethod.GetRequest),
AccessTokenEndpoint = new ServiceProviderEndpoint("https://photos.example.net/access_token", HttpDeliveryMethod.PostRequest),
};
var tokenManager = new InMemoryTokenManager();
- var sp = new ServiceProvider(spEndpoints, tokenManager);
- Consumer consumer = new Consumer {
+ var sp = new ServiceProvider(endpoints, tokenManager);
+ Consumer consumer = new Consumer(endpoints, new InMemoryTokenManager()) {
ConsumerKey = "dpf43f3p2l4k3l03",
ConsumerSecret = "kd94hf93k423kf44",
- ServiceProvider = spEndpoints,
};
Coordinator coordinator = new Coordinator(
channel => {
consumer.Channel = channel;
- string requestTokenSecret = consumer.RequestUserAuthorization(new Uri("http://printer.example.com/request_token_ready"));
- var accessTokenMessage = consumer.ProcessUserAuthorization(requestTokenSecret);
+ consumer.RequestUserAuthorization(new Uri("http://printer.example.com/request_token_ready"));
+ var accessTokenMessage = consumer.ProcessUserAuthorization();
},
channel => {
tokenManager.AddConsumer(consumer.ConsumerKey, consumer.ConsumerSecret);
diff --git a/src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs b/src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs index 2a42983..65254e2 100644 --- a/src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs +++ b/src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs @@ -6,22 +6,20 @@ namespace DotNetOAuth.Test.Scenarios {
using System;
- using System.Collections.Generic;
- using System.Linq;
using System.Reflection;
- using System.Text;
+ using System.Threading;
using DotNetOAuth.ChannelElements;
- using DotNetOAuth.Messaging.Bindings;
using DotNetOAuth.Messaging;
- using System.Threading;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
+ using DotNetOAuth.Messaging.Bindings;
using DotNetOAuth.Messaging.Reflection;
- using DotNetOAuth.Messages;
/// <summary>
/// A special channel used in test simulations to pass messages directly between two parties.
/// </summary>
internal class CoordinatingOAuthChannel : OAuthChannel {
+ private EventWaitHandle incomingMessageSignal = new AutoResetEvent(false);
+ private IProtocolMessage incomingMessage;
+
/// <summary>
/// Initializes a new instance of the <see cref="CoordinatingOAuthChannel"/> class for Consumers.
/// </summary>
@@ -37,32 +35,29 @@ namespace DotNetOAuth.Test.Scenarios { /// </summary>
internal CoordinatingOAuthChannel RemoteChannel { get; set; }
- private EventWaitHandle incomingMessageSignal = new AutoResetEvent(false);
- private IProtocolMessage incomingMessage;
-
protected override IProtocolMessage RequestInternal(IDirectedProtocolMessage request) {
TestBase.TestLogger.InfoFormat("Sending request: {0}", request);
// Drop the outgoing message in the other channel's in-slot and let them know it's there.
- RemoteChannel.incomingMessage = CloneSerializedParts(request);
- RemoteChannel.incomingMessageSignal.Set();
+ this.RemoteChannel.incomingMessage = CloneSerializedParts(request);
+ this.RemoteChannel.incomingMessageSignal.Set();
// Now wait for a response...
- return AwaitIncomingMessage();
+ return this.AwaitIncomingMessage();
}
protected override void SendDirectMessageResponse(IProtocolMessage response) {
TestBase.TestLogger.InfoFormat("Sending response: {0}", response);
- RemoteChannel.incomingMessage = CloneSerializedParts(response);
- RemoteChannel.incomingMessageSignal.Set();
+ this.RemoteChannel.incomingMessage = CloneSerializedParts(response);
+ this.RemoteChannel.incomingMessageSignal.Set();
}
protected override void SendIndirectMessage(IDirectedProtocolMessage message) {
TestBase.TestLogger.Info("Next response is an indirect message...");
// In this mock transport, direct and indirect messages are the same.
- SendDirectMessageResponse(message);
+ this.SendDirectMessageResponse(message);
}
protected override HttpRequestInfo GetRequestFromContext() {
- return new HttpRequestInfo(AwaitIncomingMessage());
+ return new HttpRequestInfo(this.AwaitIncomingMessage());
}
protected override IProtocolMessage ReadFromRequestInternal(HttpRequestInfo request) {
diff --git a/src/DotNetOAuth.Test/Scenarios/Coordinator.cs b/src/DotNetOAuth.Test/Scenarios/Coordinator.cs index 45518a2..c3eaad6 100644 --- a/src/DotNetOAuth.Test/Scenarios/Coordinator.cs +++ b/src/DotNetOAuth.Test/Scenarios/Coordinator.cs @@ -6,11 +6,7 @@ namespace DotNetOAuth.Test.Scenarios {
using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
using System.Threading;
- using DotNetOAuth.Messaging;
using DotNetOAuth.ChannelElements;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -18,8 +14,8 @@ namespace DotNetOAuth.Test.Scenarios { /// Runs a Consumer and Service Provider simultaneously so they can interact in a full simulation.
/// </summary>
internal class Coordinator {
- Actor consumerAction;
- Actor serviceProviderAction;
+ private Actor consumerAction;
+ private Actor serviceProviderAction;
/// <summary>Initializes a new instance of the <see cref="Coordinator"/> class.</summary>
/// <param name="consumerAction">The code path of the Consumer.</param>
@@ -36,6 +32,8 @@ namespace DotNetOAuth.Test.Scenarios { this.serviceProviderAction = serviceProviderAction;
}
+ internal delegate void Actor(OAuthChannel channel);
+
/// <summary>
/// Gets or sets the signing element the Consumer channel should use.
/// </summary>
@@ -44,19 +42,17 @@ namespace DotNetOAuth.Test.Scenarios { /// </remarks>
internal SigningBindingElementBase SigningElement { get; set; }
- internal delegate void Actor(OAuthChannel channel);
-
/// <summary>
/// Starts the simulation.
/// </summary>
internal void Start() {
- if (SigningElement == null) {
+ if (this.SigningElement == null) {
throw new InvalidOperationException("SigningElement must be set first.");
}
// Prepare channels that will pass messages directly back and forth.
- CoordinatingOAuthChannel consumerChannel = new CoordinatingOAuthChannel(SigningElement);
- CoordinatingOAuthChannel serviceProviderChannel = new CoordinatingOAuthChannel(SigningElement);
+ CoordinatingOAuthChannel consumerChannel = new CoordinatingOAuthChannel(this.SigningElement);
+ CoordinatingOAuthChannel serviceProviderChannel = new CoordinatingOAuthChannel(this.SigningElement);
consumerChannel.RemoteChannel = serviceProviderChannel;
serviceProviderChannel.RemoteChannel = consumerChannel;
diff --git a/src/DotNetOAuth/ChannelElements/ITokenGenerator.cs b/src/DotNetOAuth/ChannelElements/ITokenGenerator.cs index 45bc5b2..b9d690f 100644 --- a/src/DotNetOAuth/ChannelElements/ITokenGenerator.cs +++ b/src/DotNetOAuth/ChannelElements/ITokenGenerator.cs @@ -5,14 +5,36 @@ //-----------------------------------------------------------------------
namespace DotNetOAuth.ChannelElements {
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
-
+ /// <summary>
+ /// An interface allowing OAuth hosts to inject their own algorithm for generating tokens and secrets.
+ /// </summary>
internal interface ITokenGenerator {
+ /// <summary>
+ /// Generates a new token to represent a not-yet-authorized request to access protected resources.
+ /// </summary>
+ /// <param name="consumerKey">The consumer that requested this token.</param>
+ /// <returns>The newly generated token.</returns>
+ /// <remarks>
+ /// This method should not store the newly generated token in any persistent store.
+ /// This will be done in <see cref="ITokenManager.StoreNewRequestToken"/>.
+ /// </remarks>
string GenerateRequestToken(string consumerKey);
+
+ /// <summary>
+ /// Generates a new token to represent an authorized request to access protected resources.
+ /// </summary>
+ /// <param name="consumerKey">The consumer that requested this token.</param>
+ /// <returns>The newly generated token.</returns>
+ /// <remarks>
+ /// This method should not store the newly generated token in any persistent store.
+ /// This will be done in <see cref="ITokenManager.ExpireRequestTokenAndStoreNewAccessToken"/>.
+ /// </remarks>
string GenerateAccessToken(string consumerKey);
+
+ /// <summary>
+ /// Returns a cryptographically strong random string for use as a token secret.
+ /// </summary>
+ /// <returns>The generated string.</returns>
string GenerateSecret();
}
}
diff --git a/src/DotNetOAuth/ChannelElements/ITokenManager.cs b/src/DotNetOAuth/ChannelElements/ITokenManager.cs index ee3124a..9aa9299 100644 --- a/src/DotNetOAuth/ChannelElements/ITokenManager.cs +++ b/src/DotNetOAuth/ChannelElements/ITokenManager.cs @@ -10,28 +10,46 @@ namespace DotNetOAuth.ChannelElements { using System.Linq;
using System.Text;
+ /// <summary>
+ /// An interface OAuth hosts must implement for persistent storage and recall of tokens and secrets.
+ /// </summary>
public interface ITokenManager {
+ /// <summary>
+ /// Gets the Consumer Secret given a Consumer Key.
+ /// </summary>
+ /// <param name="consumerKey">The Consumer Key.</param>
+ /// <returns>The Consumer Secret.</returns>
string GetConsumerSecret(string consumerKey);
+
+ /// <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>
string GetTokenSecret(string token);
/// <summary>
- ///
+ /// Stores a newly generated unauthorized request token, secret, and optional
+ /// application-specific parameters for later recall.
/// </summary>
- /// <param name="consumerKey"></param>
- /// <param name="requestToken"></param>
- /// <param name="requestTokenSecret"></param>
- /// <param name="parameters"></param>
- /// <returns>True if there was no conflict with an existing token. False if a new token should be generated.</returns>
+ /// <param name="consumerKey">The key of the Consumer that requested this token.</param>
+ /// <param name="requestToken">The token to store.</param>
+ /// <param name="requestTokenSecret">The secret to store as associated with the request token.</param>
+ /// <param name="parameters">The optional application-specific parameters of this request.</param>
void StoreNewRequestToken(string consumerKey, string requestToken, string requestTokenSecret, IDictionary<string, string> parameters);
/// <summary>
- ///
+ /// Deletes a request token and its associated secret and stores a new access token and secret.
/// </summary>
- /// <param name="consumerKey"></param>
- /// <param name="requestToken"></param>
- /// <param name="accessToken"></param>
- /// <param name="accessTokenSecret"></param>
- /// <returns>True if there was no conflict with an existing token. False if a new token should be generated.</returns>
+ /// <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>
+ /// <remarks>
+ /// Any scope of granted privileges associated with the request token from the
+ /// original call to <see cref="StoreNewRequestToken"/> should be carried over
+ /// to the new Access Token.
+ /// </remarks>
void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret);
}
}
diff --git a/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs b/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs index 43d1e8b..a1e5feb 100644 --- a/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs +++ b/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs @@ -17,17 +17,17 @@ namespace DotNetOAuth.ChannelElements { /// </summary>
internal abstract class SigningBindingElementBase : IChannelBindingElement {
/// <summary>
- /// The signature method this binding element uses.
- /// </summary>
- private string signatureMethod;
-
- /// <summary>
/// The delegate that will initialize the non-serialized properties necessary on a signed
/// message so that its signature can be correctly calculated for verification.
/// </summary>
private readonly Action<ITamperResistantOAuthMessage> incomingMessageSignatureVerificationCallback;
/// <summary>
+ /// The signature method this binding element uses.
+ /// </summary>
+ private string signatureMethod;
+
+ /// <summary>
/// Initializes a new instance of the <see cref="SigningBindingElementBase"/> class.
/// </summary>
/// <param name="signatureMethod">The OAuth signature method that the binding element uses.</param>
diff --git a/src/DotNetOAuth/ChannelElements/StandardTokenGenerator.cs b/src/DotNetOAuth/ChannelElements/StandardTokenGenerator.cs index b54da20..fb2590a 100644 --- a/src/DotNetOAuth/ChannelElements/StandardTokenGenerator.cs +++ b/src/DotNetOAuth/ChannelElements/StandardTokenGenerator.cs @@ -6,33 +6,62 @@ namespace DotNetOAuth.ChannelElements {
using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
using System.Security.Cryptography;
+ /// <summary>
+ /// A cryptographically strong random string generator for tokens and secrets.
+ /// </summary>
internal class StandardTokenGenerator : ITokenGenerator {
- RandomNumberGenerator cryptoProvider = new RNGCryptoServiceProvider();
+ /// <summary>
+ /// The cryptographically strong random string generator for tokens and secrets.
+ /// </summary>
+ private RandomNumberGenerator cryptoProvider = new RNGCryptoServiceProvider();
#region ITokenGenerator Members
+ /// <summary>
+ /// Generates a new token to represent a not-yet-authorized request to access protected resources.
+ /// </summary>
+ /// <param name="consumerKey">The consumer that requested this token.</param>
+ /// <returns>The newly generated token.</returns>
+ /// <remarks>
+ /// This method should not store the newly generated token in any persistent store.
+ /// This will be done in <see cref="ITokenManager.StoreNewRequestToken"/>.
+ /// </remarks>
public string GenerateRequestToken(string consumerKey) {
- return GenerateCryptographicallyStrongString();
+ return this.GenerateCryptographicallyStrongString();
}
+ /// <summary>
+ /// Generates a new token to represent an authorized request to access protected resources.
+ /// </summary>
+ /// <param name="consumerKey">The consumer that requested this token.</param>
+ /// <returns>The newly generated token.</returns>
+ /// <remarks>
+ /// This method should not store the newly generated token in any persistent store.
+ /// This will be done in <see cref="ITokenManager.ExpireRequestTokenAndStoreNewAccessToken"/>.
+ /// </remarks>
public string GenerateAccessToken(string consumerKey) {
- return GenerateCryptographicallyStrongString();
+ return this.GenerateCryptographicallyStrongString();
}
+ /// <summary>
+ /// Returns a cryptographically strong random string for use as a token secret.
+ /// </summary>
+ /// <returns>The generated string.</returns>
public string GenerateSecret() {
- return GenerateCryptographicallyStrongString();
+ return this.GenerateCryptographicallyStrongString();
}
#endregion
+ /// <summary>
+ /// Returns a new random string.
+ /// </summary>
+ /// <returns>The new random string.</returns>
private string GenerateCryptographicallyStrongString() {
byte[] buffer = new byte[20];
- cryptoProvider.GetBytes(buffer);
+ this.cryptoProvider.GetBytes(buffer);
return Convert.ToBase64String(buffer);
}
}
diff --git a/src/DotNetOAuth/Consumer.cs b/src/DotNetOAuth/Consumer.cs index be5d4a5..1a99f2e 100644 --- a/src/DotNetOAuth/Consumer.cs +++ b/src/DotNetOAuth/Consumer.cs @@ -19,11 +19,22 @@ namespace DotNetOAuth { /// <summary>
/// Initializes a new instance of the <see cref="Consumer"/> class.
/// </summary>
- public Consumer() {
+ /// <param name="endpoints">The endpoints on the Service Provider.</param>
+ /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
+ public Consumer(ServiceProviderEndpoints endpoints, ITokenManager tokenManager) {
+ if (endpoints == null) {
+ throw new ArgumentNullException("endpoints");
+ }
+ if (tokenManager == null) {
+ throw new ArgumentNullException("tokenManager");
+ }
+
this.WebRequestHandler = new StandardWebRequestHandler();
SigningBindingElementBase signingElement = new PlainTextSigningBindingElement();
INonceStore store = new NonceMemoryStore(StandardExpirationBindingElement.DefaultMaximumMessageAge);
this.Channel = new OAuthChannel(signingElement, store, new OAuthMessageTypeProvider(), this.WebRequestHandler);
+ this.ServiceProvider = endpoints;
+ this.TokenManager = tokenManager;
}
/// <summary>
@@ -37,9 +48,14 @@ namespace DotNetOAuth { public string ConsumerSecret { get; set; }
/// <summary>
- /// Gets or sets the Service Provider that will be accessed.
+ /// Gets the Service Provider that will be accessed.
+ /// </summary>
+ public ServiceProviderEndpoints ServiceProvider { get; private set; }
+
+ /// <summary>
+ /// Gets the persistence store for tokens and secrets.
/// </summary>
- public ServiceProviderEndpoints ServiceProvider { get; set; }
+ public ITokenManager TokenManager { get; private set; }
/// <summary>
/// Gets the pending user agent redirect based message to be sent as an HttpResponse.
@@ -64,37 +80,46 @@ namespace DotNetOAuth { /// Begins an OAuth authorization request and redirects the user to the Service Provider
/// to provide that authorization.
/// </summary>
- /// <returns>The Request Token Secret.</returns>
- public string RequestUserAuthorization(Uri callback) {
+ /// <param name="callback">
+ /// An optional Consumer URL that the Service Provider should redirect the
+ /// User Agent to upon successful authorization.
+ /// </param>
+ public void RequestUserAuthorization(Uri callback) {
// Obtain an unauthorized request token.
- var requestToken = new RequestTokenMessage(ServiceProvider.RequestTokenEndpoint) {
+ var requestToken = new RequestTokenMessage(this.ServiceProvider.RequestTokenEndpoint) {
ConsumerKey = this.ConsumerKey,
ConsumerSecret = this.ConsumerSecret,
};
var requestTokenResponse = this.Channel.Request<UnauthorizedRequestTokenMessage>(requestToken);
+ this.TokenManager.StoreNewRequestToken(this.ConsumerKey, requestTokenResponse.RequestToken, requestTokenResponse.TokenSecret, null/*TODO*/);
// Request user authorization.
- var requestAuthorization = new DirectUserToServiceProviderMessage(ServiceProvider.UserAuthorizationEndpoint) {
+ var requestAuthorization = new DirectUserToServiceProviderMessage(this.ServiceProvider.UserAuthorizationEndpoint) {
Callback = callback,
RequestToken = requestTokenResponse.RequestToken,
};
this.Channel.Send(requestAuthorization);
this.PendingRequest = this.Channel.DequeueIndirectOrResponseMessage();
- return requestTokenResponse.TokenSecret;
}
- internal GrantAccessTokenMessage ProcessUserAuthorization(string requestTokenSecret) {
+ /// <summary>
+ /// Processes an incoming authorization-granted message from an SP and obtains an access token.
+ /// </summary>
+ /// <returns>The access token.</returns>
+ internal string ProcessUserAuthorization() {
var authorizationMessage = this.Channel.ReadFromRequest<DirectUserToConsumerMessage>();
-
+
// Exchange request token for access token.
- var requestAccess = new RequestAccessTokenMessage(ServiceProvider.AccessTokenEndpoint) {
+ string requestTokenSecret = this.TokenManager.GetTokenSecret(authorizationMessage.RequestToken);
+ var requestAccess = new RequestAccessTokenMessage(this.ServiceProvider.AccessTokenEndpoint) {
RequestToken = authorizationMessage.RequestToken,
TokenSecret = requestTokenSecret,
ConsumerKey = this.ConsumerKey,
ConsumerSecret = this.ConsumerSecret,
};
var grantAccess = this.Channel.Request<GrantAccessTokenMessage>(requestAccess);
- return grantAccess;
+ this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, authorizationMessage.RequestToken, grantAccess.AccessToken, grantAccess.TokenSecret);
+ return grantAccess.AccessToken;
}
}
}
diff --git a/src/DotNetOAuth/Messages/ITokenContainingMessage.cs b/src/DotNetOAuth/Messages/ITokenContainingMessage.cs index e0358f5..37322d6 100644 --- a/src/DotNetOAuth/Messages/ITokenContainingMessage.cs +++ b/src/DotNetOAuth/Messages/ITokenContainingMessage.cs @@ -5,7 +5,10 @@ //-----------------------------------------------------------------------
namespace DotNetOAuth.Messages {
- interface ITokenContainingMessage {
+ /// <summary>
+ /// An interface implemented by all OAuth messages that have a request or access token property.
+ /// </summary>
+ internal interface ITokenContainingMessage {
/// <summary>
/// Gets or sets the Request or Access Token.
/// </summary>
diff --git a/src/DotNetOAuth/Messages/MessageBase.cs b/src/DotNetOAuth/Messages/MessageBase.cs index 12f8b77..91530be 100644 --- a/src/DotNetOAuth/Messages/MessageBase.cs +++ b/src/DotNetOAuth/Messages/MessageBase.cs @@ -7,12 +7,11 @@ namespace DotNetOAuth.Messages {
using System;
using System.Collections.Generic;
+ using System.Globalization;
+ using System.Text;
using DotNetOAuth.ChannelElements;
using DotNetOAuth.Messaging;
- using DotNetOAuth.Messaging.Bindings;
using DotNetOAuth.Messaging.Reflection;
- using System.Text;
- using System.Globalization;
/// <summary>
/// A base class for all OAuth messages.
@@ -119,7 +118,8 @@ namespace DotNetOAuth.Messages { #endregion
/// <summary>
- /// Gets or sets whether security sensitive strings are emitted from the ToString() method.
+ /// Gets or sets a value indicating whether security sensitive strings are
+ /// emitted from the ToString() method.
/// </summary>
internal static bool LowSecurityMode { get; set; }
@@ -135,11 +135,15 @@ namespace DotNetOAuth.Messages { #endregion
+ /// <summary>
+ /// Returns a human-friendly string describing the message and all serializable properties.
+ /// </summary>
+ /// <returns>The string representation of this object.</returns>
public override string ToString() {
StringBuilder builder = new StringBuilder();
builder.AppendFormat(CultureInfo.InvariantCulture, "{0} message", GetType().Name);
- if (recipient != null) {
- builder.AppendFormat(CultureInfo.InvariantCulture, " as {0} to {1}", recipient.AllowedMethods, recipient.Location);
+ if (this.recipient != null) {
+ builder.AppendFormat(CultureInfo.InvariantCulture, " as {0} to {1}", this.recipient.AllowedMethods, this.recipient.Location);
}
builder.AppendLine();
MessageDictionary dictionary = new MessageDictionary(this);
diff --git a/src/DotNetOAuth/Messages/RequestTokenMessage.cs b/src/DotNetOAuth/Messages/RequestTokenMessage.cs index baadcdd..cab178a 100644 --- a/src/DotNetOAuth/Messages/RequestTokenMessage.cs +++ b/src/DotNetOAuth/Messages/RequestTokenMessage.cs @@ -5,9 +5,7 @@ //-----------------------------------------------------------------------
namespace DotNetOAuth.Messages {
- using System;
using DotNetOAuth.Messaging;
-using System.Collections.Generic;
/// <summary>
/// A direct message sent from Consumer to Service Provider to request a token.
diff --git a/src/DotNetOAuth/Messaging/Channel.cs b/src/DotNetOAuth/Messaging/Channel.cs index 95efbae..1d398aa 100644 --- a/src/DotNetOAuth/Messaging/Channel.cs +++ b/src/DotNetOAuth/Messaging/Channel.cs @@ -166,14 +166,33 @@ namespace DotNetOAuth.Messaging { /// </remarks>
/// <exception cref="InvalidOperationException">Thrown when <see cref="HttpContext.Current"/> is null.</exception>
internal IProtocolMessage ReadFromRequest() {
- return this.ReadFromRequest(GetRequestFromContext());
+ return this.ReadFromRequest(this.GetRequestFromContext());
}
+ /// <summary>
+ /// Gets the protocol message embedded in the given HTTP request, if present.
+ /// </summary>
+ /// <typeparam name="TREQUEST">The expected type of the message to be received.</typeparam>
+ /// <returns>The deserialized message, if one is found. Null otherwise.</returns>
+ /// <remarks>
+ /// Requires an HttpContext.Current context.
+ /// </remarks>
+ /// <exception cref="InvalidOperationException">Thrown when <see cref="HttpContext.Current"/> is null.</exception>
internal TREQUEST ReadFromRequest<TREQUEST>()
where TREQUEST : class, IProtocolMessage {
- return this.ReadFromRequest<TREQUEST>(GetRequestFromContext());
+ return this.ReadFromRequest<TREQUEST>(this.GetRequestFromContext());
}
+ /// <summary>
+ /// Gets the protocol message that may be embedded in the given HTTP request.
+ /// </summary>
+ /// <typeparam name="TREQUEST">The expected type of the message to be received.</typeparam>
+ /// <param name="httpRequest">The request to search for an embedded message.</param>
+ /// <returns>The deserialized message, if one is found. Null otherwise.</returns>
+ /// <exception cref="ProtocolException">
+ /// Thrown if no message is recognized in the request
+ /// or an unexpected type of message is received.
+ /// </exception>
protected internal TREQUEST ReadFromRequest<TREQUEST>(HttpRequestInfo httpRequest)
where TREQUEST : class, IProtocolMessage {
IProtocolMessage request = this.ReadFromRequest(httpRequest);
@@ -212,6 +231,16 @@ namespace DotNetOAuth.Messaging { return requestMessage;
}
+ /// <summary>
+ /// Sends a direct message to a remote party and waits for the response.
+ /// </summary>
+ /// <typeparam name="TRESPONSE">The expected type of the message to be received.</typeparam>
+ /// <param name="request">The message to send.</param>
+ /// <returns>The remote party's response.</returns>
+ /// <exception cref="ProtocolException">
+ /// Thrown if no message is recognized in the response
+ /// or an unexpected type of message is received.
+ /// </exception>
protected internal TRESPONSE Request<TRESPONSE>(IDirectedProtocolMessage request)
where TRESPONSE : class, IProtocolMessage {
IProtocolMessage response = this.Request(request);
diff --git a/src/DotNetOAuth/ServiceProvider.cs b/src/DotNetOAuth/ServiceProvider.cs index 25597d1..6b87079 100644 --- a/src/DotNetOAuth/ServiceProvider.cs +++ b/src/DotNetOAuth/ServiceProvider.cs @@ -27,6 +27,8 @@ namespace DotNetOAuth { /// <summary>
/// Initializes a new instance of the <see cref="ServiceProvider"/> class.
/// </summary>
+ /// <param name="endpoints">The endpoints on the Service Provider.</param>
+ /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
public ServiceProvider(ServiceProviderEndpoints endpoints, ITokenManager tokenManager) {
if (endpoints == null) {
throw new ArgumentNullException("endpoints");
@@ -35,7 +37,7 @@ namespace DotNetOAuth { throw new ArgumentNullException("tokenManager");
}
- SigningBindingElementBase signingElement = new PlainTextSigningBindingElement(TokenSignatureVerificationCallback);
+ SigningBindingElementBase signingElement = new PlainTextSigningBindingElement(this.TokenSignatureVerificationCallback);
INonceStore store = new NonceMemoryStore(StandardExpirationBindingElement.DefaultMaximumMessageAge);
this.Endpoints = endpoints;
this.Channel = new OAuthChannel(signingElement, store);
@@ -49,17 +51,23 @@ namespace DotNetOAuth { public ServiceProviderEndpoints Endpoints { get; private set; }
/// <summary>
+ /// Gets the pending user agent redirect based message to be sent as an HttpResponse.
+ /// </summary>
+ public Response PendingRequest { get; private set; }
+
+ /// <summary>
/// Gets or sets the channel to use for sending/receiving messages.
/// </summary>
internal OAuthChannel Channel { get; set; }
/// <summary>
- /// Gets the pending user agent redirect based message to be sent as an HttpResponse.
+ /// Gets or sets the generator responsible for generating new tokens and secrets.
/// </summary>
- public Response PendingRequest { get; private set; }
-
internal ITokenGenerator TokenGenerator { get; set; }
+ /// <summary>
+ /// Gets the persistence store for tokens and secrets.
+ /// </summary>
internal ITokenManager TokenManager { get; private set; }
internal RequestTokenMessage ReadTokenRequest() {
@@ -75,9 +83,9 @@ namespace DotNetOAuth { }
internal void SendUnauthorizedTokenResponse(RequestTokenMessage request) {
- string token = TokenGenerator.GenerateRequestToken(request.ConsumerKey);
- string secret = TokenGenerator.GenerateSecret();
- TokenManager.StoreNewRequestToken(request.ConsumerKey, token, secret, null/*add params*/);
+ string token = this.TokenGenerator.GenerateRequestToken(request.ConsumerKey);
+ string secret = this.TokenGenerator.GenerateSecret();
+ this.TokenManager.StoreNewRequestToken(request.ConsumerKey, token, secret, null/*add params*/);
UnauthorizedRequestTokenMessage response = new UnauthorizedRequestTokenMessage {
RequestToken = token,
TokenSecret = secret,
@@ -119,9 +127,9 @@ namespace DotNetOAuth { }
internal void SendAccessToken(RequestAccessTokenMessage request) {
- string accessToken = TokenGenerator.GenerateAccessToken(request.ConsumerKey);
- string tokenSecret = TokenGenerator.GenerateSecret();
- TokenManager.ExpireRequestTokenAndStoreNewAccessToken(request.ConsumerKey, request.RequestToken, accessToken, tokenSecret);
+ string accessToken = this.TokenGenerator.GenerateAccessToken(request.ConsumerKey);
+ string tokenSecret = this.TokenGenerator.GenerateSecret();
+ this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(request.ConsumerKey, request.RequestToken, accessToken, tokenSecret);
var grantAccess = new GrantAccessTokenMessage {
AccessToken = accessToken,
TokenSecret = tokenSecret,
@@ -131,16 +139,17 @@ namespace DotNetOAuth { }
private void TokenSignatureVerificationCallback(ITamperResistantOAuthMessage message) {
- message.ConsumerSecret = TokenManager.GetConsumerSecret(message.ConsumerKey);
+ message.ConsumerSecret = this.TokenManager.GetConsumerSecret(message.ConsumerKey);
var tokenMessage = message as ITokenContainingMessage;
if (tokenMessage != null) {
- message.TokenSecret = TokenManager.GetTokenSecret(tokenMessage.Token);
+ message.TokenSecret = this.TokenManager.GetTokenSecret(tokenMessage.Token);
}
- //message.Recipient
- //message.AdditionalParametersInHttpRequest
- //message.HttpMethod
+ // TODO: more complete filling of message properties.
+ ////message.Recipient =
+ ////message.AdditionalParametersInHttpRequest =
+ ////message.HttpMethod =
}
}
}
diff --git a/src/DotNetOAuth/ServiceProviderEndpoints.cs b/src/DotNetOAuth/ServiceProviderEndpoints.cs index e4dcf18..e635ad2 100644 --- a/src/DotNetOAuth/ServiceProviderEndpoints.cs +++ b/src/DotNetOAuth/ServiceProviderEndpoints.cs @@ -23,7 +23,7 @@ namespace DotNetOAuth { /// <summary>
/// Initializes a new instance of the <see cref="ServiceProviderEndpoints"/> class.
/// </summary>
- public ServiceProviderEndpoints(){
+ public ServiceProviderEndpoints() {
}
/// <summary>
|