diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2009-11-02 17:24:06 -0800 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2009-11-02 17:24:06 -0800 |
commit | b1cbd4b7a27a9fa02c9a99225336e609a7df5e86 (patch) | |
tree | 9ee0eae3ee45fb524091b3f1e687e5229bd68f2d /src | |
parent | 716524c4b800c06aa033c53af991151f70851b89 (diff) | |
download | DotNetOpenAuth-b1cbd4b7a27a9fa02c9a99225336e609a7df5e86.zip DotNetOpenAuth-b1cbd4b7a27a9fa02c9a99225336e609a7df5e86.tar.gz DotNetOpenAuth-b1cbd4b7a27a9fa02c9a99225336e609a7df5e86.tar.bz2 |
OPs can now opt out of verifying identifiers they are sending unsolicited assertions for.
Diffstat (limited to 'src')
4 files changed, 86 insertions, 10 deletions
diff --git a/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd b/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd index ea32f4c..a214053 100644 --- a/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd +++ b/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd @@ -197,6 +197,15 @@ </xs:choice> <xs:attribute name="requireSsl" type="xs:boolean" default="false" /> <xs:attribute name="protectDownlevelReplayAttacks" type="xs:boolean" /> + <xs:attribute name="unsolicitedAssertionVerification"> + <xs:simpleType> + <xs:restriction base="xs:NMTOKEN"> + <xs:enumeration value="RequireSuccess" /> + <xs:enumeration value="LogWarningOnFailure" /> + <xs:enumeration value="NeverVerify" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> <xs:attribute name="minimumHashBitLength" type="xs:int" /> <xs:attribute name="maximumHashBitLength" type="xs:int" /> </xs:complexType> diff --git a/src/DotNetOpenAuth/Configuration/OpenIdProviderSecuritySettingsElement.cs b/src/DotNetOpenAuth/Configuration/OpenIdProviderSecuritySettingsElement.cs index 457955c..cd927f2 100644 --- a/src/DotNetOpenAuth/Configuration/OpenIdProviderSecuritySettingsElement.cs +++ b/src/DotNetOpenAuth/Configuration/OpenIdProviderSecuritySettingsElement.cs @@ -41,6 +41,11 @@ namespace DotNetOpenAuth.Configuration { private const string RequireSslConfigName = "requireSsl"; /// <summary> + /// Gets the name of the @unsolicitedAssertionVerification attribute. + /// </summary> + private const string UnsolicitedAssertionVerificationConfigName = "unsolicitedAssertionVerification"; + + /// <summary> /// Initializes a new instance of the <see cref="OpenIdProviderSecuritySettingsElement"/> class. /// </summary> public OpenIdProviderSecuritySettingsElement() { @@ -84,6 +89,17 @@ namespace DotNetOpenAuth.Configuration { } /// <summary> + /// Gets or sets the level of verification a Provider performs on an identifier before + /// sending an unsolicited assertion for it. + /// </summary> + /// <value>The default value is <see cref="UnsolicitedAssertionVerificationLevel.Always"/>.</value> + [ConfigurationProperty(UnsolicitedAssertionVerificationConfigName, DefaultValue = ProviderSecuritySettings.UnsolicitedAssertionVerificationDefault)] + public ProviderSecuritySettings.UnsolicitedAssertionVerificationLevel UnsolicitedAssertionVerification { + get { return (ProviderSecuritySettings.UnsolicitedAssertionVerificationLevel)this[UnsolicitedAssertionVerificationConfigName]; } + set { this[UnsolicitedAssertionVerificationConfigName] = value; } + } + + /// <summary> /// Gets or sets the configured lifetimes of the various association types. /// </summary> [ConfigurationProperty(AssociationsConfigName, IsDefaultCollection = false)] @@ -109,6 +125,7 @@ namespace DotNetOpenAuth.Configuration { settings.MinimumHashBitLength = this.MinimumHashBitLength; settings.MaximumHashBitLength = this.MaximumHashBitLength; settings.ProtectDownlevelReplayAttacks = this.ProtectDownlevelReplayAttacks; + settings.UnsolicitedAssertionVerification = this.UnsolicitedAssertionVerification; foreach (AssociationTypeElement element in this.AssociationLifetimes) { Contract.Assume(element != null); settings.AssociationLifetimes.Add(element.AssociationType, element.MaximumLifetime); diff --git a/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs b/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs index e964506..b6de509 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs @@ -373,16 +373,22 @@ namespace DotNetOpenAuth.OpenId.Provider { // is authorized to send an assertion for the given claimed identifier, // do due diligence by performing our own discovery on the claimed identifier // and make sure that it is tied to this OP and OP local identifier. - var serviceEndpoint = DotNetOpenAuth.OpenId.RelyingParty.ServiceEndpoint.CreateForClaimedIdentifier(claimedIdentifier, localIdentifier, new ProviderEndpointDescription(providerEndpoint, Protocol.Default.Version), null, null); - var discoveredEndpoints = claimedIdentifier.Discover(this.WebRequestHandler); - if (!discoveredEndpoints.Contains(serviceEndpoint)) { - Logger.OpenId.DebugFormat( - "Failed to send unsolicited assertion for {0} because its discovered services did not include this endpoint: {1}{2}{1}Discovered endpoints: {1}{3}", - claimedIdentifier, - Environment.NewLine, - serviceEndpoint, - discoveredEndpoints.ToStringDeferred(true)); - ErrorUtilities.ThrowProtocol(OpenIdStrings.UnsolicitedAssertionForUnrelatedClaimedIdentifier, claimedIdentifier); + if (this.SecuritySettings.UnsolicitedAssertionVerification != ProviderSecuritySettings.UnsolicitedAssertionVerificationLevel.NeverVerify) { + var serviceEndpoint = DotNetOpenAuth.OpenId.RelyingParty.ServiceEndpoint.CreateForClaimedIdentifier(claimedIdentifier, localIdentifier, new ProviderEndpointDescription(providerEndpoint, Protocol.Default.Version), null, null); + var discoveredEndpoints = claimedIdentifier.Discover(this.WebRequestHandler); + if (!discoveredEndpoints.Contains(serviceEndpoint)) { + Logger.OpenId.WarnFormat( + "Failed to send unsolicited assertion for {0} because its discovered services did not include this endpoint: {1}{2}{1}Discovered endpoints: {1}{3}", + claimedIdentifier, + Environment.NewLine, + serviceEndpoint, + discoveredEndpoints.ToStringDeferred(true)); + + // Only FAIL if the setting is set for it. + if (this.securitySettings.UnsolicitedAssertionVerification == ProviderSecuritySettings.UnsolicitedAssertionVerificationLevel.RequireSuccess) { + ErrorUtilities.ThrowProtocol(OpenIdStrings.UnsolicitedAssertionForUnrelatedClaimedIdentifier, claimedIdentifier); + } + } } Logger.OpenId.InfoFormat("Preparing unsolicited assertion for {0}", claimedIdentifier); diff --git a/src/DotNetOpenAuth/OpenId/Provider/ProviderSecuritySettings.cs b/src/DotNetOpenAuth/OpenId/Provider/ProviderSecuritySettings.cs index 876e412..ddc10d2 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/ProviderSecuritySettings.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/ProviderSecuritySettings.cs @@ -28,6 +28,11 @@ namespace DotNetOpenAuth.OpenId.Provider { internal const bool SignOutgoingExtensionsDefault = true; /// <summary> + /// The default value for the <see cref="UnsolicitedAssertionVerification"/> property. + /// </summary> + internal const UnsolicitedAssertionVerificationLevel UnsolicitedAssertionVerificationDefault = UnsolicitedAssertionVerificationLevel.RequireSuccess; + + /// <summary> /// The subset of association types and their customized lifetimes. /// </summary> private IDictionary<string, TimeSpan> associationLifetimes = new Dictionary<string, TimeSpan>(); @@ -39,6 +44,37 @@ namespace DotNetOpenAuth.OpenId.Provider { : base(true) { this.SignOutgoingExtensions = SignOutgoingExtensionsDefault; this.ProtectDownlevelReplayAttacks = ProtectDownlevelReplayAttacksDefault; + this.UnsolicitedAssertionVerification = UnsolicitedAssertionVerificationDefault; + } + + /// <summary> + /// The behavior a Provider takes when verifying that it is authoritative for an + /// identifier it is about to send an unsolicited assertion for. + /// </summary> + public enum UnsolicitedAssertionVerificationLevel { + /// <summary> + /// Always verify that the Provider is authoritative for an identifier before + /// sending an unsolicited assertion for it and fail if it is not. + /// </summary> + RequireSuccess, + + /// <summary> + /// Always check that the Provider is authoritative for an identifier before + /// sending an unsolicited assertion for it, but only log failures, and proceed + /// to send the unsolicited assertion. + /// </summary> + LogWarningOnFailure, + + /// <summary> + /// Never verify that the Provider is authoritative for an identifier before + /// sending an unsolicited assertion for it. + /// </summary> + /// <remarks> + /// This setting is useful for web servers that refuse to allow a Provider to + /// introspectively perform an HTTP GET on itself, when sending unsolicited assertions + /// for identifiers that the OP controls. + /// </remarks> + NeverVerify, } /// <summary> @@ -57,6 +93,13 @@ namespace DotNetOpenAuth.OpenId.Provider { public bool RequireSsl { get; set; } /// <summary> + /// Gets or sets the level of verification a Provider performs on an identifier before + /// sending an unsolicited assertion for it. + /// </summary> + /// <value>The default value is <see cref="UnsolicitedAssertionVerificationLevel.Always"/>.</value> + public UnsolicitedAssertionVerificationLevel UnsolicitedAssertionVerification { get; set; } + + /// <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. @@ -101,6 +144,7 @@ namespace DotNetOpenAuth.OpenId.Provider { securitySettings.ProtectDownlevelReplayAttacks = this.ProtectDownlevelReplayAttacks; securitySettings.RequireSsl = this.RequireSsl; securitySettings.SignOutgoingExtensions = this.SignOutgoingExtensions; + securitySettings.UnsolicitedAssertionVerification = this.UnsolicitedAssertionVerification; return securitySettings; } |