summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2011-05-07 17:25:41 -0700
committerAndrew Arnott <andrewarnott@gmail.com>2011-05-07 17:25:41 -0700
commitebcf20f3fe65b7839fdc834c861c5b11978e14ae (patch)
tree4445c8297f2ebef8ed3d4dd198aa0a2f1fa59fe0 /src
parent3063b24dba973bce7f86880a00056a60bddd1f5c (diff)
downloadDotNetOpenAuth-ebcf20f3fe65b7839fdc834c861c5b11978e14ae.zip
DotNetOpenAuth-ebcf20f3fe65b7839fdc834c861c5b11978e14ae.tar.gz
DotNetOpenAuth-ebcf20f3fe65b7839fdc834c861c5b11978e14ae.tar.bz2
OpenID Provider association stores replaced with self-describing association handles.
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs5
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs10
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/ChannelElements/OpenIdChannelTests.cs2
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/ChannelElements/SigningBindingElementTests.cs8
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionTestUtilities.cs7
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Provider/PerformanceTests.cs2
-rw-r--r--src/DotNetOpenAuth/DotNetOpenAuth.csproj18
-rw-r--r--src/DotNetOpenAuth/OpenId/Association.cs5
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs98
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/ReturnToSignatureBindingElement.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs37
-rw-r--r--src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs21
-rw-r--r--src/DotNetOpenAuth/OpenId/IAssociationStore.cs189
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/AssociateDiffieHellmanResponse.cs4
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs8
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs13
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponseContract.cs3
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/AssociateUnencryptedResponse.cs4
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/CheckAuthenticationResponse.cs4
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/AssociationDataBag.cs39
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/AssociationRelyingPartyType.cs26
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/IProviderApplicationStore.cs5
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs19
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/ProviderAssociationStore.cs49
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/StandardProviderApplicationStore.cs68
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/AssociationManager.cs8
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/AssociationMemoryStore.cs (renamed from src/DotNetOpenAuth/OpenId/AssociationMemoryStore.cs)51
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs6
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/IAssociationStore.cs151
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/IRelyingPartyApplicationStore.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs4
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/PrivateSecretManager.cs4
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/StandardRelyingPartyApplicationStore.cs6
-rw-r--r--src/DotNetOpenAuth/Reporting.cs23
35 files changed, 459 insertions, 444 deletions
diff --git a/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs b/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs
index 390a5f1..ee62084 100644
--- a/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs
@@ -353,8 +353,8 @@ namespace DotNetOpenAuth.Test.OpenId {
if (expectSuccess) {
Assert.IsNotNull(rpAssociation);
Assert.AreSame(rpAssociation, coordinator.RelyingParty.AssociationManager.AssociationStoreTestHook.GetAssociation(opDescription.Uri, rpAssociation.Handle));
- opAssociation = coordinator.Provider.AssociationStore.GetAssociation(AssociationRelyingPartyType.Smart, rpAssociation.Handle);
- Assert.IsNotNull(opAssociation, "The Provider should have stored the association.");
+ opAssociation = coordinator.Provider.AssociationStore.Decode(new TestSignedDirectedMessage(), AssociationRelyingPartyType.Smart, rpAssociation.Handle);
+ Assert.IsNotNull(opAssociation, "The Provider could not decode the association handle.");
Assert.AreEqual(opAssociation.Handle, rpAssociation.Handle);
Assert.AreEqual(expectedAssociationType, rpAssociation.GetAssociationType(protocol));
@@ -372,7 +372,6 @@ namespace DotNetOpenAuth.Test.OpenId {
}
} else {
Assert.IsNull(coordinator.RelyingParty.AssociationManager.AssociationStoreTestHook.GetAssociation(opDescription.Uri, new RelyingPartySecuritySettings()));
- Assert.IsNull(coordinator.Provider.AssociationStore.GetAssociation(AssociationRelyingPartyType.Smart, new ProviderSecuritySettings()));
}
}
}
diff --git a/src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs b/src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs
index 27db93e..9e5c754 100644
--- a/src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs
@@ -138,8 +138,9 @@ namespace DotNetOpenAuth.Test.OpenId {
private void ParameterizedAuthenticationTest(Protocol protocol, bool statelessRP, bool sharedAssociation, bool positive, bool immediate, bool tamper) {
Contract.Requires<ArgumentException>(!statelessRP || !sharedAssociation, "The RP cannot be stateless while sharing an association with the OP.");
Contract.Requires<ArgumentException>(positive || !tamper, "Cannot tamper with a negative response.");
- ProviderSecuritySettings securitySettings = new ProviderSecuritySettings();
- Association association = sharedAssociation ? HmacShaAssociation.Create(protocol, protocol.Args.SignatureAlgorithm.Best, AssociationRelyingPartyType.Smart, securitySettings) : null;
+ var securitySettings = new ProviderSecuritySettings();
+ var associationStore = new ProviderAssociationStore();
+ Association association = sharedAssociation ? HmacShaAssociation.Create(protocol, protocol.Args.SignatureAlgorithm.Best, AssociationRelyingPartyType.Smart, associationStore, securitySettings) : null;
var coordinator = new OpenIdCoordinator(
rp => {
var request = new CheckIdRequest(protocol.Version, OPUri, immediate ? AuthenticationRequestMode.Immediate : AuthenticationRequestMode.Setup);
@@ -196,10 +197,7 @@ namespace DotNetOpenAuth.Test.OpenId {
}
},
op => {
- if (association != null) {
- op.AssociationStore.StoreAssociation(AssociationRelyingPartyType.Smart, association);
- }
-
+ op.AssociationStore.Secret = associationStore.Secret;
var request = op.Channel.ReadFromRequest<CheckIdRequest>();
Assert.IsNotNull(request);
IProtocolMessage response;
diff --git a/src/DotNetOpenAuth.Test/OpenId/ChannelElements/OpenIdChannelTests.cs b/src/DotNetOpenAuth.Test/OpenId/ChannelElements/OpenIdChannelTests.cs
index eaaef34..a73c355 100644
--- a/src/DotNetOpenAuth.Test/OpenId/ChannelElements/OpenIdChannelTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/ChannelElements/OpenIdChannelTests.cs
@@ -29,7 +29,7 @@ namespace DotNetOpenAuth.Test.OpenId.ChannelElements {
[SetUp]
public void Setup() {
this.webHandler = new Mocks.TestWebRequestHandler();
- this.channel = new OpenIdChannel(new AssociationMemoryStore<Uri>(), new NonceMemoryStore(maximumMessageAge), new RelyingPartySecuritySettings());
+ this.channel = new OpenIdChannel(new AssociationMemoryStore(), new NonceMemoryStore(maximumMessageAge), new RelyingPartySecuritySettings());
this.channel.WebRequestHandler = this.webHandler;
}
diff --git a/src/DotNetOpenAuth.Test/OpenId/ChannelElements/SigningBindingElementTests.cs b/src/DotNetOpenAuth.Test/OpenId/ChannelElements/SigningBindingElementTests.cs
index 6160680..dbbe7f0 100644
--- a/src/DotNetOpenAuth.Test/OpenId/ChannelElements/SigningBindingElementTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/ChannelElements/SigningBindingElementTests.cs
@@ -23,10 +23,10 @@ namespace DotNetOpenAuth.Test.OpenId.ChannelElements {
public void SignaturesMatchKnownGood() {
Protocol protocol = Protocol.V20;
var settings = new ProviderSecuritySettings();
- var store = new AssociationMemoryStore<AssociationRelyingPartyType>();
+ var store = new ProviderAssociationStore();
byte[] associationSecret = Convert.FromBase64String("rsSwv1zPWfjPRQU80hciu8FPDC+GONAMJQ/AvSo1a2M=");
- Association association = HmacShaAssociation.Create("mock", associationSecret, TimeSpan.FromDays(1));
- store.StoreAssociation(AssociationRelyingPartyType.Smart, association);
+ string handle = store.Encode(new AssociationDataBag { Secret = associationSecret, ExpiresUtc = DateTime.UtcNow.AddDays(1), AssociationType = AssociationRelyingPartyType.Smart });
+ Association association = HmacShaAssociation.Create(handle, associationSecret, TimeSpan.FromDays(1));
SigningBindingElement signer = new SigningBindingElement(store, settings);
signer.Channel = new TestChannel(this.MessageDescriptions);
@@ -45,7 +45,7 @@ namespace DotNetOpenAuth.Test.OpenId.ChannelElements {
[TestCase]
public void SignedResponsesIncludeExtraDataInSignature() {
Protocol protocol = Protocol.Default;
- SigningBindingElement sbe = new SigningBindingElement(new AssociationMemoryStore<AssociationRelyingPartyType>(), new ProviderSecuritySettings());
+ SigningBindingElement sbe = new SigningBindingElement(new ProviderAssociationStore(), new ProviderSecuritySettings());
sbe.Channel = new TestChannel(this.MessageDescriptions);
IndirectSignedResponse response = new IndirectSignedResponse(protocol.Version, RPUri);
response.ReturnTo = RPUri;
diff --git a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionTestUtilities.cs b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionTestUtilities.cs
index 334fc93..fc1c98b 100644
--- a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionTestUtilities.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionTestUtilities.cs
@@ -33,8 +33,9 @@ namespace DotNetOpenAuth.Test.OpenId.Extensions {
Protocol protocol,
IEnumerable<IOpenIdMessageExtension> requests,
IEnumerable<IOpenIdMessageExtension> responses) {
- ProviderSecuritySettings securitySettings = new ProviderSecuritySettings();
- Association association = HmacShaAssociation.Create(protocol, protocol.Args.SignatureAlgorithm.Best, AssociationRelyingPartyType.Smart, securitySettings);
+ var securitySettings = new ProviderSecuritySettings();
+ var associationStore = new ProviderAssociationStore();
+ Association association = HmacShaAssociation.Create(protocol, protocol.Args.SignatureAlgorithm.Best, AssociationRelyingPartyType.Smart, associationStore, securitySettings);
var coordinator = new OpenIdCoordinator(
rp => {
RegisterExtension(rp.Channel, Mocks.MockOpenIdExtension.Factory);
@@ -57,7 +58,7 @@ namespace DotNetOpenAuth.Test.OpenId.Extensions {
},
op => {
RegisterExtension(op.Channel, Mocks.MockOpenIdExtension.Factory);
- op.AssociationStore.StoreAssociation(AssociationRelyingPartyType.Smart, association);
+ op.AssociationStore.Secret = associationStore.Secret;
var request = op.Channel.ReadFromRequest<CheckIdRequest>();
var response = new PositiveAssertionResponse(request);
var receivedRequests = request.Extensions.Cast<IOpenIdMessageExtension>();
diff --git a/src/DotNetOpenAuth.Test/OpenId/Provider/PerformanceTests.cs b/src/DotNetOpenAuth.Test/OpenId/Provider/PerformanceTests.cs
index 4530982..365c5c5 100644
--- a/src/DotNetOpenAuth.Test/OpenId/Provider/PerformanceTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/Provider/PerformanceTests.cs
@@ -78,8 +78,8 @@ namespace DotNetOpenAuth.Test.OpenId.Provider {
protocol,
assocType,
AssociationRelyingPartyType.Smart,
+ this.provider.AssociationStore,
this.provider.SecuritySettings);
- this.provider.AssociationStore.StoreAssociation(AssociationRelyingPartyType.Smart, assoc);
var checkidRequest = this.CreateCheckIdRequest(true);
MeasurePerformance(
() => {
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
index bf16f3e..1dfe4ed 100644
--- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj
+++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
@@ -492,7 +492,10 @@ http://opensource.org/licenses/ms-pl.html
<Compile Include="OAuth\ChannelElements\OAuthServiceProviderMessageFactory.cs" />
<Compile Include="Messaging\ProtocolException.cs" />
<Compile Include="OpenId\Association.cs" />
- <Compile Include="OpenId\AssociationMemoryStore.cs" />
+ <Compile Include="OpenId\Provider\AssociationDataBag.cs" />
+ <Compile Include="OpenId\RelyingParty\AssociationMemoryStore.cs" />
+ <Compile Include="OpenId\Provider\ProviderAssociationStore.cs" />
+ <Compile Include="OpenId\RelyingParty\IAssociationStore.cs" />
<Compile Include="OpenId\Associations.cs" />
<Compile Include="OpenId\Behaviors\AXFetchAsSregTransform.cs" />
<Compile Include="OpenId\Behaviors\BehaviorStrings.Designer.cs">
@@ -573,6 +576,7 @@ http://opensource.org/licenses/ms-pl.html
<Compile Include="OpenId\Messages\SignedResponseRequest.cs" />
<Compile Include="OpenId\NoDiscoveryIdentifier.cs" />
<Compile Include="OpenId\OpenIdUtilities.cs" />
+ <Compile Include="OpenId\Provider\AssociationRelyingPartyType.cs" />
<Compile Include="OpenId\Provider\PrivatePersonalIdentifierProviderBase.cs" />
<Compile Include="OpenId\Provider\AnonymousRequest.cs" />
<Compile Include="OpenId\Provider\AnonymousRequestEventArgs.cs" />
@@ -607,7 +611,6 @@ http://opensource.org/licenses/ms-pl.html
<Compile Include="OpenId\DiffieHellman\mono\PrimeGeneratorBase.cs" />
<Compile Include="OpenId\DiffieHellman\mono\SequentialSearchPrimeGeneratorBase.cs" />
<Compile Include="OpenId\HmacShaAssociation.cs" />
- <Compile Include="OpenId\IAssociationStore.cs" />
<Compile Include="OpenId\Messages\AssociateUnencryptedRequest.cs" />
<Compile Include="OpenId\Provider\OpenIdProvider.cs" />
<Compile Include="OpenId\Messages\AssociateDiffieHellmanRequest.cs" />
@@ -865,16 +868,9 @@ http://opensource.org/licenses/ms-pl.html
<ILMergeTargetPlatformDirectory Condition=" '$(ClrVersion)' == '4' ">"$(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0"</ILMergeTargetPlatformDirectory>
</PropertyGroup>
<MakeDir Directories="$(ILMergeOutputAssemblyDirectory)" />
- <ILMerge ExcludeFile="$(ProjectRoot)ILMergeInternalizeExceptions.txt"
- InputAssemblies="@(ILMergeInputAssemblies)"
- OutputFile="$(ILMergeOutputAssembly)"
- KeyFile="$(PublicKeyFile)"
- DelaySign="true"
- ToolPath="$(ProjectRoot)tools\ILMerge"
- TargetPlatformVersion="$(ClrVersion).0"
- TargetPlatformDirectory="$(ILMergeTargetPlatformDirectory)" />
+ <ILMerge ExcludeFile="$(ProjectRoot)ILMergeInternalizeExceptions.txt" InputAssemblies="@(ILMergeInputAssemblies)" OutputFile="$(ILMergeOutputAssembly)" KeyFile="$(PublicKeyFile)" DelaySign="true" ToolPath="$(ProjectRoot)tools\ILMerge" TargetPlatformVersion="$(ClrVersion).0" TargetPlatformDirectory="$(ILMergeTargetPlatformDirectory)" />
</Target>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(ProjectRoot)tools\DotNetOpenAuth.targets" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))\EnlistmentInfo.targets" Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))' != '' " />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/DotNetOpenAuth/OpenId/Association.cs b/src/DotNetOpenAuth/OpenId/Association.cs
index 3c7e89f..5c2a09e 100644
--- a/src/DotNetOpenAuth/OpenId/Association.cs
+++ b/src/DotNetOpenAuth/OpenId/Association.cs
@@ -51,7 +51,7 @@ namespace DotNetOpenAuth.OpenId {
/// <summary>
/// Gets a unique handle by which this <see cref="Association"/> may be stored or retrieved.
/// </summary>
- public string Handle { get; private set; }
+ public string Handle { get; internal set; }
/// <summary>
/// Gets the UTC time when this <see cref="Association"/> will expire.
@@ -85,6 +85,7 @@ namespace DotNetOpenAuth.OpenId {
/// <summary>
/// Gets or sets the UTC time that this <see cref="Association"/> was first created.
/// </summary>
+ [MessagePart]
internal DateTime Issued { get; set; }
/// <summary>
@@ -102,6 +103,7 @@ namespace DotNetOpenAuth.OpenId {
/// Gets the shared secret key between the consumer and provider.
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "It is a buffer.")]
+ [MessagePart("key")]
protected internal byte[] SecretKey { get; private set; }
/// <summary>
@@ -117,6 +119,7 @@ namespace DotNetOpenAuth.OpenId {
/// <summary>
/// Gets the lifetime the OpenID provider permits this <see cref="Association"/>.
/// </summary>
+ [MessagePart("ttl")]
protected TimeSpan TotalLifeLength { get; private set; }
/// <summary>
diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs
index bc613ed..049ea3a 100644
--- a/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs
+++ b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs
@@ -49,7 +49,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
/// <param name="associationStore">The association store to use.</param>
/// <param name="nonceStore">The nonce store to use.</param>
/// <param name="securitySettings">The security settings to apply.</param>
- internal OpenIdChannel(IAssociationStore<Uri> associationStore, INonceStore nonceStore, RelyingPartySecuritySettings securitySettings)
+ internal OpenIdChannel(IAssociationStore associationStore, INonceStore nonceStore, RelyingPartySecuritySettings securitySettings)
: this(associationStore, nonceStore, new OpenIdMessageFactory(), securitySettings, false) {
Contract.Requires<ArgumentNullException>(securitySettings != null);
}
@@ -58,11 +58,11 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
/// Initializes a new instance of the <see cref="OpenIdChannel"/> class
/// for use by a Provider.
/// </summary>
- /// <param name="associationStore">The association store to use.</param>
/// <param name="nonceStore">The nonce store to use.</param>
/// <param name="securitySettings">The security settings.</param>
- internal OpenIdChannel(IAssociationStore<AssociationRelyingPartyType> associationStore, INonceStore nonceStore, ProviderSecuritySettings securitySettings)
+ internal OpenIdChannel(ProviderAssociationStore associationStore, INonceStore nonceStore, ProviderSecuritySettings securitySettings)
: this(associationStore, nonceStore, new OpenIdMessageFactory(), securitySettings) {
+ Contract.Requires<ArgumentNullException>(associationStore != null, "associationStore");
Contract.Requires<ArgumentNullException>(securitySettings != null);
}
@@ -75,7 +75,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
/// <param name="messageTypeProvider">An object that knows how to distinguish the various OpenID message types for deserialization purposes.</param>
/// <param name="securitySettings">The security settings to apply.</param>
/// <param name="nonVerifying">A value indicating whether the channel is set up with no functional security binding elements.</param>
- private OpenIdChannel(IAssociationStore<Uri> associationStore, INonceStore nonceStore, IMessageFactory messageTypeProvider, RelyingPartySecuritySettings securitySettings, bool nonVerifying) :
+ private OpenIdChannel(IAssociationStore associationStore, INonceStore nonceStore, IMessageFactory messageTypeProvider, RelyingPartySecuritySettings securitySettings, bool nonVerifying) :
this(messageTypeProvider, InitializeBindingElements(associationStore, nonceStore, securitySettings, nonVerifying)) {
Contract.Requires<ArgumentNullException>(messageTypeProvider != null);
Contract.Requires<ArgumentNullException>(securitySettings != null);
@@ -90,8 +90,9 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
/// <param name="nonceStore">The nonce store to use.</param>
/// <param name="messageTypeProvider">An object that knows how to distinguish the various OpenID message types for deserialization purposes.</param>
/// <param name="securitySettings">The security settings.</param>
- private OpenIdChannel(IAssociationStore<AssociationRelyingPartyType> associationStore, INonceStore nonceStore, IMessageFactory messageTypeProvider, ProviderSecuritySettings securitySettings) :
- this(messageTypeProvider, InitializeBindingElements(associationStore, nonceStore, securitySettings, false)) {
+ private OpenIdChannel(ProviderAssociationStore associationStore, INonceStore nonceStore, IMessageFactory messageTypeProvider, ProviderSecuritySettings securitySettings) :
+ this(messageTypeProvider, InitializeBindingElements(associationStore, nonceStore, securitySettings)) {
+ Contract.Requires<ArgumentNullException>(associationStore != null, "associationStore");
Contract.Requires<ArgumentNullException>(messageTypeProvider != null);
Contract.Requires<ArgumentNullException>(securitySettings != null);
}
@@ -302,7 +303,6 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
/// <summary>
/// Initializes the binding elements.
/// </summary>
- /// <typeparam name="T">The distinguishing factor used by the association store.</typeparam>
/// <param name="associationStore">The association store.</param>
/// <param name="nonceStore">The nonce store to use.</param>
/// <param name="securitySettings">The security settings to apply. Must be an instance of either <see cref="RelyingPartySecuritySettings"/> or <see cref="ProviderSecuritySettings"/>.</param>
@@ -310,57 +310,36 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
/// <returns>
/// An array of binding elements which may be used to construct the channel.
/// </returns>
- [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "Needed for code contracts.")]
- private static IChannelBindingElement[] InitializeBindingElements<T>(IAssociationStore<T> associationStore, INonceStore nonceStore, SecuritySettings securitySettings, bool nonVerifying) {
+ private static IChannelBindingElement[] InitializeBindingElements(IAssociationStore associationStore, INonceStore nonceStore, RelyingPartySecuritySettings securitySettings, bool nonVerifying) {
Contract.Requires<ArgumentNullException>(securitySettings != null);
- Contract.Requires<ArgumentException>(!nonVerifying || securitySettings is RelyingPartySecuritySettings);
-
- var rpSecuritySettings = securitySettings as RelyingPartySecuritySettings;
- var opSecuritySettings = securitySettings as ProviderSecuritySettings;
- ErrorUtilities.VerifyInternal(rpSecuritySettings != null || opSecuritySettings != null, "Expected an RP or OP security settings instance.");
- ErrorUtilities.VerifyInternal(!nonVerifying || rpSecuritySettings != null, "Non-verifying channels can only be constructed for relying parties.");
- bool isRelyingPartyRole = rpSecuritySettings != null;
-
- var rpAssociationStore = associationStore as IAssociationStore<Uri>;
- var opAssociationStore = associationStore as IAssociationStore<AssociationRelyingPartyType>;
- ErrorUtilities.VerifyInternal(isRelyingPartyRole || opAssociationStore != null, "Providers MUST have an association store.");
SigningBindingElement signingElement;
- if (isRelyingPartyRole) {
- signingElement = nonVerifying ? null : new SigningBindingElement(rpAssociationStore);
- } else {
- signingElement = new SigningBindingElement(opAssociationStore, opSecuritySettings);
- }
+ signingElement = nonVerifying ? null : new SigningBindingElement(associationStore);
var extensionFactory = OpenIdExtensionFactoryAggregator.LoadFromConfiguration();
List<IChannelBindingElement> elements = new List<IChannelBindingElement>(8);
elements.Add(new ExtensionsBindingElement(extensionFactory, securitySettings));
- if (isRelyingPartyRole) {
- elements.Add(new RelyingPartySecurityOptions(rpSecuritySettings));
- elements.Add(new BackwardCompatibilityBindingElement());
- ReturnToNonceBindingElement requestNonceElement = null;
-
- if (associationStore != null) {
- if (nonceStore != null) {
- // There is no point in having a ReturnToNonceBindingElement without
- // a ReturnToSignatureBindingElement because the nonce could be
- // artificially changed without it.
- requestNonceElement = new ReturnToNonceBindingElement(nonceStore, rpSecuritySettings);
- elements.Add(requestNonceElement);
- }
+ elements.Add(new RelyingPartySecurityOptions(securitySettings));
+ elements.Add(new BackwardCompatibilityBindingElement());
+ ReturnToNonceBindingElement requestNonceElement = null;
- // It is important that the return_to signing element comes last
- // so that the nonce is included in the signature.
- elements.Add(new ReturnToSignatureBindingElement(rpAssociationStore, rpSecuritySettings));
+ if (associationStore != null) {
+ if (nonceStore != null) {
+ // There is no point in having a ReturnToNonceBindingElement without
+ // a ReturnToSignatureBindingElement because the nonce could be
+ // artificially changed without it.
+ requestNonceElement = new ReturnToNonceBindingElement(nonceStore, securitySettings);
+ elements.Add(requestNonceElement);
}
- ErrorUtilities.VerifyOperation(!rpSecuritySettings.RejectUnsolicitedAssertions || requestNonceElement != null, OpenIdStrings.UnsolicitedAssertionRejectionRequiresNonceStore);
- } else {
- // Providers must always have a nonce store.
- ErrorUtilities.VerifyArgumentNotNull(nonceStore, "nonceStore");
+ // It is important that the return_to signing element comes last
+ // so that the nonce is included in the signature.
+ elements.Add(new ReturnToSignatureBindingElement(associationStore, securitySettings));
}
+ ErrorUtilities.VerifyOperation(!securitySettings.RejectUnsolicitedAssertions || requestNonceElement != null, OpenIdStrings.UnsolicitedAssertionRejectionRequiresNonceStore);
+
if (nonVerifying) {
elements.Add(new SkipSecurityBindingElement());
} else {
@@ -374,5 +353,34 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
return elements.ToArray();
}
+
+ /// <summary>
+ /// Initializes the binding elements.
+ /// </summary>
+ /// <param name="associationStore">The association store.</param>
+ /// <param name="nonceStore">The nonce store to use.</param>
+ /// <param name="securitySettings">The security settings to apply. Must be an instance of either <see cref="RelyingPartySecuritySettings"/> or <see cref="ProviderSecuritySettings"/>.</param>
+ /// <param name="nonVerifying">A value indicating whether the channel is set up with no functional security binding elements.</param>
+ /// <returns>
+ /// An array of binding elements which may be used to construct the channel.
+ /// </returns>
+ private static IChannelBindingElement[] InitializeBindingElements(ProviderAssociationStore associationStore, INonceStore nonceStore, ProviderSecuritySettings securitySettings) {
+ Contract.Requires<ArgumentNullException>(associationStore != null, "associationStore");
+ Contract.Requires<ArgumentNullException>(securitySettings != null);
+ Contract.Requires<ArgumentNullException>(nonceStore != null, "nonceStore");
+
+ SigningBindingElement signingElement;
+ signingElement = new SigningBindingElement(associationStore, securitySettings);
+
+ var extensionFactory = OpenIdExtensionFactoryAggregator.LoadFromConfiguration();
+
+ List<IChannelBindingElement> elements = new List<IChannelBindingElement>(8);
+ elements.Add(new ExtensionsBindingElement(extensionFactory, securitySettings));
+ elements.Add(new StandardReplayProtectionBindingElement(nonceStore, true));
+ elements.Add(new StandardExpirationBindingElement());
+ elements.Add(signingElement);
+
+ return elements.ToArray();
+ }
}
}
diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/ReturnToSignatureBindingElement.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/ReturnToSignatureBindingElement.cs
index 438c496..aba5dbd 100644
--- a/src/DotNetOpenAuth/OpenId/ChannelElements/ReturnToSignatureBindingElement.cs
+++ b/src/DotNetOpenAuth/OpenId/ChannelElements/ReturnToSignatureBindingElement.cs
@@ -52,7 +52,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
/// </summary>
/// <param name="secretStore">The secret store from which to retrieve the secret used for signing.</param>
/// <param name="securitySettings">The security settings.</param>
- internal ReturnToSignatureBindingElement(IAssociationStore<Uri> secretStore, RelyingPartySecuritySettings securitySettings) {
+ internal ReturnToSignatureBindingElement(IAssociationStore secretStore, RelyingPartySecuritySettings securitySettings) {
Contract.Requires<ArgumentNullException>(secretStore != null);
this.secretManager = new PrivateSecretManager(securitySettings, secretStore);
diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs
index 30310ac..be64d82 100644
--- a/src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs
+++ b/src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs
@@ -28,12 +28,12 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
/// <summary>
/// The association store used by Relying Parties to look up the secrets needed for signing.
/// </summary>
- private readonly IAssociationStore<Uri> rpAssociations;
+ private readonly IAssociationStore rpAssociations;
/// <summary>
/// The association store used by Providers to look up the secrets needed for signing.
/// </summary>
- private readonly IAssociationStore<AssociationRelyingPartyType> opAssociations;
+ private readonly ProviderAssociationStore opAssociations;
/// <summary>
/// The security settings at the Provider.
@@ -45,7 +45,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
/// Initializes a new instance of the SigningBindingElement class for use by a Relying Party.
/// </summary>
/// <param name="associationStore">The association store used to look up the secrets needed for signing. May be null for dumb Relying Parties.</param>
- internal SigningBindingElement(IAssociationStore<Uri> associationStore) {
+ internal SigningBindingElement(IAssociationStore associationStore) {
this.rpAssociations = associationStore;
}
@@ -54,8 +54,8 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
/// </summary>
/// <param name="associationStore">The association store used to look up the secrets needed for signing.</param>
/// <param name="securitySettings">The security settings.</param>
- internal SigningBindingElement(IAssociationStore<AssociationRelyingPartyType> associationStore, ProviderSecuritySettings securitySettings) {
- Contract.Requires<ArgumentNullException>(associationStore != null);
+ internal SigningBindingElement(ProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
+ Contract.Requires<ArgumentNullException>(associationStore != null, "associationStore");
Contract.Requires<ArgumentNullException>(securitySettings != null);
this.opAssociations = associationStore;
@@ -83,7 +83,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
/// Gets a value indicating whether this binding element is on a Provider channel.
/// </summary>
private bool IsOnProvider {
- get { return this.opAssociations != null; }
+ get { return this.opSecuritySettings != null; }
}
#region IChannelBindingElement Methods
@@ -232,14 +232,14 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
// get included in the list of checked parameters.
Protocol protocol = Protocol.Lookup(signedMessage.Version);
var partsRequiringProtection = from part in this.Channel.MessageDescriptions.Get(signedMessage).Mapping.Values
- where part.RequiredProtection != ProtectionLevel.None
- where part.IsRequired || part.IsNondefaultValueSet(signedMessage)
- select part.Name;
+ where part.RequiredProtection != ProtectionLevel.None
+ where part.IsRequired || part.IsNondefaultValueSet(signedMessage)
+ select part.Name;
ErrorUtilities.VerifyInternal(partsRequiringProtection.All(name => name.StartsWith(protocol.openid.Prefix, StringComparison.Ordinal)), "Signing only works when the parameters start with the 'openid.' prefix.");
string[] signedParts = signedMessage.SignedParameterOrder.Split(',');
var unsignedParts = from partName in partsRequiringProtection
- where !signedParts.Contains(partName.Substring(protocol.openid.Prefix.Length))
- select partName;
+ where !signedParts.Contains(partName.Substring(protocol.openid.Prefix.Length))
+ select partName;
ErrorUtilities.VerifyProtocol(!unsignedParts.Any(), OpenIdStrings.SignatureDoesNotIncludeMandatoryParts, string.Join(", ", unsignedParts.ToArray()));
}
@@ -292,9 +292,9 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
MessageDescription description = this.Channel.MessageDescriptions.Get(signedMessage);
var signedParts = from part in description.Mapping.Values
- where (part.RequiredProtection & System.Net.Security.ProtectionLevel.Sign) != 0
- && part.GetValue(signedMessage) != null
- select part.Name;
+ where (part.RequiredProtection & System.Net.Security.ProtectionLevel.Sign) != 0
+ && part.GetValue(signedMessage) != null
+ select part.Name;
string prefix = Protocol.V20.openid.Prefix;
ErrorUtilities.VerifyInternal(signedParts.All(name => name.StartsWith(prefix, StringComparison.Ordinal)), "All signed message parts must start with 'openid.'.");
@@ -379,7 +379,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
// or verifying a dumb one.
bool signing = string.IsNullOrEmpty(signedMessage.Signature);
AssociationRelyingPartyType type = signing ? AssociationRelyingPartyType.Smart : AssociationRelyingPartyType.Dumb;
- association = this.opAssociations.GetAssociation(type, signedMessage.AssociationHandle);
+ association = this.opAssociations.Decode(signedMessage, type, signedMessage.AssociationHandle);
if (association == null) {
// There was no valid association with the requested handle.
// Let's tell the RP to forget about that association.
@@ -403,12 +403,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
// If no assoc_handle was given or it was invalid, the only thing
// left to do is sign a message using a 'dumb' mode association.
Protocol protocol = Protocol.Default;
- Association association = this.opAssociations.GetAssociation(AssociationRelyingPartyType.Dumb, this.opSecuritySettings);
- if (association == null) {
- association = HmacShaAssociation.Create(protocol, protocol.Args.SignatureAlgorithm.HMAC_SHA256, AssociationRelyingPartyType.Dumb, this.opSecuritySettings);
- this.opAssociations.StoreAssociation(AssociationRelyingPartyType.Dumb, association);
- }
-
+ Association association = HmacShaAssociation.Create(protocol, protocol.Args.SignatureAlgorithm.HMAC_SHA256, AssociationRelyingPartyType.Dumb, this.opAssociations, this.opSecuritySettings);
return association;
}
}
diff --git a/src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs b/src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs
index edc08ee..0108566 100644
--- a/src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs
+++ b/src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs
@@ -102,7 +102,6 @@ namespace DotNetOpenAuth.OpenId {
Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(associationType));
Contract.Requires<ArgumentNullException>(secret != null);
Contract.Ensures(Contract.Result<HmacShaAssociation>() != null);
-
HmacSha match = hmacShaAssociationTypes.FirstOrDefault(sha => String.Equals(sha.GetAssociationType(protocol), associationType, StringComparison.Ordinal));
ErrorUtilities.VerifyProtocol(match != null, OpenIdStrings.NoAssociationTypeFoundByName, associationType);
return new HmacShaAssociation(match, handle, secret, totalLifeLength);
@@ -139,7 +138,7 @@ namespace DotNetOpenAuth.OpenId {
}
/// <summary>
- /// Creates a new association of a given type.
+ /// Creates a new association of a given type at an OpenID Provider.
/// </summary>
/// <param name="protocol">The protocol.</param>
/// <param name="associationType">Type of the association (i.e. HMAC-SHA1 or HMAC-SHA256)</param>
@@ -150,24 +149,15 @@ namespace DotNetOpenAuth.OpenId {
/// <remarks>
/// The new association is NOT automatically put into an association store. This must be done by the caller.
/// </remarks>
- internal static HmacShaAssociation Create(Protocol protocol, string associationType, AssociationRelyingPartyType associationUse, ProviderSecuritySettings securitySettings) {
+ internal static HmacShaAssociation Create(Protocol protocol, string associationType, AssociationRelyingPartyType associationUse, ProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
Contract.Requires<ArgumentNullException>(protocol != null);
Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(associationType));
+ Contract.Requires<ArgumentNullException>(associationStore != null, "associationStore");
Contract.Requires<ArgumentNullException>(securitySettings != null);
Contract.Ensures(Contract.Result<HmacShaAssociation>() != null);
int secretLength = GetSecretLength(protocol, associationType);
- // Generate the handle. It must be unique, and preferably unpredictable,
- // so we use a time element and a random data element to generate it.
- string uniq = MessagingUtilities.GetCryptoRandomDataAsBase64(4);
- string handle = string.Format(
- CultureInfo.InvariantCulture,
- "{{{0}}}{{{1}}}{{{2}}}",
- DateTime.UtcNow.Ticks,
- uniq,
- secretLength);
-
// Generate the secret that will be used for signing
byte[] secret = MessagingUtilities.GetCryptoRandomData(secretLength);
@@ -180,10 +170,13 @@ namespace DotNetOpenAuth.OpenId {
lifetime = DumbSecretLifetime;
}
+ string handle = associationStore.Encode(new AssociationDataBag { ExpiresUtc = DateTime.UtcNow + lifetime, Secret = secret, AssociationType = associationUse });
+
Contract.Assert(protocol != null); // All the way up to the method call, the condition holds, yet we get a Requires failure next
Contract.Assert(secret != null);
Contract.Assert(!String.IsNullOrEmpty(associationType));
- return Create(protocol, associationType, handle, secret, lifetime);
+ var result = Create(protocol, associationType, handle, secret, lifetime);
+ return result;
}
/// <summary>
diff --git a/src/DotNetOpenAuth/OpenId/IAssociationStore.cs b/src/DotNetOpenAuth/OpenId/IAssociationStore.cs
deleted file mode 100644
index fb4487c..0000000
--- a/src/DotNetOpenAuth/OpenId/IAssociationStore.cs
+++ /dev/null
@@ -1,189 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="IAssociationStore.cs" company="Andrew Arnott">
-// Copyright (c) Andrew Arnott. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OpenId {
- using System;
- using System.Diagnostics.Contracts;
-
- /// <summary>
- /// An enumeration that can specify how a given <see cref="Association"/> is used.
- /// </summary>
- public enum AssociationRelyingPartyType {
- /// <summary>
- /// The <see cref="Association"/> manages a shared secret between
- /// Provider and Relying Party sites that allows the RP to verify
- /// the signature on a message from an OP.
- /// </summary>
- Smart,
-
- /// <summary>
- /// The <see cref="Association"/> manages a secret known alone by
- /// a Provider that allows the Provider to verify its own signatures
- /// for "dumb" (stateless) relying parties.
- /// </summary>
- Dumb
- }
-
- /// <summary>
- /// Stores <see cref="Association"/>s for lookup by their handle, keeping
- /// associations separated by a given distinguishing factor (like which server the
- /// association is with).
- /// </summary>
- /// <typeparam name="TKey">
- /// <see cref="System.Uri"/> for consumers (to distinguish associations across servers) or
- /// <see cref="AssociationRelyingPartyType"/> for providers (to distinguish dumb and smart client associations).
- /// </typeparam>
- /// <remarks>
- /// Expired associations should be periodically cleared out of an association store.
- /// This should be done frequently enough to avoid a memory leak, but sparingly enough
- /// to not be a performance drain. Because this balance can vary by host, it is the
- /// responsibility of the host to initiate this cleaning.
- /// </remarks>
- ////[ContractClass(typeof(IAssociationStoreContract<>))]
- public interface IAssociationStore<TKey> {
- /// <summary>
- /// Saves an <see cref="Association"/> for later recall.
- /// </summary>
- /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for providers).</param>
- /// <param name="association">The association to store.</param>
- /// <remarks>
- /// TODO: what should implementations do on association handle conflict?
- /// </remarks>
- void StoreAssociation(TKey distinguishingFactor, Association association);
-
- /// <summary>
- /// Gets the best association (the one with the longest remaining life) for a given key.
- /// </summary>
- /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
- /// <param name="securityRequirements">The security requirements that the returned association must meet.</param>
- /// <returns>
- /// The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key.
- /// </returns>
- /// <remarks>
- /// In the event that multiple associations exist for the given
- /// <paramref name="distinguishingFactor"/>, it is important for the
- /// implementation for this method to use the <paramref name="securityRequirements"/>
- /// to pick the best (highest grade or longest living as the host's policy may dictate)
- /// association that fits the security requirements.
- /// Associations that are returned that do not meet the security requirements will be
- /// ignored and a new association created.
- /// </remarks>
- Association GetAssociation(TKey distinguishingFactor, SecuritySettings securityRequirements);
-
- /// <summary>
- /// Gets the association for a given key and handle.
- /// </summary>
- /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
- /// <param name="handle">The handle of the specific association that must be recalled.</param>
- /// <returns>The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key and handle.</returns>
- Association GetAssociation(TKey distinguishingFactor, string handle);
-
- /// <summary>Removes a specified handle that may exist in the store.</summary>
- /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
- /// <param name="handle">The handle of the specific association that must be deleted.</param>
- /// <returns>True if the association existed in this store previous to this call.</returns>
- /// <remarks>
- /// No exception should be thrown if the association does not exist in the store
- /// before this call.
- /// </remarks>
- bool RemoveAssociation(TKey distinguishingFactor, string handle);
- }
-
- // For some odd reason, having this next class causes our test project to fail to build with this error:
- // Error 42 Method 'StoreAssociation' in type 'DotNetOpenAuth.OpenId.IAssociationStoreContract_Accessor`1' from assembly 'DotNetOpenAuth_Accessor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation. DotNetOpenAuth.Test
- /////// <summary>
- /////// Code Contract for the <see cref="IAssociationStore&lt;TKey&gt;"/> class.
- /////// </summary>
- /////// <typeparam name="TKey">The type of the key.</typeparam>
- ////[ContractClassFor(typeof(IAssociationStore<>))]
- ////internal abstract class IAssociationStoreContract<TKey> : IAssociationStore<TKey> {
- //// #region IAssociationStore<TKey> Members
-
- //// /// <summary>
- //// /// Saves an <see cref="Association"/> for later recall.
- //// /// </summary>
- //// /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for providers).</param>
- //// /// <param name="association">The association to store.</param>
- //// /// <remarks>
- //// /// TODO: what should implementations do on association handle conflict?
- //// /// </remarks>
- //// void IAssociationStore<TKey>.StoreAssociation(TKey distinguishingFactor, Association association) {
- //// Contract.Requires<ArgumentNullException>(distinguishingFactor != null);
- //// Contract.Requires<ArgumentNullException>(association != null);
- //// throw new NotImplementedException();
- //// }
-
- //// /// <summary>
- //// /// Gets the best association (the one with the longest remaining life) for a given key.
- //// /// </summary>
- //// /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
- //// /// <param name="securityRequirements">The security requirements that the returned association must meet.</param>
- //// /// <returns>
- //// /// The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key.
- //// /// </returns>
- //// /// <remarks>
- //// /// In the event that multiple associations exist for the given
- //// /// <paramref name="distinguishingFactor"/>, it is important for the
- //// /// implementation for this method to use the <paramref name="securityRequirements"/>
- //// /// to pick the best (highest grade or longest living as the host's policy may dictate)
- //// /// association that fits the security requirements.
- //// /// Associations that are returned that do not meet the security requirements will be
- //// /// ignored and a new association created.
- //// /// </remarks>
- //// Association IAssociationStore<TKey>.GetAssociation(TKey distinguishingFactor, SecuritySettings securityRequirements) {
- //// Contract.Requires<ArgumentNullException>(distinguishingFactor != null);
- //// Contract.Requires<ArgumentNullException>(securityRequirements != null);
- //// throw new NotImplementedException();
- //// }
-
- //// /// <summary>
- //// /// Gets the association for a given key and handle.
- //// /// </summary>
- //// /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
- //// /// <param name="handle">The handle of the specific association that must be recalled.</param>
- //// /// <returns>
- //// /// The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key and handle.
- //// /// </returns>
- //// Association IAssociationStore<TKey>.GetAssociation(TKey distinguishingFactor, string handle) {
- //// Contract.Requires<ArgumentNullException>(distinguishingFactor != null);
- //// Contract.Requires(!String.IsNullOrEmpty(handle));
- //// throw new NotImplementedException();
- //// }
-
- //// /// <summary>
- //// /// Removes a specified handle that may exist in the store.
- //// /// </summary>
- //// /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
- //// /// <param name="handle">The handle of the specific association that must be deleted.</param>
- //// /// <returns>
- //// /// True if the association existed in this store previous to this call.
- //// /// </returns>
- //// /// <remarks>
- //// /// No exception should be thrown if the association does not exist in the store
- //// /// before this call.
- //// /// </remarks>
- //// bool IAssociationStore<TKey>.RemoveAssociation(TKey distinguishingFactor, string handle) {
- //// Contract.Requires<ArgumentNullException>(distinguishingFactor != null);
- //// Contract.Requires(!String.IsNullOrEmpty(handle));
- //// throw new NotImplementedException();
- //// }
-
- //// /// <summary>
- //// /// Clears all expired associations from the store.
- //// /// </summary>
- //// /// <remarks>
- //// /// If another algorithm is in place to periodically clear out expired associations,
- //// /// this method call may be ignored.
- //// /// This should be done frequently enough to avoid a memory leak, but sparingly enough
- //// /// to not be a performance drain.
- //// /// </remarks>
- //// void IAssociationStore<TKey>.ClearExpiredAssociations() {
- //// throw new NotImplementedException();
- //// }
-
- //// #endregion
- ////}
-}
diff --git a/src/DotNetOpenAuth/OpenId/Messages/AssociateDiffieHellmanResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/AssociateDiffieHellmanResponse.cs
index a4fdf49..86e2d8c 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/AssociateDiffieHellmanResponse.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/AssociateDiffieHellmanResponse.cs
@@ -72,14 +72,14 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// The response message is updated to include the details of the created association by this method,
/// but the resulting association is <i>not</i> added to the association store and must be done by the caller.
/// </remarks>
- protected override Association CreateAssociationAtProvider(AssociateRequest request, ProviderSecuritySettings securitySettings) {
+ protected override Association CreateAssociationAtProvider(AssociateRequest request, ProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
var diffieHellmanRequest = request as AssociateDiffieHellmanRequest;
ErrorUtilities.VerifyInternal(diffieHellmanRequest != null, "Expected a DH request type.");
this.SessionType = this.SessionType ?? request.SessionType;
// Go ahead and create the association first, complete with its secret that we're about to share.
- Association association = HmacShaAssociation.Create(this.Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, securitySettings);
+ Association association = HmacShaAssociation.Create(this.Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, associationStore, securitySettings);
// We now need to securely communicate the secret to the relying party using Diffie-Hellman.
// We do this by performing a DH algorithm on the secret and setting a couple of properties
diff --git a/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs b/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs
index 3fd9424..937c7ff 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs
@@ -129,7 +129,6 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// <summary>
/// Creates a Provider's response to an incoming association request.
/// </summary>
- /// <param name="associationStore">The association store where a new association (if created) will be stored. Must not be null.</param>
/// <param name="securitySettings">The security settings on the Provider.</param>
/// <returns>
/// The appropriate association response that is ready to be sent back to the Relying Party.
@@ -140,8 +139,8 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// <para>Successful association response messages will derive from <see cref="AssociateSuccessfulResponse"/>.
/// Failed association response messages will derive from <see cref="AssociateUnsuccessfulResponse"/>.</para>
/// </remarks>
- internal IProtocolMessage CreateResponse(IAssociationStore<AssociationRelyingPartyType> associationStore, ProviderSecuritySettings securitySettings) {
- Contract.Requires<ArgumentNullException>(associationStore != null);
+ internal IProtocolMessage CreateResponse(ProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
+ Contract.Requires<ArgumentNullException>(associationStore != null, "associationStore");
Contract.Requires<ArgumentNullException>(securitySettings != null);
IProtocolMessage response;
@@ -152,8 +151,7 @@ namespace DotNetOpenAuth.OpenId.Messages {
// Create and store the association if this is a successful response.
var successResponse = response as AssociateSuccessfulResponse;
if (successResponse != null) {
- Association association = successResponse.CreateAssociation(this, securitySettings);
- associationStore.StoreAssociation(AssociationRelyingPartyType.Smart, association);
+ successResponse.CreateAssociation(this, associationStore, securitySettings);
}
} else {
response = this.CreateUnsuccessfulResponse(securitySettings);
diff --git a/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs
index 137cd60..e3d280f 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs
@@ -102,12 +102,11 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// <param name="securitySettings">The security settings for the Provider. Should be <c>null</c> for Relying Parties.</param>
/// <returns>The created association.</returns>
/// <remarks>
- /// <para>The response message is updated to include the details of the created association by this method,
- /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para>
- /// <para>This method is called by both the Provider and the Relying Party, but actually performs
- /// quite different operations in either scenario.</para>
+ /// The response message is updated to include the details of the created association by this method.
+ /// This method is called by both the Provider and the Relying Party, but actually performs
+ /// quite different operations in either scenario.
/// </remarks>
- internal Association CreateAssociation(AssociateRequest request, ProviderSecuritySettings securitySettings) {
+ internal Association CreateAssociation(AssociateRequest request, ProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
Contract.Requires<ArgumentNullException>(request != null);
ErrorUtilities.VerifyInternal(!this.associationCreated, "The association has already been created.");
@@ -119,7 +118,7 @@ namespace DotNetOpenAuth.OpenId.Messages {
association = this.CreateAssociationAtRelyingParty(request);
} else {
ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings");
- association = this.CreateAssociationAtProvider(request, securitySettings);
+ association = this.CreateAssociationAtProvider(request, associationStore, securitySettings);
this.ExpiresIn = association.SecondsTillExpiration;
this.AssociationHandle = association.Handle;
}
@@ -142,7 +141,7 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// <para>The response message is updated to include the details of the created association by this method,
/// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para>
/// </remarks>
- protected abstract Association CreateAssociationAtProvider(AssociateRequest request, ProviderSecuritySettings securitySettings);
+ protected abstract Association CreateAssociationAtProvider(AssociateRequest request, ProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings);
/// <summary>
/// Called to create the Association based on a request previously given by the Relying Party.
diff --git a/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponseContract.cs b/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponseContract.cs
index dd37da6..c2e7a86 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponseContract.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponseContract.cs
@@ -15,8 +15,9 @@ namespace DotNetOpenAuth.OpenId.Messages {
protected AssociateSuccessfulResponseContract() : base(null, null) {
}
- protected override Association CreateAssociationAtProvider(AssociateRequest request, ProviderSecuritySettings securitySettings) {
+ protected override Association CreateAssociationAtProvider(AssociateRequest request, ProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
Contract.Requires<ArgumentNullException>(request != null);
+ Contract.Requires<ArgumentNullException>(associationStore != null, "associationStore");
Contract.Requires<ArgumentNullException>(securitySettings != null);
throw new NotImplementedException();
}
diff --git a/src/DotNetOpenAuth/OpenId/Messages/AssociateUnencryptedResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/AssociateUnencryptedResponse.cs
index 493fe6b..77079cc 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/AssociateUnencryptedResponse.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/AssociateUnencryptedResponse.cs
@@ -48,8 +48,8 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// <para>The response message is updated to include the details of the created association by this method,
/// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para>
/// </remarks>
- protected override Association CreateAssociationAtProvider(AssociateRequest request, ProviderSecuritySettings securitySettings) {
- Association association = HmacShaAssociation.Create(Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, securitySettings);
+ protected override Association CreateAssociationAtProvider(AssociateRequest request, ProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
+ Association association = HmacShaAssociation.Create(Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, associationStore, securitySettings);
this.MacKey = association.SecretKey;
return association;
}
diff --git a/src/DotNetOpenAuth/OpenId/Messages/CheckAuthenticationResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/CheckAuthenticationResponse.cs
index f1bb5ac..e4e8c7c 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/CheckAuthenticationResponse.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/CheckAuthenticationResponse.cs
@@ -44,10 +44,10 @@ namespace DotNetOpenAuth.OpenId.Messages {
this.IsValid = request.IsValid;
// Confirm the RP should invalidate the association handle only if the association
- // really doesn't exist. OpenID 2.0 section 11.4.2.2.
+ // is not valid (any longer). OpenID 2.0 section 11.4.2.2.
IndirectSignedResponse signedResponse = new IndirectSignedResponse(request, provider.Channel);
string invalidateHandle = ((ITamperResistantOpenIdMessage)signedResponse).InvalidateHandle;
- if (!string.IsNullOrEmpty(invalidateHandle) && provider.AssociationStore.GetAssociation(AssociationRelyingPartyType.Smart, invalidateHandle) == null) {
+ if (!string.IsNullOrEmpty(invalidateHandle) && provider.AssociationStore.IsValid(signedResponse, AssociationRelyingPartyType.Smart, invalidateHandle) == null) {
this.InvalidateHandle = invalidateHandle;
}
}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/AssociationDataBag.cs b/src/DotNetOpenAuth/OpenId/Provider/AssociationDataBag.cs
new file mode 100644
index 0000000..1b5be94
--- /dev/null
+++ b/src/DotNetOpenAuth/OpenId/Provider/AssociationDataBag.cs
@@ -0,0 +1,39 @@
+//-----------------------------------------------------------------------
+// <copyright file="AssociationDataBag.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Provider {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ internal class AssociationDataBag : DataBag {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AssociationDataBag"/> class.
+ /// </summary>
+ public AssociationDataBag() {
+ }
+
+ [MessagePart(IsRequired = true)]
+ internal byte[] Secret { get; set; }
+
+ [MessagePart(IsRequired = true)]
+ internal DateTime ExpiresUtc { get; set; }
+
+ [MessagePart(IsRequired = true)]
+ internal bool IsPrivateAssociation {
+ get { return this.AssociationType == AssociationRelyingPartyType.Dumb; }
+ set { this.AssociationType = value ? AssociationRelyingPartyType.Dumb : AssociationRelyingPartyType.Smart; }
+ }
+
+ internal AssociationRelyingPartyType AssociationType { get; set; }
+
+ internal static IDataBagFormatter<AssociationDataBag> CreateFormatter(byte[] symmetricSecret) {
+ return new UriStyleMessageFormatter<AssociationDataBag>(symmetricSecret, signed: true, encrypted: true);
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/AssociationRelyingPartyType.cs b/src/DotNetOpenAuth/OpenId/Provider/AssociationRelyingPartyType.cs
new file mode 100644
index 0000000..4d121b1
--- /dev/null
+++ b/src/DotNetOpenAuth/OpenId/Provider/AssociationRelyingPartyType.cs
@@ -0,0 +1,26 @@
+//-----------------------------------------------------------------------
+// <copyright file="AssociationRelyingPartyType.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Provider {
+ /// <summary>
+ /// An enumeration that can specify how a given <see cref="Association"/> is used.
+ /// </summary>
+ public enum AssociationRelyingPartyType {
+ /// <summary>
+ /// The <see cref="Association"/> manages a shared secret between
+ /// Provider and Relying Party sites that allows the RP to verify
+ /// the signature on a message from an OP.
+ /// </summary>
+ Smart,
+
+ /// <summary>
+ /// The <see cref="Association"/> manages a secret known alone by
+ /// a Provider that allows the Provider to verify its own signatures
+ /// for "dumb" (stateless) relying parties.
+ /// </summary>
+ Dumb
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/IProviderApplicationStore.cs b/src/DotNetOpenAuth/OpenId/Provider/IProviderApplicationStore.cs
index c16f1f9..cea303f 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/IProviderApplicationStore.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/IProviderApplicationStore.cs
@@ -12,9 +12,8 @@ namespace DotNetOpenAuth.OpenId.Provider {
using DotNetOpenAuth.Messaging.Bindings;
/// <summary>
- /// A hybrid of all the store interfaces that a Provider requires in order
- /// to operate in "smart" mode.
+ /// A hybrid of all the store interfaces that an OpenID Provider must implement.
/// </summary>
- public interface IProviderApplicationStore : IAssociationStore<AssociationRelyingPartyType>, INonceStore {
+ public interface IProviderApplicationStore : INonceStore {
}
}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs b/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs
index 3b4cb56..304edbe 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs
@@ -55,7 +55,6 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// </summary>
public OpenIdProvider()
: this(DotNetOpenAuthSection.Configuration.OpenId.Provider.ApplicationStore.CreateInstance(HttpApplicationStore)) {
- Contract.Ensures(this.AssociationStore != null);
Contract.Ensures(this.SecuritySettings != null);
Contract.Ensures(this.Channel != null);
}
@@ -65,9 +64,8 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// </summary>
/// <param name="applicationStore">The application store to use. Cannot be null.</param>
public OpenIdProvider(IProviderApplicationStore applicationStore)
- : this(applicationStore, applicationStore) {
+ : this((INonceStore)applicationStore) {
Contract.Requires<ArgumentNullException>(applicationStore != null);
- Contract.Ensures(this.AssociationStore == applicationStore);
Contract.Ensures(this.SecuritySettings != null);
Contract.Ensures(this.Channel != null);
}
@@ -77,14 +75,12 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// </summary>
/// <param name="associationStore">The association store to use. Cannot be null.</param>
/// <param name="nonceStore">The nonce store to use. Cannot be null.</param>
- private OpenIdProvider(IAssociationStore<AssociationRelyingPartyType> associationStore, INonceStore nonceStore) {
- Contract.Requires<ArgumentNullException>(associationStore != null);
+ private OpenIdProvider(INonceStore nonceStore) {
Contract.Requires<ArgumentNullException>(nonceStore != null);
- Contract.Ensures(this.AssociationStore == associationStore);
Contract.Ensures(this.SecuritySettings != null);
Contract.Ensures(this.Channel != null);
- this.AssociationStore = associationStore;
+ this.AssociationStore = new ProviderAssociationStore();
this.SecuritySettings = DotNetOpenAuthSection.Configuration.OpenId.Provider.SecuritySettings.CreateSecuritySettings();
this.behaviors.CollectionChanged += this.OnBehaviorsChanged;
foreach (var behavior in DotNetOpenAuthSection.Configuration.OpenId.Provider.Behaviors.CreateInstances(false)) {
@@ -93,7 +89,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
this.Channel = new OpenIdChannel(this.AssociationStore, nonceStore, this.SecuritySettings);
- Reporting.RecordFeatureAndDependencyUse(this, associationStore, nonceStore);
+ Reporting.RecordFeatureAndDependencyUse(this, nonceStore);
}
/// <summary>
@@ -175,11 +171,6 @@ namespace DotNetOpenAuth.OpenId.Provider {
}
/// <summary>
- /// Gets the association store.
- /// </summary>
- internal IAssociationStore<AssociationRelyingPartyType> AssociationStore { get; private set; }
-
- /// <summary>
/// Gets the web request handler to use for discovery and the part of
/// authentication where direct messages are sent to an untrusted remote party.
/// </summary>
@@ -187,6 +178,8 @@ namespace DotNetOpenAuth.OpenId.Provider {
get { return this.Channel.WebRequestHandler; }
}
+ internal ProviderAssociationStore AssociationStore { get; private set; }
+
/// <summary>
/// Gets the relying party used for discovery of identifiers sent in unsolicited assertions.
/// </summary>
diff --git a/src/DotNetOpenAuth/OpenId/Provider/ProviderAssociationStore.cs b/src/DotNetOpenAuth/OpenId/Provider/ProviderAssociationStore.cs
new file mode 100644
index 0000000..e503317
--- /dev/null
+++ b/src/DotNetOpenAuth/OpenId/Provider/ProviderAssociationStore.cs
@@ -0,0 +1,49 @@
+//-----------------------------------------------------------------------
+// <copyright file="ProviderAssociationStore.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Provider {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ internal class ProviderAssociationStore {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ProviderAssociationStore"/> class.
+ /// </summary>
+ internal ProviderAssociationStore() {
+ this.Secret = MessagingUtilities.GetCryptoRandomData(16);
+ }
+
+ /// <summary>
+ /// Gets or sets the symmetric secret this Provider uses for protecting messages to itself.
+ /// </summary>
+ internal byte[] Secret { get; set; }
+
+ internal string Encode(AssociationDataBag associationDataBag) {
+ var formatter = AssociationDataBag.CreateFormatter(this.Secret);
+ return formatter.Serialize(associationDataBag);
+ }
+
+ internal Association Decode(IProtocolMessage containingMessage, AssociationRelyingPartyType associationType, string handle) {
+ var formatter = AssociationDataBag.CreateFormatter(this.Secret);
+ var bag = formatter.Deserialize(containingMessage, handle);
+ ErrorUtilities.VerifyProtocol(bag.AssociationType == associationType, "Unexpected association type.");
+ Association assoc = Association.Deserialize(handle, bag.ExpiresUtc, bag.Secret);
+ return assoc;
+ }
+
+ internal bool IsValid(IProtocolMessage containingMessage, AssociationRelyingPartyType associationType, string handle) {
+ try {
+ this.Decode(containingMessage, associationType, handle);
+ return true;
+ } catch (ProtocolException) {
+ return false;
+ }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/StandardProviderApplicationStore.cs b/src/DotNetOpenAuth/OpenId/Provider/StandardProviderApplicationStore.cs
index 4fa2d64..59f79ba 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/StandardProviderApplicationStore.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/StandardProviderApplicationStore.cs
@@ -28,80 +28,12 @@ namespace DotNetOpenAuth.OpenId.Provider {
private readonly INonceStore nonceStore;
/// <summary>
- /// The association store to use.
- /// </summary>
- private readonly IAssociationStore<AssociationRelyingPartyType> associationStore;
-
- /// <summary>
/// Initializes a new instance of the <see cref="StandardProviderApplicationStore"/> class.
/// </summary>
public StandardProviderApplicationStore() {
this.nonceStore = new NonceMemoryStore(DotNetOpenAuthSection.Configuration.OpenId.MaxAuthenticationTime);
- this.associationStore = new AssociationMemoryStore<AssociationRelyingPartyType>();
- }
-
- #region IAssociationStore<AssociationRelyingPartyType> Members
-
- /// <summary>
- /// Saves an <see cref="Association"/> for later recall.
- /// </summary>
- /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for providers).</param>
- /// <param name="association">The association to store.</param>
- public void StoreAssociation(AssociationRelyingPartyType distinguishingFactor, Association association) {
- this.associationStore.StoreAssociation(distinguishingFactor, association);
- }
-
- /// <summary>
- /// Gets the best association (the one with the longest remaining life) for a given key.
- /// </summary>
- /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
- /// <param name="securityRequirements">The security requirements that the returned association must meet.</param>
- /// <returns>
- /// The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key.
- /// </returns>
- /// <remarks>
- /// In the event that multiple associations exist for the given
- /// <paramref name="distinguishingFactor"/>, it is important for the
- /// implementation for this method to use the <paramref name="securityRequirements"/>
- /// to pick the best (highest grade or longest living as the host's policy may dictate)
- /// association that fits the security requirements.
- /// Associations that are returned that do not meet the security requirements will be
- /// ignored and a new association created.
- /// </remarks>
- public Association GetAssociation(AssociationRelyingPartyType distinguishingFactor, SecuritySettings securityRequirements) {
- return this.associationStore.GetAssociation(distinguishingFactor, securityRequirements);
}
- /// <summary>
- /// Gets the association for a given key and handle.
- /// </summary>
- /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
- /// <param name="handle">The handle of the specific association that must be recalled.</param>
- /// <returns>
- /// The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key and handle.
- /// </returns>
- public Association GetAssociation(AssociationRelyingPartyType distinguishingFactor, string handle) {
- return this.associationStore.GetAssociation(distinguishingFactor, handle);
- }
-
- /// <summary>
- /// Removes a specified handle that may exist in the store.
- /// </summary>
- /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
- /// <param name="handle">The handle of the specific association that must be deleted.</param>
- /// <returns>
- /// True if the association existed in this store previous to this call.
- /// </returns>
- /// <remarks>
- /// No exception should be thrown if the association does not exist in the store
- /// before this call.
- /// </remarks>
- public bool RemoveAssociation(AssociationRelyingPartyType distinguishingFactor, string handle) {
- return this.associationStore.RemoveAssociation(distinguishingFactor, handle);
- }
-
- #endregion
-
#region INonceStore Members
/// <summary>
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/AssociationManager.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/AssociationManager.cs
index 1ae2726..90a6228 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/AssociationManager.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/AssociationManager.cs
@@ -23,7 +23,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// <summary>
/// The storage to use for saving and retrieving associations. May be null.
/// </summary>
- private readonly IAssociationStore<Uri> associationStore;
+ private readonly IAssociationStore associationStore;
/// <summary>
/// Backing field for the <see cref="Channel"/> property.
@@ -41,7 +41,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// <param name="channel">The channel the relying party is using.</param>
/// <param name="associationStore">The association store. May be null for dumb mode relying parties.</param>
/// <param name="securitySettings">The security settings.</param>
- internal AssociationManager(Channel channel, IAssociationStore<Uri> associationStore, RelyingPartySecuritySettings securitySettings) {
+ internal AssociationManager(Channel channel, IAssociationStore associationStore, RelyingPartySecuritySettings securitySettings) {
Contract.Requires<ArgumentNullException>(channel != null);
Contract.Requires<ArgumentNullException>(securitySettings != null);
@@ -93,7 +93,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// <summary>
/// Gets the storage to use for saving and retrieving associations. May be null.
/// </summary>
- internal IAssociationStore<Uri> AssociationStoreTestHook {
+ internal IAssociationStore AssociationStoreTestHook {
get { return this.associationStore; }
}
@@ -196,7 +196,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
var associateSuccessfulResponse = associateResponse as AssociateSuccessfulResponse;
var associateUnsuccessfulResponse = associateResponse as AssociateUnsuccessfulResponse;
if (associateSuccessfulResponse != null) {
- Association association = associateSuccessfulResponse.CreateAssociation(associateRequest, null);
+ Association association = associateSuccessfulResponse.CreateAssociation(associateRequest, null, null);
this.associationStore.StoreAssociation(provider.Uri, association);
return association;
} else if (associateUnsuccessfulResponse != null) {
diff --git a/src/DotNetOpenAuth/OpenId/AssociationMemoryStore.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/AssociationMemoryStore.cs
index 7a20fd5..00540b4 100644
--- a/src/DotNetOpenAuth/OpenId/AssociationMemoryStore.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/AssociationMemoryStore.cs
@@ -4,21 +4,22 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.OpenId {
+namespace DotNetOpenAuth.OpenId.RelyingParty {
+ using System;
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// Manages a set of associations in memory only (no database).
/// </summary>
- /// <typeparam name="TKey">The type of the key.</typeparam>
+ /// <typeparam name="Uri">The type of the key.</typeparam>
/// <remarks>
/// This class should be used for low-to-medium traffic relying party sites that can afford to lose associations
/// if the app pool was ever restarted. High traffic relying parties and providers should write their own
- /// implementation of <see cref="IAssociationStore&lt;TKey&gt;"/> that works against their own database schema
+ /// implementation of <see cref="IAssociationStore"/> that works against their own database schema
/// to allow for persistance and recall of associations across servers in a web farm and server restarts.
/// </remarks>
- internal class AssociationMemoryStore<TKey> : IAssociationStore<TKey> {
+ internal class AssociationMemoryStore : IAssociationStore {
/// <summary>
/// How many association store requests should occur between each spring cleaning.
/// </summary>
@@ -28,7 +29,7 @@ namespace DotNetOpenAuth.OpenId {
/// For Relying Parties, this maps OP Endpoints to a set of associations with that endpoint.
/// For Providers, this keeps smart and dumb associations in two distinct pools.
/// </summary>
- private Dictionary<TKey, Associations> serverAssocsTable = new Dictionary<TKey, Associations>();
+ private Dictionary<Uri, Associations> serverAssocsTable = new Dictionary<Uri, Associations>();
/// <summary>
/// A counter to track how close we are to an expired association cleaning run.
@@ -38,14 +39,14 @@ namespace DotNetOpenAuth.OpenId {
/// <summary>
/// Stores a given association for later recall.
/// </summary>
- /// <param name="distinguishingFactor">The distinguishing factor, either an OP Endpoint or smart/dumb mode.</param>
+ /// <param name="providerEndpoint">The distinguishing factor, either an OP Endpoint or smart/dumb mode.</param>
/// <param name="association">The association to store.</param>
- public void StoreAssociation(TKey distinguishingFactor, Association association) {
+ public void StoreAssociation(Uri providerEndpoint, Association association) {
lock (this) {
- if (!this.serverAssocsTable.ContainsKey(distinguishingFactor)) {
- this.serverAssocsTable.Add(distinguishingFactor, new Associations());
+ if (!this.serverAssocsTable.ContainsKey(providerEndpoint)) {
+ this.serverAssocsTable.Add(providerEndpoint, new Associations());
}
- Associations server_assocs = this.serverAssocsTable[distinguishingFactor];
+ Associations server_assocs = this.serverAssocsTable[providerEndpoint];
server_assocs.Set(association);
@@ -61,35 +62,35 @@ namespace DotNetOpenAuth.OpenId {
/// <summary>
/// Gets the best association (the one with the longest remaining life) for a given key.
/// </summary>
- /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
+ /// <param name="providerEndpoint">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
/// <param name="securitySettings">The security settings.</param>
/// <returns>
/// The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key.
/// </returns>
- public Association GetAssociation(TKey distinguishingFactor, SecuritySettings securitySettings) {
+ public Association GetAssociation(Uri providerEndpoint, SecuritySettings securitySettings) {
lock (this) {
- return this.GetServerAssociations(distinguishingFactor).Best.FirstOrDefault(assoc => securitySettings.IsAssociationInPermittedRange(assoc));
+ return this.GetServerAssociations(providerEndpoint).Best.FirstOrDefault(assoc => securitySettings.IsAssociationInPermittedRange(assoc));
}
}
/// <summary>
/// Gets the association for a given key and handle.
/// </summary>
- /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
+ /// <param name="providerEndpoint">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
/// <param name="handle">The handle of the specific association that must be recalled.</param>
/// <returns>
/// The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key and handle.
/// </returns>
- public Association GetAssociation(TKey distinguishingFactor, string handle) {
+ public Association GetAssociation(Uri providerEndpoint, string handle) {
lock (this) {
- return this.GetServerAssociations(distinguishingFactor).Get(handle);
+ return this.GetServerAssociations(providerEndpoint).Get(handle);
}
}
/// <summary>
/// Removes a specified handle that may exist in the store.
/// </summary>
- /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
+ /// <param name="providerEndpoint">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
/// <param name="handle">The handle of the specific association that must be deleted.</param>
/// <returns>
/// True if the association existed in this store previous to this call.
@@ -98,24 +99,24 @@ namespace DotNetOpenAuth.OpenId {
/// No exception should be thrown if the association does not exist in the store
/// before this call.
/// </remarks>
- public bool RemoveAssociation(TKey distinguishingFactor, string handle) {
+ public bool RemoveAssociation(Uri providerEndpoint, string handle) {
lock (this) {
- return this.GetServerAssociations(distinguishingFactor).Remove(handle);
+ return this.GetServerAssociations(providerEndpoint).Remove(handle);
}
}
/// <summary>
/// Gets the server associations for a given OP Endpoint or dumb/smart mode.
/// </summary>
- /// <param name="distinguishingFactor">The distinguishing factor, either an OP Endpoint (for relying parties) or smart/dumb (for providers).</param>
- /// <returns>The collection of associations that fit the <paramref name="distinguishingFactor"/>.</returns>
- internal Associations GetServerAssociations(TKey distinguishingFactor) {
+ /// <param name="providerEndpoint">The distinguishing factor, either an OP Endpoint (for relying parties) or smart/dumb (for providers).</param>
+ /// <returns>The collection of associations that fit the <paramref name="providerEndpoint"/>.</returns>
+ internal Associations GetServerAssociations(Uri providerEndpoint) {
lock (this) {
- if (!this.serverAssocsTable.ContainsKey(distinguishingFactor)) {
- this.serverAssocsTable.Add(distinguishingFactor, new Associations());
+ if (!this.serverAssocsTable.ContainsKey(providerEndpoint)) {
+ this.serverAssocsTable.Add(providerEndpoint, new Associations());
}
- return this.serverAssocsTable[distinguishingFactor];
+ return this.serverAssocsTable[providerEndpoint];
}
}
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
index 3a17263..be06a23 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
@@ -212,7 +212,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// small to ensure successful authentication. About 1.5KB is about all that should be stored.</para>
/// </remarks>
public void AddCallbackArguments(IDictionary<string, string> arguments) {
- ErrorUtilities.VerifyOperation(this.RelyingParty.CanSignCallbackArguments, OpenIdStrings.CallbackArgumentsRequireSecretStore, typeof(IAssociationStore<Uri>).Name, typeof(OpenIdRelyingParty).Name);
+ ErrorUtilities.VerifyOperation(this.RelyingParty.CanSignCallbackArguments, OpenIdStrings.CallbackArgumentsRequireSecretStore, typeof(IAssociationStore).Name, typeof(OpenIdRelyingParty).Name);
this.returnToArgsMustBeSigned = true;
foreach (var pair in arguments) {
@@ -239,7 +239,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// small to ensure successful authentication. About 1.5KB is about all that should be stored.</para>
/// </remarks>
public void AddCallbackArguments(string key, string value) {
- ErrorUtilities.VerifyOperation(this.RelyingParty.CanSignCallbackArguments, OpenIdStrings.CallbackArgumentsRequireSecretStore, typeof(IAssociationStore<Uri>).Name, typeof(OpenIdRelyingParty).Name);
+ ErrorUtilities.VerifyOperation(this.RelyingParty.CanSignCallbackArguments, OpenIdStrings.CallbackArgumentsRequireSecretStore, typeof(IAssociationStore).Name, typeof(OpenIdRelyingParty).Name);
this.returnToArgsMustBeSigned = true;
this.returnToArgs.Add(key, value);
@@ -260,7 +260,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// small to ensure successful authentication. About 1.5KB is about all that should be stored.</para>
/// </remarks>
public void SetCallbackArgument(string key, string value) {
- ErrorUtilities.VerifyOperation(this.RelyingParty.CanSignCallbackArguments, OpenIdStrings.CallbackArgumentsRequireSecretStore, typeof(IAssociationStore<Uri>).Name, typeof(OpenIdRelyingParty).Name);
+ ErrorUtilities.VerifyOperation(this.RelyingParty.CanSignCallbackArguments, OpenIdStrings.CallbackArgumentsRequireSecretStore, typeof(IAssociationStore).Name, typeof(OpenIdRelyingParty).Name);
this.returnToArgsMustBeSigned = true;
this.returnToArgs[key] = value;
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/IAssociationStore.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/IAssociationStore.cs
new file mode 100644
index 0000000..63c6526
--- /dev/null
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/IAssociationStore.cs
@@ -0,0 +1,151 @@
+//-----------------------------------------------------------------------
+// <copyright file="IAssociationStore.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.RelyingParty {
+ using System;
+ using System.Diagnostics.Contracts;
+
+ /// <summary>
+ /// Stores <see cref="Association"/>s for lookup by their handle, keeping
+ /// associations separated by a given distinguishing factor (like which server the
+ /// association is with).
+ /// </summary>
+ /// <remarks>
+ /// Expired associations should be periodically cleared out of an association store.
+ /// This should be done frequently enough to avoid a memory leak, but sparingly enough
+ /// to not be a performance drain. Because this balance can vary by host, it is the
+ /// responsibility of the host to initiate this cleaning.
+ /// </remarks>
+ [ContractClass(typeof(IAssociationStoreContract))]
+ public interface IAssociationStore {
+ /// <summary>
+ /// Saves an <see cref="Association"/> for later recall.
+ /// </summary>
+ /// <param name="providerEndpoint">The OP Endpoint with which the association is established.</param>
+ /// <param name="association">The association to store.</param>
+ /// <remarks>
+ /// TODO: what should implementations do on association handle conflict?
+ /// </remarks>
+ void StoreAssociation(Uri providerEndpoint, Association association);
+
+ /// <summary>
+ /// Gets the best association (the one with the longest remaining life) for a given key.
+ /// </summary>
+ /// <param name="providerEndpoint">The OP Endpoint with which the association is established.</param>
+ /// <param name="securityRequirements">The security requirements that the returned association must meet.</param>
+ /// <returns>
+ /// The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key.
+ /// </returns>
+ /// <remarks>
+ /// In the event that multiple associations exist for the given
+ /// <paramref name="providerEndpoint"/>, it is important for the
+ /// implementation for this method to use the <paramref name="securityRequirements"/>
+ /// to pick the best (highest grade or longest living as the host's policy may dictate)
+ /// association that fits the security requirements.
+ /// Associations that are returned that do not meet the security requirements will be
+ /// ignored and a new association created.
+ /// </remarks>
+ Association GetAssociation(Uri providerEndpoint, SecuritySettings securityRequirements);
+
+ /// <summary>
+ /// Gets the association for a given key and handle.
+ /// </summary>
+ /// <param name="providerEndpoint">The OP Endpoint with which the association is established.</param>
+ /// <param name="handle">The handle of the specific association that must be recalled.</param>
+ /// <returns>The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key and handle.</returns>
+ Association GetAssociation(Uri providerEndpoint, string handle);
+
+ /// <summary>Removes a specified handle that may exist in the store.</summary>
+ /// <param name="providerEndpoint">The OP Endpoint with which the association is established.</param>
+ /// <param name="handle">The handle of the specific association that must be deleted.</param>
+ /// <returns>True if the association existed in this store previous to this call.</returns>
+ /// <remarks>
+ /// No exception should be thrown if the association does not exist in the store
+ /// before this call.
+ /// </remarks>
+ bool RemoveAssociation(Uri providerEndpoint, string handle);
+ }
+
+ /// <summary>
+ /// Code Contract for the <see cref="IAssociationStore&lt;Uri&gt;"/> class.
+ /// </summary>
+ /// <typeparam name="Uri">The type of the key.</typeparam>
+ [ContractClassFor(typeof(IAssociationStore))]
+ internal abstract class IAssociationStoreContract : IAssociationStore {
+ #region IAssociationStore Members
+
+ /// <summary>
+ /// Saves an <see cref="Association"/> for later recall.
+ /// </summary>
+ /// <param name="providerEndpoint">The Uri (for relying parties) or Smart/Dumb (for providers).</param>
+ /// <param name="association">The association to store.</param>
+ /// <remarks>
+ /// TODO: what should implementations do on association handle conflict?
+ /// </remarks>
+ void IAssociationStore.StoreAssociation(Uri providerEndpoint, Association association) {
+ Contract.Requires<ArgumentNullException>(providerEndpoint != null);
+ Contract.Requires<ArgumentNullException>(association != null);
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Gets the best association (the one with the longest remaining life) for a given key.
+ /// </summary>
+ /// <param name="providerEndpoint">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
+ /// <param name="securityRequirements">The security requirements that the returned association must meet.</param>
+ /// <returns>
+ /// The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key.
+ /// </returns>
+ /// <remarks>
+ /// In the event that multiple associations exist for the given
+ /// <paramref name="providerEndpoint"/>, it is important for the
+ /// implementation for this method to use the <paramref name="securityRequirements"/>
+ /// to pick the best (highest grade or longest living as the host's policy may dictate)
+ /// association that fits the security requirements.
+ /// Associations that are returned that do not meet the security requirements will be
+ /// ignored and a new association created.
+ /// </remarks>
+ Association IAssociationStore.GetAssociation(Uri providerEndpoint, SecuritySettings securityRequirements) {
+ Contract.Requires<ArgumentNullException>(providerEndpoint != null);
+ Contract.Requires<ArgumentNullException>(securityRequirements != null);
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Gets the association for a given key and handle.
+ /// </summary>
+ /// <param name="providerEndpoint">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
+ /// <param name="handle">The handle of the specific association that must be recalled.</param>
+ /// <returns>
+ /// The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key and handle.
+ /// </returns>
+ Association IAssociationStore.GetAssociation(Uri providerEndpoint, string handle) {
+ Contract.Requires<ArgumentNullException>(providerEndpoint != null);
+ Contract.Requires(!String.IsNullOrEmpty(handle));
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Removes a specified handle that may exist in the store.
+ /// </summary>
+ /// <param name="providerEndpoint">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
+ /// <param name="handle">The handle of the specific association that must be deleted.</param>
+ /// <returns>
+ /// True if the association existed in this store previous to this call.
+ /// </returns>
+ /// <remarks>
+ /// No exception should be thrown if the association does not exist in the store
+ /// before this call.
+ /// </remarks>
+ bool IAssociationStore.RemoveAssociation(Uri providerEndpoint, string handle) {
+ Contract.Requires<ArgumentNullException>(providerEndpoint != null);
+ Contract.Requires(!String.IsNullOrEmpty(handle));
+ throw new NotImplementedException();
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/IRelyingPartyApplicationStore.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/IRelyingPartyApplicationStore.cs
index 77838c8..519dae8 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/IRelyingPartyApplicationStore.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/IRelyingPartyApplicationStore.cs
@@ -16,6 +16,6 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// A hybrid of all the store interfaces that a Relying Party requires in order
/// to operate in "smart" mode.
/// </summary>
- public interface IRelyingPartyApplicationStore : IAssociationStore<Uri>, INonceStore {
+ public interface IRelyingPartyApplicationStore : IAssociationStore, INonceStore {
}
}
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs
index 57c1f05..02c821f 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs
@@ -110,7 +110,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// <param name="associationStore">The association store. If null, the relying party will always operate in "dumb mode".</param>
/// <param name="nonceStore">The nonce store to use. If null, the relying party will always operate in "dumb mode".</param>
[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Unavoidable")]
- private OpenIdRelyingParty(IAssociationStore<Uri> associationStore, INonceStore nonceStore) {
+ private OpenIdRelyingParty(IAssociationStore associationStore, INonceStore nonceStore) {
// If we are a smart-mode RP (supporting associations), then we MUST also be
// capable of storing nonces to prevent replay attacks.
// If we're a dumb-mode RP, then 2.0 OPs are responsible for preventing replays.
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs
index 5cfa191..fb1970c 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs
@@ -174,7 +174,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
if (this.response.ReturnToParametersSignatureValidated) {
return this.GetUntrustedCallbackArgument(key);
} else {
- Logger.OpenId.WarnFormat(OpenIdStrings.CallbackArgumentsRequireSecretStore, typeof(IAssociationStore<Uri>).Name, typeof(OpenIdRelyingParty).Name);
+ Logger.OpenId.WarnFormat(OpenIdStrings.CallbackArgumentsRequireSecretStore, typeof(IAssociationStore).Name, typeof(OpenIdRelyingParty).Name);
return null;
}
}
@@ -214,7 +214,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
if (this.response.ReturnToParametersSignatureValidated) {
return this.GetUntrustedCallbackArguments();
} else {
- Logger.OpenId.WarnFormat(OpenIdStrings.CallbackArgumentsRequireSecretStore, typeof(IAssociationStore<Uri>).Name, typeof(OpenIdRelyingParty).Name);
+ Logger.OpenId.WarnFormat(OpenIdStrings.CallbackArgumentsRequireSecretStore, typeof(IAssociationStore).Name, typeof(OpenIdRelyingParty).Name);
return EmptyDictionary<string, string>.Instance;
}
}
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/PrivateSecretManager.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/PrivateSecretManager.cs
index 6d55e39..dfd8f5d 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/PrivateSecretManager.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/PrivateSecretManager.cs
@@ -36,14 +36,14 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// <summary>
/// The association store
/// </summary>
- private IAssociationStore<Uri> store;
+ private IAssociationStore store;
/// <summary>
/// Initializes a new instance of the <see cref="PrivateSecretManager"/> class.
/// </summary>
/// <param name="securitySettings">The security settings.</param>
/// <param name="store">The association store.</param>
- internal PrivateSecretManager(RelyingPartySecuritySettings securitySettings, IAssociationStore<Uri> store) {
+ internal PrivateSecretManager(RelyingPartySecuritySettings securitySettings, IAssociationStore store) {
Contract.Requires<ArgumentNullException>(securitySettings != null);
Contract.Requires<ArgumentNullException>(store != null);
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/StandardRelyingPartyApplicationStore.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/StandardRelyingPartyApplicationStore.cs
index fdb6931..3e15f6a 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/StandardRelyingPartyApplicationStore.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/StandardRelyingPartyApplicationStore.cs
@@ -23,17 +23,17 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// <summary>
/// The association store to use.
/// </summary>
- private readonly IAssociationStore<Uri> associationStore;
+ private readonly IAssociationStore associationStore;
/// <summary>
/// Initializes a new instance of the <see cref="StandardRelyingPartyApplicationStore"/> class.
/// </summary>
public StandardRelyingPartyApplicationStore() {
this.nonceStore = new NonceMemoryStore(DotNetOpenAuthSection.Configuration.OpenId.MaxAuthenticationTime);
- this.associationStore = new AssociationMemoryStore<Uri>();
+ this.associationStore = new AssociationMemoryStore();
}
- #region IAssociationStore<Uri> Members
+ #region IAssociationStore Members
/// <summary>
/// Saves an <see cref="Association"/> for later recall.
diff --git a/src/DotNetOpenAuth/Reporting.cs b/src/DotNetOpenAuth/Reporting.cs
index 03d7460..1673881 100644
--- a/src/DotNetOpenAuth/Reporting.cs
+++ b/src/DotNetOpenAuth/Reporting.cs
@@ -237,6 +237,29 @@ namespace DotNetOpenAuth {
/// </summary>
/// <param name="value">The object whose type is the feature to set as used.</param>
/// <param name="dependency1">Some dependency used by <paramref name="value"/>.</param>
+ internal static void RecordFeatureAndDependencyUse(object value, object dependency1) {
+ Contract.Requires(value != null);
+
+ // In release builds, just quietly return.
+ if (value == null) {
+ return;
+ }
+
+ if (Enabled && Configuration.IncludeFeatureUsage) {
+ StringBuilder builder = new StringBuilder();
+ builder.Append(value.GetType().Name);
+ builder.Append(" ");
+ builder.Append(dependency1 != null ? dependency1.GetType().Name : "(null)");
+ observedFeatures.Add(builder.ToString());
+ Touch();
+ }
+ }
+
+ /// <summary>
+ /// Records the use of a feature by object type.
+ /// </summary>
+ /// <param name="value">The object whose type is the feature to set as used.</param>
+ /// <param name="dependency1">Some dependency used by <paramref name="value"/>.</param>
/// <param name="dependency2">Some dependency used by <paramref name="value"/>.</param>
internal static void RecordFeatureAndDependencyUse(object value, object dependency1, object dependency2) {
Contract.Requires(value != null);