diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2009-11-19 22:28:08 -0800 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2009-11-19 22:28:08 -0800 |
commit | bf833ec35eef4a3514cc8426c36139bc8cca68bc (patch) | |
tree | 8be76aad52f81a154cec08299a0a796c31f21e29 /src | |
parent | 2d1eedc3bdf0f58dff78aedc7fc41459ba7af944 (diff) | |
parent | 71ba020b6cdec56990363e4808453da2e80d0e7f (diff) | |
download | DotNetOpenAuth-bf833ec35eef4a3514cc8426c36139bc8cca68bc.zip DotNetOpenAuth-bf833ec35eef4a3514cc8426c36139bc8cca68bc.tar.gz DotNetOpenAuth-bf833ec35eef4a3514cc8426c36139bc8cca68bc.tar.bz2 |
Merge branch 'v3.3'
Diffstat (limited to 'src')
23 files changed, 273 insertions, 37 deletions
diff --git a/src/DotNetOpenAuth.Test/OAuth/OAuthCoordinator.cs b/src/DotNetOpenAuth.Test/OAuth/OAuthCoordinator.cs index 4373402..5967a03 100644 --- a/src/DotNetOpenAuth.Test/OAuth/OAuthCoordinator.cs +++ b/src/DotNetOpenAuth.Test/OAuth/OAuthCoordinator.cs @@ -8,6 +8,7 @@ namespace DotNetOpenAuth.Test { using System; using System.Diagnostics.Contracts; using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.Messaging.Bindings; using DotNetOpenAuth.OAuth; using DotNetOpenAuth.OAuth.ChannelElements; using DotNetOpenAuth.Test.Mocks; @@ -58,7 +59,7 @@ namespace DotNetOpenAuth.Test { WebConsumer consumer = new WebConsumer(this.serviceDescription, consumerTokenManager) { OAuthChannel = consumerChannel, }; - ServiceProvider serviceProvider = new ServiceProvider(this.serviceDescription, serviceTokenManager) { + ServiceProvider serviceProvider = new ServiceProvider(this.serviceDescription, serviceTokenManager, new NonceMemoryStore()) { OAuthChannel = serviceProviderChannel, }; diff --git a/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd b/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd index a214053..a637d1f 100644 --- a/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd +++ b/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd @@ -272,6 +272,47 @@ <xs:attribute name="maxAuthenticationTime" type="xs:string" /> </xs:complexType> </xs:element> + <xs:element name="oauth"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="consumer"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="security"> + <xs:complexType> + + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> + <xs:element name="serviceProvider"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="security"> + <xs:complexType> + <xs:attribute name="minimumRequiredOAuthVersion" default="V10"> + <xs:simpleType> + <xs:restriction base="xs:NMTOKEN"> + <xs:enumeration value="V10" /> + <xs:enumeration value="V10a" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="maxAuthorizationTime" type="xs:string" default="0:05" /> + </xs:complexType> + </xs:element> + <xs:element name="store"> + <xs:complexType> + <xs:attribute name="type" type="xs:string"/> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> </xs:choice> </xs:complexType> </xs:element> diff --git a/src/DotNetOpenAuth/Configuration/OAuthServiceProviderElement.cs b/src/DotNetOpenAuth/Configuration/OAuthServiceProviderElement.cs index 5ff528d..8e910a0 100644 --- a/src/DotNetOpenAuth/Configuration/OAuthServiceProviderElement.cs +++ b/src/DotNetOpenAuth/Configuration/OAuthServiceProviderElement.cs @@ -6,12 +6,18 @@ namespace DotNetOpenAuth.Configuration { using System.Configuration; + using DotNetOpenAuth.Messaging.Bindings; /// <summary> /// Represents the <oauth/serviceProvider> element in the host's .config file. /// </summary> internal class OAuthServiceProviderElement : ConfigurationElement { /// <summary> + /// The name of the custom store sub-element. + /// </summary> + private const string StoreConfigName = "store"; + + /// <summary> /// Gets the name of the security sub-element. /// </summary> private const string SecuritySettingsConfigName = "security"; @@ -23,6 +29,15 @@ namespace DotNetOpenAuth.Configuration { } /// <summary> + /// Gets or sets the type to use for storing application state. + /// </summary> + [ConfigurationProperty(StoreConfigName)] + public TypeConfigurationElement<INonceStore> ApplicationStore { + get { return (TypeConfigurationElement<INonceStore>)this[StoreConfigName] ?? new TypeConfigurationElement<INonceStore>(); } + set { this[StoreConfigName] = value; } + } + + /// <summary> /// Gets or sets the security settings. /// </summary> [ConfigurationProperty(SecuritySettingsConfigName)] diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj index bf2e26c..f339d97 100644 --- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj +++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj @@ -75,7 +75,7 @@ http://opensource.org/licenses/ms-pl.html </CodeContractsCustomRewriterAssembly> <CodeContractsCustomRewriterClass> </CodeContractsCustomRewriterClass> - <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel> + <CodeContractsRuntimeCheckingLevel>ReleaseRequires</CodeContractsRuntimeCheckingLevel> <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis> <CodeContractsBuildReferenceAssembly>True</CodeContractsBuildReferenceAssembly> <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations> diff --git a/src/DotNetOpenAuth/Logger.cs b/src/DotNetOpenAuth/Logger.cs index 1c1b8a5..a9dbef2 100644 --- a/src/DotNetOpenAuth/Logger.cs +++ b/src/DotNetOpenAuth/Logger.cs @@ -143,6 +143,7 @@ namespace DotNetOpenAuth { /// <param name="name">A name that will be included in the log file.</param> /// <returns>The <see cref="ILog"/> instance created with the given name.</returns> internal static ILog CreateWithBanner(string name) { + Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(name)); ILog log = Create(name); log.Info(Util.LibraryVersion); return log; diff --git a/src/DotNetOpenAuth/Messaging/Bindings/INonceStore.cs b/src/DotNetOpenAuth/Messaging/Bindings/INonceStore.cs index fff251a..6b6e2e1 100644 --- a/src/DotNetOpenAuth/Messaging/Bindings/INonceStore.cs +++ b/src/DotNetOpenAuth/Messaging/Bindings/INonceStore.cs @@ -19,11 +19,12 @@ namespace DotNetOpenAuth.Messaging.Bindings { /// The context SHOULD be treated as case-sensitive. /// The value will never be <c>null</c> but may be the empty string.</param> /// <param name="nonce">A series of random characters.</param> - /// <param name="timestamp">The timestamp that together with the nonce string make it unique. + /// <param name="timestampUtc">The UTC timestamp that together with the nonce string make it unique + /// within the given <paramref name="context"/>. /// The timestamp may also be used by the data store to clear out old nonces.</param> /// <returns> - /// True if the nonce+timestamp (combination) was not previously in the database. - /// False if the nonce was stored previously with the same timestamp. + /// True if the context+nonce+timestamp (combination) was not previously in the database. + /// False if the nonce was stored previously with the same timestamp and context. /// </returns> /// <remarks> /// The nonce must be stored for no less than the maximum time window a message may @@ -33,6 +34,6 @@ namespace DotNetOpenAuth.Messaging.Bindings { /// property, accessible via the <see cref="DotNetOpenAuth.Configuration.DotNetOpenAuthSection.Configuration"/> /// property. /// </remarks> - bool StoreNonce(string context, string nonce, DateTime timestamp); + bool StoreNonce(string context, string nonce, DateTime timestampUtc); } } diff --git a/src/DotNetOpenAuth/Messaging/Bindings/NonceMemoryStore.cs b/src/DotNetOpenAuth/Messaging/Bindings/NonceMemoryStore.cs index 3d624a6..6e64acc 100644 --- a/src/DotNetOpenAuth/Messaging/Bindings/NonceMemoryStore.cs +++ b/src/DotNetOpenAuth/Messaging/Bindings/NonceMemoryStore.cs @@ -47,6 +47,13 @@ namespace DotNetOpenAuth.Messaging.Bindings { /// <summary> /// Initializes a new instance of the <see cref="NonceMemoryStore"/> class. /// </summary> + internal NonceMemoryStore() + : this(StandardExpirationBindingElement.MaximumMessageAge) { + } + + /// <summary> + /// Initializes a new instance of the <see cref="NonceMemoryStore"/> class. + /// </summary> /// <param name="maximumMessageAge">The maximum age a message can be before it is discarded.</param> internal NonceMemoryStore(TimeSpan maximumMessageAge) { this.maximumMessageAge = maximumMessageAge; diff --git a/src/DotNetOpenAuth/Messaging/MessageReceivingEndpoint.cs b/src/DotNetOpenAuth/Messaging/MessageReceivingEndpoint.cs index c7ac581..e26a672 100644 --- a/src/DotNetOpenAuth/Messaging/MessageReceivingEndpoint.cs +++ b/src/DotNetOpenAuth/Messaging/MessageReceivingEndpoint.cs @@ -21,7 +21,10 @@ namespace DotNetOpenAuth.Messaging { /// <param name="locationUri">The URL of this endpoint.</param> /// <param name="method">The HTTP method(s) allowed.</param> public MessageReceivingEndpoint(string locationUri, HttpDeliveryMethods method) - : this(new Uri(locationUri), method) { } + : this(new Uri(locationUri), method) { + Contract.Requires<ArgumentNullException>(locationUri != null); + Contract.Requires<ArgumentOutOfRangeException>(method != HttpDeliveryMethods.None); + } /// <summary> /// Initializes a new instance of the <see cref="MessageReceivingEndpoint"/> class. @@ -30,7 +33,7 @@ namespace DotNetOpenAuth.Messaging { /// <param name="method">The HTTP method(s) allowed.</param> public MessageReceivingEndpoint(Uri location, HttpDeliveryMethods method) { Contract.Requires<ArgumentNullException>(location != null); - Contract.Requires<ArgumentOutOfRangeException>(method != HttpDeliveryMethods.None, "method"); + Contract.Requires<ArgumentOutOfRangeException>(method != HttpDeliveryMethods.None); Contract.Requires<ArgumentOutOfRangeException>((method & HttpDeliveryMethods.HttpVerbMask) != 0, MessagingStrings.GetOrPostFlagsRequired); this.Location = location; diff --git a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs index ba68227..e1e3f59 100644 --- a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs +++ b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs @@ -326,6 +326,10 @@ namespace DotNetOpenAuth.Messaging { /// The positions are NOT reset after copying is complete. /// </remarks> internal static int CopyTo(this Stream copyFrom, Stream copyTo) { + Contract.Requires<ArgumentNullException>(copyFrom != null); + Contract.Requires<ArgumentNullException>(copyTo != null); + Contract.Requires<ArgumentException>(copyFrom.CanRead, MessagingStrings.StreamUnreadable); + Contract.Requires<ArgumentException>(copyTo.CanWrite, MessagingStrings.StreamUnwritable); return CopyTo(copyFrom, copyTo, int.MaxValue); } @@ -366,6 +370,7 @@ namespace DotNetOpenAuth.Messaging { /// <returns>A seekable stream with the same contents as the original.</returns> internal static Stream CreateSnapshot(this Stream copyFrom) { Contract.Requires<ArgumentNullException>(copyFrom != null); + Contract.Requires<ArgumentException>(copyFrom.CanRead); MemoryStream copyTo = new MemoryStream(copyFrom.CanSeek ? (int)copyFrom.Length : 4 * 1024); copyFrom.CopyTo(copyTo); @@ -380,6 +385,7 @@ namespace DotNetOpenAuth.Messaging { /// <returns>The newly created instance.</returns> internal static HttpWebRequest Clone(this HttpWebRequest request) { Contract.Requires<ArgumentNullException>(request != null); + Contract.Requires<ArgumentException>(request.RequestUri != null); return Clone(request, request.RequestUri); } @@ -547,6 +553,8 @@ namespace DotNetOpenAuth.Messaging { /// <param name="second">The second dictionary in the comparison. May not be null.</param> /// <returns>True if the arrays equal; false otherwise.</returns> internal static bool AreEquivalent<TKey, TValue>(IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second) { + Contract.Requires<ArgumentNullException>(first != null); + Contract.Requires<ArgumentNullException>(second != null); return AreEquivalent(first.ToArray(), second.ToArray()); } @@ -752,6 +760,9 @@ namespace DotNetOpenAuth.Messaging { /// <param name="comparer">A comparison function to compare keys.</param> /// <returns>An System.Linq.IOrderedEnumerable<TElement> whose elements are sorted according to a key.</returns> internal static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Comparison<TKey> comparer) { + Contract.Requires<ArgumentNullException>(source != null); + Contract.Requires<ArgumentNullException>(comparer != null); + Contract.Requires<ArgumentNullException>(keySelector != null); Contract.Ensures(Contract.Result<IOrderedEnumerable<TSource>>() != null); return System.Linq.Enumerable.OrderBy<TSource, TKey>(source, keySelector, new ComparisonHelper<TKey>(comparer)); } @@ -850,6 +861,8 @@ namespace DotNetOpenAuth.Messaging { /// host actually having this configuration element present. /// </remarks> internal static string EscapeUriDataStringRfc3986(string value) { + Contract.Requires<ArgumentNullException>(value != null); + // Start with RFC 2396 escaping by calling the .NET method to do the work. // This MAY sometimes exhibit RFC 3986 behavior (according to the documentation). // If it does, the escaping we do that follows it will be a no-op since the diff --git a/src/DotNetOpenAuth/OAuth/ServiceProvider.cs b/src/DotNetOpenAuth/OAuth/ServiceProvider.cs index 5883273..e2c82bb 100644 --- a/src/DotNetOpenAuth/OAuth/ServiceProvider.cs +++ b/src/DotNetOpenAuth/OAuth/ServiceProvider.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.OAuth { using System; using System.Collections.Generic; + using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; @@ -36,6 +37,12 @@ namespace DotNetOpenAuth.OAuth { /// </remarks> public class ServiceProvider : IDisposable { /// <summary> + /// The name of the key to use in the HttpApplication cache to store the + /// instance of <see cref="NonceMemoryStore"/> to use. + /// </summary> + private const string ApplicationStoreKey = "DotNetOpenAuth.OAuth.ServiceProvider.HttpApplicationStore"; + + /// <summary> /// The length of the verifier code (in raw bytes before base64 encoding) to generate. /// </summary> private const int VerifierCodeLength = 5; @@ -61,7 +68,7 @@ namespace DotNetOpenAuth.OAuth { /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param> /// <param name="messageTypeProvider">An object that can figure out what type of message is being received for deserialization.</param> public ServiceProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager, OAuthServiceProviderMessageFactory messageTypeProvider) - : this(serviceDescription, tokenManager, new NonceMemoryStore(StandardExpirationBindingElement.MaximumMessageAge), messageTypeProvider) { + : this(serviceDescription, tokenManager, DotNetOpenAuthSection.Configuration.OAuth.ServiceProvider.ApplicationStore.CreateInstance(HttpApplicationStore), messageTypeProvider) { Contract.Requires<ArgumentNullException>(serviceDescription != null); Contract.Requires<ArgumentNullException>(tokenManager != null); Contract.Requires<ArgumentNullException>(messageTypeProvider != null); @@ -98,6 +105,33 @@ namespace DotNetOpenAuth.OAuth { } /// <summary> + /// Gets the standard state storage mechanism that uses ASP.NET's + /// HttpApplication state dictionary to store associations and nonces. + /// </summary> + [EditorBrowsable(EditorBrowsableState.Advanced)] + public static INonceStore HttpApplicationStore { + get { + Contract.Ensures(Contract.Result<INonceStore>() != null); + + HttpContext context = HttpContext.Current; + ErrorUtilities.VerifyOperation(context != null, Strings.StoreRequiredWhenNoHttpContextAvailable, typeof(INonceStore).Name); + var store = (INonceStore)context.Application[ApplicationStoreKey]; + if (store == null) { + context.Application.Lock(); + try { + if ((store = (INonceStore)context.Application[ApplicationStoreKey]) == null) { + context.Application[ApplicationStoreKey] = store = new NonceMemoryStore(StandardExpirationBindingElement.MaximumMessageAge); + } + } finally { + context.Application.UnLock(); + } + } + + return store; + } + } + + /// <summary> /// Gets the description of this Service Provider. /// </summary> public ServiceProviderDescription ServiceDescription { get; private set; } diff --git a/src/DotNetOpenAuth/OpenId/Association.cs b/src/DotNetOpenAuth/OpenId/Association.cs index d2c84cb..311ba58 100644 --- a/src/DotNetOpenAuth/OpenId/Association.cs +++ b/src/DotNetOpenAuth/OpenId/Association.cs @@ -54,7 +54,7 @@ namespace DotNetOpenAuth.OpenId { public string Handle { get; private set; } /// <summary> - /// Gets the time when this <see cref="Association"/> will expire. + /// Gets the UTC time when this <see cref="Association"/> will expire. /// </summary> public DateTime Expires { get { return this.Issued + this.TotalLifeLength; } @@ -83,7 +83,7 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> - /// Gets or sets the time that this <see cref="Association"/> was first created. + /// Gets or sets the UTC time that this <see cref="Association"/> was first created. /// </summary> internal DateTime Issued { get; set; } @@ -146,8 +146,8 @@ namespace DotNetOpenAuth.OpenId { /// <param name="handle"> /// The <see cref="Handle"/> property of the previous <see cref="Association"/> instance. /// </param> - /// <param name="expires"> - /// The value of the <see cref="Expires"/> property of the previous <see cref="Association"/> instance. + /// <param name="expiresUtc"> + /// The UTC value of the <see cref="Expires"/> property of the previous <see cref="Association"/> instance. /// </param> /// <param name="privateData"> /// The byte array returned by a call to <see cref="SerializePrivateData"/> on the previous @@ -158,13 +158,13 @@ namespace DotNetOpenAuth.OpenId { /// from a custom association store's /// <see cref="IAssociationStore<TKey>.GetAssociation(TKey, SecuritySettings)"/> method. /// </returns> - public static Association Deserialize(string handle, DateTime expires, byte[] privateData) { + public static Association Deserialize(string handle, DateTime expiresUtc, byte[] privateData) { Contract.Requires<ArgumentNullException>(!String.IsNullOrEmpty(handle)); Contract.Requires<ArgumentNullException>(privateData != null); Contract.Ensures(Contract.Result<Association>() != null); - expires = expires.ToUniversalTimeSafe(); - TimeSpan remainingLifeLength = expires - DateTime.UtcNow; + expiresUtc = expiresUtc.ToUniversalTimeSafe(); + TimeSpan remainingLifeLength = expiresUtc - DateTime.UtcNow; byte[] secret = privateData; // the whole of privateData is the secret key for now. // We figure out what derived type to instantiate based on the length of the secret. try { diff --git a/src/DotNetOpenAuth/OpenId/Extensions/AliasManager.cs b/src/DotNetOpenAuth/OpenId/Extensions/AliasManager.cs index 13f9907..0a84266 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/AliasManager.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/AliasManager.cs @@ -20,7 +20,7 @@ namespace DotNetOpenAuth.OpenId.Extensions { /// <summary> /// The format of auto-generated aliases. /// </summary> - private readonly string aliasFormat = "alias{0}"; + private const string AliasFormat = "alias{0}"; /// <summary> /// Tracks extension Type URIs and aliases assigned to them. @@ -68,6 +68,8 @@ namespace DotNetOpenAuth.OpenId.Extensions { /// <param name="typeUris">The type URIs to create aliases for.</param> /// <param name="preferredTypeUriToAliases">An optional dictionary of URI/alias pairs that suggest preferred aliases to use if available for certain type URIs.</param> public void AssignAliases(IEnumerable<string> typeUris, IDictionary<string, string> preferredTypeUriToAliases) { + Contract.Requires<ArgumentNullException>(typeUris != null); + // First go through the actually used type URIs and see which ones have matching preferred aliases. if (preferredTypeUriToAliases != null) { foreach (string typeUri in typeUris) { @@ -126,6 +128,7 @@ namespace DotNetOpenAuth.OpenId.Extensions { /// <returns>The Type URI.</returns> /// <exception cref="ArgumentOutOfRangeException">Thrown if the given alias does not have a matching TypeURI.</exception> public string ResolveAlias(string alias) { + Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(alias)); string typeUri = this.TryResolveAlias(alias); if (typeUri == null) { throw new ArgumentOutOfRangeException("alias"); @@ -175,7 +178,7 @@ namespace DotNetOpenAuth.OpenId.Extensions { private string AssignNewAlias(string typeUri) { Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(typeUri)); ErrorUtilities.VerifyInternal(!this.typeUriToAliasMap.ContainsKey(typeUri), "Oops! This type URI already has an alias!"); - string alias = string.Format(CultureInfo.InvariantCulture, this.aliasFormat, this.typeUriToAliasMap.Count + 1); + string alias = string.Format(CultureInfo.InvariantCulture, AliasFormat, this.typeUriToAliasMap.Count + 1); this.typeUriToAliasMap.Add(typeUri, alias); this.aliasToTypeUriMap.Add(alias, typeUri); return alias; diff --git a/src/DotNetOpenAuth/OpenId/Interop/OpenIdRelyingPartyShim.cs b/src/DotNetOpenAuth/OpenId/Interop/OpenIdRelyingPartyShim.cs index 41c4e21..86e80ba 100644 --- a/src/DotNetOpenAuth/OpenId/Interop/OpenIdRelyingPartyShim.cs +++ b/src/DotNetOpenAuth/OpenId/Interop/OpenIdRelyingPartyShim.cs @@ -16,8 +16,8 @@ namespace DotNetOpenAuth.OpenId.Interop { using DotNetOpenAuth.OpenId.RelyingParty; /// <summary> - /// The COM interface describing the DotNetOpenId functionality available to - /// COM client relying parties. + /// The COM interface describing the DotNetOpenAuth functionality available to + /// COM client OpenID relying parties. /// </summary> [Guid("56BD3DB0-EE0D-4191-ADFC-1F3705CD2636")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] diff --git a/src/DotNetOpenAuth/OpenId/Messages/IOpenIdMessageExtension.cs b/src/DotNetOpenAuth/OpenId/Messages/IOpenIdMessageExtension.cs index 95080e6..57233ac 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/IOpenIdMessageExtension.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/IOpenIdMessageExtension.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.OpenId.Messages { using System; using System.Collections.Generic; + using System.Diagnostics.Contracts; using System.Linq; using System.Text; using DotNetOpenAuth.Messaging; @@ -19,6 +20,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// [<see cref="SerializableAttribute"/>] to allow serializing state servers /// to cache messages, particularly responses. /// </remarks> + [ContractClass(typeof(IOpenIdMessageExtensionContract))] public interface IOpenIdMessageExtension : IExtensionMessage { /// <summary> /// Gets the TypeURI the extension uses in the OpenID protocol and in XRDS advertisements. @@ -51,4 +53,110 @@ namespace DotNetOpenAuth.OpenId.Messages { /// </value> bool IsSignedByRemoteParty { get; set; } } + + /// <summary> + /// Code contract class for the IOpenIdMessageExtension interface. + /// </summary> + [ContractClassFor(typeof(IOpenIdMessageExtension))] + internal class IOpenIdMessageExtensionContract : IOpenIdMessageExtension { + /// <summary> + /// Prevents a default instance of the <see cref="IOpenIdMessageExtensionContract"/> class from being created. + /// </summary> + private IOpenIdMessageExtensionContract() { + } + + #region IOpenIdMessageExtension Members + + /// <summary> + /// Gets the TypeURI the extension uses in the OpenID protocol and in XRDS advertisements. + /// </summary> + string IOpenIdMessageExtension.TypeUri { + get { + Contract.Ensures(!String.IsNullOrEmpty(Contract.Result<string>())); + throw new NotImplementedException(); + } + } + + /// <summary> + /// Gets the additional TypeURIs that are supported by this extension, in preferred order. + /// May be empty if none other than <see cref="IOpenIdMessageExtension.TypeUri"/> is supported, but + /// should not be null. + /// </summary> + /// <remarks> + /// Useful for reading in messages with an older version of an extension. + /// The value in the <see cref="IOpenIdMessageExtension.TypeUri"/> property is always checked before + /// trying this list. + /// If you do support multiple versions of an extension using this method, + /// consider adding a CreateResponse method to your request extension class + /// so that the response can have the context it needs to remain compatible + /// given the version of the extension in the request message. + /// The <see cref="Extensions.SimpleRegistration.ClaimsRequest.CreateResponse"/> for an example. + /// </remarks> + IEnumerable<string> IOpenIdMessageExtension.AdditionalSupportedTypeUris { + get { + Contract.Ensures(Contract.Result<IEnumerable<string>>() != null); + throw new NotImplementedException(); + } + } + + /// <summary> + /// Gets or sets a value indicating whether this extension was + /// signed by the sender. + /// </summary> + /// <value> + /// <c>true</c> if this instance is signed by the sender; otherwise, <c>false</c>. + /// </value> + bool IOpenIdMessageExtension.IsSignedByRemoteParty { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + #endregion + + #region IMessage Members + + /// <summary> + /// Gets the version of the protocol or extension this message is prepared to implement. + /// </summary> + /// <remarks> + /// Implementations of this interface should ensure that this property never returns null. + /// </remarks> + Version IMessage.Version { + get { + Contract.Ensures(Contract.Result<Version>() != null); + throw new NotImplementedException(); + } + } + + /// <summary> + /// Gets the extra, non-standard Protocol parameters included in the message. + /// </summary> + /// <remarks> + /// Implementations of this interface should ensure that this property never returns null. + /// </remarks> + IDictionary<string, string> IMessage.ExtraData { + get { + Contract.Ensures(Contract.Result<IDictionary<string, string>>() != null); + throw new NotImplementedException(); + } + } + + /// <summary> + /// Checks the message state for conformity to the protocol specification + /// and throws an exception if the message is invalid. + /// </summary> + /// <remarks> + /// <para>Some messages have required fields, or combinations of fields that must relate to each other + /// in specialized ways. After deserializing a message, this method checks the state of the + /// message to see if it conforms to the protocol.</para> + /// <para>Note that this property should <i>not</i> check signatures or perform any state checks + /// outside this scope of this particular message.</para> + /// </remarks> + /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception> + void IMessage.EnsureValidMessage() { + throw new NotImplementedException(); + } + + #endregion + } } diff --git a/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs b/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs index 05daed0..33a16f8 100644 --- a/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs +++ b/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs @@ -632,15 +632,6 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> - /// Looks up a localized string similar to No current HttpContext was detected, so an {0} instance must be explicitly provided or specified in the .config file. Call the constructor overload that takes an {0}.. - /// </summary> - internal static string StoreRequiredWhenNoHttpContextAvailable { - get { - return ResourceManager.GetString("StoreRequiredWhenNoHttpContextAvailable", resourceCulture); - } - } - - /// <summary> /// Looks up a localized string similar to The type must implement {0}.. /// </summary> internal static string TypeMustImplementX { diff --git a/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx b/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx index 919d873..c5f506d 100644 --- a/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx +++ b/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx @@ -244,9 +244,6 @@ Discovered endpoint info: <data name="XriResolutionFailed" xml:space="preserve"> <value>XRI resolution failed.</value> </data> - <data name="StoreRequiredWhenNoHttpContextAvailable" xml:space="preserve"> - <value>No current HttpContext was detected, so an {0} instance must be explicitly provided or specified in the .config file. Call the constructor overload that takes an {0}.</value> - </data> <data name="AttributeAlreadyAdded" xml:space="preserve"> <value>An attribute with type URI '{0}' has already been added.</value> </data> diff --git a/src/DotNetOpenAuth/OpenId/ProviderEndpointDescription.cs b/src/DotNetOpenAuth/OpenId/ProviderEndpointDescription.cs index 2014df4..4cfbac5 100644 --- a/src/DotNetOpenAuth/OpenId/ProviderEndpointDescription.cs +++ b/src/DotNetOpenAuth/OpenId/ProviderEndpointDescription.cs @@ -112,6 +112,7 @@ namespace DotNetOpenAuth.OpenId { /// the extension in the request and see if a response comes back for that extension. /// </remarks> public bool IsExtensionSupported<T>() where T : IOpenIdMessageExtension, new() { + ErrorUtilities.VerifyOperation(this.Capabilities != null, OpenIdStrings.ExtensionLookupSupportUnavailable); T extension = new T(); return this.IsExtensionSupported(extension); } @@ -131,6 +132,7 @@ namespace DotNetOpenAuth.OpenId { /// the extension in the request and see if a response comes back for that extension. /// </remarks> public bool IsExtensionSupported(Type extensionType) { + ErrorUtilities.VerifyOperation(this.Capabilities != null, OpenIdStrings.ExtensionLookupSupportUnavailable); var extension = (IOpenIdMessageExtension)Activator.CreateInstance(extensionType); return this.IsExtensionSupported(extension); } @@ -159,6 +161,8 @@ namespace DotNetOpenAuth.OpenId { /// </returns> protected internal bool IsExtensionSupported(IOpenIdMessageExtension extension) { Contract.Requires<ArgumentNullException>(extension != null); + Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(extension.TypeUri)); + Contract.Requires<InvalidOperationException>(this.Capabilities != null, OpenIdStrings.ExtensionLookupSupportUnavailable); // Consider the primary case. if (this.IsExtensionSupported(extension.TypeUri)) { diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/IProviderEndpoint.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/IProviderEndpoint.cs index 566a929..a90ddd4 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/IProviderEndpoint.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/IProviderEndpoint.cs @@ -20,7 +20,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// Because information provided by this interface is suppplied by a /// user's individually published documents, it may be incomplete or inaccurate. /// </remarks> - ////[ContractClass(typeof(IProviderEndpointContract))] + [ContractClass(typeof(IProviderEndpointContract))] public interface IProviderEndpoint { /// <summary> /// Gets the detected version of OpenID implemented by the Provider. diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs index 2808d39..bdf6c5b 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs @@ -41,7 +41,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// The name of the key to use in the HttpApplication cache to store the /// instance of <see cref="StandardRelyingPartyApplicationStore"/> to use. /// </summary> - private const string ApplicationStoreKey = "DotNetOpenAuth.OpenId.RelyingParty.OpenIdRelyingParty.ApplicationStore"; + private const string ApplicationStoreKey = "DotNetOpenAuth.OpenId.RelyingParty.OpenIdRelyingParty.HttpApplicationStore"; /// <summary> /// Backing store for the <see cref="Behaviors"/> property. @@ -128,7 +128,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { Contract.Ensures(Contract.Result<IRelyingPartyApplicationStore>() != null); HttpContext context = HttpContext.Current; - ErrorUtilities.VerifyOperation(context != null, OpenIdStrings.StoreRequiredWhenNoHttpContextAvailable, typeof(IRelyingPartyApplicationStore).Name); + ErrorUtilities.VerifyOperation(context != null, Strings.StoreRequiredWhenNoHttpContextAvailable, typeof(IRelyingPartyApplicationStore).Name); var store = (IRelyingPartyApplicationStore)context.Application[ApplicationStoreKey]; if (store == null) { context.Application.Lock(); diff --git a/src/DotNetOpenAuth/Strings.Designer.cs b/src/DotNetOpenAuth/Strings.Designer.cs index 43fec22..38c89f7 100644 --- a/src/DotNetOpenAuth/Strings.Designer.cs +++ b/src/DotNetOpenAuth/Strings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. -// Runtime Version:2.0.50727.4918 +// Runtime Version:2.0.50727.4927 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -70,6 +70,15 @@ namespace DotNetOpenAuth { } /// <summary> + /// Looks up a localized string similar to No current HttpContext was detected, so an {0} instance must be explicitly provided or specified in the .config file. Call the constructor overload that takes an {0}.. + /// </summary> + internal static string StoreRequiredWhenNoHttpContextAvailable { + get { + return ResourceManager.GetString("StoreRequiredWhenNoHttpContextAvailable", resourceCulture); + } + } + + /// <summary> /// Looks up a localized string similar to The configuration XAML reference to {0} requires a current HttpContext to resolve.. /// </summary> internal static string ConfigurationXamlReferenceRequiresHttpContext { diff --git a/src/DotNetOpenAuth/Strings.resx b/src/DotNetOpenAuth/Strings.resx index bbfa162..a7f080d 100644 --- a/src/DotNetOpenAuth/Strings.resx +++ b/src/DotNetOpenAuth/Strings.resx @@ -120,7 +120,10 @@ <data name="ConfigurationTypeMustBePublic" xml:space="preserve"> <value>The configuration-specified type {0} must be public, and is not.</value> </data> + <data name="StoreRequiredWhenNoHttpContextAvailable" xml:space="preserve"> + <value>No current HttpContext was detected, so an {0} instance must be explicitly provided or specified in the .config file. Call the constructor overload that takes an {0}.</value> + </data> <data name="ConfigurationXamlReferenceRequiresHttpContext" xml:space="preserve"> <value>The configuration XAML reference to {0} requires a current HttpContext to resolve.</value> </data> -</root>
\ No newline at end of file +</root> diff --git a/src/DotNetOpenAuth/Xrds/TypeElement.cs b/src/DotNetOpenAuth/Xrds/TypeElement.cs index f6c2217..c413629 100644 --- a/src/DotNetOpenAuth/Xrds/TypeElement.cs +++ b/src/DotNetOpenAuth/Xrds/TypeElement.cs @@ -5,6 +5,8 @@ //----------------------------------------------------------------------- namespace DotNetOpenAuth.Xrds { + using System; + using System.Diagnostics.Contracts; using System.Xml.XPath; /// <summary> @@ -18,6 +20,8 @@ namespace DotNetOpenAuth.Xrds { /// <param name="parent">The parent.</param> public TypeElement(XPathNavigator typeElement, ServiceElement parent) : base(typeElement, parent) { + Contract.Requires<ArgumentNullException>(typeElement != null); + Contract.Requires<ArgumentNullException>(parent != null); } /// <summary> diff --git a/src/DotNetOpenAuth/Xrds/XrdsNode.cs b/src/DotNetOpenAuth/Xrds/XrdsNode.cs index 5e7d7e7..f8fa0af 100644 --- a/src/DotNetOpenAuth/Xrds/XrdsNode.cs +++ b/src/DotNetOpenAuth/Xrds/XrdsNode.cs @@ -45,6 +45,7 @@ namespace DotNetOpenAuth.Xrds { /// <param name="document">The document's root node, which this instance represents.</param> protected XrdsNode(XPathNavigator document) { Contract.Requires<ArgumentNullException>(document != null); + Contract.Requires<ArgumentException>(document.NameTable != null); this.Node = document; this.XmlNamespaceResolver = new XmlNamespaceManager(document.NameTable); |