summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--samples/OAuthServiceProvider/App_Code/DataClasses.dbml3
-rw-r--r--samples/OAuthServiceProvider/App_Code/DataClasses.dbml.layout8
-rw-r--r--samples/OAuthServiceProvider/App_Code/DataClasses.designer.cs72
-rw-r--r--samples/OAuthServiceProvider/App_Code/DatabaseTokenManager.cs51
-rw-r--r--samples/OAuthServiceProvider/App_Code/OAuthConsumer.cs41
-rw-r--r--samples/OAuthServiceProvider/App_Code/OAuthToken.cs40
-rw-r--r--samples/OAuthServiceProvider/Members/Authorize.aspx.cs2
-rw-r--r--src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs74
-rw-r--r--src/DotNetOpenAuth.Test/OAuth/ChannelElements/OAuthChannelTests.cs10
-rw-r--r--src/DotNetOpenAuth/DotNetOpenAuth.csproj3
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/IConsumerCertificateProvider.cs23
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/IConsumerDescription.cs59
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderRequestToken.cs47
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs50
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs2
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs2
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/RsaSha1SigningBindingElement.cs58
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/TokenHandlingBindingElement.cs8
-rw-r--r--src/DotNetOpenAuth/OAuth/OAuthStrings.Designer.cs9
-rw-r--r--src/DotNetOpenAuth/OAuth/OAuthStrings.resx3
-rw-r--r--src/DotNetOpenAuth/OAuth/ServiceProvider.cs18
21 files changed, 378 insertions, 205 deletions
diff --git a/samples/OAuthServiceProvider/App_Code/DataClasses.dbml b/samples/OAuthServiceProvider/App_Code/DataClasses.dbml
index c05df5f..78518c2 100644
--- a/samples/OAuthServiceProvider/App_Code/DataClasses.dbml
+++ b/samples/OAuthServiceProvider/App_Code/DataClasses.dbml
@@ -25,6 +25,9 @@
<Column Name="ConsumerId" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" />
<Column Name="ConsumerKey" Type="System.String" DbType="NVarChar(50) NOT NULL" CanBeNull="false" />
<Column Name="ConsumerSecret" Type="System.String" DbType="NVarChar(50) NOT NULL" CanBeNull="false" />
+ <Column Member="Callback" Type="System.String" CanBeNull="true" />
+ <Column Member="VerificationCodeFormat" Type="DotNetOpenAuth.OAuth.VerificationCodeFormat" CanBeNull="false" />
+ <Column Member="VerificationCodeLength" Type="System.Int32" CanBeNull="false" />
<Association Name="OAuthConsumer_OAuthToken" Member="OAuthTokens" ThisKey="ConsumerId" OtherKey="ConsumerId" Type="OAuthToken" />
</Type>
</Table>
diff --git a/samples/OAuthServiceProvider/App_Code/DataClasses.dbml.layout b/samples/OAuthServiceProvider/App_Code/DataClasses.dbml.layout
index e8195a7..71bd4aa 100644
--- a/samples/OAuthServiceProvider/App_Code/DataClasses.dbml.layout
+++ b/samples/OAuthServiceProvider/App_Code/DataClasses.dbml.layout
@@ -14,10 +14,10 @@
<elementListCompartment Id="eba736b9-f9ec-484b-8083-c77155a49e4e" absoluteBounds="3.515, 1.085, 1.9700000000000002, 0.8262939453125" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
</nestedChildShapes>
</classShape>
- <classShape Id="f909becb-85b1-4fe6-bb16-3feb3e4fe3ee" absoluteBounds="0.625, 3.25, 2, 1.3862939453124998">
+ <classShape Id="f909becb-85b1-4fe6-bb16-3feb3e4fe3ee" absoluteBounds="0.625, 3.25, 2, 1.9631982421874996">
<DataClassMoniker Name="/DataClassesDataContext/OAuthConsumer" />
<nestedChildShapes>
- <elementListCompartment Id="464308c4-d112-4448-b0c9-d9b82fb0ca4e" absoluteBounds="0.64, 3.71, 1.9700000000000002, 0.8262939453125" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+ <elementListCompartment Id="464308c4-d112-4448-b0c9-d9b82fb0ca4e" absoluteBounds="0.64, 3.71, 1.9700000000000002, 1.4031982421875" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
</nestedChildShapes>
</classShape>
<classShape Id="895ebbc8-8352-4c04-9e53-b8e6c8302d36" absoluteBounds="3.5, 3.125, 2, 2.9247054036458326">
@@ -33,14 +33,14 @@
<classShapeMoniker Id="8a79b099-7f87-4766-907a-db2c3e1b5716" />
</nodes>
</associationConnector>
- <associationConnector edgePoints="[(2.625 : 3.94314697265625); (3.5 : 3.94314697265625)]" fixedFrom="NotFixed" fixedTo="NotFixed">
+ <associationConnector edgePoints="[(2.625 : 4.23159912109375); (3.5 : 4.23159912109375)]" fixedFrom="Algorithm" fixedTo="Algorithm">
<AssociationMoniker Name="/DataClassesDataContext/OAuthConsumer/OAuthConsumer_OAuthToken" />
<nodes>
<classShapeMoniker Id="f909becb-85b1-4fe6-bb16-3feb3e4fe3ee" />
<classShapeMoniker Id="895ebbc8-8352-4c04-9e53-b8e6c8302d36" />
</nodes>
</associationConnector>
- <associationConnector edgePoints="[(0.53125 : 2.27089680989583); (0.53125 : 5.37424967447917); (3.5 : 5.37424967447917)]" fixedFrom="NotFixed" fixedTo="NotFixed">
+ <associationConnector edgePoints="[(0.53125 : 2.27089680989583); (0.53125 : 5.66270182291667); (3.5 : 5.66270182291667)]" fixedFrom="Algorithm" fixedTo="Algorithm">
<AssociationMoniker Name="/DataClassesDataContext/User/User_OAuthToken" />
<nodes>
<classShapeMoniker Id="696d2c69-040e-411d-9257-bb664b743834" />
diff --git a/samples/OAuthServiceProvider/App_Code/DataClasses.designer.cs b/samples/OAuthServiceProvider/App_Code/DataClasses.designer.cs
index 09b7b53..b66e75f 100644
--- a/samples/OAuthServiceProvider/App_Code/DataClasses.designer.cs
+++ b/samples/OAuthServiceProvider/App_Code/DataClasses.designer.cs
@@ -483,6 +483,12 @@ public partial class OAuthConsumer : INotifyPropertyChanging, INotifyPropertyCha
private string _ConsumerSecret;
+ private string _Callback;
+
+ private DotNetOpenAuth.OAuth.VerificationCodeFormat _VerificationCodeFormat;
+
+ private int _VerificationCodeLength;
+
private EntitySet<OAuthToken> _OAuthTokens;
#region Extensibility Method Definitions
@@ -495,6 +501,12 @@ public partial class OAuthConsumer : INotifyPropertyChanging, INotifyPropertyCha
partial void OnConsumerKeyChanged();
partial void OnConsumerSecretChanging(string value);
partial void OnConsumerSecretChanged();
+ partial void OnCallbackChanging(string value);
+ partial void OnCallbackChanged();
+ partial void OnVerificationCodeFormatChanging(DotNetOpenAuth.OAuth.VerificationCodeFormat value);
+ partial void OnVerificationCodeFormatChanged();
+ partial void OnVerificationCodeLengthChanging(int value);
+ partial void OnVerificationCodeLengthChanged();
#endregion
public OAuthConsumer()
@@ -563,6 +575,66 @@ public partial class OAuthConsumer : INotifyPropertyChanging, INotifyPropertyCha
}
}
+ [Column(Storage="_Callback")]
+ public string Callback
+ {
+ get
+ {
+ return this._Callback;
+ }
+ set
+ {
+ if ((this._Callback != value))
+ {
+ this.OnCallbackChanging(value);
+ this.SendPropertyChanging();
+ this._Callback = value;
+ this.SendPropertyChanged("Callback");
+ this.OnCallbackChanged();
+ }
+ }
+ }
+
+ [Column(Storage="_VerificationCodeFormat")]
+ public DotNetOpenAuth.OAuth.VerificationCodeFormat VerificationCodeFormat
+ {
+ get
+ {
+ return this._VerificationCodeFormat;
+ }
+ set
+ {
+ if ((this._VerificationCodeFormat != value))
+ {
+ this.OnVerificationCodeFormatChanging(value);
+ this.SendPropertyChanging();
+ this._VerificationCodeFormat = value;
+ this.SendPropertyChanged("VerificationCodeFormat");
+ this.OnVerificationCodeFormatChanged();
+ }
+ }
+ }
+
+ [Column(Storage="_VerificationCodeLength")]
+ public int VerificationCodeLength
+ {
+ get
+ {
+ return this._VerificationCodeLength;
+ }
+ set
+ {
+ if ((this._VerificationCodeLength != value))
+ {
+ this.OnVerificationCodeLengthChanging(value);
+ this.SendPropertyChanging();
+ this._VerificationCodeLength = value;
+ this.SendPropertyChanged("VerificationCodeLength");
+ this.OnVerificationCodeLengthChanged();
+ }
+ }
+ }
+
[Association(Name="OAuthConsumer_OAuthToken", Storage="_OAuthTokens", ThisKey="ConsumerId", OtherKey="ConsumerId")]
public EntitySet<OAuthToken> OAuthTokens
{
diff --git a/samples/OAuthServiceProvider/App_Code/DatabaseTokenManager.cs b/samples/OAuthServiceProvider/App_Code/DatabaseTokenManager.cs
index 143bbfb..f4f34de 100644
--- a/samples/OAuthServiceProvider/App_Code/DatabaseTokenManager.cs
+++ b/samples/OAuthServiceProvider/App_Code/DatabaseTokenManager.cs
@@ -14,61 +14,18 @@ using DotNetOpenAuth.OAuth.Messages;
public class DatabaseTokenManager : IServiceProviderTokenManager {
#region IServiceProviderTokenManager
- public string GetConsumerSecret(string consumerKey) {
+ public IConsumerDescription GetConsumer(string consumerKey) {
var consumerRow = Global.DataContext.OAuthConsumers.SingleOrDefault(
consumerCandidate => consumerCandidate.ConsumerKey == consumerKey);
if (consumerRow == null) {
throw new ArgumentException();
}
- return consumerRow.ConsumerSecret;
+ return consumerRow;
}
- public void SetRequestTokenVerifier(string requestToken, string verifier) {
- if (String.IsNullOrEmpty(requestToken)) {
- throw new ArgumentNullException("requestToken");
- }
- if (String.IsNullOrEmpty(verifier)) {
- throw new ArgumentNullException("verifier");
- }
-
- Global.DataContext.OAuthTokens.First(token => token.Token == requestToken).RequestTokenVerifier = verifier;
- }
-
- public string GetRequestTokenVerifier(string requestToken) {
- if (String.IsNullOrEmpty(requestToken)) {
- throw new ArgumentNullException("requestToken");
- }
-
- return Global.DataContext.OAuthTokens.First(token => token.Token == requestToken).RequestTokenVerifier;
- }
-
- public void SetRequestTokenCallback(string requestToken, Uri callback) {
- if (String.IsNullOrEmpty(requestToken)) {
- throw new ArgumentNullException("requestToken");
- }
-
- Global.DataContext.OAuthTokens.First(token => token.Token == requestToken).RequestTokenCallback = callback.AbsoluteUri;
- }
-
- public Uri GetRequestTokenCallback(string requestToken) {
- string callback = Global.DataContext.OAuthTokens.First(token => token.Token == requestToken).RequestTokenCallback;
- return callback != null ? new Uri(callback) : null;
- }
-
- public void SetTokenConsumerVersion(string token, Version version) {
- if (String.IsNullOrEmpty(token)) {
- throw new ArgumentNullException("token");
- }
- if (version == null) {
- throw new ArgumentNullException("version");
- }
-
- Global.DataContext.OAuthTokens.First(t => t.Token == token).ConsumerVersion = version.ToString();
- }
-
- public Version GetTokenConsumerVersion(string token) {
- return new Version(Global.DataContext.OAuthTokens.First(t => t.Token == token).ConsumerVersion);
+ public IServiceProviderRequestToken GetRequestToken(string token) {
+ return Global.DataContext.OAuthTokens.First(t => t.Token == token);
}
#endregion
diff --git a/samples/OAuthServiceProvider/App_Code/OAuthConsumer.cs b/samples/OAuthServiceProvider/App_Code/OAuthConsumer.cs
new file mode 100644
index 0000000..2de1e85
--- /dev/null
+++ b/samples/OAuthServiceProvider/App_Code/OAuthConsumer.cs
@@ -0,0 +1,41 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthConsumer.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using DotNetOpenAuth.OAuth.ChannelElements;
+
+public partial class OAuthConsumer : IConsumerDescription {
+ #region IConsumerDescription Members
+
+ string IConsumerDescription.Key {
+ get { return this.ConsumerKey; }
+ }
+
+ string IConsumerDescription.Secret {
+ get { return this.ConsumerSecret; }
+ }
+
+ System.Security.Cryptography.X509Certificates.X509Certificate2 IConsumerDescription.Certificate {
+ get { return null; }
+ }
+
+ Uri IConsumerDescription.Callback {
+ get { return new Uri(this.Callback); }
+ }
+
+ DotNetOpenAuth.OAuth.VerificationCodeFormat IConsumerDescription.VerificationCodeFormat {
+ get { return this.VerificationCodeFormat; }
+ }
+
+ int IConsumerDescription.VerificationCodeLength {
+ get { return this.VerificationCodeLength; }
+ }
+
+ #endregion
+}
diff --git a/samples/OAuthServiceProvider/App_Code/OAuthToken.cs b/samples/OAuthServiceProvider/App_Code/OAuthToken.cs
new file mode 100644
index 0000000..445e88c
--- /dev/null
+++ b/samples/OAuthServiceProvider/App_Code/OAuthToken.cs
@@ -0,0 +1,40 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthToken.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using DotNetOpenAuth.OAuth.ChannelElements;
+
+public partial class OAuthToken : IServiceProviderRequestToken {
+ #region IServiceProviderRequestToken Members
+
+ string IServiceProviderRequestToken.Token {
+ get { return this.Token; }
+ }
+
+ string IServiceProviderRequestToken.ConsumerKey {
+ get { return this.OAuthConsumer.ConsumerKey; }
+ }
+
+ Uri IServiceProviderRequestToken.Callback {
+ get { return new Uri(this.RequestTokenCallback); }
+ set { this.RequestTokenCallback = value.AbsoluteUri; }
+ }
+
+ string IServiceProviderRequestToken.VerificationCode {
+ get { return this.RequestTokenVerifier; }
+ set { this.RequestTokenVerifier = value; }
+ }
+
+ Version IServiceProviderRequestToken.ConsumerVersion {
+ get { return new Version(this.ConsumerVersion); }
+ set { this.ConsumerVersion = value.ToString(); }
+ }
+
+ #endregion
+}
diff --git a/samples/OAuthServiceProvider/Members/Authorize.aspx.cs b/samples/OAuthServiceProvider/Members/Authorize.aspx.cs
index e396017..f936c60 100644
--- a/samples/OAuthServiceProvider/Members/Authorize.aspx.cs
+++ b/samples/OAuthServiceProvider/Members/Authorize.aspx.cs
@@ -63,7 +63,7 @@ public partial class Authorize : System.Web.UI.Page {
string verifier = ServiceProvider.CreateVerificationCode(VerificationCodeFormat.AlphaNumericNoLookAlikes, 10);
verificationCodeLabel.Text = verifier;
ITokenContainingMessage requestTokenMessage = pending;
- Global.TokenManager.SetRequestTokenVerifier(requestTokenMessage.Token, verifier);
+ Global.TokenManager.GetRequestToken(requestTokenMessage.Token).VerificationCode = verifier;
}
}
}
diff --git a/src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs b/src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs
index f9cf612..5585107 100644
--- a/src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs
+++ b/src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs
@@ -14,7 +14,7 @@ namespace DotNetOpenAuth.Test.Mocks {
using DotNetOpenAuth.OAuth.Messages;
internal class InMemoryTokenManager : IConsumerTokenManager, IServiceProviderTokenManager {
- private Dictionary<string, string> consumersAndSecrets = new Dictionary<string, string>();
+ private KeyedCollectionDelegate<string, ConsumerInfo> consumers = new KeyedCollectionDelegate<string, ConsumerInfo>(c => c.Key);
private KeyedCollectionDelegate<string, TokenInfo> tokens = new KeyedCollectionDelegate<string, TokenInfo>(t => t.Token);
/// <summary>
@@ -30,11 +30,11 @@ namespace DotNetOpenAuth.Test.Mocks {
#region IConsumerTokenManager Members
public string ConsumerKey {
- get { return this.consumersAndSecrets.Keys.Single(); }
+ get { return this.consumers.Single().Key; }
}
public string ConsumerSecret {
- get { return this.consumersAndSecrets.Values.Single(); }
+ get { return this.consumers.Single().Secret; }
}
#endregion
@@ -46,7 +46,7 @@ namespace DotNetOpenAuth.Test.Mocks {
}
public void StoreNewRequestToken(UnauthorizedTokenRequest request, ITokenSecretContainingMessage response) {
- this.tokens.Add(new TokenInfo { Token = response.Token, Secret = response.TokenSecret });
+ this.tokens.Add(new TokenInfo { ConsumerKey = request.ConsumerKey, Token = response.Token, Secret = response.TokenSecret });
this.requestTokens.Add(response.Token, false);
}
@@ -94,32 +94,12 @@ namespace DotNetOpenAuth.Test.Mocks {
#region IServiceProviderTokenManager Members
- public string GetConsumerSecret(string consumerKey) {
- return this.consumersAndSecrets[consumerKey];
+ public IConsumerDescription GetConsumer(string consumerKey) {
+ return this.consumers[consumerKey];
}
- public void SetRequestTokenVerifier(string requestToken, string verifier) {
- this.tokens[requestToken].Verifier = verifier;
- }
-
- public string GetRequestTokenVerifier(string requestToken) {
- return this.tokens[requestToken].Verifier;
- }
-
- public void SetRequestTokenCallback(string requestToken, Uri callback) {
- this.tokens[requestToken].Callback = callback;
- }
-
- public Uri GetRequestTokenCallback(string requestToken) {
- return this.tokens[requestToken].Callback;
- }
-
- public void SetTokenConsumerVersion(string token, Version version) {
- this.tokens[token].ConsumerVersion = version;
- }
-
- public Version GetTokenConsumerVersion(string token) {
- return this.tokens[token].ConsumerVersion;
+ public IServiceProviderRequestToken GetRequestToken(string token) {
+ return this.tokens[token];
}
#endregion
@@ -130,7 +110,7 @@ namespace DotNetOpenAuth.Test.Mocks {
/// </summary>
/// <param name="consumerDescription">The consumer description.</param>
internal void AddConsumer(ConsumerDescription consumerDescription) {
- this.consumersAndSecrets.Add(consumerDescription.ConsumerKey, consumerDescription.ConsumerSecret);
+ this.consumers.Add(new ConsumerInfo { Key = consumerDescription.ConsumerKey, Secret = consumerDescription.ConsumerSecret });
}
/// <summary>
@@ -145,12 +125,36 @@ namespace DotNetOpenAuth.Test.Mocks {
this.requestTokens[requestToken] = true;
}
- private class TokenInfo {
- internal string Token;
- internal string Verifier;
- internal string Secret;
- internal Uri Callback;
- internal Version ConsumerVersion;
+ private class TokenInfo : IServiceProviderRequestToken {
+ public string ConsumerKey { get; set; }
+
+ public string Token { get; set; }
+
+ public string VerificationCode { get; set; }
+
+ public Uri Callback { get; set; }
+
+ public Version ConsumerVersion { get; set; }
+
+ internal string Secret { get; set; }
+ }
+
+ private class ConsumerInfo : IConsumerDescription {
+ #region IConsumerDescription Members
+
+ public string Key { get; set; }
+
+ public string Secret { get; set; }
+
+ public System.Security.Cryptography.X509Certificates.X509Certificate2 Certificate { get; set; }
+
+ public Uri Callback { get; set; }
+
+ public DotNetOpenAuth.OAuth.VerificationCodeFormat VerificationCodeFormat { get; set; }
+
+ public int VerificationCodeLength { get; set; }
+
+ #endregion
}
}
}
diff --git a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/OAuthChannelTests.cs b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/OAuthChannelTests.cs
index 449a033..1251e2c 100644
--- a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/OAuthChannelTests.cs
+++ b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/OAuthChannelTests.cs
@@ -33,7 +33,7 @@ namespace DotNetOpenAuth.Test.ChannelElements {
base.SetUp();
this.webRequestHandler = new TestWebRequestHandler();
- this.signingElement = new RsaSha1SigningBindingElement();
+ this.signingElement = new RsaSha1SigningBindingElement(new InMemoryTokenManager());
this.nonceStore = new NonceMemoryStore(StandardExpirationBindingElement.DefaultMaximumMessageAge);
this.channel = new OAuthChannel(this.signingElement, this.nonceStore, new InMemoryTokenManager(), new TestMessageFactory());
this.accessor = OAuthChannel_Accessor.AttachShadow(this.channel);
@@ -47,22 +47,22 @@ namespace DotNetOpenAuth.Test.ChannelElements {
[TestMethod, ExpectedException(typeof(ArgumentNullException))]
public void CtorNullStore() {
- new OAuthChannel(new RsaSha1SigningBindingElement(), null, new InMemoryTokenManager(), new TestMessageFactory());
+ new OAuthChannel(this.signingElement, null, new InMemoryTokenManager(), new TestMessageFactory());
}
[TestMethod, ExpectedException(typeof(ArgumentNullException))]
public void CtorNullTokenManager() {
- new OAuthChannel(new RsaSha1SigningBindingElement(), this.nonceStore, null, new TestMessageFactory());
+ new OAuthChannel(this.signingElement, this.nonceStore, null, new TestMessageFactory());
}
[TestMethod]
public void CtorSimpleConsumer() {
- new OAuthChannel(new RsaSha1SigningBindingElement(), this.nonceStore, (IConsumerTokenManager)new InMemoryTokenManager());
+ new OAuthChannel(this.signingElement, this.nonceStore, (IConsumerTokenManager)new InMemoryTokenManager());
}
[TestMethod]
public void CtorSimpleServiceProvider() {
- new OAuthChannel(new RsaSha1SigningBindingElement(), this.nonceStore, (IServiceProviderTokenManager)new InMemoryTokenManager());
+ new OAuthChannel(this.signingElement, this.nonceStore, (IServiceProviderTokenManager)new InMemoryTokenManager());
}
[TestMethod]
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
index 01be98f..ae23e2e 100644
--- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj
+++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
@@ -224,7 +224,7 @@
<Compile Include="Messaging\Reflection\IMessagePartEncoder.cs" />
<Compile Include="Messaging\Reflection\IMessagePartNullEncoder.cs" />
<Compile Include="Messaging\Reflection\MessageDescriptionCollection.cs" />
- <Compile Include="OAuth\ChannelElements\IConsumerCertificateProvider.cs" />
+ <Compile Include="OAuth\ChannelElements\IConsumerDescription.cs" />
<Compile Include="OAuth\ChannelElements\IConsumerTokenManager.cs" />
<Compile Include="OAuth\ChannelElements\IServiceProviderTokenManager.cs" />
<Compile Include="OAuth\ChannelElements\OAuthConsumerMessageFactory.cs" />
@@ -233,6 +233,7 @@
<Compile Include="OAuth\ChannelElements\OAuthHttpMethodBindingElement.cs" />
<Compile Include="OAuth\ChannelElements\PlaintextSigningBindingElement.cs" />
<Compile Include="OAuth\ChannelElements\HmacSha1SigningBindingElement.cs" />
+ <Compile Include="OAuth\ChannelElements\IServiceProviderRequestToken.cs" />
<Compile Include="OAuth\ChannelElements\SigningBindingElementBaseContract.cs" />
<Compile Include="OAuth\ChannelElements\SigningBindingElementChain.cs" />
<Compile Include="OAuth\ChannelElements\StandardTokenGenerator.cs" />
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/IConsumerCertificateProvider.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/IConsumerCertificateProvider.cs
deleted file mode 100644
index 7e6ae54..0000000
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/IConsumerCertificateProvider.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="IConsumerCertificateProvider.cs" company="Andrew Arnott">
-// Copyright (c) Andrew Arnott. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth.ChannelElements {
- using System.Security.Cryptography.X509Certificates;
-
- /// <summary>
- /// A provider that hosts can implement to hook up their RSA-SHA1 binding elements
- /// to their list of known Consumers' certificates.
- /// </summary>
- public interface IConsumerCertificateProvider {
- /// <summary>
- /// Gets the certificate that can be used to verify the signature of an incoming
- /// message from a Consumer.
- /// </summary>
- /// <param name="consumerMessage">The incoming message from some Consumer.</param>
- /// <returns>The public key from the Consumer's X.509 Certificate, if one can be found; otherwise <c>null</c>.</returns>
- X509Certificate2 GetCertificate(ITamperResistantOAuthMessage consumerMessage);
- }
-}
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/IConsumerDescription.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/IConsumerDescription.cs
new file mode 100644
index 0000000..db505d5
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/IConsumerDescription.cs
@@ -0,0 +1,59 @@
+//-----------------------------------------------------------------------
+// <copyright file="IConsumerDescription.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth.ChannelElements {
+ using System;
+ using System.Security.Cryptography.X509Certificates;
+
+ /// <summary>
+ /// A description of a consumer from a Service Provider's point of view.
+ /// </summary>
+ public interface IConsumerDescription {
+ /// <summary>
+ /// Gets the Consumer key.
+ /// </summary>
+ string Key { get; }
+
+ /// <summary>
+ /// Gets the consumer secret.
+ /// </summary>
+ string Secret { get; }
+
+ /// <summary>
+ /// Gets the certificate that can be used to verify the signature of an incoming
+ /// message from a Consumer.
+ /// </summary>
+ /// <returns>The public key from the Consumer's X.509 Certificate, if one can be found; otherwise <c>null</c>.</returns>
+ /// <remarks>
+ /// This property must be implemented only if the RSA-SHA1 algorithm is supported by the Service Provider.
+ /// </remarks>
+ X509Certificate2 Certificate { get; }
+
+ /// <summary>
+ /// Gets the callback URI that this consumer has pre-registered with the service provider, if any.
+ /// </summary>
+ /// <value>A URI that user authorization responses should be directed to; or <c>null</c> if no preregistered callback was arranged.</value>
+ Uri Callback { get; }
+
+ /// <summary>
+ /// Gets the verification code format that is most appropriate for this consumer
+ /// when a callback URI is not available.
+ /// </summary>
+ /// <value>A set of characters that can be easily keyed in by the user given the Consumer's
+ /// application type and form factor.</value>
+ /// <remarks>
+ /// The value <see cref="OAuth.VerificationCodeFormat.IncludedInCallback"/> should NEVER be returned
+ /// since this property is only used in no callback scenarios anyway.
+ /// </remarks>
+ VerificationCodeFormat VerificationCodeFormat { get; }
+
+ /// <summary>
+ /// Gets the length of the verification code to issue for this Consumer.
+ /// </summary>
+ /// <value>A positive number, generally at least 4.</value>
+ int VerificationCodeLength { get; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderRequestToken.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderRequestToken.cs
new file mode 100644
index 0000000..48f39a6
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderRequestToken.cs
@@ -0,0 +1,47 @@
+//-----------------------------------------------------------------------
+// <copyright file="IServiceProviderRequestToken.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth.ChannelElements {
+ using System;
+ using DotNetOpenAuth.OAuth.Messages;
+
+ /// <summary>
+ /// A description of a request token and its metadata as required by a Service Provider
+ /// </summary>
+ public interface IServiceProviderRequestToken {
+ /// <summary>
+ /// Gets the token itself.
+ /// </summary>
+ string Token { get; }
+
+ /// <summary>
+ /// Gets the consumer key that requested this token.
+ /// </summary>
+ string ConsumerKey { get; }
+
+ /// <summary>
+ /// Gets or sets the callback associated specifically with this token, if any.
+ /// </summary>
+ /// <value>The callback URI; or <c>null</c> if no callback was specifically assigned to this token.</value>
+ Uri Callback { get; set; }
+
+ /// <summary>
+ /// Gets or sets the verifier that the consumer must include in the <see cref="AuthorizedTokenRequest"/>
+ /// message to exchange this request token for an access token.
+ /// </summary>
+ /// <value>The verifier code, or <c>null</c> if none has been assigned (yet).</value>
+ string VerificationCode { get; set; }
+
+ /// <summary>
+ /// Gets or sets the version of the Consumer that requested this token.
+ /// </summary>
+ /// <remarks>
+ /// This property is used to determine whether a <see cref="VerificationCode"/> must be
+ /// generated when the user authorizes the Consumer or not.
+ /// </remarks>
+ Version ConsumerVersion { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs
index 58b61a4..f841aa9 100644
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs
@@ -16,54 +16,18 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
/// </summary>
public interface IServiceProviderTokenManager : ITokenManager {
/// <summary>
- /// Gets the Consumer Secret for a given a Consumer Key.
+ /// Gets the Consumer description for a given a Consumer Key.
/// </summary>
/// <param name="consumerKey">The Consumer Key.</param>
- /// <returns>The Consumer Secret.</returns>
+ /// <returns>A description of the consumer.</returns>
/// <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);
+ IConsumerDescription GetConsumer(string consumerKey);
/// <summary>
- /// Sets the verifier code associated with an authorized request token.
+ /// Gets details on the named 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);
-
- /// <summary>
- /// Sets the request token consumer callback.
- /// </summary>
- /// <param name="requestToken">The request token.</param>
- /// <param name="callback">The callback.</param>
- void SetRequestTokenCallback(string requestToken, Uri callback);
-
- /// <summary>
- /// Gets the request token consumer callback.
- /// </summary>
- /// <param name="requestToken">The request token.</param>
- /// <returns>The callback Uri. May be <c>null</c>.</returns>
- Uri GetRequestTokenCallback(string requestToken);
-
- /// <summary>
- /// Sets the OAuth version used by the Consumer to request a token.
- /// </summary>
- /// <param name="token">The token.</param>
- /// <param name="version">The OAuth version.</param>
- void SetTokenConsumerVersion(string token, Version version);
-
- /// <summary>
- /// Gets the OAuth version used by the Consumer to request a token.
- /// </summary>
- /// <param name="token">The token.</param>
- /// <returns>The OAuth version</returns>
- Version GetTokenConsumerVersion(string token);
+ /// <param name="token">The request token.</param>
+ /// <returns>A description of the token</returns>
+ IServiceProviderRequestToken GetRequestToken(string token);
}
}
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs
index e2a58d0..2487845 100644
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs
@@ -389,7 +389,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
ErrorUtilities.VerifyInternal(consumerKey == consumerTokenManager.ConsumerKey, "The token manager consumer key and the consumer key set earlier do not match!");
return consumerTokenManager.ConsumerSecret;
} else {
- return ((IServiceProviderTokenManager)this.TokenManager).GetConsumerSecret(consumerKey);
+ return ((IServiceProviderTokenManager)this.TokenManager).GetConsumer(consumerKey).Secret;
}
}
}
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs
index e8e8382..d8e3af2 100644
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs
@@ -59,7 +59,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
if (fields.TryGetValue("oauth_token", out token)) {
// Discern between 1.0 and 1.0a requests by checking on the consumer version we stored
// when the consumer first requested an unauthorized token.
- protocol = Protocol.Lookup(this.tokenManager.GetTokenConsumerVersion(token));
+ protocol = Protocol.Lookup(this.tokenManager.GetRequestToken(token).ConsumerVersion);
}
if (fields.ContainsKey("oauth_consumer_key") && !fields.ContainsKey("oauth_token")) {
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/RsaSha1SigningBindingElement.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/RsaSha1SigningBindingElement.cs
index 779f2c5..4f8b5e5 100644
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/RsaSha1SigningBindingElement.cs
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/RsaSha1SigningBindingElement.cs
@@ -6,6 +6,7 @@
namespace DotNetOpenAuth.OAuth.ChannelElements {
using System;
+ using System.Diagnostics.Contracts;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
@@ -16,15 +17,24 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
/// </summary>
public class RsaSha1SigningBindingElement : SigningBindingElementBase {
/// <summary>
+ /// The name of the hash algorithm to use.
+ /// </summary>
+ private const string HashAlgorithmName = "RSA-SHA1";
+
+ /// <summary>
+ /// The token manager for the service provider.
+ /// </summary>
+ private IServiceProviderTokenManager tokenManager;
+
+ /// <summary>
/// Initializes a new instance of the <see cref="RsaSha1SigningBindingElement"/> class
/// for use by Consumers.
/// </summary>
/// <param name="signingCertificate">The certificate used to sign outgoing messages.</param>
public RsaSha1SigningBindingElement(X509Certificate2 signingCertificate)
- : this() {
- if (signingCertificate == null) {
- throw new ArgumentNullException("signingCertificate");
- }
+ : base(HashAlgorithmName) {
+ Contract.Requires(signingCertificate != null);
+ ErrorUtilities.VerifyArgumentNotNull(signingCertificate, "signingCertificate");
this.SigningCertificate = signingCertificate;
}
@@ -33,21 +43,21 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
/// Initializes a new instance of the <see cref="RsaSha1SigningBindingElement"/> class
/// for use by Service Providers.
/// </summary>
- public RsaSha1SigningBindingElement()
- : base("RSA-SHA1") {
+ /// <param name="tokenManager">The token manager.</param>
+ public RsaSha1SigningBindingElement(IServiceProviderTokenManager tokenManager)
+ : base(HashAlgorithmName) {
+ Contract.Requires(tokenManager != null);
+ ErrorUtilities.VerifyArgumentNotNull(tokenManager, "tokenManager");
+
+ this.tokenManager = tokenManager;
}
/// <summary>
- /// Gets or sets the certificate used to sign outgoing messages.
+ /// Gets or sets the certificate used to sign outgoing messages. Used only by Consumers.
/// </summary>
public X509Certificate2 SigningCertificate { get; set; }
/// <summary>
- /// Gets or sets the consumer certificate provider.
- /// </summary>
- public IConsumerCertificateProvider ConsumerCertificateProvider { get; set; }
-
- /// <summary>
/// Calculates a signature for a given message.
/// </summary>
/// <param name="message">The message to sign.</param>
@@ -56,13 +66,8 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
/// This method signs the message per OAuth 1.0 section 9.3.
/// </remarks>
protected override string GetSignature(ITamperResistantOAuthMessage message) {
- if (message == null) {
- throw new ArgumentNullException("message");
- }
-
- if (this.SigningCertificate == null) {
- throw new InvalidOperationException(OAuthStrings.X509CertificateNotProvidedForSigning);
- }
+ ErrorUtilities.VerifyArgumentNotNull(message, "message");
+ ErrorUtilities.VerifyOperation(this.SigningCertificate != null, OAuthStrings.X509CertificateNotProvidedForSigning);
string signatureBaseString = ConstructSignatureBaseString(message, this.Channel.MessageDescriptions.GetAccessor(message));
byte[] data = Encoding.ASCII.GetBytes(signatureBaseString);
@@ -80,16 +85,14 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
/// <c>true</c> if the signature on the message is valid; otherwise, <c>false</c>.
/// </returns>
protected override bool IsSignatureValid(ITamperResistantOAuthMessage message) {
- if (this.ConsumerCertificateProvider == null) {
- throw new InvalidOperationException(OAuthStrings.ConsumerCertificateProviderNotAvailable);
- }
+ ErrorUtilities.VerifyInternal(this.tokenManager != null, "No token manager available for fetching Consumer public certificates.");
string signatureBaseString = ConstructSignatureBaseString(message, this.Channel.MessageDescriptions.GetAccessor(message));
byte[] data = Encoding.ASCII.GetBytes(signatureBaseString);
byte[] carriedSignature = Convert.FromBase64String(message.Signature);
- X509Certificate2 cert = this.ConsumerCertificateProvider.GetCertificate(message);
+ X509Certificate2 cert = this.tokenManager.GetConsumer(message.ConsumerKey).Certificate;
if (cert == null) {
Logger.Signatures.WarnFormat("Incoming message from consumer '{0}' could not be matched with an appropriate X.509 certificate for signature verification.", message.ConsumerKey);
return false;
@@ -105,10 +108,11 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
/// </summary>
/// <returns>A new instance of the binding element.</returns>
protected override ITamperProtectionChannelBindingElement Clone() {
- return new RsaSha1SigningBindingElement() {
- ConsumerCertificateProvider = this.ConsumerCertificateProvider,
- SigningCertificate = this.SigningCertificate,
- };
+ if (this.tokenManager != null) {
+ return new RsaSha1SigningBindingElement(this.tokenManager);
+ } else {
+ return new RsaSha1SigningBindingElement(this.SigningCertificate);
+ }
}
}
}
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/TokenHandlingBindingElement.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/TokenHandlingBindingElement.cs
index 2ec5e0e..b8273c3 100644
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/TokenHandlingBindingElement.cs
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/TokenHandlingBindingElement.cs
@@ -71,7 +71,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
var userAuthResponse = message as UserAuthorizationResponse;
if (userAuthResponse != null && userAuthResponse.Version >= Protocol.V10a.Version) {
- this.tokenManager.SetRequestTokenVerifier(userAuthResponse.RequestToken, userAuthResponse.VerificationCode);
+ this.tokenManager.GetRequestToken(userAuthResponse.RequestToken).VerificationCode = userAuthResponse.VerificationCode;
return MessageProtections.None;
}
@@ -79,9 +79,9 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
var grantRequestTokenResponse = message as UnauthorizedTokenResponse;
if (grantRequestTokenResponse != null) {
this.tokenManager.StoreNewRequestToken(grantRequestTokenResponse.RequestMessage, grantRequestTokenResponse);
- this.tokenManager.SetTokenConsumerVersion(grantRequestTokenResponse.RequestToken, grantRequestTokenResponse.Version);
+ this.tokenManager.GetRequestToken(grantRequestTokenResponse.RequestToken).ConsumerVersion = grantRequestTokenResponse.Version;
if (grantRequestTokenResponse.RequestMessage.Callback != null) {
- this.tokenManager.SetRequestTokenCallback(grantRequestTokenResponse.RequestToken, grantRequestTokenResponse.RequestMessage.Callback);
+ this.tokenManager.GetRequestToken(grantRequestTokenResponse.RequestToken).Callback = grantRequestTokenResponse.RequestMessage.Callback;
}
return MessageProtections.None;
@@ -112,7 +112,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
var authorizedTokenRequest = message as AuthorizedTokenRequest;
if (authorizedTokenRequest != null && authorizedTokenRequest.Version >= Protocol.V10a.Version) {
- string expectedVerifier = this.tokenManager.GetRequestTokenVerifier(authorizedTokenRequest.RequestToken);
+ string expectedVerifier = this.tokenManager.GetRequestToken(authorizedTokenRequest.RequestToken).VerificationCode;
ErrorUtilities.VerifyProtocol(string.Equals(authorizedTokenRequest.VerificationCode, expectedVerifier, StringComparison.Ordinal), OAuthStrings.IncorrectVerifier);
return MessageProtections.None;
}
diff --git a/src/DotNetOpenAuth/OAuth/OAuthStrings.Designer.cs b/src/DotNetOpenAuth/OAuth/OAuthStrings.Designer.cs
index d1811c4..b9391ec 100644
--- a/src/DotNetOpenAuth/OAuth/OAuthStrings.Designer.cs
+++ b/src/DotNetOpenAuth/OAuth/OAuthStrings.Designer.cs
@@ -79,15 +79,6 @@ namespace DotNetOpenAuth.OAuth {
}
/// <summary>
- /// Looks up a localized string similar to The RSA-SHA1 signing binding element&apos;s consumer certificate provider has not been set, so no incoming messages from consumers using this signature method can be verified..
- /// </summary>
- internal static string ConsumerCertificateProviderNotAvailable {
- get {
- return ResourceManager.GetString("ConsumerCertificateProviderNotAvailable", resourceCulture);
- }
- }
-
- /// <summary>
/// Looks up a localized string similar to Failure looking up secret for consumer or token..
/// </summary>
internal static string ConsumerOrTokenSecretNotFound {
diff --git a/src/DotNetOpenAuth/OAuth/OAuthStrings.resx b/src/DotNetOpenAuth/OAuth/OAuthStrings.resx
index 2e82bdb..0de00a3 100644
--- a/src/DotNetOpenAuth/OAuth/OAuthStrings.resx
+++ b/src/DotNetOpenAuth/OAuth/OAuthStrings.resx
@@ -123,9 +123,6 @@
<data name="BadAccessTokenInProtectedResourceRequest" xml:space="preserve">
<value>The access token '{0}' is invalid or expired.</value>
</data>
- <data name="ConsumerCertificateProviderNotAvailable" xml:space="preserve">
- <value>The RSA-SHA1 signing binding element's consumer certificate provider has not been set, so no incoming messages from consumers using this signature method can be verified.</value>
- </data>
<data name="ConsumerOrTokenSecretNotFound" xml:space="preserve">
<value>Failure looking up secret for consumer or token.</value>
</data>
diff --git a/src/DotNetOpenAuth/OAuth/ServiceProvider.cs b/src/DotNetOpenAuth/OAuth/ServiceProvider.cs
index 311e531..721d40b 100644
--- a/src/DotNetOpenAuth/OAuth/ServiceProvider.cs
+++ b/src/DotNetOpenAuth/OAuth/ServiceProvider.cs
@@ -236,7 +236,23 @@ namespace DotNetOpenAuth.OAuth {
// It is very important for us to ignore the oauth_callback argument in the
// UserAuthorizationRequest if the Consumer is a 1.0a consumer or else we
// open up a security exploit.
- Uri callback = request.Version >= Protocol.V10a.Version ? this.TokenManager.GetRequestTokenCallback(request.RequestToken) : request.Callback;
+ IServiceProviderRequestToken token = this.TokenManager.GetRequestToken(request.RequestToken);
+ Uri callback;
+ if (request.Version >= Protocol.V10a.Version) {
+ // In OAuth 1.0a, we'll prefer the token-specific callback to the pre-registered one.
+ if (token.Callback != null) {
+ callback = token.Callback;
+ } else {
+ IConsumerDescription consumer = this.TokenManager.GetConsumer(token.ConsumerKey);
+ callback = consumer.Callback;
+ }
+ } else {
+ // In OAuth 1.0, we'll prefer the pre-registered callback over the token-specific one
+ // since 1.0 has a security weakness for user-modified callback URIs.
+ IConsumerDescription consumer = this.TokenManager.GetConsumer(token.ConsumerKey);
+ callback = consumer.Callback ?? request.Callback;
+ }
+
return callback != null ? this.PrepareAuthorizationResponse(request, callback) : null;
}