summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2008-09-25 08:31:40 -0700
committerAndrew <andrewarnott@gmail.com>2008-09-25 08:31:40 -0700
commita9fb696c40441e06ef817d7e28bae74c6a6cb6e4 (patch)
treee78f45395a2cee9592bceed86f3cbf2aba7c9022
parente99268dcde5f942a2577a2d4d271febf991b6fa1 (diff)
downloadDotNetOpenAuth-a9fb696c40441e06ef817d7e28bae74c6a6cb6e4.zip
DotNetOpenAuth-a9fb696c40441e06ef817d7e28bae74c6a6cb6e4.tar.gz
DotNetOpenAuth-a9fb696c40441e06ef817d7e28bae74c6a6cb6e4.tar.bz2
Added enough token management that the Appendix A scenario test is passing again.
-rw-r--r--src/DotNetOAuth.Test/DotNetOAuth.Test.csproj3
-rw-r--r--src/DotNetOAuth.Test/Mocks/InMemoryTokenManager.cs37
-rw-r--r--src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs27
-rw-r--r--src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs5
-rw-r--r--src/DotNetOAuth.Test/ServiceProviderEndpointsTests.cs (renamed from src/DotNetOAuth.Test/ServiceProviderTests.cs)14
-rw-r--r--src/DotNetOAuth/ChannelElements/ITamperResistantOAuthMessage.cs5
-rw-r--r--src/DotNetOAuth/ChannelElements/ITokenGenerator.cs18
-rw-r--r--src/DotNetOAuth/ChannelElements/ITokenManager.cs37
-rw-r--r--src/DotNetOAuth/ChannelElements/StandardTokenGenerator.cs39
-rw-r--r--src/DotNetOAuth/Consumer.cs2
-rw-r--r--src/DotNetOAuth/DotNetOAuth.csproj5
-rw-r--r--src/DotNetOAuth/Messages/AccessProtectedResourcesMessage.cs16
-rw-r--r--src/DotNetOAuth/Messages/ITokenContainingMessage.cs14
-rw-r--r--src/DotNetOAuth/Messages/OAuth Messages.cd39
-rw-r--r--src/DotNetOAuth/Messages/RequestAccessTokenMessage.cs16
-rw-r--r--src/DotNetOAuth/Messages/RequestTokenMessage.cs7
-rw-r--r--src/DotNetOAuth/Messages/SignedMessageBase.cs7
-rw-r--r--src/DotNetOAuth/ServiceProvider.cs87
-rw-r--r--src/DotNetOAuth/ServiceProviderEndpoints.cs71
19 files changed, 339 insertions, 110 deletions
diff --git a/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj b/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj
index 6551281..8771050 100644
--- a/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj
+++ b/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj
@@ -70,6 +70,7 @@
<Compile Include="Messaging\Bindings\StandardExpirationBindingElementTests.cs" />
<Compile Include="Messaging\Reflection\MessagePartTests.cs" />
<Compile Include="Messaging\Reflection\ValueMappingTests.cs" />
+ <Compile Include="Mocks\InMemoryTokenManager.cs" />
<Compile Include="Mocks\MockTransformationBindingElement.cs" />
<Compile Include="Mocks\MockReplayProtectionBindingElement.cs" />
<Compile Include="Mocks\TestBaseMessage.cs" />
@@ -91,7 +92,7 @@
<Compile Include="Scenarios\AppendixScenarios.cs" />
<Compile Include="Scenarios\CoordinatingOAuthChannel.cs" />
<Compile Include="Scenarios\Coordinator.cs" />
- <Compile Include="ServiceProviderTests.cs" />
+ <Compile Include="ServiceProviderEndpointsTests.cs" />
<Compile Include="TestBase.cs" />
<Compile Include="UriUtilTests.cs" />
</ItemGroup>
diff --git a/src/DotNetOAuth.Test/Mocks/InMemoryTokenManager.cs b/src/DotNetOAuth.Test/Mocks/InMemoryTokenManager.cs
new file mode 100644
index 0000000..002eee1
--- /dev/null
+++ b/src/DotNetOAuth.Test/Mocks/InMemoryTokenManager.cs
@@ -0,0 +1,37 @@
+namespace DotNetOAuth.Test.Mocks {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOAuth.ChannelElements;
+
+ internal class InMemoryTokenManager : ITokenManager {
+ Dictionary<string, string> consumersAndSecrets = new Dictionary<string, string>();
+ Dictionary<string, string> tokensAndSecrets = new Dictionary<string, string>();
+
+ #region ITokenManager Members
+
+ public string GetConsumerSecret(string consumerKey) {
+ return consumersAndSecrets[consumerKey];
+ }
+
+ public string GetTokenSecret(string token) {
+ return tokensAndSecrets[token];
+ }
+
+ public void StoreNewRequestToken(string consumerKey, string requestToken, string requestTokenSecret, IDictionary<string, string> parameters) {
+ tokensAndSecrets[requestToken] = requestTokenSecret;
+ }
+
+ public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) {
+ tokensAndSecrets.Remove(requestToken);
+ tokensAndSecrets[accessToken] = accessTokenSecret;
+ }
+
+ #endregion
+
+ internal void AddConsumer(string key, string secret) {
+ consumersAndSecrets.Add(key, secret);
+ }
+ }
+}
diff --git a/src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs b/src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs
index 86d5d43..563fac3 100644
--- a/src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs
+++ b/src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs
@@ -8,45 +8,50 @@ 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.Test.Mocks;
[TestClass]
public class AppendixScenarios : TestBase {
[TestMethod]
public void SpecAppendixAExample() {
- ServiceProvider sp = new ServiceProvider {
+ ServiceProviderEndpoints spEndpoints = 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 {
+ ConsumerKey = "dpf43f3p2l4k3l03",
+ ConsumerSecret = "kd94hf93k423kf44",
+ ServiceProvider = spEndpoints,
+ };
Coordinator coordinator = new Coordinator(
channel => {
- Consumer consumer = new Consumer {
- Channel = channel,
- ConsumerKey = "dpf43f3p2l4k3l03",
- ConsumerSecret = "kd94hf93k423kf44",
- ServiceProvider = sp,
- };
-
+ consumer.Channel = channel;
string requestTokenSecret = consumer.RequestUserAuthorization(new Uri("http://printer.example.com/request_token_ready"));
var accessTokenMessage = consumer.ProcessUserAuthorization(requestTokenSecret);
},
channel => {
+ tokenManager.AddConsumer(consumer.ConsumerKey, consumer.ConsumerSecret);
sp.Channel = channel;
var requestTokenMessage = sp.ReadTokenRequest();
- sp.SendUnauthorizedTokenResponse("hh5s93j4hdidpola", "hdhd0244k9j7ao03");
+ sp.SendUnauthorizedTokenResponse(requestTokenMessage);
var authRequest = sp.ReadAuthorizationRequest();
sp.SendAuthorizationResponse(authRequest);
var accessRequest = sp.ReadAccessTokenRequest();
- sp.SendAccessToken("nnch734d00sl2jdk", "pfkkdhi9sl3r4s00");
+ sp.SendAccessToken(accessRequest);
});
- coordinator.SigningElement = new PlainTextSigningBindingElement();
+ coordinator.SigningElement = (SigningBindingElementBase)sp.Channel.BindingElements.Single(el => el is SigningBindingElementBase);
coordinator.Start();
}
}
diff --git a/src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs b/src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs
index 1de449a..2a42983 100644
--- a/src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs
+++ b/src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs
@@ -16,6 +16,7 @@ namespace DotNetOAuth.Test.Scenarios {
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using DotNetOAuth.Messaging.Reflection;
+ using DotNetOAuth.Messages;
/// <summary>
/// A special channel used in test simulations to pass messages directly between two parties.
@@ -92,8 +93,10 @@ namespace DotNetOAuth.Test.Scenarios {
directedMessage.Recipient,
directedMessage.HttpMethods);
cloned = (T)ctor.Invoke(new object[] { endpoint });
+ } else if ((ctor = message.GetType().GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null)) != null) {
+ cloned = (T)ctor.Invoke(new object[0]);
} else {
- throw new InvalidOperationException("Unrecognized constructor signature.");
+ throw new InvalidOperationException("Unrecognized constructor signature on type " + message.GetType());
}
} else {
cloned = (T)Activator.CreateInstance(message.GetType(), true);
diff --git a/src/DotNetOAuth.Test/ServiceProviderTests.cs b/src/DotNetOAuth.Test/ServiceProviderEndpointsTests.cs
index 001bacf..513f880 100644
--- a/src/DotNetOAuth.Test/ServiceProviderTests.cs
+++ b/src/DotNetOAuth.Test/ServiceProviderEndpointsTests.cs
@@ -1,5 +1,5 @@
//-----------------------------------------------------------------------
-// <copyright file="ServiceProviderTests.cs" company="Andrew Arnott">
+// <copyright file="ServiceProviderEndpointsTests.cs" company="Andrew Arnott">
// Copyright (c) Andrew Arnott. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
@@ -10,16 +10,16 @@ namespace DotNetOAuth.Test {
using Microsoft.VisualStudio.TestTools.UnitTesting;
/// <summary>
- /// Tests for the <see cref="ServiceProvider"/> class.
+ /// Tests for the <see cref="ServiceProviderEndpoints"/> class.
/// </summary>
[TestClass]
- public class ServiceProviderTests : TestBase {
+ public class ServiceProviderEndpointsTests : TestBase {
/// <summary>
/// A test for UserAuthorizationUri
/// </summary>
[TestMethod]
public void UserAuthorizationUriTest() {
- ServiceProvider target = new ServiceProvider();
+ ServiceProviderEndpoints target = new ServiceProviderEndpoints();
ServiceProviderEndpoint expected = new ServiceProviderEndpoint("http://localhost/authorization", HttpDeliveryMethod.GetRequest);
ServiceProviderEndpoint actual;
target.UserAuthorizationEndpoint = expected;
@@ -35,7 +35,7 @@ namespace DotNetOAuth.Test {
/// </summary>
[TestMethod]
public void RequestTokenUriTest() {
- ServiceProvider target = new ServiceProvider();
+ var target = new ServiceProviderEndpoints();
ServiceProviderEndpoint expected = new ServiceProviderEndpoint("http://localhost/requesttoken", HttpDeliveryMethod.GetRequest);
ServiceProviderEndpoint actual;
target.RequestTokenEndpoint = expected;
@@ -52,7 +52,7 @@ namespace DotNetOAuth.Test {
/// </summary>
[TestMethod, ExpectedException(typeof(ArgumentException))]
public void RequestTokenUriWithOAuthParametersTest() {
- ServiceProvider target = new ServiceProvider();
+ var target = new ServiceProviderEndpoints();
target.RequestTokenEndpoint = new ServiceProviderEndpoint("http://localhost/requesttoken?oauth_token=something", HttpDeliveryMethod.GetRequest);
}
@@ -61,7 +61,7 @@ namespace DotNetOAuth.Test {
/// </summary>
[TestMethod]
public void AccessTokenUriTest() {
- ServiceProvider target = new ServiceProvider();
+ var target = new ServiceProviderEndpoints();
ServiceProviderEndpoint expected = new ServiceProviderEndpoint("http://localhost/accesstoken", HttpDeliveryMethod.GetRequest);
ServiceProviderEndpoint actual;
target.AccessTokenEndpoint = expected;
diff --git a/src/DotNetOAuth/ChannelElements/ITamperResistantOAuthMessage.cs b/src/DotNetOAuth/ChannelElements/ITamperResistantOAuthMessage.cs
index 6077fb7..a7f9892 100644
--- a/src/DotNetOAuth/ChannelElements/ITamperResistantOAuthMessage.cs
+++ b/src/DotNetOAuth/ChannelElements/ITamperResistantOAuthMessage.cs
@@ -24,6 +24,11 @@ namespace DotNetOAuth.ChannelElements {
string TokenSecret { get; set; }
/// <summary>
+ /// Gets or sets the Consumer key.
+ /// </summary>
+ string ConsumerKey { get; set; }
+
+ /// <summary>
/// Gets or sets the Consumer Secret used to sign the message.
/// </summary>
string ConsumerSecret { get; set; }
diff --git a/src/DotNetOAuth/ChannelElements/ITokenGenerator.cs b/src/DotNetOAuth/ChannelElements/ITokenGenerator.cs
new file mode 100644
index 0000000..45bc5b2
--- /dev/null
+++ b/src/DotNetOAuth/ChannelElements/ITokenGenerator.cs
@@ -0,0 +1,18 @@
+//-----------------------------------------------------------------------
+// <copyright file="ITokenGenerator.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ internal interface ITokenGenerator {
+ string GenerateRequestToken(string consumerKey);
+ string GenerateAccessToken(string consumerKey);
+ string GenerateSecret();
+ }
+}
diff --git a/src/DotNetOAuth/ChannelElements/ITokenManager.cs b/src/DotNetOAuth/ChannelElements/ITokenManager.cs
new file mode 100644
index 0000000..ee3124a
--- /dev/null
+++ b/src/DotNetOAuth/ChannelElements/ITokenManager.cs
@@ -0,0 +1,37 @@
+//-----------------------------------------------------------------------
+// <copyright file="ITokenManager.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ public interface ITokenManager {
+ string GetConsumerSecret(string consumerKey);
+ string GetTokenSecret(string token);
+
+ /// <summary>
+ ///
+ /// </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>
+ void StoreNewRequestToken(string consumerKey, string requestToken, string requestTokenSecret, IDictionary<string, string> parameters);
+
+ /// <summary>
+ ///
+ /// </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>
+ void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret);
+ }
+}
diff --git a/src/DotNetOAuth/ChannelElements/StandardTokenGenerator.cs b/src/DotNetOAuth/ChannelElements/StandardTokenGenerator.cs
new file mode 100644
index 0000000..b54da20
--- /dev/null
+++ b/src/DotNetOAuth/ChannelElements/StandardTokenGenerator.cs
@@ -0,0 +1,39 @@
+//-----------------------------------------------------------------------
+// <copyright file="StandardTokenGenerator.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Security.Cryptography;
+
+ internal class StandardTokenGenerator : ITokenGenerator {
+ RandomNumberGenerator cryptoProvider = new RNGCryptoServiceProvider();
+
+ #region ITokenGenerator Members
+
+ public string GenerateRequestToken(string consumerKey) {
+ return GenerateCryptographicallyStrongString();
+ }
+
+ public string GenerateAccessToken(string consumerKey) {
+ return GenerateCryptographicallyStrongString();
+ }
+
+ public string GenerateSecret() {
+ return GenerateCryptographicallyStrongString();
+ }
+
+ #endregion
+
+ private string GenerateCryptographicallyStrongString() {
+ byte[] buffer = new byte[20];
+ cryptoProvider.GetBytes(buffer);
+ return Convert.ToBase64String(buffer);
+ }
+ }
+}
diff --git a/src/DotNetOAuth/Consumer.cs b/src/DotNetOAuth/Consumer.cs
index f8f22fd..be5d4a5 100644
--- a/src/DotNetOAuth/Consumer.cs
+++ b/src/DotNetOAuth/Consumer.cs
@@ -39,7 +39,7 @@ namespace DotNetOAuth {
/// <summary>
/// Gets or sets the Service Provider that will be accessed.
/// </summary>
- public ServiceProvider ServiceProvider { get; set; }
+ public ServiceProviderEndpoints ServiceProvider { get; set; }
/// <summary>
/// Gets the pending user agent redirect based message to be sent as an HttpResponse.
diff --git a/src/DotNetOAuth/DotNetOAuth.csproj b/src/DotNetOAuth/DotNetOAuth.csproj
index 7e7b567..54a3957 100644
--- a/src/DotNetOAuth/DotNetOAuth.csproj
+++ b/src/DotNetOAuth/DotNetOAuth.csproj
@@ -57,8 +57,13 @@
<Reference Include="System.XML" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="ChannelElements\ITokenGenerator.cs" />
+ <Compile Include="ChannelElements\ITokenManager.cs" />
<Compile Include="ChannelElements\PlainTextSigningBindingElement.cs" />
<Compile Include="ChannelElements\HmacSha1SigningBindingElement.cs" />
+ <Compile Include="ChannelElements\StandardTokenGenerator.cs" />
+ <Compile Include="ServiceProviderEndpoints.cs" />
+ <Compile Include="Messages\ITokenContainingMessage.cs" />
<Compile Include="Messages\SignedMessageBase.cs" />
<Compile Include="Messaging\Bindings\NonceMemoryStore.cs" />
<Compile Include="ChannelElements\SigningBindingElementBase.cs" />
diff --git a/src/DotNetOAuth/Messages/AccessProtectedResourcesMessage.cs b/src/DotNetOAuth/Messages/AccessProtectedResourcesMessage.cs
index 8b8c1d5..85db448 100644
--- a/src/DotNetOAuth/Messages/AccessProtectedResourcesMessage.cs
+++ b/src/DotNetOAuth/Messages/AccessProtectedResourcesMessage.cs
@@ -12,7 +12,7 @@ namespace DotNetOAuth.Messages {
/// A message attached to a request for protected resources that provides the necessary
/// credentials to be granted access to those resources.
/// </summary>
- internal class AccessProtectedResourcesMessage : SignedMessageBase {
+ internal class AccessProtectedResourcesMessage : SignedMessageBase, ITokenContainingMessage {
/// <summary>
/// Initializes a new instance of the <see cref="AccessProtectedResourcesMessage"/> class.
/// </summary>
@@ -22,15 +22,17 @@ namespace DotNetOAuth.Messages {
}
/// <summary>
- /// Gets or sets the Consumer key.
- /// </summary>
- [MessagePart(Name = "oauth_consumer_key", IsRequired = true)]
- public string ConsumerKey { get; set; }
-
- /// <summary>
/// Gets or sets the Access Token.
/// </summary>
[MessagePart(Name = "oauth_token", IsRequired = true)]
public string AccessToken { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Token.
+ /// </summary>
+ string ITokenContainingMessage.Token {
+ get { return this.AccessToken; }
+ set { this.AccessToken = value; }
+ }
}
}
diff --git a/src/DotNetOAuth/Messages/ITokenContainingMessage.cs b/src/DotNetOAuth/Messages/ITokenContainingMessage.cs
new file mode 100644
index 0000000..e0358f5
--- /dev/null
+++ b/src/DotNetOAuth/Messages/ITokenContainingMessage.cs
@@ -0,0 +1,14 @@
+//-----------------------------------------------------------------------
+// <copyright file="ITokenContainingMessage.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Messages {
+ interface ITokenContainingMessage {
+ /// <summary>
+ /// Gets or sets the Request or Access Token.
+ /// </summary>
+ string Token { get; set; }
+ }
+}
diff --git a/src/DotNetOAuth/Messages/OAuth Messages.cd b/src/DotNetOAuth/Messages/OAuth Messages.cd
index 9b3e367..634a154 100644
--- a/src/DotNetOAuth/Messages/OAuth Messages.cd
+++ b/src/DotNetOAuth/Messages/OAuth Messages.cd
@@ -3,7 +3,7 @@
<Class Name="DotNetOAuth.Messages.AccessProtectedResourcesMessage">
<Position X="0.5" Y="7.5" Width="3.5" />
<TypeIdentifier>
- <HashCode>AAAAAAAAAAAAAAAAAAAAAgAAEAAAAAAAAAAAAAAAAAA=</HashCode>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Messages\AccessProtectedResourcesMessage.cs</FileName>
</TypeIdentifier>
</Class>
@@ -61,7 +61,7 @@
<Compartment Name="Fields" Collapsed="true" />
</Compartments>
<TypeIdentifier>
- <HashCode>AAAKAAAAYAAAAAAAAIAAAAAAAAQEIAAAAgCAACAAAAA=</HashCode>
+ <HashCode>AAAKAAAAYAAAAAAEAIAAAAAAAAQEIBAAIgCAACAAAAA=</HashCode>
<FileName>Messages\MessageBase.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
@@ -73,15 +73,15 @@
</Compartments>
<InheritanceLine Type="DotNetOAuth.Messages.SignedMessageBase" ManuallyRouted="true" FixedFromPoint="true" FixedToPoint="true">
<Path>
- <Point X="4.75" Y="7.625" />
- <Point X="4.5" Y="7.625" />
+ <Point X="4.75" Y="7.669" />
+ <Point X="4.5" Y="7.669" />
<Point X="4.5" Y="7.153" />
<Point X="3.125" Y="7.153" />
- <Point X="3.125" Y="6.627" />
+ <Point X="3.125" Y="6.435" />
</Path>
</InheritanceLine>
<TypeIdentifier>
- <HashCode>AAAAAAAAAAAAAAAAAAAAAgAAAIAAAAAAAAAAAAAAAAA=</HashCode>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Messages\RequestAccessTokenMessage.cs</FileName>
</TypeIdentifier>
</Class>
@@ -94,34 +94,33 @@
</Compartments>
<InheritanceLine Type="DotNetOAuth.Messages.SignedMessageBase" FixedFromPoint="true">
<Path>
- <Point X="4.75" Y="6.875" />
- <Point X="4.375" Y="6.875" />
+ <Point X="4.75" Y="6.881" />
+ <Point X="4.375" Y="6.881" />
<Point X="4.375" Y="4.877" />
<Point X="4.75" Y="4.877" />
- <Point X="4.75" Y="1.496" />
- <Point X="3.5" Y="1.496" />
+ <Point X="4.75" Y="1.27" />
+ <Point X="3.5" Y="1.27" />
</Path>
</InheritanceLine>
<TypeIdentifier>
- <HashCode>AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Messages\RequestTokenMessage.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="DotNetOAuth.Messages.SignedMessageBase">
<Position X="4.75" Y="6.75" Width="3.5" />
- <InheritanceLine Type="DotNetOAuth.Messages.MessageBase" ManuallyRouted="true" FixedToPoint="true">
- <Path>
- <Point X="6.75" Y="4.478" />
- <Point X="6.75" Y="5.104" />
- <Point X="7.5" Y="5.104" />
- <Point X="7.5" Y="6.75" />
- </Path>
- </InheritanceLine>
<TypeIdentifier>
- <HashCode>IAAAFAAAAIAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <HashCode>IAAAFAAAAIAAAAAAAACAAgAAAgAAIAQAAAAAoAAQAAA=</HashCode>
<FileName>Messages\SignedMessageBase.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
+ <Interface Name="DotNetOAuth.ChannelElements.ITamperResistantOAuthMessage" Collapsed="true">
+ <Position X="10.25" Y="7.75" Width="1.5" />
+ <TypeIdentifier>
+ <HashCode>AIAAAAAAAAAAAAAAAIAAAhAAAAAAIAQAAAAAAAAAAAA=</HashCode>
+ <FileName>ChannelElements\ITamperResistantOAuthMessage.cs</FileName>
+ </TypeIdentifier>
+ </Interface>
<Font Name="Segoe UI" Size="9" />
</ClassDiagram> \ No newline at end of file
diff --git a/src/DotNetOAuth/Messages/RequestAccessTokenMessage.cs b/src/DotNetOAuth/Messages/RequestAccessTokenMessage.cs
index 143b67d..8b7adee 100644
--- a/src/DotNetOAuth/Messages/RequestAccessTokenMessage.cs
+++ b/src/DotNetOAuth/Messages/RequestAccessTokenMessage.cs
@@ -12,7 +12,7 @@ namespace DotNetOAuth.Messages {
/// A direct message sent by the Consumer to exchange a Request Token for an Access Token
/// and Token Secret.
/// </summary>
- internal class RequestAccessTokenMessage : SignedMessageBase {
+ internal class RequestAccessTokenMessage : SignedMessageBase, ITokenContainingMessage {
/// <summary>
/// Initializes a new instance of the <see cref="RequestAccessTokenMessage"/> class.
/// </summary>
@@ -22,15 +22,17 @@ namespace DotNetOAuth.Messages {
}
/// <summary>
- /// Gets or sets the Consumer Key.
- /// </summary>
- [MessagePart(Name = "oauth_consumer_key", IsRequired = true)]
- public string ConsumerKey { get; set; }
-
- /// <summary>
/// Gets or sets the Request Token.
/// </summary>
[MessagePart(Name = "oauth_token", IsRequired = true)]
public string RequestToken { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Token.
+ /// </summary>
+ string ITokenContainingMessage.Token {
+ get { return this.RequestToken; }
+ set { this.RequestToken = value; }
+ }
}
}
diff --git a/src/DotNetOAuth/Messages/RequestTokenMessage.cs b/src/DotNetOAuth/Messages/RequestTokenMessage.cs
index 2a8cdfe..baadcdd 100644
--- a/src/DotNetOAuth/Messages/RequestTokenMessage.cs
+++ b/src/DotNetOAuth/Messages/RequestTokenMessage.cs
@@ -7,6 +7,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.
@@ -19,11 +20,5 @@ namespace DotNetOAuth.Messages {
internal RequestTokenMessage(ServiceProviderEndpoint serviceProvider)
: base(MessageTransport.Direct, serviceProvider) {
}
-
- /// <summary>
- /// Gets or sets the consumer key.
- /// </summary>
- [MessagePart(Name = "oauth_consumer_key", IsRequired = true)]
- public string ConsumerKey { get; set; }
}
}
diff --git a/src/DotNetOAuth/Messages/SignedMessageBase.cs b/src/DotNetOAuth/Messages/SignedMessageBase.cs
index 460a509..28026e6 100644
--- a/src/DotNetOAuth/Messages/SignedMessageBase.cs
+++ b/src/DotNetOAuth/Messages/SignedMessageBase.cs
@@ -58,6 +58,12 @@ namespace DotNetOAuth.Messages {
public string TokenSecret { get; set; }
/// <summary>
+ /// Gets or sets the Consumer key.
+ /// </summary>
+ [MessagePart(Name = "oauth_consumer_key", IsRequired = true)]
+ public string ConsumerKey { get; set; }
+
+ /// <summary>
/// Gets or sets the Consumer Secret used to sign the message.
/// Only applicable to Consumer.
/// </summary>
@@ -71,7 +77,6 @@ namespace DotNetOAuth.Messages {
/// <summary>
/// Gets or sets the extra, non-OAuth parameters that will be included in the request.
- /// Only applicable to Consumer.
/// </summary>
IDictionary<string, string> ITamperResistantOAuthMessage.AdditionalParametersInHttpRequest { get; set; }
diff --git a/src/DotNetOAuth/ServiceProvider.cs b/src/DotNetOAuth/ServiceProvider.cs
index 327e5ca..25597d1 100644
--- a/src/DotNetOAuth/ServiceProvider.cs
+++ b/src/DotNetOAuth/ServiceProvider.cs
@@ -25,60 +25,28 @@ namespace DotNetOAuth {
/// </remarks>
public class ServiceProvider {
/// <summary>
- /// The field used to store the value of the <see cref="RequestTokenEndpoint"/> property.
- /// </summary>
- private ServiceProviderEndpoint requestTokenEndpoint;
-
- /// <summary>
/// Initializes a new instance of the <see cref="ServiceProvider"/> class.
/// </summary>
- public ServiceProvider() {
- SigningBindingElementBase signingElement = new PlainTextSigningBindingElement(/*TODO*/);
- INonceStore store = new NonceMemoryStore(StandardExpirationBindingElement.DefaultMaximumMessageAge);
- this.Channel = new OAuthChannel(signingElement, store);
- }
-
- /// <summary>
- /// Gets or sets the URL used to obtain an unauthorized Request Token,
- /// described in Section 6.1 (Obtaining an Unauthorized Request Token).
- /// </summary>
- /// <remarks>
- /// The request URL query MUST NOT contain any OAuth Protocol Parameters.
- /// This is the URL that <see cref="Messages.RequestTokenMessage"/> messages are directed to.
- /// </remarks>
- /// <exception cref="ArgumentException">Thrown if this property is set to a URI with OAuth protocol parameters.</exception>
- public ServiceProviderEndpoint RequestTokenEndpoint {
- get {
- return this.requestTokenEndpoint;
+ public ServiceProvider(ServiceProviderEndpoints endpoints, ITokenManager tokenManager) {
+ if (endpoints == null) {
+ throw new ArgumentNullException("endpoints");
}
-
- set {
- if (value != null && UriUtil.QueryStringContainsOAuthParameters(value.Location)) {
- throw new ArgumentException(Strings.RequestUrlMustNotHaveOAuthParameters);
- }
-
- this.requestTokenEndpoint = value;
+ if (tokenManager == null) {
+ throw new ArgumentNullException("tokenManager");
}
- }
- /// <summary>
- /// Gets or sets the URL used to obtain User authorization for Consumer access,
- /// described in Section 6.2 (Obtaining User Authorization).
- /// </summary>
- /// <remarks>
- /// This is the URL that <see cref="Messages.DirectUserToServiceProviderMessage"/> messages are
- /// indirectly (via the user agent) sent to.
- /// </remarks>
- public ServiceProviderEndpoint UserAuthorizationEndpoint { get; set; }
+ SigningBindingElementBase signingElement = new PlainTextSigningBindingElement(TokenSignatureVerificationCallback);
+ INonceStore store = new NonceMemoryStore(StandardExpirationBindingElement.DefaultMaximumMessageAge);
+ this.Endpoints = endpoints;
+ this.Channel = new OAuthChannel(signingElement, store);
+ this.TokenGenerator = new StandardTokenGenerator();
+ this.TokenManager = tokenManager;
+ }
/// <summary>
- /// Gets or sets the URL used to exchange the User-authorized Request Token
- /// for an Access Token, described in Section 6.3 (Obtaining an Access Token).
+ /// Gets the endpoints exposed by this Service Provider.
/// </summary>
- /// <remarks>
- /// This is the URL that <see cref="Messages.RequestAccessTokenMessage"/> messages are directed to.
- /// </remarks>
- public ServiceProviderEndpoint AccessTokenEndpoint { get; set; }
+ public ServiceProviderEndpoints Endpoints { get; private set; }
/// <summary>
/// Gets or sets the channel to use for sending/receiving messages.
@@ -90,6 +58,10 @@ namespace DotNetOAuth {
/// </summary>
public Response PendingRequest { get; private set; }
+ internal ITokenGenerator TokenGenerator { get; set; }
+
+ internal ITokenManager TokenManager { get; private set; }
+
internal RequestTokenMessage ReadTokenRequest() {
return this.Channel.ReadFromRequest<RequestTokenMessage>();
}
@@ -102,7 +74,10 @@ namespace DotNetOAuth {
return this.Channel.ReadFromRequest<RequestTokenMessage>(request);
}
- internal void SendUnauthorizedTokenResponse(string token, string secret) {
+ internal void SendUnauthorizedTokenResponse(RequestTokenMessage request) {
+ string token = TokenGenerator.GenerateRequestToken(request.ConsumerKey);
+ string secret = TokenGenerator.GenerateSecret();
+ TokenManager.StoreNewRequestToken(request.ConsumerKey, token, secret, null/*add params*/);
UnauthorizedRequestTokenMessage response = new UnauthorizedRequestTokenMessage {
RequestToken = token,
TokenSecret = secret,
@@ -143,7 +118,10 @@ namespace DotNetOAuth {
return this.Channel.ReadFromRequest<RequestAccessTokenMessage>(request);
}
- internal void SendAccessToken(string accessToken, string tokenSecret) {
+ internal void SendAccessToken(RequestAccessTokenMessage request) {
+ string accessToken = TokenGenerator.GenerateAccessToken(request.ConsumerKey);
+ string tokenSecret = TokenGenerator.GenerateSecret();
+ TokenManager.ExpireRequestTokenAndStoreNewAccessToken(request.ConsumerKey, request.RequestToken, accessToken, tokenSecret);
var grantAccess = new GrantAccessTokenMessage {
AccessToken = accessToken,
TokenSecret = tokenSecret,
@@ -151,5 +129,18 @@ namespace DotNetOAuth {
this.Channel.Send(grantAccess);
}
+
+ private void TokenSignatureVerificationCallback(ITamperResistantOAuthMessage message) {
+ message.ConsumerSecret = TokenManager.GetConsumerSecret(message.ConsumerKey);
+
+ var tokenMessage = message as ITokenContainingMessage;
+ if (tokenMessage != null) {
+ message.TokenSecret = TokenManager.GetTokenSecret(tokenMessage.Token);
+ }
+
+ //message.Recipient
+ //message.AdditionalParametersInHttpRequest
+ //message.HttpMethod
+ }
}
}
diff --git a/src/DotNetOAuth/ServiceProviderEndpoints.cs b/src/DotNetOAuth/ServiceProviderEndpoints.cs
new file mode 100644
index 0000000..e4dcf18
--- /dev/null
+++ b/src/DotNetOAuth/ServiceProviderEndpoints.cs
@@ -0,0 +1,71 @@
+//-----------------------------------------------------------------------
+// <copyright file="ServiceProviderEndpoints.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOAuth.Messaging;
+
+ /// <summary>
+ /// A description of the endpoints on a Service Provider.
+ /// </summary>
+ public class ServiceProviderEndpoints {
+ /// <summary>
+ /// The field used to store the value of the <see cref="RequestTokenEndpoint"/> property.
+ /// </summary>
+ private ServiceProviderEndpoint requestTokenEndpoint;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ServiceProviderEndpoints"/> class.
+ /// </summary>
+ public ServiceProviderEndpoints(){
+ }
+
+ /// <summary>
+ /// Gets or sets the URL used to obtain an unauthorized Request Token,
+ /// described in Section 6.1 (Obtaining an Unauthorized Request Token).
+ /// </summary>
+ /// <remarks>
+ /// The request URL query MUST NOT contain any OAuth Protocol Parameters.
+ /// This is the URL that <see cref="Messages.RequestTokenMessage"/> messages are directed to.
+ /// </remarks>
+ /// <exception cref="ArgumentException">Thrown if this property is set to a URI with OAuth protocol parameters.</exception>
+ public ServiceProviderEndpoint RequestTokenEndpoint {
+ get {
+ return this.requestTokenEndpoint;
+ }
+
+ set {
+ if (value != null && UriUtil.QueryStringContainsOAuthParameters(value.Location)) {
+ throw new ArgumentException(Strings.RequestUrlMustNotHaveOAuthParameters);
+ }
+
+ this.requestTokenEndpoint = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the URL used to obtain User authorization for Consumer access,
+ /// described in Section 6.2 (Obtaining User Authorization).
+ /// </summary>
+ /// <remarks>
+ /// This is the URL that <see cref="Messages.DirectUserToServiceProviderMessage"/> messages are
+ /// indirectly (via the user agent) sent to.
+ /// </remarks>
+ public ServiceProviderEndpoint UserAuthorizationEndpoint { get; set; }
+
+ /// <summary>
+ /// Gets or sets the URL used to exchange the User-authorized Request Token
+ /// for an Access Token, described in Section 6.3 (Obtaining an Access Token).
+ /// </summary>
+ /// <remarks>
+ /// This is the URL that <see cref="Messages.RequestAccessTokenMessage"/> messages are directed to.
+ /// </remarks>
+ public ServiceProviderEndpoint AccessTokenEndpoint { get; set; }
+ }
+}