diff options
7 files changed, 259 insertions, 5 deletions
diff --git a/samples/OpenIdRelyingPartyWebForms/Web.config b/samples/OpenIdRelyingPartyWebForms/Web.config index 5d3a33b..497af21 100644 --- a/samples/OpenIdRelyingPartyWebForms/Web.config +++ b/samples/OpenIdRelyingPartyWebForms/Web.config @@ -28,7 +28,11 @@ <dotNetOpenAuth> <openid> <relyingParty> - <security requireSsl="false" /> + <security requireSsl="false"> + <trustedProviders rejectAssertionsFromUntrustedProviders="true"> + <add endpoint="https://www.google.com/accounts/o8/ud" allowSubPath="true" allowAdditionalQueryParameters="true" /> + </trustedProviders> + </security> <behaviors> <!-- The following OPTIONAL behavior allows RPs to use SREG only, but be compatible with OPs that use Attribute Exchange (in various formats). --> diff --git a/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd b/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd index 9c0ab77..3774490 100644 --- a/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd +++ b/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd @@ -243,6 +243,58 @@ </xs:documentation> </xs:annotation> <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="trustedProviders"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="add"> + <xs:complexType> + <xs:attribute name="endpoint" type="xs:string" use="required"> + <xs:annotation> + <xs:documentation> + The OpenID Provider Endpoint (aka "OP Endpoint") that this relying party trusts. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute name="allowSubPath" type="xs:boolean" default="false"> + <xs:annotation> + <xs:documentation> + A value indicating whether the OP Endpoint given here is a base path, and sub-paths concatenated to it are equally trusted. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute name="allowAdditionalQueryParameters" type="xs:boolean" default="false"> + <xs:annotation> + <xs:documentation> + A value indicating whether the OP Endpoint given here is equally trusted if query string parameters are added to it. + </xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:complexType> + </xs:element> + <xs:element name="remove"> + <xs:complexType> + <xs:attribute name="endpoint" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="clear"> + <xs:complexType> + <!--tag is empty--> + </xs:complexType> + </xs:element> + </xs:choice> + <xs:attribute name="rejectAssertionsFromUntrustedProviders" type="xs:boolean" default="false"> + <xs:annotation> + <xs:documentation> + A value indicating whether any login attempt coming from an OpenID Provider Endpoint that is not on this + whitelist of trusted OP Endpoints will be rejected. If the trusted providers list is empty and this value + is true, all assertions are rejected. + </xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:complexType> + </xs:element> + </xs:choice> <xs:attribute name="requireSsl" type="xs:boolean" default="false"> <xs:annotation> <xs:documentation> @@ -269,7 +321,7 @@ <xs:attribute name="minimumHashBitLength" type="xs:int"> <xs:annotation> <xs:documentation> - Shared associations with OpenID Providers will only be formed or used if they + Shared associations with OpenID Providers will only be formed or used if they are willing to form associations equal to or greater than a given level of protection. </xs:documentation> </xs:annotation> @@ -524,7 +576,7 @@ so security is comparable to OpenID 2.0 relying parties. </xs:documentation> </xs:annotation> - </xs:attribute> + </xs:attribute> <xs:attribute name="unsolicitedAssertionVerification"> <xs:annotation> <xs:documentation> @@ -735,7 +787,7 @@ </xs:documentation> </xs:annotation> <xs:complexType> - + </xs:complexType> </xs:element> </xs:choice> @@ -856,7 +908,7 @@ <xs:attribute name="includeEventStatistics" type="xs:boolean" default="true"> <xs:annotation> <xs:documentation> - Whether a set of counters that track how often certain events (such as an + Whether a set of counters that track how often certain events (such as an successful or failed authentication) is included in the report. </xs:documentation> </xs:annotation> diff --git a/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartySecuritySettingsElement.cs b/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartySecuritySettingsElement.cs index 1bf2ebc..e138acd 100644 --- a/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartySecuritySettingsElement.cs +++ b/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartySecuritySettingsElement.cs @@ -81,6 +81,11 @@ namespace DotNetOpenAuth.Configuration { private const string ProtectDownlevelReplayAttacksConfigName = "protectDownlevelReplayAttacks"; /// <summary> + /// The name of the <trustedProviders> sub-element. + /// </summary> + private const string TrustedProvidersElementName = "trustedProviders"; + + /// <summary> /// Initializes a new instance of the <see cref="OpenIdRelyingPartySecuritySettingsElement"/> class. /// </summary> public OpenIdRelyingPartySecuritySettingsElement() { @@ -235,6 +240,16 @@ namespace DotNetOpenAuth.Configuration { } /// <summary> + /// Gets or sets the set of trusted OpenID Provider Endpoints. + /// </summary> + [ConfigurationProperty(TrustedProvidersElementName, IsDefaultCollection = false)] + [ConfigurationCollection(typeof(TrustedProviderConfigurationCollection))] + public TrustedProviderConfigurationCollection TrustedProviders { + get { return (TrustedProviderConfigurationCollection)this[TrustedProvidersElementName] ?? new TrustedProviderConfigurationCollection(); } + set { this[TrustedProvidersElementName] = 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> @@ -256,6 +271,12 @@ namespace DotNetOpenAuth.Configuration { settings.AllowApproximateIdentifierDiscovery = this.AllowApproximateIdentifierDiscovery; settings.ProtectDownlevelReplayAttacks = this.ProtectDownlevelReplayAttacks; + settings.RejectAssertionsFromUntrustedProviders = this.TrustedProviders.RejectAssertionsFromUntrustedProviders; + foreach (TrustedProviderEndpointConfigurationElement opEndpoint in this.TrustedProviders) { + var endpointSetting = new RelyingPartySecuritySettings.TrustedProviderEndpointSettings(opEndpoint.AllowSubPath, opEndpoint.AllowAdditionalQueryParameters); + settings.TrustedProviderEndpoints.Add(opEndpoint.ProviderEndpoint, endpointSetting); + } + return settings; } } diff --git a/src/DotNetOpenAuth/Configuration/TrustedProviderConfigurationCollection.cs b/src/DotNetOpenAuth/Configuration/TrustedProviderConfigurationCollection.cs new file mode 100644 index 0000000..78c74e9 --- /dev/null +++ b/src/DotNetOpenAuth/Configuration/TrustedProviderConfigurationCollection.cs @@ -0,0 +1,71 @@ +//----------------------------------------------------------------------- +// <copyright file="TrustedProviderConfigurationCollection.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Configuration { + using System; + using System.Collections.Generic; + using System.Configuration; + using System.Diagnostics.Contracts; + + /// <summary> + /// A configuration collection of trusted OP Endpoints. + /// </summary> + internal class TrustedProviderConfigurationCollection : ConfigurationElementCollection { + /// <summary> + /// The name of the "rejectAssertionsFromUntrustedProviders" element. + /// </summary> + private const string RejectAssertionsFromUntrustedProvidersConfigName = "rejectAssertionsFromUntrustedProviders"; + + /// <summary> + /// Initializes a new instance of the <see cref="TrustedProviderConfigurationCollection"/> class. + /// </summary> + internal TrustedProviderConfigurationCollection() { + } + + /// <summary> + /// Initializes a new instance of the <see cref="TrustedProviderConfigurationCollection"/> class. + /// </summary> + internal TrustedProviderConfigurationCollection(IEnumerable<TrustedProviderEndpointConfigurationElement> elements) { + Contract.Requires<ArgumentNullException>(elements != null); + + foreach (TrustedProviderEndpointConfigurationElement element in elements) { + this.BaseAdd(element); + } + } + + /// <summary> + /// Gets or sets a value indicating whether any login attempt coming from an OpenID Provider Endpoint that is not on this + /// whitelist of trusted OP Endpoints will be rejected. If the trusted providers list is empty and this value + /// is true, all assertions are rejected. + /// </summary> + [ConfigurationProperty(RejectAssertionsFromUntrustedProvidersConfigName, DefaultValue = false)] + internal bool RejectAssertionsFromUntrustedProviders { + get { return (bool)this[RejectAssertionsFromUntrustedProvidersConfigName]; } + set { this[RejectAssertionsFromUntrustedProvidersConfigName] = value; } + } + + /// <summary> + /// When overridden in a derived class, creates a new <see cref="T:System.Configuration.ConfigurationElement"/>. + /// </summary> + /// <returns> + /// A new <see cref="T:System.Configuration.ConfigurationElement"/>. + /// </returns> + protected override ConfigurationElement CreateNewElement() { + return new TrustedProviderEndpointConfigurationElement(); + } + + /// <summary> + /// Gets the element key for a specified configuration element when overridden in a derived class. + /// </summary> + /// <param name="element">The <see cref="T:System.Configuration.ConfigurationElement"/> to return the key for.</param> + /// <returns> + /// An <see cref="T:System.Object"/> that acts as the key for the specified <see cref="T:System.Configuration.ConfigurationElement"/>. + /// </returns> + protected override object GetElementKey(ConfigurationElement element) { + return ((TrustedProviderEndpointConfigurationElement)element).ProviderEndpoint; + } + } +} diff --git a/src/DotNetOpenAuth/Configuration/TrustedProviderEndpointConfigurationElement.cs b/src/DotNetOpenAuth/Configuration/TrustedProviderEndpointConfigurationElement.cs new file mode 100644 index 0000000..106b8b7 --- /dev/null +++ b/src/DotNetOpenAuth/Configuration/TrustedProviderEndpointConfigurationElement.cs @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------- +// <copyright file="TrustedProviderEndpoint.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Configuration { + using System; + using System.Configuration; + + /// <summary> + /// A configuration element that records a trusted Provider Endpoint. + /// </summary> + internal class TrustedProviderEndpointConfigurationElement : ConfigurationElement { + /// <summary> + /// The name of the attribute that stores the <see cref="ProviderEndpoint"/> value. + /// </summary> + private const string ProviderEndpointConfigName = "endpoint"; + + /// <summary> + /// The name of the attribute that stores the <see cref="AllowSubPath"/> value. + /// </summary> + private const string AllowSubPathConfigName = "allowSubPath"; + + /// <summary> + /// The name of the attribute that stores the <see cref="AllowAdditionalQueryParameters"/> value. + /// </summary> + private const string AllowAdditionalQueryParametersConfigName = "allowAdditionalQueryParameters"; + + /// <summary> + /// Initializes a new instance of the <see cref="TrustedProviderEndpointConfigurationElement"/> class. + /// </summary> + public TrustedProviderEndpointConfigurationElement() { + } + + /// <summary> + /// Gets or sets the OpenID Provider Endpoint (aka "OP Endpoint") that this relying party trusts. + /// </summary> + [ConfigurationProperty(ProviderEndpointConfigName, IsRequired = true, IsKey = true)] + public Uri ProviderEndpoint { + get { return (Uri)this[ProviderEndpointConfigName]; } + set { this[ProviderEndpointConfigName] = value; } + } + + /// <summary> + /// Gets or sets a value indicating whether the OP Endpoint given here is a base path, and sub-paths concatenated to it are equally trusted. + /// </summary> + [ConfigurationProperty(AllowSubPathConfigName, DefaultValue = false)] + public bool AllowSubPath { + get { return (bool)this[AllowSubPathConfigName]; } + set { this[AllowSubPathConfigName] = value; } + } + + /// <summary> + /// Gets or sets a value indicating whether the OP Endpoint given here is equally trusted if query string parameters are added to it. + /// </summary> + [ConfigurationProperty(AllowAdditionalQueryParametersConfigName, DefaultValue = false)] + public bool AllowAdditionalQueryParameters { + get { return (bool)this[AllowAdditionalQueryParametersConfigName]; } + set { this[AllowAdditionalQueryParametersConfigName] = value; } + } + } +} diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj index 4073bde..6517a87 100644 --- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj +++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj @@ -295,6 +295,8 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="Configuration\OpenIdRelyingPartyElement.cs" /> <Compile Include="Configuration\OpenIdRelyingPartySecuritySettingsElement.cs" /> <Compile Include="Configuration\ReportingElement.cs" /> + <Compile Include="Configuration\TrustedProviderConfigurationCollection.cs" /> + <Compile Include="Configuration\TrustedProviderEndpointConfigurationElement.cs" /> <Compile Include="Configuration\TypeConfigurationCollection.cs" /> <Compile Include="Configuration\TypeConfigurationElement.cs" /> <Compile Include="Configuration\UntrustedWebRequestElement.cs" /> diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs index a7686c5..3031134 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs @@ -8,6 +8,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System; using System.Collections.Generic; using System.Collections.ObjectModel; + using System.Diagnostics.CodeAnalysis; + using System.Diagnostics.Contracts; using System.Linq; using DotNetOpenAuth.Messaging; @@ -28,6 +30,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { this.PrivateSecretMaximumAge = TimeSpan.FromDays(7); this.ProtectDownlevelReplayAttacks = ProtectDownlevelReplayAttacksDefault; this.AllowApproximateIdentifierDiscovery = true; + this.TrustedProviderEndpoints = new Dictionary<Uri, TrustedProviderEndpointSettings>(); } /// <summary> @@ -143,6 +146,19 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { public bool AllowApproximateIdentifierDiscovery { get; set; } /// <summary> + /// Gets the set of trusted OpenID Provider Endpoint URIs and settings that describe them. + /// </summary> + public IDictionary<Uri, TrustedProviderEndpointSettings> TrustedProviderEndpoints { get; private set; } + + /// <summary> + /// Gets or sets a value indicating whether any login attempt coming from an OpenID Provider Endpoint that is not on this + /// whitelist of trusted OP Endpoints will be rejected. If the trusted providers list is empty and this value + /// is true, all assertions are rejected. + /// </summary> + /// <value>Default is <c>false</c>.</value> + public bool RejectAssertionsFromUntrustedProviders { get; set; } + + /// <summary> /// Gets or sets a value indicating whether special measures are taken to /// protect users from replay attacks when those users' identities are hosted /// by OpenID 1.x Providers. @@ -167,5 +183,30 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { .Where(se => !this.RejectDelegatingIdentifiers || se.ClaimedIdentifier == se.ProviderLocalIdentifier) .Where(se => !this.RequireDirectedIdentity || se.ClaimedIdentifier == se.Protocol.ClaimedIdentifierForOPIdentifier); } + + /// <summary> + /// A trusted OpenID Provider endpoint and flags regarding how it is trusted. + /// </summary> + public class TrustedProviderEndpointSettings { + /// <summary> + /// Initializes a new instance of the <see cref="TrustedProviderEndpointSettings"/> class. + /// </summary> + /// <param name="allowSubPath">A value indicating whether the OP Endpoint given here is a base path, and sub-paths concatenated to it are equally trusted.</param> + /// <param name="allowAdditionalQueryParameters">A value indicating whether the OP Endpoint given here is equally trusted if query string parameters are added to it.</param> + public TrustedProviderEndpointSettings(bool allowSubPath = false, bool allowAdditionalQueryParameters = false) { + this.AllowSubPath = allowSubPath; + this.AllowAdditionalQueryParameters = allowAdditionalQueryParameters; + } + + /// <summary> + /// Gets or sets a value indicating whether the OP Endpoint given here is a base path, and sub-paths concatenated to it are equally trusted. + /// </summary> + public bool AllowSubPath { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether the OP Endpoint given here is equally trusted if query string parameters are added to it. + /// </summary> + public bool AllowAdditionalQueryParameters { get; set; } + } } } |