summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2009-06-02 00:21:35 -0700
committerAndrew Arnott <andrewarnott@gmail.com>2009-06-02 16:59:52 -0700
commit66cb72fc2e8f41784f60526eb235186c8d830e6c (patch)
tree5bf11cfdcb553542b4e69253b557a2d2c6d28fac
parent12a5e3e0fc4d76b0d75dd740fb0c1c88031f7556 (diff)
downloadDotNetOpenAuth-66cb72fc2e8f41784f60526eb235186c8d830e6c.zip
DotNetOpenAuth-66cb72fc2e8f41784f60526eb235186c8d830e6c.tar.gz
DotNetOpenAuth-66cb72fc2e8f41784f60526eb235186c8d830e6c.tar.bz2
Redesign of GSA security profile so that OPs can work with and without it on the same endpoint.
-rw-r--r--samples/OpenIdProviderMvc/Web.config12
-rw-r--r--samples/OpenIdRelyingPartyWebForms/Web.config10
-rw-r--r--src/DotNetOpenAuth/Configuration/OpenIdProviderElement.cs15
-rw-r--r--src/DotNetOpenAuth/Configuration/OpenIdProviderSecuritySettingsElement.cs19
-rw-r--r--src/DotNetOpenAuth/Configuration/OpenIdRelyingPartyElement.cs15
-rw-r--r--src/DotNetOpenAuth/Configuration/OpenIdRelyingPartySecuritySettingsElement.cs19
-rw-r--r--src/DotNetOpenAuth/DotNetOpenAuth.csproj1
-rw-r--r--src/DotNetOpenAuth/OpenId/ISecurityProfile.cs80
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/AutoResponsiveRequest.cs10
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs4
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/IHostProcessedRequest.cs12
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/IProviderSecurityProfile.cs21
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/IRequest.cs17
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs39
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/ProviderSecuritySettings.cs32
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/Request.cs19
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/RequestContract.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs4
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/IRelyingPartySecurityProfile.cs19
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs32
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs20
-rw-r--r--src/DotNetOpenAuth/OpenId/SecurityProfiles/USGovernmentLevel1.cs127
-rw-r--r--src/DotNetOpenAuth/OpenId/SecuritySettings.cs27
23 files changed, 264 insertions, 292 deletions
diff --git a/samples/OpenIdProviderMvc/Web.config b/samples/OpenIdProviderMvc/Web.config
index 153de83..1490413 100644
--- a/samples/OpenIdProviderMvc/Web.config
+++ b/samples/OpenIdProviderMvc/Web.config
@@ -47,11 +47,13 @@
<dotNetOpenAuth>
<openid>
<provider>
- <security requireSsl="false">
- <profiles>
- <add type="DotNetOpenAuth.OpenId.SecurityProfiles.USGovernmentLevel1, DotNetOpenAuth" />
- </profiles>
- </security>
+ <security requireSsl="false" />
+ <securityProfiles>
+ <!-- Security profiles activate themselves automatically for individual matching requests.
+ The first one in this list to match an incoming request "owns" the request. If no
+ profile matches, the default behavior is assumed. -->
+ <add type="DotNetOpenAuth.OpenId.SecurityProfiles.USGovernmentLevel1, DotNetOpenAuth" />
+ </securityProfiles>
<!-- Uncomment the following to activate the sample custom store. -->
<!--<store type="RelyingPartyWebForms.CustomStore, RelyingPartyWebForms" />-->
</provider>
diff --git a/samples/OpenIdRelyingPartyWebForms/Web.config b/samples/OpenIdRelyingPartyWebForms/Web.config
index aae4101..228606d 100644
--- a/samples/OpenIdRelyingPartyWebForms/Web.config
+++ b/samples/OpenIdRelyingPartyWebForms/Web.config
@@ -23,16 +23,14 @@
<!--<servicePointManager checkCertificateRevocationList="true"/>-->
</settings>
</system.net>
-
<!-- this is an optional configuration section where aspects of dotnetopenauth can be customized -->
<dotNetOpenAuth>
<openid>
<relyingParty>
- <security requireSsl="false">
- <profiles>
- <add type="DotNetOpenAuth.OpenId.SecurityProfiles.USGovernmentLevel1, DotNetOpenAuth" />
- </profiles>
- </security>
+ <security requireSsl="false" />
+ <securityProfiles>
+ <!--<add type="DotNetOpenAuth.OpenId.SecurityProfiles.USGovernmentLevel1, DotNetOpenAuth" />-->
+ </securityProfiles>
<!-- Uncomment the following to activate the sample custom store. -->
<!--<store type="OpenIdRelyingPartyWebForms.CustomStore, OpenIdRelyingPartyWebForms" />-->
</relyingParty>
diff --git a/src/DotNetOpenAuth/Configuration/OpenIdProviderElement.cs b/src/DotNetOpenAuth/Configuration/OpenIdProviderElement.cs
index d84766b..7674536 100644
--- a/src/DotNetOpenAuth/Configuration/OpenIdProviderElement.cs
+++ b/src/DotNetOpenAuth/Configuration/OpenIdProviderElement.cs
@@ -20,6 +20,11 @@ namespace DotNetOpenAuth.Configuration {
private const string SecuritySettingsConfigName = "security";
/// <summary>
+ /// Gets the name of the &lt;securityProfiles&gt; sub-element.
+ /// </summary>
+ private const string SecurityProfilesElementName = "securityProfiles";
+
+ /// <summary>
/// The name of the custom store sub-element.
/// </summary>
private const string StoreConfigName = "store";
@@ -40,6 +45,16 @@ namespace DotNetOpenAuth.Configuration {
}
/// <summary>
+ /// Gets or sets the predefined security profiles to apply.
+ /// </summary>
+ [ConfigurationProperty(SecurityProfilesElementName, IsDefaultCollection = false)]
+ [ConfigurationCollection(typeof(TypeConfigurationCollection<IProviderSecurityProfile>))]
+ public TypeConfigurationCollection<IProviderSecurityProfile> SecurityProfiles {
+ get { return (TypeConfigurationCollection<IProviderSecurityProfile>)this[SecurityProfilesElementName] ?? new TypeConfigurationCollection<IProviderSecurityProfile>(); }
+ set { this[SecurityProfilesElementName] = value; }
+ }
+
+ /// <summary>
/// Gets or sets the type to use for storing application state.
/// </summary>
[ConfigurationProperty(StoreConfigName)]
diff --git a/src/DotNetOpenAuth/Configuration/OpenIdProviderSecuritySettingsElement.cs b/src/DotNetOpenAuth/Configuration/OpenIdProviderSecuritySettingsElement.cs
index 03f4786..457955c 100644
--- a/src/DotNetOpenAuth/Configuration/OpenIdProviderSecuritySettingsElement.cs
+++ b/src/DotNetOpenAuth/Configuration/OpenIdProviderSecuritySettingsElement.cs
@@ -41,11 +41,6 @@ namespace DotNetOpenAuth.Configuration {
private const string RequireSslConfigName = "requireSsl";
/// <summary>
- /// Gets the name of the &lt;profiles&gt; sub-element.
- /// </summary>
- private const string ProfilesElementName = "profiles";
-
- /// <summary>
/// Initializes a new instance of the <see cref="OpenIdProviderSecuritySettingsElement"/> class.
/// </summary>
public OpenIdProviderSecuritySettingsElement() {
@@ -89,16 +84,6 @@ namespace DotNetOpenAuth.Configuration {
}
/// <summary>
- /// Gets or sets the predefined security profiles to apply.
- /// </summary>
- [ConfigurationProperty(ProfilesElementName, IsDefaultCollection = false)]
- [ConfigurationCollection(typeof(TypeConfigurationCollection<IProviderSecurityProfile>))]
- public TypeConfigurationCollection<IProviderSecurityProfile> Profiles {
- get { return (TypeConfigurationCollection<IProviderSecurityProfile>)this[ProfilesElementName] ?? new TypeConfigurationCollection<IProviderSecurityProfile>(); }
- set { this[ProfilesElementName] = value; }
- }
-
- /// <summary>
/// Gets or sets the configured lifetimes of the various association types.
/// </summary>
[ConfigurationProperty(AssociationsConfigName, IsDefaultCollection = false)]
@@ -129,10 +114,6 @@ namespace DotNetOpenAuth.Configuration {
settings.AssociationLifetimes.Add(element.AssociationType, element.MaximumLifetime);
}
- foreach (var profile in this.Profiles.CreateInstances(false)) {
- settings.SecurityProfiles.Add(profile);
- }
-
return settings;
}
}
diff --git a/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartyElement.cs b/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartyElement.cs
index e311969..7c1162c 100644
--- a/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartyElement.cs
+++ b/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartyElement.cs
@@ -25,6 +25,11 @@ namespace DotNetOpenAuth.Configuration {
private const string SecuritySettingsConfigName = "security";
/// <summary>
+ /// Gets the name of the &lt;securityProfiles&gt; sub-element.
+ /// </summary>
+ private const string SecurityProfilesElementName = "securityProfiles";
+
+ /// <summary>
/// Initializes a new instance of the <see cref="OpenIdRelyingPartyElement"/> class.
/// </summary>
public OpenIdRelyingPartyElement() {
@@ -40,6 +45,16 @@ namespace DotNetOpenAuth.Configuration {
}
/// <summary>
+ /// Gets or sets the predefined security profiles to apply.
+ /// </summary>
+ [ConfigurationProperty(SecurityProfilesElementName, IsDefaultCollection = false)]
+ [ConfigurationCollection(typeof(TypeConfigurationCollection<IRelyingPartySecurityProfile>))]
+ public TypeConfigurationCollection<IRelyingPartySecurityProfile> SecurityProfiles {
+ get { return (TypeConfigurationCollection<IRelyingPartySecurityProfile>)this[SecurityProfilesElementName] ?? new TypeConfigurationCollection<IRelyingPartySecurityProfile>(); }
+ set { this[SecurityProfilesElementName] = value; }
+ }
+
+ /// <summary>
/// Gets or sets the type to use for storing application state.
/// </summary>
[ConfigurationProperty(StoreConfigName)]
diff --git a/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartySecuritySettingsElement.cs b/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartySecuritySettingsElement.cs
index ffc5616..d10d9bd 100644
--- a/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartySecuritySettingsElement.cs
+++ b/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartySecuritySettingsElement.cs
@@ -66,11 +66,6 @@ namespace DotNetOpenAuth.Configuration {
private const string PrivateSecretMaximumAgeConfigName = "privateSecretMaximumAge";
/// <summary>
- /// Gets the name of the &lt;profiles&gt; sub-element.
- /// </summary>
- private const string ProfilesElementName = "profiles";
-
- /// <summary>
/// Initializes a new instance of the <see cref="OpenIdRelyingPartySecuritySettingsElement"/> class.
/// </summary>
public OpenIdRelyingPartySecuritySettingsElement() {
@@ -188,16 +183,6 @@ namespace DotNetOpenAuth.Configuration {
}
/// <summary>
- /// Gets or sets the predefined security profiles to apply.
- /// </summary>
- [ConfigurationProperty(ProfilesElementName, IsDefaultCollection = false)]
- [ConfigurationCollection(typeof(TypeConfigurationCollection<IRelyingPartySecurityProfile>))]
- public TypeConfigurationCollection<IRelyingPartySecurityProfile> Profiles {
- get { return (TypeConfigurationCollection<IRelyingPartySecurityProfile>)this[ProfilesElementName] ?? new TypeConfigurationCollection<IRelyingPartySecurityProfile>(); }
- set { this[ProfilesElementName] = value; }
- }
-
- /// <summary>
/// Initializes a programmatically manipulatable bag of these security settings with the settings from the config file.
/// </summary>
/// <returns>The newly created security settings object.</returns>
@@ -216,10 +201,6 @@ namespace DotNetOpenAuth.Configuration {
settings.RejectDelegatingIdentifiers = this.RejectDelegatingIdentifiers;
settings.IgnoreUnsignedExtensions = this.IgnoreUnsignedExtensions;
- foreach (var profile in this.Profiles.CreateInstances(false)) {
- settings.SecurityProfiles.Add(profile);
- }
-
return settings;
}
}
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
index 6c137a4..7af9539 100644
--- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj
+++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
@@ -368,7 +368,6 @@
<Compile Include="OpenId\Interop\AuthenticationResponseShim.cs" />
<Compile Include="OpenId\Interop\ClaimsResponseShim.cs" />
<Compile Include="OpenId\Interop\OpenIdRelyingPartyShim.cs" />
- <Compile Include="OpenId\ISecurityProfile.cs" />
<Compile Include="OpenId\Messages\CheckAuthenticationRequest.cs" />
<Compile Include="OpenId\Messages\CheckAuthenticationResponse.cs" />
<Compile Include="OpenId\Messages\CheckIdRequest.cs" />
diff --git a/src/DotNetOpenAuth/OpenId/ISecurityProfile.cs b/src/DotNetOpenAuth/OpenId/ISecurityProfile.cs
deleted file mode 100644
index b9ec1fe..0000000
--- a/src/DotNetOpenAuth/OpenId/ISecurityProfile.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="ISecurityProfile.cs" company="Andrew Arnott">
-// Copyright (c) Andrew Arnott. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OpenId {
- using System.Diagnostics.Contracts;
- using DotNetOpenAuth.Messaging;
-
- /// <summary>
- /// Applies a custom security policy to certain OpenID security settings and behaviors.
- /// </summary>
- [ContractClass(typeof(ISecurityProfileContract))]
- internal interface ISecurityProfile {
- /// <summary>
- /// Applies a well known set of security requirements.
- /// </summary>
- /// <param name="securitySettings">The security settings to enhance with the requirements of this profile.</param>
- /// <remarks>
- /// Care should be taken to never decrease security when applying a profile.
- /// Profiles should only enhance security requirements to avoid being
- /// incompatible with each other.
- /// </remarks>
- void ApplySecuritySettings(SecuritySettings securitySettings);
-
- /// <summary>
- /// Checks whether the given security settings comply with security requirements and throws otherwise.
- /// </summary>
- /// <param name="securitySettings">The security settings to check for compliance.</param>
- /// <remarks>
- /// Security settings should <em>not</em> be changed by this method. Any settings
- /// that do not comply should cause an exception to be thrown.
- /// </remarks>
- /// <exception cref="ProtocolException">Thrown if the given security settings are not compliant with the requirements of this security profile.</exception>
- void EnsureCompliance(SecuritySettings securitySettings);
- }
-
- /// <summary>
- /// Code contract for the <see cref="ISecurityProfile"/> type.
- /// </summary>
- [ContractClassFor(typeof(ISecurityProfile))]
- internal abstract class ISecurityProfileContract : ISecurityProfile {
- /// <summary>
- /// Prevents a default instance of the <see cref="ISecurityProfileContract"/> class from being created.
- /// </summary>
- private ISecurityProfileContract() {
- }
-
- #region ISecurityProfile Members
-
- /// <summary>
- /// Applies a well known set of security requirements.
- /// </summary>
- /// <param name="securitySettings">The security settings to enhance with the requirements of this profile.</param>
- /// <remarks>
- /// Care should be taken to never decrease security when applying a profile.
- /// Profiles should only enhance security requirements to avoid being
- /// incompatible with each other.
- /// </remarks>
- void ISecurityProfile.ApplySecuritySettings(SecuritySettings securitySettings) {
- Contract.Requires(securitySettings != null);
- }
-
- /// <summary>
- /// Checks whether the given security settings comply with security requirements and throws otherwise.
- /// </summary>
- /// <param name="securitySettings">The security settings to check for compliance.</param>
- /// <remarks>
- /// Security settings should <em>not</em> be changed by this method. Any settings
- /// that do not comply should cause an exception to be thrown.
- /// </remarks>
- /// <exception cref="ProtocolException">Thrown if the given security settings are not compliant with the requirements of this security profile.</exception>
- void ISecurityProfile.EnsureCompliance(SecuritySettings securitySettings) {
- Contract.Requires(securitySettings != null);
- }
-
- #endregion
- }
-}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/AutoResponsiveRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/AutoResponsiveRequest.cs
index 344c72f..d1d310e 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/AutoResponsiveRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/AutoResponsiveRequest.cs
@@ -28,8 +28,9 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// </summary>
/// <param name="request">The request message.</param>
/// <param name="response">The response that is ready for transmittal.</param>
- internal AutoResponsiveRequest(IDirectedProtocolMessage request, IProtocolMessage response)
- : base(request) {
+ /// <param name="securitySettings">The security settings.</param>
+ internal AutoResponsiveRequest(IDirectedProtocolMessage request, IProtocolMessage response, ProviderSecuritySettings securitySettings)
+ : base(request, securitySettings) {
ErrorUtilities.VerifyArgumentNotNull(response, "response");
this.response = response;
@@ -40,8 +41,9 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// for a response to an unrecognizable request.
/// </summary>
/// <param name="response">The response that is ready for transmittal.</param>
- internal AutoResponsiveRequest(IProtocolMessage response)
- : base(IndirectResponseBase.GetVersion(response)) {
+ /// <param name="securitySettings">The security settings.</param>
+ internal AutoResponsiveRequest(IProtocolMessage response, ProviderSecuritySettings securitySettings)
+ : base(IndirectResponseBase.GetVersion(response), securitySettings) {
ErrorUtilities.VerifyArgumentNotNull(response, "response");
this.response = response;
diff --git a/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs
index 5de245c..e772b77 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs
@@ -35,7 +35,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// <param name="provider">The provider that received the request.</param>
/// <param name="request">The incoming request message.</param>
protected HostProcessedRequest(OpenIdProvider provider, SignedResponseRequest request)
- : base(request) {
+ : base(request, provider.SecuritySettings) {
Contract.Requires(provider != null);
this.negativeResponse = new NegativeAssertionResponse(request, provider.Channel);
@@ -126,7 +126,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
ErrorUtilities.VerifyInternal(this.Realm != null, "Realm should have been read or derived by now.");
try {
- if (provider.SecuritySettings.RequireSsl && this.Realm.Scheme != Uri.UriSchemeHttps) {
+ if (this.SecuritySettings.RequireSsl && this.Realm.Scheme != Uri.UriSchemeHttps) {
Logger.OpenId.WarnFormat("RP discovery failed because RequireSsl is true and RP discovery would begin at insecure URL {0}.", this.Realm);
return RelyingPartyDiscoveryResult.NoServiceDocument;
}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/IHostProcessedRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/IHostProcessedRequest.cs
index eee99f1..5256fdd 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/IHostProcessedRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/IHostProcessedRequest.cs
@@ -5,6 +5,7 @@
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.OpenId.Provider {
+ using System;
using System.Diagnostics.Contracts;
using DotNetOpenAuth.Messaging;
@@ -80,6 +81,17 @@ namespace DotNetOpenAuth.OpenId.Provider {
#region IRequest Members
/// <summary>
+ /// Gets or sets the security settings that apply to this request.
+ /// </summary>
+ /// <value>
+ /// Defaults to the <see cref="OpenIdProvider.SecuritySettings"/> on the <see cref="OpenIdProvider"/>.
+ /// </value>
+ ProviderSecuritySettings IRequest.SecuritySettings {
+ get { throw new NotImplementedException(); }
+ set { throw new NotImplementedException(); }
+ }
+
+ /// <summary>
/// Gets a value indicating whether the response is ready to be sent to the user agent.
/// </summary>
/// <remarks>
diff --git a/src/DotNetOpenAuth/OpenId/Provider/IProviderSecurityProfile.cs b/src/DotNetOpenAuth/OpenId/Provider/IProviderSecurityProfile.cs
index cf5e732..19217be 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/IProviderSecurityProfile.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/IProviderSecurityProfile.cs
@@ -14,19 +14,30 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// BEFORE MARKING THIS INTERFACE PUBLIC: it's very important that we shift the methods to be channel-level
/// rather than facade class level and for the OpenIdChannel to be the one to invoke these methods.
/// </remarks>
- internal interface IProviderSecurityProfile : ISecurityProfile {
+ internal interface IProviderSecurityProfile {
/// <summary>
/// Called when a request is received by the Provider.
/// </summary>
- /// <param name="provider">The provider.</param>
/// <param name="request">The incoming request.</param>
- void OnIncomingRequest(OpenIdProvider provider, IRequest request);
+ /// <returns>
+ /// <c>true</c> if this security profile owns this request and wants to stop other security profiles
+ /// from handling it; <c>false</c> to allow other security profiles to process this request.
+ /// </returns>
+ /// <remarks>
+ /// Implementations may set a new value to <see cref="IRequest.SecuritySettings"/> but
+ /// should not change the properties on the instance of <see cref="ProviderSecuritySettings"/>
+ /// itself as that instance may be shared across many requests.
+ /// </remarks>
+ bool OnIncomingRequest(IRequest request);
/// <summary>
/// Called when the Provider is preparing to send a response to an authentication request.
/// </summary>
- /// <param name="provider">The provider.</param>
/// <param name="request">The request that is configured to generate the outgoing response.</param>
- void OnOutgoingResponse(OpenIdProvider provider, IAuthenticationRequest request);
+ /// <returns>
+ /// <c>true</c> if this security profile owns this request and wants to stop other security profiles
+ /// from handling it; <c>false</c> to allow other security profiles to process this request.
+ /// </returns>
+ bool OnOutgoingResponse(IAuthenticationRequest request);
}
}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/IRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/IRequest.cs
index 9f0f633..2ca96ca 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/IRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/IRequest.cs
@@ -33,6 +33,12 @@ namespace DotNetOpenAuth.OpenId.Provider {
bool IsResponseReady { get; }
/// <summary>
+ /// Gets or sets the security settings that apply to this request.
+ /// </summary>
+ /// <value>Defaults to the <see cref="OpenIdProvider.SecuritySettings"/> on the <see cref="OpenIdProvider"/>.</value>
+ ProviderSecuritySettings SecuritySettings { get; set; }
+
+ /// <summary>
/// Adds an extension to the response to send to the relying party.
/// </summary>
/// <param name="extension">The extension to add to the response message.</param>
@@ -68,6 +74,17 @@ namespace DotNetOpenAuth.OpenId.Provider {
#region IRequest Members
/// <summary>
+ /// Gets or sets the security settings that apply to this request.
+ /// </summary>
+ /// <value>
+ /// Defaults to the <see cref="OpenIdProvider.SecuritySettings"/> on the <see cref="OpenIdProvider"/>.
+ /// </value>
+ ProviderSecuritySettings IRequest.SecuritySettings {
+ get { throw new NotImplementedException(); }
+ set { throw new NotImplementedException(); }
+ }
+
+ /// <summary>
/// Gets a value indicating whether the response is ready to be sent to the user agent.
/// </summary>
/// <value></value>
diff --git a/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs b/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs
index 0eb8d7e..2e769f3 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs
@@ -7,6 +7,7 @@
namespace DotNetOpenAuth.OpenId.Provider {
using System;
using System.Collections.Generic;
+ using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
@@ -31,6 +32,11 @@ namespace DotNetOpenAuth.OpenId.Provider {
private const string ApplicationStoreKey = "DotNetOpenAuth.OpenId.Provider.OpenIdProvider.ApplicationStore";
/// <summary>
+ /// Backing store for the <see cref="SecurityProfiles"/> property.
+ /// </summary>
+ private readonly Collection<IProviderSecurityProfile> securityProfiles = new Collection<IProviderSecurityProfile>();
+
+ /// <summary>
/// Backing field for the <see cref="SecuritySettings"/> property.
/// </summary>
private ProviderSecuritySettings securitySettings;
@@ -73,6 +79,10 @@ namespace DotNetOpenAuth.OpenId.Provider {
this.AssociationStore = associationStore;
this.SecuritySettings = DotNetOpenAuthSection.Configuration.OpenId.Provider.SecuritySettings.CreateSecuritySettings();
+ foreach (var securityProfile in DotNetOpenAuthSection.Configuration.OpenId.Provider.SecurityProfiles.CreateInstances(false)) {
+ this.securityProfiles.Add(securityProfile);
+ }
+
this.Channel = new OpenIdChannel(this.AssociationStore, nonceStore, this.SecuritySettings);
}
@@ -138,6 +148,13 @@ namespace DotNetOpenAuth.OpenId.Provider {
public IErrorReporting ErrorReporting { get; set; }
/// <summary>
+ /// Gets a list of custom security profiles to apply to OpenID actions.
+ /// </summary>
+ internal ICollection<IProviderSecurityProfile> SecurityProfiles {
+ get { return this.securityProfiles; }
+ }
+
+ /// <summary>
/// Gets the association store.
/// </summary>
internal IAssociationStore<AssociationRelyingPartyType> AssociationStore { get; private set; }
@@ -216,20 +233,23 @@ namespace DotNetOpenAuth.OpenId.Provider {
if (result == null) {
var checkAuthMessage = incomingMessage as CheckAuthenticationRequest;
if (checkAuthMessage != null) {
- result = new AutoResponsiveRequest(incomingMessage, new CheckAuthenticationResponse(checkAuthMessage, this));
+ result = new AutoResponsiveRequest(incomingMessage, new CheckAuthenticationResponse(checkAuthMessage, this), this.SecuritySettings);
}
}
if (result == null) {
var associateMessage = incomingMessage as AssociateRequest;
if (associateMessage != null) {
- result = new AutoResponsiveRequest(incomingMessage, associateMessage.CreateResponse(this.AssociationStore, this.SecuritySettings));
+ result = new AutoResponsiveRequest(incomingMessage, associateMessage.CreateResponse(this.AssociationStore, this.SecuritySettings), this.SecuritySettings);
}
}
if (result != null) {
- foreach (var profile in this.SecuritySettings.SecurityProfiles) {
- profile.OnIncomingRequest(this, result);
+ foreach (var profile in this.SecurityProfiles) {
+ if (profile.OnIncomingRequest(result)) {
+ // This security profile matched this request.
+ break;
+ }
}
return result;
@@ -415,8 +435,11 @@ namespace DotNetOpenAuth.OpenId.Provider {
private void ApplySecurityProfilesToResponse(IRequest request) {
var authRequest = request as IAuthenticationRequest;
if (authRequest != null) {
- foreach (var profile in this.SecuritySettings.SecurityProfiles) {
- profile.OnOutgoingResponse(this, authRequest);
+ foreach (var profile in this.SecurityProfiles) {
+ if (profile.OnOutgoingResponse(authRequest)) {
+ // This security profile matched this request.
+ break;
+ }
}
}
}
@@ -476,9 +499,9 @@ namespace DotNetOpenAuth.OpenId.Provider {
}
if (incomingMessage != null) {
- return new AutoResponsiveRequest(incomingMessage, errorMessage);
+ return new AutoResponsiveRequest(incomingMessage, errorMessage, this.SecuritySettings);
} else {
- return new AutoResponsiveRequest(errorMessage);
+ return new AutoResponsiveRequest(errorMessage, this.SecuritySettings);
}
}
}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/ProviderSecuritySettings.cs b/src/DotNetOpenAuth/OpenId/Provider/ProviderSecuritySettings.cs
index bedc6d0..876e412 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/ProviderSecuritySettings.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/ProviderSecuritySettings.cs
@@ -15,6 +15,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// <summary>
/// Security settings that are applicable to providers.
/// </summary>
+ [Serializable]
public sealed class ProviderSecuritySettings : SecuritySettings {
/// <summary>
/// The default value for the <see cref="ProtectDownlevelReplayAttacks"/> property.
@@ -27,11 +28,6 @@ namespace DotNetOpenAuth.OpenId.Provider {
internal const bool SignOutgoingExtensionsDefault = true;
/// <summary>
- /// Backing store for the <see cref="SecurityProfiles"/> property.
- /// </summary>
- private readonly ObservableCollection<IProviderSecurityProfile> securityProfiles = new ObservableCollection<IProviderSecurityProfile>();
-
- /// <summary>
/// The subset of association types and their customized lifetimes.
/// </summary>
private IDictionary<string, TimeSpan> associationLifetimes = new Dictionary<string, TimeSpan>();
@@ -43,7 +39,6 @@ namespace DotNetOpenAuth.OpenId.Provider {
: base(true) {
this.SignOutgoingExtensions = SignOutgoingExtensionsDefault;
this.ProtectDownlevelReplayAttacks = ProtectDownlevelReplayAttacksDefault;
- this.securityProfiles.CollectionChanged += this.OnSecurityProfilesChanged;
}
/// <summary>
@@ -62,13 +57,6 @@ namespace DotNetOpenAuth.OpenId.Provider {
public bool RequireSsl { get; set; }
/// <summary>
- /// Gets a list of custom security profiles to apply to OpenID actions.
- /// </summary>
- internal ICollection<IProviderSecurityProfile> SecurityProfiles {
- get { return this.securityProfiles; }
- }
-
- /// <summary>
/// Gets or sets a value indicating whether OpenID 1.x relying parties that may not be
/// protecting their users from replay attacks are protected from
/// replay attacks by this provider.
@@ -99,10 +87,22 @@ namespace DotNetOpenAuth.OpenId.Provider {
internal bool SignOutgoingExtensions { get; set; }
/// <summary>
- /// Gets the custom security profiles.
+ /// Creates a deep clone of this instance.
/// </summary>
- internal override IEnumerable<ISecurityProfile> CustomSecurityProfiles {
- get { return this.securityProfiles.Cast<ISecurityProfile>(); }
+ /// <returns>A new instance that is a deep clone of this instance.</returns>
+ internal ProviderSecuritySettings Clone() {
+ var securitySettings = new ProviderSecuritySettings();
+ foreach (var pair in this.AssociationLifetimes) {
+ securitySettings.AssociationLifetimes.Add(pair);
+ }
+
+ securitySettings.MaximumHashBitLength = this.MaximumHashBitLength;
+ securitySettings.MinimumHashBitLength = this.MinimumHashBitLength;
+ securitySettings.ProtectDownlevelReplayAttacks = this.ProtectDownlevelReplayAttacks;
+ securitySettings.RequireSsl = this.RequireSsl;
+ securitySettings.SignOutgoingExtensions = this.SignOutgoingExtensions;
+
+ return securitySettings;
}
}
}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/Request.cs b/src/DotNetOpenAuth/OpenId/Provider/Request.cs
index 1c5ad02..4c2ee98 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/Request.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/Request.cs
@@ -52,11 +52,15 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// Initializes a new instance of the <see cref="Request"/> class.
/// </summary>
/// <param name="request">The incoming request message.</param>
- protected Request(IDirectedProtocolMessage request) {
+ /// <param name="securitySettings">The security settings from the channel.</param>
+ protected Request(IDirectedProtocolMessage request, ProviderSecuritySettings securitySettings) {
Contract.Requires(request != null);
+ Contract.Requires(securitySettings != null);
ErrorUtilities.VerifyArgumentNotNull(request, "request");
+ ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings");
this.request = request;
+ this.SecuritySettings = securitySettings;
this.protocolVersion = this.request.Version;
this.extensibleMessage = request as IProtocolMessageWithExtensions;
}
@@ -65,11 +69,15 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// Initializes a new instance of the <see cref="Request"/> class.
/// </summary>
/// <param name="version">The version.</param>
- protected Request(Version version) {
+ /// <param name="securitySettings">The security settings.</param>
+ protected Request(Version version, ProviderSecuritySettings securitySettings) {
Contract.Requires(version != null);
+ Contract.Requires(securitySettings != null);
ErrorUtilities.VerifyArgumentNotNull(version, "version");
+ ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings");
this.protocolVersion = version;
+ this.SecuritySettings = securitySettings;
}
#region IRequest Members
@@ -77,7 +85,6 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// <summary>
/// Gets a value indicating whether the response is ready to be sent to the user agent.
/// </summary>
- /// <value></value>
/// <remarks>
/// This property returns false if there are properties that must be set on this
/// request instance before the response can be sent.
@@ -85,6 +92,12 @@ namespace DotNetOpenAuth.OpenId.Provider {
public abstract bool IsResponseReady { get; }
/// <summary>
+ /// Gets or sets the security settings that apply to this request.
+ /// </summary>
+ /// <value>Defaults to the <see cref="OpenIdProvider.SecuritySettings"/> on the <see cref="OpenIdProvider"/>.</value>
+ public ProviderSecuritySettings SecuritySettings { get; set; }
+
+ /// <summary>
/// Gets the response to send to the user agent.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if <see cref="IsResponseReady"/> is <c>false</c>.</exception>
diff --git a/src/DotNetOpenAuth/OpenId/Provider/RequestContract.cs b/src/DotNetOpenAuth/OpenId/Provider/RequestContract.cs
index ab84289..b94b37d 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/RequestContract.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/RequestContract.cs
@@ -20,7 +20,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// <summary>
/// Prevents a default instance of the <see cref="RequestContract"/> class from being created.
/// </summary>
- private RequestContract() : base((Version)null) {
+ private RequestContract() : base((Version)null, null) {
}
/// <summary>
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
index c2c07f4..83decb8 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
@@ -90,8 +90,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// <value></value>
public OutgoingWebResponse RedirectingResponse {
get {
- foreach (var profile in this.RelyingParty.SecuritySettings.SecurityProfiles) {
- profile.OnOutgoingAuthenticationRequest(this.RelyingParty, this);
+ foreach (var profile in this.RelyingParty.SecurityProfiles) {
+ profile.OnOutgoingAuthenticationRequest(this);
}
return this.RelyingParty.Channel.PrepareResponse(this.CreateRequestMessage());
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/IRelyingPartySecurityProfile.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/IRelyingPartySecurityProfile.cs
index da7f06a..8d3848d 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/IRelyingPartySecurityProfile.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/IRelyingPartySecurityProfile.cs
@@ -12,23 +12,32 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// BEFORE MARKING THIS INTERFACE PUBLIC: it's very important that we shift the methods to be channel-level
/// rather than facade class level and for the OpenIdChannel to be the one to invoke these methods.
/// </remarks>
- internal interface IRelyingPartySecurityProfile : ISecurityProfile {
+ internal interface IRelyingPartySecurityProfile {
+ /// <summary>
+ /// Applies a well known set of security requirements to a default set of security settings.
+ /// </summary>
+ /// <param name="securitySettings">The security settings to enhance with the requirements of this profile.</param>
+ /// <remarks>
+ /// Care should be taken to never decrease security when applying a profile.
+ /// Profiles should only enhance security requirements to avoid being
+ /// incompatible with each other.
+ /// </remarks>
+ void ApplySecuritySettings(RelyingPartySecuritySettings securitySettings);
+
/// <summary>
/// Called when an authentication request is about to be sent.
/// </summary>
- /// <param name="relyingParty">The relying party.</param>
/// <param name="request">The request.</param>
/// <remarks>
/// Implementations should be prepared to be called multiple times on the same outgoing message
/// without malfunctioning.
/// </remarks>
- void OnOutgoingAuthenticationRequest(OpenIdRelyingParty relyingParty, IAuthenticationRequest request);
+ void OnOutgoingAuthenticationRequest(IAuthenticationRequest request);
/// <summary>
/// Called when an incoming positive assertion is received.
/// </summary>
- /// <param name="relyingParty">The relying party.</param>
/// <param name="assertion">The positive assertion.</param>
- void OnIncomingPositiveAssertion(OpenIdRelyingParty relyingParty, IAuthenticationResponse assertion);
+ void OnIncomingPositiveAssertion(IAuthenticationResponse assertion);
}
}
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs
index f2c8cc3..932e647 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs
@@ -7,6 +7,7 @@
namespace DotNetOpenAuth.OpenId.RelyingParty {
using System;
using System.Collections.Generic;
+ using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
@@ -43,6 +44,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
private const string ApplicationStoreKey = "DotNetOpenAuth.OpenId.RelyingParty.OpenIdRelyingParty.ApplicationStore";
/// <summary>
+ /// Backing store for the <see cref="SecurityProfiles"/> property.
+ /// </summary>
+ private readonly ObservableCollection<IRelyingPartySecurityProfile> securityProfiles = new ObservableCollection<IRelyingPartySecurityProfile>();
+
+ /// <summary>
/// Backing field for the <see cref="SecuritySettings"/> property.
/// </summary>
private RelyingPartySecuritySettings securitySettings;
@@ -85,6 +91,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
ErrorUtilities.VerifyArgument(associationStore == null || nonceStore != null, OpenIdStrings.AssociationStoreRequiresNonceStore);
this.securitySettings = DotNetOpenAuthSection.Configuration.OpenId.RelyingParty.SecuritySettings.CreateSecuritySettings();
+ this.securityProfiles.CollectionChanged += this.OnSecurityProfilesChanged;
+ foreach (var securityProfile in DotNetOpenAuthSection.Configuration.OpenId.RelyingParty.SecurityProfiles.CreateInstances(false)) {
+ this.securityProfiles.Add(securityProfile);
+ }
// Without a nonce store, we must rely on the Provider to protect against
// replay attacks. But only 2.0+ Providers can be expected to provide
@@ -210,6 +220,13 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
}
/// <summary>
+ /// Gets a list of custom security profiles to apply to OpenID actions.
+ /// </summary>
+ internal ICollection<IRelyingPartySecurityProfile> SecurityProfiles {
+ get { return this.securityProfiles; }
+ }
+
+ /// <summary>
/// Gets a value indicating whether this Relying Party can sign its return_to
/// parameter in outgoing authentication requests.
/// </summary>
@@ -475,8 +492,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
IndirectSignedResponse positiveExtensionOnly;
if ((positiveAssertion = message as PositiveAssertionResponse) != null) {
var response = new PositiveAuthenticationResponse(positiveAssertion, this);
- foreach (var profile in this.SecuritySettings.SecurityProfiles) {
- profile.OnIncomingPositiveAssertion(this, response);
+ foreach (var profile in this.SecurityProfiles) {
+ profile.OnIncomingPositiveAssertion(response);
}
return response;
@@ -560,5 +577,16 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
}
}
}
+
+ /// <summary>
+ /// Called by derived classes when security profiles are added or removed.
+ /// </summary>
+ /// <param name="sender">The collection being modified.</param>
+ /// <param name="e">The <see cref="System.Collections.Specialized.NotifyCollectionChangedEventArgs"/> instance containing the event data.</param>
+ private void OnSecurityProfilesChanged(object sender, NotifyCollectionChangedEventArgs e) {
+ foreach (IRelyingPartySecurityProfile profile in e.NewItems) {
+ profile.ApplySecuritySettings(this.SecuritySettings);
+ }
+ }
}
}
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs
index 7c6a59c..ff29498 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs
@@ -16,17 +16,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// </summary>
public sealed class RelyingPartySecuritySettings : SecuritySettings {
/// <summary>
- /// Backing store for the <see cref="SecurityProfiles"/> property.
- /// </summary>
- private readonly ObservableCollection<IRelyingPartySecurityProfile> securityProfiles = new ObservableCollection<IRelyingPartySecurityProfile>();
-
- /// <summary>
/// Initializes a new instance of the <see cref="RelyingPartySecuritySettings"/> class.
/// </summary>
internal RelyingPartySecuritySettings()
: base(false) {
this.PrivateSecretMaximumAge = TimeSpan.FromDays(7);
- this.securityProfiles.CollectionChanged += this.OnSecurityProfilesChanged;
}
/// <summary>
@@ -117,20 +111,6 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
public bool RequireAssociation { get; set; }
/// <summary>
- /// Gets a list of custom security profiles to apply to OpenID actions.
- /// </summary>
- internal ICollection<IRelyingPartySecurityProfile> SecurityProfiles {
- get { return this.securityProfiles; }
- }
-
- /// <summary>
- /// Gets the custom security profiles.
- /// </summary>
- internal override IEnumerable<ISecurityProfile> CustomSecurityProfiles {
- get { return this.securityProfiles.Cast<ISecurityProfile>(); }
- }
-
- /// <summary>
/// Filters out any disallowed endpoints.
/// </summary>
/// <param name="endpoints">The endpoints discovered on an Identifier.</param>
diff --git a/src/DotNetOpenAuth/OpenId/SecurityProfiles/USGovernmentLevel1.cs b/src/DotNetOpenAuth/OpenId/SecurityProfiles/USGovernmentLevel1.cs
index b0e92f9..2e5dd18 100644
--- a/src/DotNetOpenAuth/OpenId/SecurityProfiles/USGovernmentLevel1.cs
+++ b/src/DotNetOpenAuth/OpenId/SecurityProfiles/USGovernmentLevel1.cs
@@ -6,12 +6,9 @@
namespace DotNetOpenAuth.OpenId.SecurityProfiles {
using System;
- using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
- using System.Text;
using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.OpenId.ChannelElements;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
using DotNetOpenAuth.OpenId.Extensions.ProviderAuthenticationPolicy;
using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
@@ -36,8 +33,6 @@ namespace DotNetOpenAuth.OpenId.SecurityProfiles {
/// Initializes a new instance of the <see cref="USGovernmentLevel1"/> class.
/// </summary>
public USGovernmentLevel1() {
- AllowPersonallyIdentifiableInformation = true;
- DisableSslRequirement = true;
}
/// <summary>
@@ -51,9 +46,12 @@ namespace DotNetOpenAuth.OpenId.SecurityProfiles {
/// <value>The default value is <c>false</c>.</value>
public static bool AllowPersonallyIdentifiableInformation { get; set; }
+ /// <summary>
+ /// Gets or sets a value indicating whether to ignore the SSL requirement (for testing purposes only).
+ /// </summary>
public static bool DisableSslRequirement { get; set; }
- #region ISecurityProfile Members
+ #region IRelyingPartySecurityProfile Members
/// <summary>
/// Applies a well known set of security requirements.
@@ -64,71 +62,26 @@ namespace DotNetOpenAuth.OpenId.SecurityProfiles {
/// Profiles should only enhance security requirements to avoid being
/// incompatible with each other.
/// </remarks>
- void ISecurityProfile.ApplySecuritySettings(SecuritySettings securitySettings) {
+ void IRelyingPartySecurityProfile.ApplySecuritySettings(RelyingPartySecuritySettings securitySettings) {
ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings");
if (securitySettings.MaximumHashBitLength < 256) {
securitySettings.MaximumHashBitLength = 256;
}
- var rpSecuritySettings = securitySettings as RelyingPartySecuritySettings;
- if (rpSecuritySettings != null) {
- rpSecuritySettings.RequireSsl = !DisableSslRequirement;
- rpSecuritySettings.RequireDirectedIdentity = true;
- rpSecuritySettings.RequireAssociation = true;
- rpSecuritySettings.RejectDelegatingIdentifiers = true;
- rpSecuritySettings.IgnoreUnsignedExtensions = true;
- rpSecuritySettings.MinimumRequiredOpenIdVersion = ProtocolVersion.V20;
- }
-
- var opSecuritySettings = securitySettings as ProviderSecuritySettings;
- if (opSecuritySettings != null) {
- opSecuritySettings.RequireSsl = !DisableSslRequirement;
- SetMaximumAssociationLifetimeToNotExceed(Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA256, MaximumAssociationLifetime, opSecuritySettings);
- SetMaximumAssociationLifetimeToNotExceed(Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, MaximumAssociationLifetime, opSecuritySettings);
- }
- }
-
- /// <summary>
- /// Checks whether the given security settings comply with security requirements and throws otherwise.
- /// </summary>
- /// <param name="securitySettings">The security settings to check for compliance.</param>
- /// <remarks>
- /// Security settings should <em>not</em> be changed by this method. Any settings
- /// that do not comply should cause an exception to be thrown.
- /// </remarks>
- /// <exception cref="ProtocolException">Thrown if the given security settings are not compliant with the requirements of this security profile.</exception>
- void ISecurityProfile.EnsureCompliance(SecuritySettings securitySettings) {
- ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings");
- ErrorUtilities.VerifyProtocol(securitySettings.MaximumHashBitLength >= 256, SecurityProfileStrings.SecuritySettingsNotCompliantWithProfile, this.GetType().Name);
-
- var rpSecuritySettings = securitySettings as RelyingPartySecuritySettings;
- if (rpSecuritySettings != null) {
- ErrorUtilities.VerifyProtocol(rpSecuritySettings.RequireSsl || DisableSslRequirement, SecurityProfileStrings.SecuritySettingsNotCompliantWithProfile, this.GetType().Name);
- ErrorUtilities.VerifyProtocol(rpSecuritySettings.RequireDirectedIdentity, SecurityProfileStrings.SecuritySettingsNotCompliantWithProfile, this.GetType().Name);
- ErrorUtilities.VerifyProtocol(rpSecuritySettings.RequireAssociation, SecurityProfileStrings.SecuritySettingsNotCompliantWithProfile, this.GetType().Name);
- ErrorUtilities.VerifyProtocol(rpSecuritySettings.IgnoreUnsignedExtensions, SecurityProfileStrings.SecuritySettingsNotCompliantWithProfile, this.GetType().Name);
- }
-
- var opSecuritySettings = securitySettings as ProviderSecuritySettings;
- if (opSecuritySettings != null) {
- ErrorUtilities.VerifyProtocol(opSecuritySettings.RequireSsl || DisableSslRequirement, SecurityProfileStrings.SecuritySettingsNotCompliantWithProfile, this.GetType().Name);
- ErrorUtilities.VerifyProtocol(opSecuritySettings.AssociationLifetimes.ContainsKey(Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA256) && opSecuritySettings.AssociationLifetimes[Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA256] <= MaximumAssociationLifetime, SecurityProfileStrings.SecuritySettingsNotCompliantWithProfile, this.GetType().Name);
- ErrorUtilities.VerifyProtocol(opSecuritySettings.AssociationLifetimes.ContainsKey(Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1) && opSecuritySettings.AssociationLifetimes[Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1] <= MaximumAssociationLifetime, SecurityProfileStrings.SecuritySettingsNotCompliantWithProfile, this.GetType().Name);
- }
+ securitySettings.RequireSsl = !DisableSslRequirement;
+ securitySettings.RequireDirectedIdentity = true;
+ securitySettings.RequireAssociation = true;
+ securitySettings.RejectDelegatingIdentifiers = true;
+ securitySettings.IgnoreUnsignedExtensions = true;
+ securitySettings.MinimumRequiredOpenIdVersion = ProtocolVersion.V20;
}
- #endregion
-
- #region IRelyingPartySecurityProfile Members
-
/// <summary>
/// Called when an authentication request is about to be sent.
/// </summary>
- /// <param name="relyingParty">The relying party.</param>
/// <param name="request">The request.</param>
- void IRelyingPartySecurityProfile.OnOutgoingAuthenticationRequest(OpenIdRelyingParty relyingParty, RelyingParty.IAuthenticationRequest request) {
- ErrorUtilities.VerifyArgumentNotNull(relyingParty, "relyingParty");
+ void IRelyingPartySecurityProfile.OnOutgoingAuthenticationRequest(RelyingParty.IAuthenticationRequest request) {
ErrorUtilities.VerifyArgumentNotNull(request, "request");
RelyingParty.AuthenticationRequest requestInternal = (RelyingParty.AuthenticationRequest)request;
@@ -162,10 +115,8 @@ namespace DotNetOpenAuth.OpenId.SecurityProfiles {
/// <summary>
/// Called when an incoming positive assertion is received.
/// </summary>
- /// <param name="relyingParty">The relying party.</param>
/// <param name="assertion">The positive assertion.</param>
- void IRelyingPartySecurityProfile.OnIncomingPositiveAssertion(OpenIdRelyingParty relyingParty, IAuthenticationResponse assertion) {
- ErrorUtilities.VerifyArgumentNotNull(relyingParty, "relyingParty");
+ void IRelyingPartySecurityProfile.OnIncomingPositiveAssertion(IAuthenticationResponse assertion) {
ErrorUtilities.VerifyArgumentNotNull(assertion, "assertion");
PolicyResponse pape = assertion.GetExtension<PolicyResponse>();
@@ -192,10 +143,17 @@ namespace DotNetOpenAuth.OpenId.SecurityProfiles {
/// <summary>
/// Called when a request is received by the Provider.
/// </summary>
- /// <param name="provider">The provider.</param>
/// <param name="request">The incoming request.</param>
- void IProviderSecurityProfile.OnIncomingRequest(OpenIdProvider provider, IRequest request) {
- ErrorUtilities.VerifyArgumentNotNull(provider, "provider");
+ /// <returns>
+ /// <c>true</c> if this security profile owns this request and wants to stop other security profiles
+ /// from handling it; <c>false</c> to allow other security profiles to process this request.
+ /// </returns>
+ /// <remarks>
+ /// Implementations may set a new value to <see cref="IRequest.SecuritySettings"/> but
+ /// should not change the properties on the instance of <see cref="ProviderSecuritySettings"/>
+ /// itself as that instance may be shared across many requests.
+ /// </remarks>
+ bool IProviderSecurityProfile.OnIncomingRequest(IRequest request) {
ErrorUtilities.VerifyArgumentNotNull(request, "request");
var hostProcessedRequest = request as IHostProcessedRequest;
@@ -207,23 +165,32 @@ namespace DotNetOpenAuth.OpenId.SecurityProfiles {
// Whenever we see this GSA policy requested, we MUST also see the PPID policy requested.
ErrorUtilities.VerifyProtocol(papeRequest.PreferredPolicies.Contains(AuthenticationPolicies.PrivatePersonalIdentifier), SecurityProfileStrings.PapeRequestMissingRequiredPolicies);
ErrorUtilities.VerifyProtocol(string.Equals(hostProcessedRequest.Realm.Scheme, Uri.UriSchemeHttps, StringComparison.Ordinal) || DisableSslRequirement, SecurityProfileStrings.RealmMustBeHttps);
+
+ request.SecuritySettings = GetProviderSecuritySettings(request.SecuritySettings);
+ return true;
}
}
}
+
+ return false;
}
/// <summary>
/// Called when the Provider is preparing to send a response to an authentication request.
/// </summary>
- /// <param name="provider">The provider.</param>
/// <param name="request">The request that is configured to generate the outgoing response.</param>
- void IProviderSecurityProfile.OnOutgoingResponse(OpenIdProvider provider, Provider.IAuthenticationRequest request) {
- ErrorUtilities.VerifyArgumentNotNull(provider, "provider");
+ /// <returns>
+ /// <c>true</c> if this security profile owns this request and wants to stop other security profiles
+ /// from handling it; <c>false</c> to allow other security profiles to process this request.
+ /// </returns>
+ bool IProviderSecurityProfile.OnOutgoingResponse(Provider.IAuthenticationRequest request) {
ErrorUtilities.VerifyArgumentNotNull(request, "request");
+ bool result = false;
+
// Nothing to do for negative assertions.
if (!request.IsAuthenticated.Value) {
- return;
+ return result;
}
var requestInternal = (Provider.AuthenticationRequest)request;
@@ -238,6 +205,7 @@ namespace DotNetOpenAuth.OpenId.SecurityProfiles {
}
if (papeRequest.PreferredPolicies.Contains(AuthenticationPolicies.USGovernmentTrustLevel1)) {
+ result = true;
if (!papeResponse.ActualPolicies.Contains(AuthenticationPolicies.USGovernmentTrustLevel1)) {
papeResponse.ActualPolicies.Add(AuthenticationPolicies.USGovernmentTrustLevel1);
}
@@ -277,11 +245,32 @@ namespace DotNetOpenAuth.OpenId.SecurityProfiles {
}
}
}
+
+ return result;
}
#endregion
/// <summary>
+ /// Adapts the default security settings to the requirements of this security profile.
+ /// </summary>
+ /// <param name="originalSecuritySettings">The original security settings.</param>
+ /// <returns>A new security settings instance that should be used for all qualifying incoming requests.</returns>
+ private static ProviderSecuritySettings GetProviderSecuritySettings(ProviderSecuritySettings originalSecuritySettings) {
+ var securitySettings = originalSecuritySettings.Clone();
+
+ if (securitySettings.MaximumHashBitLength < 256) {
+ securitySettings.MaximumHashBitLength = 256;
+ }
+
+ securitySettings.RequireSsl = !DisableSslRequirement;
+ SetMaximumAssociationLifetimeToNotExceed(Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA256, MaximumAssociationLifetime, securitySettings);
+ SetMaximumAssociationLifetimeToNotExceed(Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, MaximumAssociationLifetime, securitySettings);
+
+ return securitySettings;
+ }
+
+ /// <summary>
/// Ensures the maximum association lifetime does not exceed a given limit.
/// </summary>
/// <param name="associationType">Type of the association.</param>
diff --git a/src/DotNetOpenAuth/OpenId/SecuritySettings.cs b/src/DotNetOpenAuth/OpenId/SecuritySettings.cs
index 43533c7..d4df697 100644
--- a/src/DotNetOpenAuth/OpenId/SecuritySettings.cs
+++ b/src/DotNetOpenAuth/OpenId/SecuritySettings.cs
@@ -5,6 +5,7 @@
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.OpenId {
+ using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using DotNetOpenAuth.Messaging;
@@ -12,6 +13,7 @@ namespace DotNetOpenAuth.OpenId {
/// <summary>
/// Security settings that may be applicable to both relying parties and providers.
/// </summary>
+ [Serializable]
public abstract class SecuritySettings {
/// <summary>
/// Gets the default minimum hash bit length.
@@ -65,11 +67,6 @@ namespace DotNetOpenAuth.OpenId {
public int MaximumHashBitLength { get; set; }
/// <summary>
- /// Gets the custom security profiles that apply to these security settings.
- /// </summary>
- internal abstract IEnumerable<ISecurityProfile> CustomSecurityProfiles { get; }
-
- /// <summary>
/// Determines whether a named association fits the security requirements.
/// </summary>
/// <param name="protocol">The protocol carrying the association.</param>
@@ -93,25 +90,5 @@ namespace DotNetOpenAuth.OpenId {
ErrorUtilities.VerifyArgumentNotNull(association, "association");
return association.HashBitLength >= this.MinimumHashBitLength && association.HashBitLength <= this.MaximumHashBitLength;
}
-
- /// <summary>
- /// Ensures that all security profiles are satisfied.
- /// </summary>
- internal void EnsureSecurityProfilesSatisfied() {
- foreach (ISecurityProfile profile in this.CustomSecurityProfiles) {
- profile.EnsureCompliance(this);
- }
- }
-
- /// <summary>
- /// Called by derived classes when security profiles are added or removed.
- /// </summary>
- /// <param name="sender">The collection being modified.</param>
- /// <param name="e">The <see cref="System.Collections.Specialized.NotifyCollectionChangedEventArgs"/> instance containing the event data.</param>
- protected void OnSecurityProfilesChanged(object sender, NotifyCollectionChangedEventArgs e) {
- foreach (ISecurityProfile profile in e.NewItems) {
- profile.ApplySecuritySettings(this);
- }
- }
}
}