diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2010-02-13 06:10:55 -0800 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2010-02-13 06:10:55 -0800 |
commit | 66e2b799c300cd6af3a42d4c4b297718a9f79f04 (patch) | |
tree | b356864526ae31a54106de161e994dbf6ce9fc4c /src | |
parent | 982a8ac73e6fa9f178a0fb15d9e04c91515c3e49 (diff) | |
parent | 09398b5febaef7834f2dc822161dc73995439c7e (diff) | |
download | DotNetOpenAuth-66e2b799c300cd6af3a42d4c4b297718a9f79f04.zip DotNetOpenAuth-66e2b799c300cd6af3a42d4c4b297718a9f79f04.tar.gz DotNetOpenAuth-66e2b799c300cd6af3a42d4c4b297718a9f79f04.tar.bz2 |
Merge branch 'v3.3' into v3.4
Conflicts:
lib/DotNetOpenAuth.BuildTasks.dll
lib/DotNetOpenAuth.BuildTasks.pdb
Diffstat (limited to 'src')
17 files changed, 145 insertions, 42 deletions
diff --git a/src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs b/src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs index 8a8ae25..2b0e8f9 100644 --- a/src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs +++ b/src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs @@ -153,6 +153,7 @@ namespace DotNetOpenAuth.Test.Messaging Match m = Regex.Match(req.ContentType, "multipart/form-data; boundary=(.+)"); Assert.IsTrue(m.Success, "Content-Type HTTP header not set correctly."); string boundary = m.Groups[1].Value; + boundary = boundary.Substring(0, boundary.IndexOf(';')); // trim off charset string expectedEntity = "--{0}\r\nContent-Disposition: form-data; name=\"a\"\r\n\r\nb\r\n--{0}--\r\n"; expectedEntity = string.Format(expectedEntity, boundary); string actualEntity = httpHandler.RequestEntityAsString; diff --git a/src/DotNetOpenAuth.Test/Messaging/OutgoingWebResponseTests.cs b/src/DotNetOpenAuth.Test/Messaging/OutgoingWebResponseTests.cs index 16576d6..10045de 100644 --- a/src/DotNetOpenAuth.Test/Messaging/OutgoingWebResponseTests.cs +++ b/src/DotNetOpenAuth.Test/Messaging/OutgoingWebResponseTests.cs @@ -6,6 +6,7 @@ namespace DotNetOpenAuth.Test.Messaging { using System.Net; + using System.Net.Mime; using System.Text; using DotNetOpenAuth.Messaging; using NUnit.Framework; @@ -30,7 +31,8 @@ namespace DotNetOpenAuth.Test.Messaging { CollectionAssert.AreEqual(expectedBuffer, actualBuffer); // Verify that the header was set correctly. - Assert.AreEqual(encoding.HeaderName, response.Headers[HttpResponseHeader.ContentEncoding]); + Assert.IsNull(response.Headers[HttpResponseHeader.ContentEncoding]); + Assert.AreEqual(encoding.HeaderName, new ContentType(response.Headers[HttpResponseHeader.ContentType]).CharSet); } } } diff --git a/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd b/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd index 18e1c5c..a9c5965 100644 --- a/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd +++ b/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd @@ -658,6 +658,14 @@ </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"> diff --git a/src/DotNetOpenAuth/Configuration/DotNetOpenAuthSection.cs b/src/DotNetOpenAuth/Configuration/DotNetOpenAuthSection.cs index aa956d1..117a542 100644 --- a/src/DotNetOpenAuth/Configuration/DotNetOpenAuthSection.cs +++ b/src/DotNetOpenAuth/Configuration/DotNetOpenAuthSection.cs @@ -51,7 +51,10 @@ namespace DotNetOpenAuth.Configuration { /// Gets the configuration section from the .config file. /// </summary> public static DotNetOpenAuthSection Configuration { - get { return (DotNetOpenAuthSection)ConfigurationManager.GetSection(SectionName) ?? new DotNetOpenAuthSection(); } + get { + Contract.Ensures(Contract.Result<DotNetOpenAuthSection>() != null); + return (DotNetOpenAuthSection)ConfigurationManager.GetSection(SectionName) ?? new DotNetOpenAuthSection(); + } } /// <summary> @@ -59,8 +62,14 @@ namespace DotNetOpenAuth.Configuration { /// </summary> [ConfigurationProperty(MessagingElementName)] public MessagingElement Messaging { - get { return (MessagingElement)this[MessagingElementName] ?? new MessagingElement(); } - set { this[MessagingElementName] = value; } + get { + Contract.Ensures(Contract.Result<MessagingElement>() != null); + return (MessagingElement)this[MessagingElementName] ?? new MessagingElement(); + } + + set { + this[MessagingElementName] = value; + } } /// <summary> @@ -68,8 +77,14 @@ namespace DotNetOpenAuth.Configuration { /// </summary> [ConfigurationProperty(OpenIdElementName)] internal OpenIdElement OpenId { - get { return (OpenIdElement)this[OpenIdElementName] ?? new OpenIdElement(); } - set { this[OpenIdElementName] = value; } + get { + Contract.Ensures(Contract.Result<OpenIdElement>() != null); + return (OpenIdElement)this[OpenIdElementName] ?? new OpenIdElement(); + } + + set { + this[OpenIdElementName] = value; + } } /// <summary> @@ -77,8 +92,14 @@ namespace DotNetOpenAuth.Configuration { /// </summary> [ConfigurationProperty(OAuthElementName)] internal OAuthElement OAuth { - get { return (OAuthElement)this[OAuthElementName] ?? new OAuthElement(); } - set { this[OAuthElementName] = value; } + get { + Contract.Ensures(Contract.Result<OAuthElement>() != null); + return (OAuthElement)this[OAuthElementName] ?? new OAuthElement(); + } + + set { + this[OAuthElementName] = value; + } } /// <summary> @@ -86,8 +107,14 @@ namespace DotNetOpenAuth.Configuration { /// </summary> [ConfigurationProperty(ReportingElementName)] internal ReportingElement Reporting { - get { return (ReportingElement)this[ReportingElementName] ?? new ReportingElement(); } - set { this[ReportingElementName] = value; } + get { + Contract.Ensures(Contract.Result<ReportingElement>() != null); + return (ReportingElement)this[ReportingElementName] ?? new ReportingElement(); + } + + set { + this[ReportingElementName] = value; + } } } } diff --git a/src/DotNetOpenAuth/Messaging/Channel.cs b/src/DotNetOpenAuth/Messaging/Channel.cs index 1bddf02..7198c78 100644 --- a/src/DotNetOpenAuth/Messaging/Channel.cs +++ b/src/DotNetOpenAuth/Messaging/Channel.cs @@ -16,6 +16,7 @@ namespace DotNetOpenAuth.Messaging { using System.Linq; using System.Net; using System.Net.Cache; + using System.Net.Mime; using System.Text; using System.Threading; using System.Web; @@ -39,6 +40,13 @@ namespace DotNetOpenAuth.Messaging { protected internal const string HttpFormUrlEncoded = "application/x-www-form-urlencoded"; /// <summary> + /// The content-type used on HTTP POST requests where the POST entity is a + /// URL-encoded series of key=value pairs. + /// This includes the <see cref="PostEntityEncoding"/> character encoding. + /// </summary> + protected internal static readonly ContentType HttpFormUrlEncodedContentType = new ContentType(HttpFormUrlEncoded) { CharSet = PostEntityEncoding.WebName }; + + /// <summary> /// 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 @@ -927,15 +935,9 @@ namespace DotNetOpenAuth.Messaging { Contract.Requires<ArgumentNullException>(httpRequest != null); Contract.Requires<ArgumentNullException>(fields != null); - httpRequest.ContentType = HttpFormUrlEncoded; - - // Setting the content-encoding to "utf-8" causes Google to reply - // with a 415 UnsupportedMediaType. But adding it doesn't buy us - // anything specific, so we disable it until we know how to get it right. - ////httpRequest.Headers[HttpRequestHeader.ContentEncoding] = PostEntityEncoding.WebName; - string requestBody = MessagingUtilities.CreateQueryString(fields); byte[] requestBytes = PostEntityEncoding.GetBytes(requestBody); + httpRequest.ContentType = HttpFormUrlEncodedContentType.ToString(); httpRequest.ContentLength = requestBytes.Length; Stream requestStream = this.WebRequestHandler.GetRequestStream(httpRequest); try { diff --git a/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs b/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs index 94990c8..6ce87a8 100644 --- a/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs +++ b/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs @@ -13,6 +13,7 @@ namespace DotNetOpenAuth.Messaging { using System.Globalization; using System.IO; using System.Net; + using System.Net.Mime; using System.ServiceModel.Channels; using System.Web; @@ -233,7 +234,8 @@ namespace DotNetOpenAuth.Messaging { get { Contract.Ensures(Contract.Result<NameValueCollection>() != null); if (this.form == null) { - if (this.HttpMethod == "POST" && this.Headers[HttpRequestHeader.ContentType] == Channel.HttpFormUrlEncoded) { + ContentType contentType = string.IsNullOrEmpty(this.Headers[HttpRequestHeader.ContentType]) ? null : new ContentType(this.Headers[HttpRequestHeader.ContentType]); + if (this.HttpMethod == "POST" && contentType != null && string.Equals(contentType.MediaType, Channel.HttpFormUrlEncoded, StringComparison.Ordinal)) { StreamReader reader = new StreamReader(this.InputStream); long originalPosition = 0; if (this.InputStream.CanSeek) { diff --git a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs index 81b33b0..a52f51b 100644 --- a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs +++ b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs @@ -14,6 +14,7 @@ namespace DotNetOpenAuth.Messaging { using System.IO; using System.Linq; using System.Net; + using System.Net.Mime; using System.Security; using System.Security.Cryptography; using System.Text; @@ -191,20 +192,19 @@ namespace DotNetOpenAuth.Messaging { string initialPartLeadingBoundary = string.Format(CultureInfo.InvariantCulture, "--{0}\r\n", boundary); string partLeadingBoundary = string.Format(CultureInfo.InvariantCulture, "\r\n--{0}\r\n", boundary); string finalTrailingBoundary = string.Format(CultureInfo.InvariantCulture, "\r\n--{0}--\r\n", boundary); + var contentType = new ContentType("multipart/form-data") { + Boundary = boundary, + CharSet = Channel.PostEntityEncoding.WebName, + }; request.Method = "POST"; - request.ContentType = "multipart/form-data; boundary=" + boundary; + request.ContentType = contentType.ToString(); long contentLength = parts.Sum(p => partLeadingBoundary.Length + p.Length) + finalTrailingBoundary.Length; if (parts.Any()) { contentLength -= 2; // the initial part leading boundary has no leading \r\n } request.ContentLength = contentLength; - // Setting the content-encoding to "utf-8" causes Google to reply - // with a 415 UnsupportedMediaType. But adding it doesn't buy us - // anything specific, so we disable it until we know how to get it right. - ////request.Headers[HttpRequestHeader.ContentEncoding] = Channel.PostEntityEncoding.WebName; - var requestStream = requestHandler.GetRequestStream(request); try { StreamWriter writer = new StreamWriter(requestStream, Channel.PostEntityEncoding); diff --git a/src/DotNetOpenAuth/Messaging/OutgoingWebResponse.cs b/src/DotNetOpenAuth/Messaging/OutgoingWebResponse.cs index 52d0e39..cf22bb2 100644 --- a/src/DotNetOpenAuth/Messaging/OutgoingWebResponse.cs +++ b/src/DotNetOpenAuth/Messaging/OutgoingWebResponse.cs @@ -10,6 +10,7 @@ namespace DotNetOpenAuth.Messaging { using System.Diagnostics.Contracts; using System.IO; using System.Net; + using System.Net.Mime; using System.Text; using System.Threading; using System.Web; @@ -87,7 +88,7 @@ namespace DotNetOpenAuth.Messaging { /// </summary> public string Body { get { return this.ResponseStream != null ? this.GetResponseReader().ReadToEnd() : null; } - set { this.SetResponse(value); } + set { this.SetResponse(value, null); } } /// <summary> @@ -205,13 +206,23 @@ namespace DotNetOpenAuth.Messaging { /// Sets the response to some string, encoded as UTF-8. /// </summary> /// <param name="body">The string to set the response to.</param> - internal void SetResponse(string body) { + /// <param name="contentType">Type of the content. May be null.</param> + internal void SetResponse(string body, ContentType contentType) { if (body == null) { this.ResponseStream = null; return; } - this.Headers[HttpResponseHeader.ContentEncoding] = bodyStringEncoder.HeaderName; + if (contentType == null) { + contentType = new ContentType("text/html"); + contentType.CharSet = bodyStringEncoder.WebName; + } else if (contentType.CharSet != bodyStringEncoder.WebName) { + // clone the original so we're not tampering with our inputs if it came as a parameter. + contentType = new ContentType(contentType.ToString()); + contentType.CharSet = bodyStringEncoder.WebName; + } + + this.Headers[HttpResponseHeader.ContentType] = contentType.ToString(); this.ResponseStream = new MemoryStream(); StreamWriter writer = new StreamWriter(this.ResponseStream, bodyStringEncoder); writer.Write(body); diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs index b0e938f..ed41183 100644 --- a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs +++ b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs @@ -13,6 +13,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { using System.IO; using System.Linq; using System.Net; + using System.Net.Mime; using System.Text; using System.Web; using DotNetOpenAuth.Messaging; @@ -141,9 +142,12 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { } // Scrape the entity - if (string.Equals(request.Headers[HttpRequestHeader.ContentType], HttpFormUrlEncoded, StringComparison.Ordinal)) { - foreach (string key in request.Form) { - fields.Add(key, request.Form[key]); + if (!string.IsNullOrEmpty(request.Headers[HttpRequestHeader.ContentType])) { + ContentType contentType = new ContentType(request.Headers[HttpRequestHeader.ContentType]); + if (string.Equals(contentType.MediaType, HttpFormUrlEncoded, StringComparison.Ordinal)) { + foreach (string key in request.Form) { + fields.Add(key, request.Form[key]); + } } } diff --git a/src/DotNetOpenAuth/OAuth/ConsumerBase.cs b/src/DotNetOpenAuth/OAuth/ConsumerBase.cs index 48f54d7..dddbe9e 100644 --- a/src/DotNetOpenAuth/OAuth/ConsumerBase.cs +++ b/src/DotNetOpenAuth/OAuth/ConsumerBase.cs @@ -224,7 +224,7 @@ namespace DotNetOpenAuth.OAuth { // Fine-tune our understanding of the SP's supported OAuth version if it's wrong. if (this.ServiceProvider.Version != requestTokenResponse.Version) { - Logger.OAuth.WarnFormat("Expected OAuth service provider at endpoint {0} to use OAuth {1} but {2} was detected. Adjusting service description to new version.", this.ServiceProvider.RequestTokenEndpoint, this.ServiceProvider.Version, requestTokenResponse.Version); + Logger.OAuth.WarnFormat("Expected OAuth service provider at endpoint {0} to use OAuth {1} but {2} was detected. Adjusting service description to new version.", this.ServiceProvider.RequestTokenEndpoint.Location, this.ServiceProvider.Version, requestTokenResponse.Version); this.ServiceProvider.ProtocolVersion = Protocol.Lookup(requestTokenResponse.Version).ProtocolVersion; } diff --git a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeRequest.cs b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeRequest.cs index 358db9b..2dc9c69 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeRequest.cs @@ -15,6 +15,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange { /// the Attribute Exchange extension. /// </summary> [Serializable] + [DebuggerDisplay("{TypeUri} (required: {IsRequired}) ({Count})")] public class AttributeRequest { /// <summary> /// Backing field for the <see cref="Count"/> property. diff --git a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeValues.cs b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeValues.cs index 6466cda..b2fc1fe 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeValues.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeValues.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange { using System; using System.Collections.Generic; + using System.Diagnostics; using System.Diagnostics.Contracts; using DotNetOpenAuth.Messaging; @@ -16,6 +17,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange { /// a fetch request, or by a relying party as part of a store request. /// </summary> [Serializable] + [DebuggerDisplay("{TypeUri}")] public class AttributeValues { /// <summary> /// Initializes a new instance of the <see cref="AttributeValues"/> class. diff --git a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchRequest.cs b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchRequest.cs index a69e226..124a18c 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchRequest.cs @@ -8,6 +8,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange { using System; using System.Collections.Generic; using System.Collections.ObjectModel; + using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using DotNetOpenAuth.Messaging; @@ -67,7 +68,10 @@ namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange { /// <value>A collection where the keys are the attribute type URIs, and the value /// is all the attribute request details.</value> public KeyedCollection<string, AttributeRequest> Attributes { - get { return this.attributes; } + get { + Contract.Ensures(Contract.Result<KeyedCollection<string, AttributeRequest>>() != null); + return this.attributes; + } } /// <summary> diff --git a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchResponse.cs b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchResponse.cs index 758b20c..14b1caa 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchResponse.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchResponse.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange { using System; using System.Collections.ObjectModel; + using System.Diagnostics.Contracts; using System.Linq; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId.Messages; @@ -52,7 +53,10 @@ namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange { /// Gets a sequence of the attributes whose values are provided by the OpenID Provider. /// </summary> public KeyedCollection<string, AttributeValues> Attributes { - get { return this.attributesProvided; } + get { + Contract.Ensures(Contract.Result<KeyedCollection<string, AttributeValues>>() != null); + return this.attributesProvided; + } } /// <summary> diff --git a/src/DotNetOpenAuth/OpenId/Identifier.cs b/src/DotNetOpenAuth/OpenId/Identifier.cs index 548a673..2ab5360 100644 --- a/src/DotNetOpenAuth/OpenId/Identifier.cs +++ b/src/DotNetOpenAuth/OpenId/Identifier.cs @@ -68,6 +68,8 @@ namespace DotNetOpenAuth.OpenId { [DebuggerStepThrough] public static implicit operator Identifier(string identifier) { Contract.Requires<ArgumentException>(identifier == null || identifier.Length > 0); + Contract.Ensures((identifier == null) == (Contract.Result<Identifier>() == null)); + if (identifier == null) { return null; } @@ -82,6 +84,7 @@ namespace DotNetOpenAuth.OpenId { [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates", Justification = "We have a Parse function.")] [DebuggerStepThrough] public static implicit operator Identifier(Uri identifier) { + Contract.Ensures((identifier == null) == (Contract.Result<Identifier>() == null)); if (identifier == null) { return null; } @@ -97,7 +100,7 @@ namespace DotNetOpenAuth.OpenId { [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates", Justification = "We have a Parse function.")] [DebuggerStepThrough] public static implicit operator string(Identifier identifier) { - Contract.Ensures((identifier == null && Contract.Result<string>() == null) || (identifier != null && Contract.Result<string>() != null)); + Contract.Ensures((identifier == null) == (Contract.Result<string>() == null)); if (identifier == null) { return null; } @@ -113,6 +116,8 @@ namespace DotNetOpenAuth.OpenId { [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "Some of these identifiers are not properly formatted to be Uris at this stage.")] public static Identifier Parse(string identifier) { Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(identifier)); + Contract.Ensures(Contract.Result<Identifier>() != null); + if (XriIdentifier.IsValidXri(identifier)) { return new XriIdentifier(identifier); } else { diff --git a/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs b/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs index f778b76..445978e 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs @@ -43,7 +43,12 @@ namespace DotNetOpenAuth.OpenId.Provider { /// <summary> /// Backing field for the <see cref="Provider"/> property. /// </summary> - private static OpenIdProvider provider = CreateProvider(); + private static OpenIdProvider provider; + + /// <summary> + /// The lock that must be obtained when initializing the provider field. + /// </summary> + private static object providerInitializerLock = new object(); /// <summary> /// Fired when an incoming OpenID request is an authentication challenge @@ -64,6 +69,15 @@ namespace DotNetOpenAuth.OpenId.Provider { /// <value>The default value is an <see cref="OpenIdProvider"/> instance initialized according to the web.config file.</value> public static OpenIdProvider Provider { get { + Contract.Ensures(Contract.Result<OpenIdProvider>() != null); + if (provider == null) { + lock (providerInitializerLock) { + if (provider == null) { + provider = CreateProvider(); + } + } + } + return provider; } @@ -83,8 +97,14 @@ namespace DotNetOpenAuth.OpenId.Provider { /// before responding to the relying party's authentication request. /// </remarks> public static IAuthenticationRequest PendingAuthenticationRequest { - get { return HttpContext.Current.Session[PendingRequestKey] as IAuthenticationRequest; } - set { HttpContext.Current.Session[PendingRequestKey] = value; } + get { + Contract.Ensures(Contract.Result<IAuthenticationRequest>() == null || PendingRequest != null); + return HttpContext.Current.Session[PendingRequestKey] as IAuthenticationRequest; + } + + set { + HttpContext.Current.Session[PendingRequestKey] = value; + } } /// <summary> @@ -97,8 +117,14 @@ namespace DotNetOpenAuth.OpenId.Provider { /// before responding to the relying party's request. /// </remarks> public static IAnonymousRequest PendingAnonymousRequest { - get { return HttpContext.Current.Session[PendingRequestKey] as IAnonymousRequest; } - set { HttpContext.Current.Session[PendingRequestKey] = value; } + get { + Contract.Ensures(Contract.Result<IAnonymousRequest>() == null || PendingRequest != null); + return HttpContext.Current.Session[PendingRequestKey] as IAnonymousRequest; + } + + set { + HttpContext.Current.Session[PendingRequestKey] = value; + } } /// <summary> @@ -159,7 +185,7 @@ namespace DotNetOpenAuth.OpenId.Provider { // Then try the configuration file specified one. Finally, use the default // in-memory one that's built into OpenIdProvider. // determine what incoming message was received - IRequest request = provider.GetRequest(); + IRequest request = Provider.GetRequest(); if (request != null) { PendingRequest = null; @@ -179,7 +205,7 @@ namespace DotNetOpenAuth.OpenId.Provider { } } if (request.IsResponseReady) { - provider.SendResponse(request); + Provider.SendResponse(request); Page.Response.End(); PendingAuthenticationRequest = null; } @@ -218,6 +244,7 @@ namespace DotNetOpenAuth.OpenId.Provider { /// </summary> /// <returns>The new instance of OpenIdProvider.</returns> private static OpenIdProvider CreateProvider() { + Contract.Ensures(Contract.Result<OpenIdProvider>() != null); return new OpenIdProvider(DotNetOpenAuthSection.Configuration.OpenId.Provider.ApplicationStore.CreateInstance(OpenIdProvider.HttpApplicationStore)); } } diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs index c9106de..a0a0fb9 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs @@ -109,7 +109,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // replay attacks. But only 2.0+ Providers can be expected to provide // replay protection. if (nonceStore == null) { - this.SecuritySettings.MinimumRequiredOpenIdVersion = ProtocolVersion.V20; + if (this.SecuritySettings.MinimumRequiredOpenIdVersion < ProtocolVersion.V20) { + Logger.OpenId.Warn("Raising minimum OpenID version requirement for Providers to 2.0 to protect this stateless RP from replay attacks."); + this.SecuritySettings.MinimumRequiredOpenIdVersion = ProtocolVersion.V20; + } } this.channel = new OpenIdChannel(associationStore, nonceStore, this.SecuritySettings); |