summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.Core/Configuration
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth.Core/Configuration')
-rw-r--r--src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuth.xsd968
-rw-r--r--src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuthSection.cs70
-rw-r--r--src/DotNetOpenAuth.Core/Configuration/HostNameElement.cs45
-rw-r--r--src/DotNetOpenAuth.Core/Configuration/HostNameOrRegexCollection.cs70
-rw-r--r--src/DotNetOpenAuth.Core/Configuration/MessagingElement.cs209
-rw-r--r--src/DotNetOpenAuth.Core/Configuration/ReportingElement.cs155
-rw-r--r--src/DotNetOpenAuth.Core/Configuration/TrustedProviderConfigurationCollection.cs74
-rw-r--r--src/DotNetOpenAuth.Core/Configuration/TrustedProviderEndpointConfigurationElement.cs35
-rw-r--r--src/DotNetOpenAuth.Core/Configuration/TypeConfigurationCollection.cs76
-rw-r--r--src/DotNetOpenAuth.Core/Configuration/TypeConfigurationElement.cs141
-rw-r--r--src/DotNetOpenAuth.Core/Configuration/UntrustedWebRequestElement.cs141
11 files changed, 1984 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuth.xsd b/src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuth.xsd
new file mode 100644
index 0000000..d193776
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuth.xsd
@@ -0,0 +1,968 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified">
+ <xs:element name="dotNetOpenAuth">
+ <xs:annotation>
+ <xs:documentation>
+ Customizations and configuration of DotNetOpenAuth behavior.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="messaging">
+ <xs:annotation>
+ <xs:documentation>
+ Options for general messaging protocols, such as whitelist/blacklist hosts and maximum message age.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="untrustedWebRequest">
+ <xs:annotation>
+ <xs:documentation>
+ Restrictions and settings to apply to outgoing HTTP requests to hosts that are not
+ trusted by this web site. Useful for OpenID-supporting hosts because HTTP connections
+ are initiated based on user input to arbitrary servers.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="whitelistHosts">
+ <xs:annotation>
+ <xs:documentation>
+ A set of host names (including domain names) to allow outgoing connections to
+ that would otherwise not be allowed based on security restrictions.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="add">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The host name to trust. For example: "localhost" or "www.mypartners.com".
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="remove">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The host name to NOT trust. For example: "localhost" or "www.mypartners.com".
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="clear">
+ <xs:annotation>
+ <xs:documentation>
+ Clears all hosts from the whitelist.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <!--tag is empty-->
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="whitelistHostsRegex">
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="add">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string" use="required" />
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="remove">
+ <xs:complexType>
+ <xs:attribute name="name" 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:complexType>
+ </xs:element>
+ <xs:element name="blacklistHosts">
+ <xs:annotation>
+ <xs:documentation>
+ A set of host names (including domain names) to disallow outgoing connections to
+ that would otherwise be allowed based on security restrictions.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="add">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The host name known to add to the blacklist. For example: "localhost" or "www.mypartners.com".
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="remove">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The host name known to remove to the blacklist. For example: "localhost" or "www.mypartners.com".
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="clear">
+ <xs:annotation>
+ <xs:documentation>
+ Clears all hosts from the blacklist.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <!--tag is empty-->
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="blacklistHostsRegex">
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="add">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string" use="required" />
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="remove">
+ <xs:complexType>
+ <xs:attribute name="name" 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:complexType>
+ </xs:element>
+ </xs:choice>
+ <xs:attribute name="timeout" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum time to allow for an outgoing HTTP request to complete before giving up.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="readWriteTimeout" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum time to allow for an outgoing HTTP request to either send or receive data before giving up.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="maximumBytesToRead" type="xs:int">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum bytes to read from an untrusted server during an outgoing HTTP request before cutting off the response.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="maximumRedirections" type="xs:int">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum redirection instructions to follow before giving up.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="webResourceUrlProvider">
+ <xs:annotation>
+ <xs:documentation>
+ The type that implements the DotNetOpenAuth.IEmbeddedResourceRetrieval interface
+ to instantiate for obtaining URLs that fetch embedded resource streams.
+ Primarily useful when the System.Web.UI.Page class is not used in the ASP.NET pipeline.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ The fully-qualified name of the type that implements the IEmbeddedResourceRetrieval interface.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="xaml" type="xs:string" use="optional" />
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ <xs:attribute name="lifetime" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum time allowed between a message being sent to when it is received before
+ it is considered expired.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="clockSkew" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum time to consider a safe difference in server clocks.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="strict" type="xs:boolean" default="true">
+ <xs:annotation>
+ <xs:documentation>
+ Whether remote parties will be held strictly to the protocol specifications.
+ Strict will require that remote parties adhere strictly to the specifications,
+ even when a loose interpretation would not compromise security.
+ true is a good default because it shakes out interoperability bugs in remote services
+ so they can be identified and corrected. But some web sites want things to Just Work
+ more than they want to file bugs against others, so false is the setting for them.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="relaxSslRequirements" type="xs:boolean" default="false">
+ <xs:annotation>
+ <xs:documentation>
+ Whether SSL requirements within the library are disabled/relaxed.
+ Use for TESTING ONLY.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="maximumIndirectMessageUrlLength" type="xs:int" default="2048">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum allowable size for a 301 Redirect response before we send
+ a 200 OK response with a scripted form POST with the parameters instead
+ in order to ensure successfully sending a large payload to another server
+ that might have a maximum allowable size restriction on its GET request.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="privateSecretMaximumAge" type="xs:string" default="28.00:00:00">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum age of a secret used for private signing or encryption before it is renewed.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="openid">
+ <xs:annotation>
+ <xs:documentation>
+ Configuration for OpenID authentication (relying parties and providers).
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="relyingParty">
+ <xs:annotation>
+ <xs:documentation>
+ Configuration specific for OpenID relying parties.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="security">
+ <xs:annotation>
+ <xs:documentation>
+ Security settings that apply to OpenID relying parties.
+ </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: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>
+ Restricts OpenID logins to identifiers that use HTTPS throughout the discovery process,
+ and only uses HTTPS OpenID Provider endpoints.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="minimumRequiredOpenIdVersion">
+ <xs:annotation>
+ <xs:documentation>
+ Optionally restricts interoperability with remote parties that
+ implement older versions of OpenID.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:NMTOKEN">
+ <xs:enumeration value="V10" />
+ <xs:enumeration value="V11" />
+ <xs:enumeration value="V20" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="minimumHashBitLength" type="xs:int">
+ <xs:annotation>
+ <xs:documentation>
+ 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>
+ </xs:attribute>
+ <xs:attribute name="maximumHashBitLength" type="xs:int">
+ <xs:annotation>
+ <xs:documentation>
+ Shared associaitons with OpenID Providers will only be formed or used if they
+ are willing to form associations equal to or less than a given level of protection.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="requireDirectedIdentity" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Requires that OpenID identifiers upon which authentication requests are created
+ are to be OP Identifiers. Claimed Identifiers are not allowed.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="requireAssociation" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Requires that the relying party can form a shared association with an
+ OpenID Provider before creating an authentication request for it.
+ Note that this does not require that the Provider actually use a
+ shared association in its response.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="rejectUnsolicitedAssertions" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Requires that users begin their login experience at the relying party
+ rather than at a Provider or using other forms of unsolicited assertions.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="rejectDelegatingIdentifiers" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Requires that the claimed identifiers used to log into the relying party
+ be the same ones that are originally issued by the Provider.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="ignoreUnsignedExtensions" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Makes it impossible for the relying party to read authentication response
+ extensions that are not signed by the Provider.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="allowDualPurposeIdentifiers" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Controls whether identifiers that are both OP Identifiers and Claimed Identifiers
+ should ever be recognized as claimed identifiers.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="allowApproximateIdentifierDiscovery" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Controls whether certain Claimed Identifiers that exploit
+ features that .NET does not have the ability to send exact HTTP requests for will
+ still be allowed by using an approximate HTTP request.
+ Only impacts hosts running under partial trust.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="protectDownlevelReplayAttacks" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Controls whether the relying party should take special care
+ to protect users against replay attacks when interoperating with OpenID 1.1 Providers.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="behaviors">
+ <xs:annotation>
+ <xs:documentation>
+ Manipulates the set of custom behaviors that are automatically applied
+ to incoming and outgoing OpenID messages.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="add">
+ <xs:complexType>
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ The fully-qualified name of the type that implements the IRelyingPartyBehavior interface.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="xaml" type="xs:string" use="optional" />
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="remove">
+ <xs:complexType>
+ <xs:attribute name="type" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The fully-qualified name of the type that implements the IRelyingPartyBehavior interface.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="clear">
+ <xs:complexType>
+ <!--tag is empty-->
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="discoveryServices">
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="add">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string" use="required" />
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="remove">
+ <xs:complexType>
+ <xs:attribute name="name" 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:complexType>
+ </xs:element>
+ <xs:element name="store">
+ <xs:annotation>
+ <xs:documentation>
+ A custom implementation of IRelyingPartyApplicationStore to use by default for new
+ instances of OpenIdRelyingParty.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="type" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ A fully-qualified type name of the custom implementation of IRelyingPartyApplicationStore.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ <xs:attribute name="preserveUserSuppliedIdentifier" type="xs:boolean" default="true">
+ <xs:annotation>
+ <xs:documentation>
+ Whether "dnoa.userSuppliedIdentifier" is tacked onto the openid.return_to URL in order to preserve what the user typed into the OpenID box.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="provider">
+ <xs:annotation>
+ <xs:documentation>
+ Configuration specific for OpenID providers.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="security">
+ <xs:annotation>
+ <xs:documentation>
+ Security settings that apply to OpenID providers.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="associations">
+ <xs:annotation>
+ <xs:documentation>
+ Sets maximum ages for shared associations of various strengths.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="add">
+ <xs:complexType>
+ <xs:attribute name="type" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The OpenID association type (i.e. HMAC-SHA1 or HMAC-SHA256)
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="lifetime" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The lifetime a shared association of this type will be used for.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="remove">
+ <xs:complexType>
+ <xs:attribute name="type" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The OpenID association type (i.e. HMAC-SHA1 or HMAC-SHA256)
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="clear">
+ <xs:complexType>
+ <!--tag is empty-->
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ <xs:attribute name="requireSsl" type="xs:boolean" default="false">
+ <xs:annotation>
+ <xs:documentation>
+ Requires that relying parties' realm URLs be protected by HTTPS,
+ ensuring that the RP discovery step is not vulnerable to DNS poisoning attacks.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="protectDownlevelReplayAttacks" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Provides automatic security protections to OpenID 1.x relying parties
+ so security is comparable to OpenID 2.0 relying parties.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="encodeAssociationSecretsInHandles" type="xs:boolean" default="true">
+ <xs:annotation>
+ <xs:documentation>
+ Whether the Provider should ease the burden of storing associations
+ by encoding their secrets (in signed, encrypted form) into the association handles themselves, storing only
+ a few rotating, private symmetric keys in the Provider's store instead.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="unsolicitedAssertionVerification">
+ <xs:annotation>
+ <xs:documentation>
+ The level of verification done on a claimed identifier before an unsolicited
+ assertion for that identifier is issued by this Provider.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:NMTOKEN">
+ <xs:enumeration value="RequireSuccess">
+ <xs:annotation>
+ <xs:documentation>
+ The claimed identifier being asserted must delegate to this Provider
+ and this must be verifiable by the Provider to send the assertion.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:enumeration>
+ <xs:enumeration value="LogWarningOnFailure">
+ <xs:annotation>
+ <xs:documentation>
+ The claimed identifier being asserted is checked for delegation to this Provider
+ and an warning is logged, but the assertion is allowed to go through.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:enumeration>
+ <xs:enumeration value="NeverVerify">
+ <xs:annotation>
+ <xs:documentation>
+ The claimed identifier being asserted is not checked to see that this Provider
+ has authority to assert its identity.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="minimumHashBitLength" type="xs:int">
+ <xs:annotation>
+ <xs:documentation>
+ The minimum shared association strength to form with relying parties.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="maximumHashBitLength" type="xs:int">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum shared association strength to form with relying parties.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="behaviors">
+ <xs:annotation>
+ <xs:documentation>
+ Manipulates the set of custom behaviors that are automatically applied
+ to incoming and outgoing OpenID messages.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="add">
+ <xs:complexType>
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ The fully-qualified name of the type that implements the IRelyingPartyBehavior interface.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="xaml" type="xs:string" use="optional" />
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="remove">
+ <xs:complexType>
+ <xs:attribute name="type" 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:complexType>
+ </xs:element>
+ <xs:element name="store">
+ <xs:annotation>
+ <xs:documentation>
+ A custom implementation of IProviderApplicationStore to use by default for new
+ instances of OpenIdRelyingParty.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="type" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ A fully-qualified type name of the custom implementation of IProviderApplicationStore.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="extensionFactories">
+ <xs:annotation>
+ <xs:documentation>
+ Adjusts the list of known OpenID extensions via the registration of extension factories.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="add">
+ <xs:complexType>
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ The fully-qualified name of the type that implements IOpenIdExtensionFactory.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="xaml" type="xs:string" use="optional" />
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="remove">
+ <xs:complexType>
+ <xs:attribute name="type" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The fully-qualified name of the type that implements IOpenIdExtensionFactory.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="clear">
+ <xs:complexType>
+ <!--tag is empty-->
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="xriResolver">
+ <xs:annotation>
+ <xs:documentation>
+ Controls XRI resolution to XRDS documents.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="enabled" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Controls whether XRI identifiers are allowed at all.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="proxy" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The XRI proxy resolver to use for obtaining XRDS documents from an XRI.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ <xs:attribute name="maxAuthenticationTime" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum time a user can take at the Provider while logging in before a relying party considers
+ the authentication lost.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="cacheDiscovery" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Whether the results of identifier discovery should be cached for a short time to improve performance
+ on subsequent requests, at the potential risk of reading stale data.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="oauth">
+ <xs:annotation>
+ <xs:documentation>
+ Settings for OAuth consumers and service providers.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="consumer">
+ <xs:annotation>
+ <xs:documentation>
+ Settings applicable to OAuth Consumers.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="security">
+ <xs:annotation>
+ <xs:documentation>
+ Security settings applicable to OAuth Consumers.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="serviceProvider">
+ <xs:annotation>
+ <xs:documentation>
+ Settings applicable to OAuth Service Providers.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="security">
+ <xs:annotation>
+ <xs:documentation>
+ Security settings applicable to OAuth Service Providers.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="minimumRequiredOAuthVersion" default="V10">
+ <xs:annotation>
+ <xs:documentation>
+ Optionally restricts interoperability with OAuth consumers that implement
+ older versions of OAuth.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:NMTOKEN">
+ <xs:enumeration value="V10">
+ <xs:annotation>
+ <xs:documentation>
+ The initial version of OAuth, now known to be vulnerable to certain social engineering attacks.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:enumeration>
+ <xs:enumeration value="V10a">
+ <xs:annotation>
+ <xs:documentation>
+ The OAuth version that protects against social engineering attacks by introducing
+ the oauth_verifier parameter.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="maxAuthorizationTime" type="xs:string" default="0:05">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum time allowed for users to authorize a consumer before request tokens expire.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="store">
+ <xs:annotation>
+ <xs:documentation>
+ Sets the custom type that implements the INonceStore interface to use for nonce checking.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="type" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ A fully-qualified type name of the custom implementation of INonceStore.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="reporting">
+ <xs:annotation>
+ <xs:documentation>
+ Adjusts statistical reports DotNetOpenAuth may send to the library authors to
+ assist with future development of the library.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="enabled" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Controls whether reporting is active at all or entirely inactive.
+ Note that even if active, the reports may be more or less empty based
+ on other settings.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="minimumReportingInterval" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ Controls how frequently reports are collected and transmitted.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="minimumFlushInterval" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ Controls how frequently the statistics that are collected in memory are persisted to disk.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="includeFeatureUsage" type="xs:boolean" default="true">
+ <xs:annotation>
+ <xs:documentation>
+ Whether a list of features in DotNetOpenAuth that are actually used by this host
+ are included in the report.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <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
+ successful or failed authentication) is included in the report.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="includeLocalRequestUris" type="xs:boolean" default="true">
+ <xs:annotation>
+ <xs:documentation>
+ Whether to include a few of this host's URLs that contain DotNetOpenAuth components.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="includeCultures" type="xs:boolean" default="true">
+ <xs:annotation>
+ <xs:documentation>
+ Whether to include the cultures as set on the user agents of incoming requests to pages
+ that contain DotNetOpenAuth components.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+</xs:schema>
diff --git a/src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuthSection.cs b/src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuthSection.cs
new file mode 100644
index 0000000..e0c7fc4
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuthSection.cs
@@ -0,0 +1,70 @@
+//-----------------------------------------------------------------------
+// <copyright file="DotNetOpenAuthSection.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Configuration {
+ using System;
+ using System.Configuration;
+ using System.Diagnostics.Contracts;
+ using System.Web;
+ using System.Web.Configuration;
+
+ /// <summary>
+ /// Represents the section in the host's .config file that configures
+ /// this library's settings.
+ /// </summary>
+ [ContractVerification(true)]
+ public class DotNetOpenAuthSection : ConfigurationSectionGroup {
+ /// <summary>
+ /// The name of the section under which this library's settings must be found.
+ /// </summary>
+ internal const string SectionName = "dotNetOpenAuth";
+
+ /// <summary>
+ /// The name of the &lt;openid&gt; sub-element.
+ /// </summary>
+ private const string OpenIdElementName = "openid";
+
+ /// <summary>
+ /// The name of the &lt;oauth&gt; sub-element.
+ /// </summary>
+ private const string OAuthElementName = "oauth";
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DotNetOpenAuthSection"/> class.
+ /// </summary>
+ internal DotNetOpenAuthSection() {
+ }
+
+ /// <summary>
+ /// Gets the messaging configuration element.
+ /// </summary>
+ public static MessagingElement Messaging {
+ get { return MessagingElement.Configuration; }
+ }
+
+ /// <summary>
+ /// Gets the reporting configuration element.
+ /// </summary>
+ internal static ReportingElement Reporting {
+ get { return ReportingElement.Configuration; }
+ }
+
+ /// <summary>
+ /// Gets a named section in this section group, or <c>null</c> if no such section is defined.
+ /// </summary>
+ /// <param name="name">The name of the section to obtain.</param>
+ /// <returns>The desired section, or null if it could not be obtained.</returns>
+ internal static ConfigurationSection GetNamedSection(string name) {
+ string fullyQualifiedSectionName = SectionName + "/" + name;
+ if (HttpContext.Current != null) {
+ return (ConfigurationSection)WebConfigurationManager.GetSection(fullyQualifiedSectionName);
+ } else {
+ var configuration = ConfigurationManager.OpenExeConfiguration(null);
+ return configuration != null ? configuration.GetSection(fullyQualifiedSectionName) : null;
+ }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Core/Configuration/HostNameElement.cs b/src/DotNetOpenAuth.Core/Configuration/HostNameElement.cs
new file mode 100644
index 0000000..9df218e
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Configuration/HostNameElement.cs
@@ -0,0 +1,45 @@
+//-----------------------------------------------------------------------
+// <copyright file="HostNameElement.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Configuration {
+ using System.Configuration;
+ using System.Diagnostics.Contracts;
+
+ /// <summary>
+ /// Represents the name of a single host or a regex pattern for host names.
+ /// </summary>
+ [ContractVerification(true)]
+ internal class HostNameElement : ConfigurationElement {
+ /// <summary>
+ /// Gets the name of the @name attribute.
+ /// </summary>
+ private const string NameConfigName = "name";
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="HostNameElement"/> class.
+ /// </summary>
+ internal HostNameElement() {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="HostNameElement"/> class.
+ /// </summary>
+ /// <param name="name">The default value of the <see cref="Name"/> property.</param>
+ internal HostNameElement(string name) {
+ this.Name = name;
+ }
+
+ /// <summary>
+ /// Gets or sets the name of the host on the white or black list.
+ /// </summary>
+ [ConfigurationProperty(NameConfigName, IsRequired = true, IsKey = true)]
+ ////[StringValidator(MinLength = 1)]
+ public string Name {
+ get { return (string)this[NameConfigName]; }
+ set { this[NameConfigName] = value; }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Core/Configuration/HostNameOrRegexCollection.cs b/src/DotNetOpenAuth.Core/Configuration/HostNameOrRegexCollection.cs
new file mode 100644
index 0000000..c7d963b
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Configuration/HostNameOrRegexCollection.cs
@@ -0,0 +1,70 @@
+//-----------------------------------------------------------------------
+// <copyright file="HostNameOrRegexCollection.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Configuration {
+ using System.Collections.Generic;
+ using System.Configuration;
+ using System.Diagnostics.Contracts;
+ using System.Text.RegularExpressions;
+
+ /// <summary>
+ /// Represents a collection of child elements that describe host names either as literal host names or regex patterns.
+ /// </summary>
+ [ContractVerification(true)]
+ internal class HostNameOrRegexCollection : ConfigurationElementCollection {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="HostNameOrRegexCollection"/> class.
+ /// </summary>
+ public HostNameOrRegexCollection() {
+ }
+
+ /// <summary>
+ /// Gets all the members of the collection assuming they are all literal host names.
+ /// </summary>
+ internal IEnumerable<string> KeysAsStrings {
+ get {
+ foreach (HostNameElement element in this) {
+ yield return element.Name;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets all the members of the collection assuming they are all host names regex patterns.
+ /// </summary>
+ internal IEnumerable<Regex> KeysAsRegexs {
+ get {
+ foreach (HostNameElement element in this) {
+ if (element.Name != null) {
+ yield return new Regex(element.Name);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Creates a new child host name element.
+ /// </summary>
+ /// <returns>
+ /// A new <see cref="T:System.Configuration.ConfigurationElement"/>.
+ /// </returns>
+ protected override ConfigurationElement CreateNewElement() {
+ return new HostNameElement();
+ }
+
+ /// <summary>
+ /// Gets the element key for a specified configuration element.
+ /// </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) {
+ Contract.Assume(element != null); // this should be Contract.Requires in base class.
+ return ((HostNameElement)element).Name ?? string.Empty;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Core/Configuration/MessagingElement.cs b/src/DotNetOpenAuth.Core/Configuration/MessagingElement.cs
new file mode 100644
index 0000000..7c3e242
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Configuration/MessagingElement.cs
@@ -0,0 +1,209 @@
+//-----------------------------------------------------------------------
+// <copyright file="MessagingElement.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Configuration {
+ using System;
+ using System.Configuration;
+ using System.Diagnostics.Contracts;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Bindings;
+
+ /// <summary>
+ /// Represents the &lt;messaging&gt; element in the host's .config file.
+ /// </summary>
+ [ContractVerification(true)]
+ public class MessagingElement : ConfigurationSection {
+ /// <summary>
+ /// The name of the &lt;webResourceUrlProvider&gt; sub-element.
+ /// </summary>
+ private const string WebResourceUrlProviderName = "webResourceUrlProvider";
+
+ /// <summary>
+ /// The name of the &lt;untrustedWebRequest&gt; sub-element.
+ /// </summary>
+ private const string UntrustedWebRequestElementName = "untrustedWebRequest";
+
+ /// <summary>
+ /// The name of the attribute that stores the association's maximum lifetime.
+ /// </summary>
+ private const string MaximumMessageLifetimeConfigName = "lifetime";
+
+ /// <summary>
+ /// The name of the attribute that stores the maximum allowable clock skew.
+ /// </summary>
+ private const string MaximumClockSkewConfigName = "clockSkew";
+
+ /// <summary>
+ /// The name of the attribute that indicates whether to disable SSL requirements across the library.
+ /// </summary>
+ private const string RelaxSslRequirementsConfigName = "relaxSslRequirements";
+
+ /// <summary>
+ /// The name of the attribute that controls whether messaging rules are strictly followed.
+ /// </summary>
+ private const string StrictConfigName = "strict";
+
+ /// <summary>
+ /// The default value for the <see cref="MaximumIndirectMessageUrlLength"/> property.
+ /// </summary>
+ /// <value>
+ /// 2KB, recommended by OpenID group
+ /// </value>
+ private const int DefaultMaximumIndirectMessageUrlLength = 2 * 1024;
+
+ /// <summary>
+ /// The name of the attribute that controls the maximum length of a URL before it is converted
+ /// to a POST payload.
+ /// </summary>
+ private const string MaximumIndirectMessageUrlLengthConfigName = "maximumIndirectMessageUrlLength";
+
+ /// <summary>
+ /// Gets the name of the @privateSecretMaximumAge attribute.
+ /// </summary>
+ private const string PrivateSecretMaximumAgeConfigName = "privateSecretMaximumAge";
+
+ /// <summary>
+ /// The name of the &lt;messaging&gt; sub-element.
+ /// </summary>
+ private const string MessagingElementName = DotNetOpenAuthSection.SectionName + "/messaging";
+
+ /// <summary>
+ /// Gets the configuration section from the .config file.
+ /// </summary>
+ public static MessagingElement Configuration {
+ get {
+ Contract.Ensures(Contract.Result<MessagingElement>() != null);
+ return (MessagingElement)ConfigurationManager.GetSection(MessagingElementName) ?? new MessagingElement();
+ }
+ }
+
+ /// <summary>
+ /// Gets the actual maximum message lifetime that a program should allow.
+ /// </summary>
+ /// <value>The sum of the <see cref="MaximumMessageLifetime"/> and
+ /// <see cref="MaximumClockSkew"/> property values.</value>
+ public TimeSpan MaximumMessageLifetime {
+ get { return this.MaximumMessageLifetimeNoSkew + this.MaximumClockSkew; }
+ }
+
+ /// <summary>
+ /// Gets or sets the maximum lifetime of a private symmetric secret,
+ /// that may be used for signing or encryption.
+ /// </summary>
+ /// <value>The default value is 28 days (twice the age of the longest association).</value>
+ [ConfigurationProperty(PrivateSecretMaximumAgeConfigName, DefaultValue = "28.00:00:00")]
+ public TimeSpan PrivateSecretMaximumAge {
+ get { return (TimeSpan)this[PrivateSecretMaximumAgeConfigName]; }
+ set { this[PrivateSecretMaximumAgeConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the time between a message's creation and its receipt
+ /// before it is considered expired.
+ /// </summary>
+ /// <value>
+ /// The default value value is 3 minutes.
+ /// </value>
+ /// <remarks>
+ /// <para>Smaller timespans mean lower tolerance for delays in message delivery.
+ /// Larger timespans mean more nonces must be stored to provide replay protection.</para>
+ /// <para>The maximum age a message implementing the
+ /// <see cref="IExpiringProtocolMessage"/> interface can be before
+ /// being discarded as too old.</para>
+ /// <para>This time limit should NOT take into account expected
+ /// time skew for servers across the Internet. Time skew is added to
+ /// this value and is controlled by the <see cref="MaximumClockSkew"/> property.</para>
+ /// </remarks>
+ [ConfigurationProperty(MaximumMessageLifetimeConfigName, DefaultValue = "00:03:00")]
+ internal TimeSpan MaximumMessageLifetimeNoSkew {
+ get { return (TimeSpan)this[MaximumMessageLifetimeConfigName]; }
+ set { this[MaximumMessageLifetimeConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the maximum clock skew.
+ /// </summary>
+ /// <value>The default value is 10 minutes.</value>
+ /// <remarks>
+ /// <para>Smaller timespans mean lower tolerance for
+ /// time variance due to server clocks not being synchronized.
+ /// Larger timespans mean greater chance for replay attacks and
+ /// larger nonce caches.</para>
+ /// <para>For example, if a server could conceivably have its
+ /// clock d = 5 minutes off UTC time, then any two servers could have
+ /// their clocks disagree by as much as 2*d = 10 minutes. </para>
+ /// </remarks>
+ [ConfigurationProperty(MaximumClockSkewConfigName, DefaultValue = "00:10:00")]
+ internal TimeSpan MaximumClockSkew {
+ get { return (TimeSpan)this[MaximumClockSkewConfigName]; }
+ set { this[MaximumClockSkewConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether SSL requirements within the library are disabled/relaxed.
+ /// Use for TESTING ONLY.
+ /// </summary>
+ [ConfigurationProperty(RelaxSslRequirementsConfigName, DefaultValue = false)]
+ internal bool RelaxSslRequirements {
+ get { return (bool)this[RelaxSslRequirementsConfigName]; }
+ set { this[RelaxSslRequirementsConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether messaging rules are strictly
+ /// adhered to.
+ /// </summary>
+ /// <value><c>true</c> by default.</value>
+ /// <remarks>
+ /// Strict will require that remote parties adhere strictly to the specifications,
+ /// even when a loose interpretation would not compromise security.
+ /// <c>true</c> is a good default because it shakes out interoperability bugs in remote services
+ /// so they can be identified and corrected. But some web sites want things to Just Work
+ /// more than they want to file bugs against others, so <c>false</c> is the setting for them.
+ /// </remarks>
+ [ConfigurationProperty(StrictConfigName, DefaultValue = true)]
+ internal bool Strict {
+ get { return (bool)this[StrictConfigName]; }
+ set { this[StrictConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the configuration for the <see cref="UntrustedWebRequestHandler"/> class.
+ /// </summary>
+ /// <value>The untrusted web request.</value>
+ [ConfigurationProperty(UntrustedWebRequestElementName)]
+ internal UntrustedWebRequestElement UntrustedWebRequest {
+ get { return (UntrustedWebRequestElement)this[UntrustedWebRequestElementName] ?? new UntrustedWebRequestElement(); }
+ set { this[UntrustedWebRequestElementName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the maximum allowable size for a 301 Redirect response before we send
+ /// a 200 OK response with a scripted form POST with the parameters instead
+ /// in order to ensure successfully sending a large payload to another server
+ /// that might have a maximum allowable size restriction on its GET request.
+ /// </summary>
+ /// <value>The default value is 2048.</value>
+ [ConfigurationProperty(MaximumIndirectMessageUrlLengthConfigName, DefaultValue = DefaultMaximumIndirectMessageUrlLength)]
+ [IntegerValidator(MinValue = 500, MaxValue = 4096)]
+ internal int MaximumIndirectMessageUrlLength {
+ get { return (int)this[MaximumIndirectMessageUrlLengthConfigName]; }
+ set { this[MaximumIndirectMessageUrlLengthConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the embedded resource retrieval provider.
+ /// </summary>
+ /// <value>
+ /// The embedded resource retrieval provider.
+ /// </value>
+ [ConfigurationProperty(WebResourceUrlProviderName)]
+ internal TypeConfigurationElement<IEmbeddedResourceRetrieval> EmbeddedResourceRetrievalProvider {
+ get { return (TypeConfigurationElement<IEmbeddedResourceRetrieval>)this[WebResourceUrlProviderName] ?? new TypeConfigurationElement<IEmbeddedResourceRetrieval>(); }
+ set { this[WebResourceUrlProviderName] = value; }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Core/Configuration/ReportingElement.cs b/src/DotNetOpenAuth.Core/Configuration/ReportingElement.cs
new file mode 100644
index 0000000..a8eb7d3
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Configuration/ReportingElement.cs
@@ -0,0 +1,155 @@
+//-----------------------------------------------------------------------
+// <copyright file="ReportingElement.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;
+ using System.Linq;
+ using System.Text;
+
+ /// <summary>
+ /// Represents the &lt;reporting&gt; element in the host's .config file.
+ /// </summary>
+ internal class ReportingElement : ConfigurationSection {
+ /// <summary>
+ /// The name of the @enabled attribute.
+ /// </summary>
+ private const string EnabledAttributeName = "enabled";
+
+ /// <summary>
+ /// The name of the @minimumReportingInterval attribute.
+ /// </summary>
+ private const string MinimumReportingIntervalAttributeName = "minimumReportingInterval";
+
+ /// <summary>
+ /// The name of the @minimumFlushInterval attribute.
+ /// </summary>
+ private const string MinimumFlushIntervalAttributeName = "minimumFlushInterval";
+
+ /// <summary>
+ /// The name of the @includeFeatureUsage attribute.
+ /// </summary>
+ private const string IncludeFeatureUsageAttributeName = "includeFeatureUsage";
+
+ /// <summary>
+ /// The name of the @includeEventStatistics attribute.
+ /// </summary>
+ private const string IncludeEventStatisticsAttributeName = "includeEventStatistics";
+
+ /// <summary>
+ /// The name of the @includeLocalRequestUris attribute.
+ /// </summary>
+ private const string IncludeLocalRequestUrisAttributeName = "includeLocalRequestUris";
+
+ /// <summary>
+ /// The name of the @includeCultures attribute.
+ /// </summary>
+ private const string IncludeCulturesAttributeName = "includeCultures";
+
+ /// <summary>
+ /// The name of the &lt;reporting&gt; sub-element.
+ /// </summary>
+ private const string ReportingElementName = DotNetOpenAuthSection.SectionName + "/reporting";
+
+ /// <summary>
+ /// The default value for the @minimumFlushInterval attribute.
+ /// </summary>
+#if DEBUG
+ private const string MinimumFlushIntervalDefault = "0";
+#else
+ private const string MinimumFlushIntervalDefault = "0:15";
+#endif
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ReportingElement"/> class.
+ /// </summary>
+ internal ReportingElement() {
+ }
+
+ /// <summary>
+ /// Gets the configuration section from the .config file.
+ /// </summary>
+ public static ReportingElement Configuration {
+ get {
+ Contract.Ensures(Contract.Result<ReportingElement>() != null);
+ return (ReportingElement)ConfigurationManager.GetSection(ReportingElementName) ?? new ReportingElement();
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this reporting is enabled.
+ /// </summary>
+ /// <value><c>true</c> if enabled; otherwise, <c>false</c>.</value>
+ [ConfigurationProperty(EnabledAttributeName, DefaultValue = true)]
+ internal bool Enabled {
+ get { return (bool)this[EnabledAttributeName]; }
+ set { this[EnabledAttributeName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the maximum frequency that reports will be published.
+ /// </summary>
+ [ConfigurationProperty(MinimumReportingIntervalAttributeName, DefaultValue = "1")] // 1 day default
+ internal TimeSpan MinimumReportingInterval {
+ get { return (TimeSpan)this[MinimumReportingIntervalAttributeName]; }
+ set { this[MinimumReportingIntervalAttributeName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the maximum frequency the set can be flushed to disk.
+ /// </summary>
+ [ConfigurationProperty(MinimumFlushIntervalAttributeName, DefaultValue = MinimumFlushIntervalDefault)]
+ internal TimeSpan MinimumFlushInterval {
+ get { return (TimeSpan)this[MinimumFlushIntervalAttributeName]; }
+ set { this[MinimumFlushIntervalAttributeName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to include a list of library features used in the report.
+ /// </summary>
+ /// <value><c>true</c> to include a report of features used; otherwise, <c>false</c>.</value>
+ [ConfigurationProperty(IncludeFeatureUsageAttributeName, DefaultValue = true)]
+ internal bool IncludeFeatureUsage {
+ get { return (bool)this[IncludeFeatureUsageAttributeName]; }
+ set { this[IncludeFeatureUsageAttributeName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to include statistics of certain events such as
+ /// authentication success and failure counting, and can include remote endpoint URIs.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> to include event counters in the report; otherwise, <c>false</c>.
+ /// </value>
+ [ConfigurationProperty(IncludeEventStatisticsAttributeName, DefaultValue = true)]
+ internal bool IncludeEventStatistics {
+ get { return (bool)this[IncludeEventStatisticsAttributeName]; }
+ set { this[IncludeEventStatisticsAttributeName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to include a few URLs to pages on the hosting
+ /// web site that host DotNetOpenAuth components.
+ /// </summary>
+ [ConfigurationProperty(IncludeLocalRequestUrisAttributeName, DefaultValue = true)]
+ internal bool IncludeLocalRequestUris {
+ get { return (bool)this[IncludeLocalRequestUrisAttributeName]; }
+ set { this[IncludeLocalRequestUrisAttributeName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to include the cultures requested by the user agent
+ /// on pages that host DotNetOpenAuth components.
+ /// </summary>
+ [ConfigurationProperty(IncludeCulturesAttributeName, DefaultValue = true)]
+ internal bool IncludeCultures {
+ get { return (bool)this[IncludeCulturesAttributeName]; }
+ set { this[IncludeCulturesAttributeName] = value; }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Core/Configuration/TrustedProviderConfigurationCollection.cs b/src/DotNetOpenAuth.Core/Configuration/TrustedProviderConfigurationCollection.cs
new file mode 100644
index 0000000..1a287fd
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Configuration/TrustedProviderConfigurationCollection.cs
@@ -0,0 +1,74 @@
+//-----------------------------------------------------------------------
+// <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.CodeAnalysis;
+ 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>
+ /// <param name="elements">The elements to initialize the collection with.</param>
+ [SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors", Justification = "Seems unavoidable")]
+ internal TrustedProviderConfigurationCollection(IEnumerable<TrustedProviderEndpointConfigurationElement> elements) {
+ Requires.NotNull(elements, "elements");
+
+ 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.Core/Configuration/TrustedProviderEndpointConfigurationElement.cs b/src/DotNetOpenAuth.Core/Configuration/TrustedProviderEndpointConfigurationElement.cs
new file mode 100644
index 0000000..2576eb0
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Configuration/TrustedProviderEndpointConfigurationElement.cs
@@ -0,0 +1,35 @@
+//-----------------------------------------------------------------------
+// <copyright file="TrustedProviderEndpointConfigurationElement.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>
+ /// 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; }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Core/Configuration/TypeConfigurationCollection.cs b/src/DotNetOpenAuth.Core/Configuration/TypeConfigurationCollection.cs
new file mode 100644
index 0000000..95b9c50
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Configuration/TypeConfigurationCollection.cs
@@ -0,0 +1,76 @@
+//-----------------------------------------------------------------------
+// <copyright file="TypeConfigurationCollection.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;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// A collection of <see cref="TypeConfigurationElement&lt;T&gt;"/>.
+ /// </summary>
+ /// <typeparam name="T">The type that all types specified in the elements must derive from.</typeparam>
+ [ContractVerification(true)]
+ internal class TypeConfigurationCollection<T> : ConfigurationElementCollection
+ where T : class {
+ /// <summary>
+ /// Initializes a new instance of the TypeConfigurationCollection class.
+ /// </summary>
+ internal TypeConfigurationCollection() {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the TypeConfigurationCollection class.
+ /// </summary>
+ /// <param name="elements">The elements that should be added to the collection initially.</param>
+ internal TypeConfigurationCollection(IEnumerable<Type> elements) {
+ Requires.NotNull(elements, "elements");
+
+ foreach (Type element in elements) {
+ this.BaseAdd(new TypeConfigurationElement<T> { TypeName = element.AssemblyQualifiedName });
+ }
+ }
+
+ /// <summary>
+ /// Creates instances of all the types listed in the collection.
+ /// </summary>
+ /// <param name="allowInternals">if set to <c>true</c> then internal types may be instantiated.</param>
+ /// <returns>A sequence of instances generated from types in this collection. May be empty, but never null.</returns>
+ internal IEnumerable<T> CreateInstances(bool allowInternals) {
+ Contract.Ensures(Contract.Result<IEnumerable<T>>() != null);
+ return from element in this.Cast<TypeConfigurationElement<T>>()
+ where !element.IsEmpty
+ select element.CreateInstance(default(T), allowInternals);
+ }
+
+ /// <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 TypeConfigurationElement<T>();
+ }
+
+ /// <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) {
+ Contract.Assume(element != null); // this should be Contract.Requires in base class.
+ TypeConfigurationElement<T> typedElement = (TypeConfigurationElement<T>)element;
+ return (!string.IsNullOrEmpty(typedElement.TypeName) ? typedElement.TypeName : typedElement.XamlSource) ?? string.Empty;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Core/Configuration/TypeConfigurationElement.cs b/src/DotNetOpenAuth.Core/Configuration/TypeConfigurationElement.cs
new file mode 100644
index 0000000..fb1dee0
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Configuration/TypeConfigurationElement.cs
@@ -0,0 +1,141 @@
+//-----------------------------------------------------------------------
+// <copyright file="TypeConfigurationElement.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Configuration {
+ using System;
+ using System.Configuration;
+ using System.Diagnostics.Contracts;
+ using System.IO;
+ using System.Reflection;
+ using System.Web;
+#if CLR4
+ using System.Xaml;
+#else
+ using System.Windows.Markup;
+#endif
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// Represents an element in a .config file that allows the user to provide a @type attribute specifying
+ /// the full type that provides some service used by this library.
+ /// </summary>
+ /// <typeparam name="T">A constraint on the type the user may provide.</typeparam>
+ internal class TypeConfigurationElement<T> : ConfigurationElement
+ where T : class {
+ /// <summary>
+ /// The name of the attribute whose value is the full name of the type the user is specifying.
+ /// </summary>
+ private const string CustomTypeConfigName = "type";
+
+ /// <summary>
+ /// The name of the attribute whose value is the path to the XAML file to deserialize to obtain the type.
+ /// </summary>
+ private const string XamlReaderSourceConfigName = "xaml";
+
+ /// <summary>
+ /// Initializes a new instance of the TypeConfigurationElement class.
+ /// </summary>
+ public TypeConfigurationElement() {
+ }
+
+ /// <summary>
+ /// Gets or sets the full name of the type.
+ /// </summary>
+ /// <value>The full name of the type, such as: "ConsumerPortal.Code.CustomStore, ConsumerPortal".</value>
+ [ConfigurationProperty(CustomTypeConfigName)]
+ ////[SubclassTypeValidator(typeof(T))] // this attribute is broken in .NET, I think.
+ public string TypeName {
+ get { return (string)this[CustomTypeConfigName]; }
+ set { this[CustomTypeConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the path to the XAML file to deserialize to obtain the instance.
+ /// </summary>
+ [ConfigurationProperty(XamlReaderSourceConfigName)]
+ public string XamlSource {
+ get { return (string)this[XamlReaderSourceConfigName]; }
+ set { this[XamlReaderSourceConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets the type described in the .config file.
+ /// </summary>
+ public Type CustomType {
+ get { return string.IsNullOrEmpty(this.TypeName) ? null : Type.GetType(this.TypeName); }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this type has no meaningful type to instantiate.
+ /// </summary>
+ public bool IsEmpty {
+ get { return this.CustomType == null && string.IsNullOrEmpty(this.XamlSource); }
+ }
+
+ /// <summary>
+ /// Creates an instance of the type described in the .config file.
+ /// </summary>
+ /// <param name="defaultValue">The value to return if no type is given in the .config file.</param>
+ /// <returns>The newly instantiated type.</returns>
+ public T CreateInstance(T defaultValue) {
+ Contract.Ensures(Contract.Result<T>() != null || Contract.Result<T>() == defaultValue);
+
+ return this.CreateInstance(defaultValue, false);
+ }
+
+ /// <summary>
+ /// Creates an instance of the type described in the .config file.
+ /// </summary>
+ /// <param name="defaultValue">The value to return if no type is given in the .config file.</param>
+ /// <param name="allowInternals">if set to <c>true</c> then internal types may be instantiated.</param>
+ /// <returns>The newly instantiated type.</returns>
+ public T CreateInstance(T defaultValue, bool allowInternals) {
+ Contract.Ensures(Contract.Result<T>() != null || Contract.Result<T>() == defaultValue);
+
+ if (this.CustomType != null) {
+ if (!allowInternals) {
+ // Although .NET will usually prevent our instantiating non-public types,
+ // it will allow our instantiation of internal types within this same assembly.
+ // But we don't want the host site to be able to do this, so we check ourselves.
+ ErrorUtilities.VerifyArgument((this.CustomType.Attributes & TypeAttributes.Public) != 0, Strings.ConfigurationTypeMustBePublic, this.CustomType.FullName);
+ }
+ return (T)Activator.CreateInstance(this.CustomType);
+ } else if (!string.IsNullOrEmpty(this.XamlSource)) {
+ string source = this.XamlSource;
+ if (source.StartsWith("~/", StringComparison.Ordinal)) {
+ ErrorUtilities.VerifyHost(HttpContext.Current != null, Strings.ConfigurationXamlReferenceRequiresHttpContext, this.XamlSource);
+ source = HttpContext.Current.Server.MapPath(source);
+ }
+ using (Stream xamlFile = File.OpenRead(source)) {
+ return CreateInstanceFromXaml(xamlFile);
+ }
+ } else {
+ return defaultValue;
+ }
+ }
+
+ /// <summary>
+ /// Creates the instance from xaml.
+ /// </summary>
+ /// <param name="xaml">The stream of xaml to deserialize.</param>
+ /// <returns>The deserialized object.</returns>
+ /// <remarks>
+ /// This exists as its own method to prevent the CLR's JIT compiler from failing
+ /// to compile the CreateInstance method just because the PresentationFramework.dll
+ /// may be missing (which it is on some shared web hosts). This way, if the
+ /// XamlSource attribute is never used, the PresentationFramework.dll never need
+ /// be present.
+ /// </remarks>
+ private static T CreateInstanceFromXaml(Stream xaml) {
+ Contract.Ensures(Contract.Result<T>() != null);
+#if CLR4
+ return (T)XamlServices.Load(xaml);
+#else
+ return (T)XamlReader.Load(xaml);
+#endif
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Core/Configuration/UntrustedWebRequestElement.cs b/src/DotNetOpenAuth.Core/Configuration/UntrustedWebRequestElement.cs
new file mode 100644
index 0000000..43e41d9
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Configuration/UntrustedWebRequestElement.cs
@@ -0,0 +1,141 @@
+//-----------------------------------------------------------------------
+// <copyright file="UntrustedWebRequestElement.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Configuration {
+ using System;
+ using System.Configuration;
+ using System.Diagnostics.Contracts;
+
+ /// <summary>
+ /// Represents the section of a .config file where security policies regarding web requests
+ /// to user-provided, untrusted servers is controlled.
+ /// </summary>
+ internal class UntrustedWebRequestElement : ConfigurationElement {
+ #region Attribute names
+
+ /// <summary>
+ /// Gets the name of the @timeout attribute.
+ /// </summary>
+ private const string TimeoutConfigName = "timeout";
+
+ /// <summary>
+ /// Gets the name of the @readWriteTimeout attribute.
+ /// </summary>
+ private const string ReadWriteTimeoutConfigName = "readWriteTimeout";
+
+ /// <summary>
+ /// Gets the name of the @maximumBytesToRead attribute.
+ /// </summary>
+ private const string MaximumBytesToReadConfigName = "maximumBytesToRead";
+
+ /// <summary>
+ /// Gets the name of the @maximumRedirections attribute.
+ /// </summary>
+ private const string MaximumRedirectionsConfigName = "maximumRedirections";
+
+ /// <summary>
+ /// Gets the name of the @whitelistHosts attribute.
+ /// </summary>
+ private const string WhitelistHostsConfigName = "whitelistHosts";
+
+ /// <summary>
+ /// Gets the name of the @whitelistHostsRegex attribute.
+ /// </summary>
+ private const string WhitelistHostsRegexConfigName = "whitelistHostsRegex";
+
+ /// <summary>
+ /// Gets the name of the @blacklistHosts attribute.
+ /// </summary>
+ private const string BlacklistHostsConfigName = "blacklistHosts";
+
+ /// <summary>
+ /// Gets the name of the @blacklistHostsRegex attribute.
+ /// </summary>
+ private const string BlacklistHostsRegexConfigName = "blacklistHostsRegex";
+
+ #endregion
+
+ /// <summary>
+ /// Gets or sets the read/write timeout after which an HTTP request will fail.
+ /// </summary>
+ [ConfigurationProperty(ReadWriteTimeoutConfigName, DefaultValue = "00:00:01.500")]
+ [PositiveTimeSpanValidator]
+ public TimeSpan ReadWriteTimeout {
+ get { return (TimeSpan)this[ReadWriteTimeoutConfigName]; }
+ set { this[ReadWriteTimeoutConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the timeout after which an HTTP request will fail.
+ /// </summary>
+ [ConfigurationProperty(TimeoutConfigName, DefaultValue = "00:00:10")]
+ [PositiveTimeSpanValidator]
+ public TimeSpan Timeout {
+ get { return (TimeSpan)this[TimeoutConfigName]; }
+ set { this[TimeoutConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the maximum bytes to read from an untrusted web server.
+ /// </summary>
+ [ConfigurationProperty(MaximumBytesToReadConfigName, DefaultValue = 1024 * 1024)]
+ [IntegerValidator(MinValue = 2048)]
+ public int MaximumBytesToRead {
+ get { return (int)this[MaximumBytesToReadConfigName]; }
+ set { this[MaximumBytesToReadConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the maximum redirections that will be followed before an HTTP request fails.
+ /// </summary>
+ [ConfigurationProperty(MaximumRedirectionsConfigName, DefaultValue = 10)]
+ [IntegerValidator(MinValue = 0)]
+ public int MaximumRedirections {
+ get { return (int)this[MaximumRedirectionsConfigName]; }
+ set { this[MaximumRedirectionsConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the collection of hosts on the whitelist.
+ /// </summary>
+ [ConfigurationProperty(WhitelistHostsConfigName, IsDefaultCollection = false)]
+ [ConfigurationCollection(typeof(HostNameOrRegexCollection))]
+ public HostNameOrRegexCollection WhitelistHosts {
+ get { return (HostNameOrRegexCollection)this[WhitelistHostsConfigName] ?? new HostNameOrRegexCollection(); }
+ set { this[WhitelistHostsConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the collection of hosts on the blacklist.
+ /// </summary>
+ [ConfigurationProperty(BlacklistHostsConfigName, IsDefaultCollection = false)]
+ [ConfigurationCollection(typeof(HostNameOrRegexCollection))]
+ public HostNameOrRegexCollection BlacklistHosts {
+ get { return (HostNameOrRegexCollection)this[BlacklistHostsConfigName] ?? new HostNameOrRegexCollection(); }
+ set { this[BlacklistHostsConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the collection of regular expressions that describe hosts on the whitelist.
+ /// </summary>
+ [ConfigurationProperty(WhitelistHostsRegexConfigName, IsDefaultCollection = false)]
+ [ConfigurationCollection(typeof(HostNameOrRegexCollection))]
+ public HostNameOrRegexCollection WhitelistHostsRegex {
+ get { return (HostNameOrRegexCollection)this[WhitelistHostsRegexConfigName] ?? new HostNameOrRegexCollection(); }
+ set { this[WhitelistHostsRegexConfigName] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the collection of regular expressions that describe hosts on the blacklist.
+ /// </summary>
+ [ConfigurationProperty(BlacklistHostsRegexConfigName, IsDefaultCollection = false)]
+ [ConfigurationCollection(typeof(HostNameOrRegexCollection))]
+ public HostNameOrRegexCollection BlacklistHostsRegex {
+ get { return (HostNameOrRegexCollection)this[BlacklistHostsRegexConfigName] ?? new HostNameOrRegexCollection(); }
+ set { this[BlacklistHostsRegexConfigName] = value; }
+ }
+ }
+}