diff options
Diffstat (limited to 'src/DotNetOpenAuth.Core/Configuration')
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 <openid> sub-element. + /// </summary> + private const string OpenIdElementName = "openid"; + + /// <summary> + /// The name of the <oauth> 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 <messaging> element in the host's .config file. + /// </summary> + [ContractVerification(true)] + public class MessagingElement : ConfigurationSection { + /// <summary> + /// The name of the <webResourceUrlProvider> sub-element. + /// </summary> + private const string WebResourceUrlProviderName = "webResourceUrlProvider"; + + /// <summary> + /// The name of the <untrustedWebRequest> 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 <messaging> 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 <reporting> 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 <reporting> 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<T>"/>. + /// </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; } + } + } +} |