diff options
Diffstat (limited to 'src/DotNetOpenAuth.Core')
8 files changed, 285 insertions, 47 deletions
diff --git a/src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuth.xsd b/src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuth.xsd index 74d4db4..8a970f4 100644 --- a/src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuth.xsd +++ b/src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuth.xsd @@ -475,6 +475,11 @@ </xs:complexType> </xs:element> <xs:element name="discoveryServices"> + <xs:annotation> + <xs:documentation> + Adds or removes OpenID discovery mechanisms to use on OpenID identifiers. + </xs:documentation> + </xs:annotation> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="add"> @@ -502,6 +507,24 @@ </xs:choice> </xs:complexType> </xs:element> + <xs:element name="hostMetaDiscovery"> + <xs:annotation> + <xs:documentation> + Customizes the non-standard host-meta discovery process, when that discovery service is enabled. + </xs:documentation> + </xs:annotation> + <xs:complexType> + <xs:attribute name="enableCertificateValidationCache" type="xs:boolean" default="false"> + <xs:annotation> + <xs:documentation> + Allows DotNetOpenAuth to remember X509Certificates that it has already verified are valid + to avoid validating them each time. Use when operating on a server with long delays when + validating certificates. + </xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:complexType> + </xs:element> <xs:element name="store"> <xs:annotation> <xs:documentation> diff --git a/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj b/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj index 5e079a0..eb38711 100644 --- a/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj +++ b/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj @@ -29,6 +29,7 @@ <Compile Include="Messaging\CachedDirectWebResponse.cs" /> <Compile Include="Messaging\ChannelContract.cs" /> <Compile Include="Messaging\DataBagFormatterBase.cs" /> + <Compile Include="Messaging\HmacAlgorithms.cs" /> <Compile Include="Messaging\HttpRequestHeaders.cs" /> <Compile Include="Messaging\IHttpDirectRequest.cs" /> <Compile Include="Messaging\IHttpDirectRequestContract.cs" /> diff --git a/src/DotNetOpenAuth.Core/Loggers/TraceLogger.cs b/src/DotNetOpenAuth.Core/Loggers/TraceLogger.cs index 9b0bb0f..1b80c7d 100644 --- a/src/DotNetOpenAuth.Core/Loggers/TraceLogger.cs +++ b/src/DotNetOpenAuth.Core/Loggers/TraceLogger.cs @@ -77,210 +77,270 @@ namespace DotNetOpenAuth.Loggers { /// See <see cref="ILog"/>. /// </summary> public void Debug(object message) { - Trace.TraceInformation(message.ToString()); + if (this.IsDebugEnabled) { + Trace.TraceInformation(message.ToString()); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void Debug(object message, Exception exception) { - Trace.TraceInformation(message + ": " + exception.ToString()); + if (this.IsDebugEnabled) { + Trace.TraceInformation(message + ": " + exception.ToString()); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void DebugFormat(string format, params object[] args) { - Trace.TraceInformation(format, args); + if (this.IsDebugEnabled) { + Trace.TraceInformation(format, args); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void DebugFormat(string format, object arg0) { - Trace.TraceInformation(format, arg0); + if (this.IsDebugEnabled) { + Trace.TraceInformation(format, arg0); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void DebugFormat(string format, object arg0, object arg1) { - Trace.TraceInformation(format, arg0, arg1); + if (this.IsDebugEnabled) { + Trace.TraceInformation(format, arg0, arg1); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void DebugFormat(string format, object arg0, object arg1, object arg2) { - Trace.TraceInformation(format, arg0, arg1, arg2); + if (this.IsDebugEnabled) { + Trace.TraceInformation(format, arg0, arg1, arg2); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void Info(object message) { - Trace.TraceInformation(message.ToString()); + if (this.IsInfoEnabled) { + Trace.TraceInformation(message.ToString()); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void Info(object message, Exception exception) { - Trace.TraceInformation(message + ": " + exception.ToString()); + if (this.IsInfoEnabled) { + Trace.TraceInformation(message + ": " + exception.ToString()); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void InfoFormat(string format, params object[] args) { - Trace.TraceInformation(format, args); + if (this.IsInfoEnabled) { + Trace.TraceInformation(format, args); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void InfoFormat(string format, object arg0) { - Trace.TraceInformation(format, arg0); + if (this.IsInfoEnabled) { + Trace.TraceInformation(format, arg0); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void InfoFormat(string format, object arg0, object arg1) { - Trace.TraceInformation(format, arg0, arg1); + if (this.IsInfoEnabled) { + Trace.TraceInformation(format, arg0, arg1); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void InfoFormat(string format, object arg0, object arg1, object arg2) { - Trace.TraceInformation(format, arg0, arg1, arg2); + if (this.IsInfoEnabled) { + Trace.TraceInformation(format, arg0, arg1, arg2); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void Warn(object message) { - Trace.TraceWarning(message.ToString()); + if (this.IsWarnEnabled) { + Trace.TraceWarning(message.ToString()); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void Warn(object message, Exception exception) { - Trace.TraceWarning(message + ": " + exception.ToString()); + if (this.IsWarnEnabled) { + Trace.TraceWarning(message + ": " + exception.ToString()); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void WarnFormat(string format, params object[] args) { - Trace.TraceWarning(format, args); + if (this.IsWarnEnabled) { + Trace.TraceWarning(format, args); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void WarnFormat(string format, object arg0) { - Trace.TraceWarning(format, arg0); + if (this.IsWarnEnabled) { + Trace.TraceWarning(format, arg0); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void WarnFormat(string format, object arg0, object arg1) { - Trace.TraceWarning(format, arg0, arg1); + if (this.IsWarnEnabled) { + Trace.TraceWarning(format, arg0, arg1); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void WarnFormat(string format, object arg0, object arg1, object arg2) { - Trace.TraceWarning(format, arg0, arg1, arg2); + if (this.IsWarnEnabled) { + Trace.TraceWarning(format, arg0, arg1, arg2); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void Error(object message) { - Trace.TraceError(message.ToString()); + if (this.IsErrorEnabled) { + Trace.TraceError(message.ToString()); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void Error(object message, Exception exception) { - Trace.TraceError(message + ": " + exception.ToString()); + if (this.IsErrorEnabled) { + Trace.TraceError(message + ": " + exception.ToString()); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void ErrorFormat(string format, params object[] args) { - Trace.TraceError(format, args); + if (this.IsErrorEnabled) { + Trace.TraceError(format, args); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void ErrorFormat(string format, object arg0) { - Trace.TraceError(format, arg0); + if (this.IsErrorEnabled) { + Trace.TraceError(format, arg0); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void ErrorFormat(string format, object arg0, object arg1) { - Trace.TraceError(format, arg0, arg1); + if (this.IsErrorEnabled) { + Trace.TraceError(format, arg0, arg1); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void ErrorFormat(string format, object arg0, object arg1, object arg2) { - Trace.TraceError(format, arg0, arg1, arg2); + if (this.IsErrorEnabled) { + Trace.TraceError(format, arg0, arg1, arg2); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void Fatal(object message) { - Trace.TraceError(message.ToString()); + if (this.IsFatalEnabled) { + Trace.TraceError(message.ToString()); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void Fatal(object message, Exception exception) { - Trace.TraceError(message + ": " + exception.ToString()); + if (this.IsFatalEnabled) { + Trace.TraceError(message + ": " + exception.ToString()); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void FatalFormat(string format, params object[] args) { - Trace.TraceError(format, args); + if (this.IsFatalEnabled) { + Trace.TraceError(format, args); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void FatalFormat(string format, object arg0) { - Trace.TraceError(format, arg0); + if (this.IsFatalEnabled) { + Trace.TraceError(format, arg0); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void FatalFormat(string format, object arg0, object arg1) { - Trace.TraceError(format, arg0, arg1); + if (this.IsFatalEnabled) { + Trace.TraceError(format, arg0, arg1); + } } /// <summary> /// See <see cref="ILog"/>. /// </summary> public void FatalFormat(string format, object arg0, object arg1, object arg2) { - Trace.TraceError(format, arg0, arg1, arg2); + if (this.IsFatalEnabled) { + Trace.TraceError(format, arg0, arg1, arg2); + } } #endregion diff --git a/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs b/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs index c9ceb81..69ee8dc 100644 --- a/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs +++ b/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs @@ -286,7 +286,7 @@ namespace DotNetOpenAuth.Messaging { Requires.NotNull(signature, "signature"); if (this.asymmetricSigning != null) { - using (var hasher = new SHA1CryptoServiceProvider()) { + using (var hasher = SHA1.Create()) { return this.asymmetricSigning.VerifyData(signedData, hasher, signature); } } else { @@ -309,13 +309,13 @@ namespace DotNetOpenAuth.Messaging { Contract.Ensures(Contract.Result<byte[]>() != null); if (this.asymmetricSigning != null) { - using (var hasher = new SHA1CryptoServiceProvider()) { + using (var hasher = SHA1.Create()) { return this.asymmetricSigning.SignData(bytesToSign, hasher); } } else { var key = this.cryptoKeyStore.GetKey(this.cryptoKeyBucket, symmetricSecretHandle); ErrorUtilities.VerifyProtocol(key != null, MessagingStrings.MissingDecryptionKeyForHandle, this.cryptoKeyBucket, symmetricSecretHandle); - using (var symmetricHasher = new HMACSHA256(key.Key)) { + using (var symmetricHasher = HmacAlgorithms.Create(HmacAlgorithms.HmacSha256, key.Key)) { return symmetricHasher.ComputeHash(bytesToSign); } } diff --git a/src/DotNetOpenAuth.Core/Messaging/HmacAlgorithms.cs b/src/DotNetOpenAuth.Core/Messaging/HmacAlgorithms.cs new file mode 100644 index 0000000..872b4ac --- /dev/null +++ b/src/DotNetOpenAuth.Core/Messaging/HmacAlgorithms.cs @@ -0,0 +1,60 @@ +//----------------------------------------------------------------------- +// <copyright file="HmacAlgorithms.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Messaging { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Security.Cryptography; + using System.Text; + + /// <summary> + /// HMAC-SHA algorithm names that can be passed to the <see cref="HMAC.Create(string)"/> method. + /// </summary> + internal static class HmacAlgorithms { + /// <summary> + /// The name of the HMAC-SHA1 algorithm. + /// </summary> + internal const string HmacSha1 = "HMACSHA1"; + + /// <summary> + /// The name of the HMAC-SHA256 algorithm. + /// </summary> + internal const string HmacSha256 = "HMACSHA256"; + + /// <summary> + /// The name of the HMAC-SHA384 algorithm. + /// </summary> + internal const string HmacSha384 = "HMACSHA384"; + + /// <summary> + /// The name of the HMAC-SHA512 algorithm. + /// </summary> + internal const string HmacSha512 = "HMACSHA512"; + + /// <summary> + /// Creates an HMAC-SHA algorithm with the specified name and key. + /// </summary> + /// <param name="algorithmName">A name from the available choices in the static const members of this class.</param> + /// <param name="key">The secret key used as the HMAC.</param> + /// <returns>The HMAC algorithm instance.</returns> + internal static HMAC Create(string algorithmName, byte[] key) { + Requires.NotNullOrEmpty(algorithmName, "algorithmName"); + Requires.NotNull(key, "key"); + + HMAC hmac = HMAC.Create(algorithmName); + try { + hmac.Key = key; + return hmac; + } catch { +#if CLR4 + hmac.Dispose(); +#endif + throw; + } + } + } +} diff --git a/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs b/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs index f613dc5..4b4a3fe 100644 --- a/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs +++ b/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs @@ -13,6 +13,10 @@ namespace DotNetOpenAuth.Messaging { using System.Globalization; using System.IO; using System.Net; +#if CLR4 + using System.Net.Http; + using System.Net.Http.Headers; +#endif using System.Net.Mime; using System.ServiceModel.Channels; using System.Web; @@ -105,12 +109,33 @@ namespace DotNetOpenAuth.Messaging { this.requestUri = listenerRequest.Url; this.queryString = listenerRequest.QueryString; this.headers = listenerRequest.Headers; - this.form = ParseFormData(listenerRequest.HttpMethod, listenerRequest.Headers, listenerRequest.InputStream); + this.form = ParseFormData(listenerRequest.HttpMethod, listenerRequest.Headers, () => listenerRequest.InputStream); this.serverVariables = new NameValueCollection(); Reporting.RecordRequestStatistics(this); } +#if CLR4 + /// <summary> + /// Initializes a new instance of the <see cref="HttpRequestInfo" /> class. + /// </summary> + /// <param name="request">The request.</param> + internal HttpRequestInfo(HttpRequestMessage request) { + Requires.NotNull(request, "request"); + + this.httpMethod = request.Method.ToString(); + this.requestUri = request.RequestUri; + this.queryString = HttpUtility.ParseQueryString(request.RequestUri.Query); + this.headers = new NameValueCollection(); + AddHeaders(this.headers, request.Headers); + AddHeaders(this.headers, request.Content.Headers); + this.form = ParseFormData(this.httpMethod, this.headers, () => request.Content.ReadAsStreamAsync().Result); + this.serverVariables = new NameValueCollection(); + + Reporting.RecordRequestStatistics(this); + } +#endif + /// <summary> /// Initializes a new instance of the <see cref="HttpRequestInfo"/> class. /// </summary> @@ -126,7 +151,7 @@ namespace DotNetOpenAuth.Messaging { this.requestUri = requestUri; this.headers = headers; this.queryString = HttpUtility.ParseQueryString(requestUri.Query); - this.form = ParseFormData(httpMethod, headers, inputStream); + this.form = ParseFormData(httpMethod, headers, () => inputStream); this.serverVariables = new NameValueCollection(); Reporting.RecordRequestStatistics(this); @@ -200,6 +225,17 @@ namespace DotNetOpenAuth.Messaging { return new HttpRequestInfo(listenerRequest); } +#if CLR4 + /// <summary> + /// Creates an <see cref="HttpRequestBase"/> instance that describes the specified HTTP request. + /// </summary> + /// <param name="request">The HTTP request.</param> + /// <returns>An instance of <see cref="HttpRequestBase"/>.</returns> + public static HttpRequestBase Create(HttpRequestMessage request) { + return new HttpRequestInfo(request); + } +#endif + /// <summary> /// Creates an <see cref="HttpRequestBase"/> instance that describes the specified HTTP request. /// </summary> @@ -229,14 +265,15 @@ namespace DotNetOpenAuth.Messaging { /// </summary> /// <param name="httpMethod">The HTTP method.</param> /// <param name="headers">The headers.</param> - /// <param name="inputStream">The input stream.</param> + /// <param name="inputStreamFunc">A function that returns the input stream.</param> /// <returns>The non-null collection of form variables.</returns> - private static NameValueCollection ParseFormData(string httpMethod, NameValueCollection headers, Stream inputStream) { + private static NameValueCollection ParseFormData(string httpMethod, NameValueCollection headers, Func<Stream> inputStreamFunc) { Requires.NotNullOrEmpty(httpMethod, "httpMethod"); Requires.NotNull(headers, "headers"); ContentType contentType = string.IsNullOrEmpty(headers[HttpRequestHeaders.ContentType]) ? null : new ContentType(headers[HttpRequestHeaders.ContentType]); - if (inputStream != null && httpMethod == "POST" && contentType != null && string.Equals(contentType.MediaType, Channel.HttpFormUrlEncoded, StringComparison.Ordinal)) { + if (httpMethod == "POST" && contentType != null && string.Equals(contentType.MediaType, Channel.HttpFormUrlEncoded, StringComparison.Ordinal) && inputStreamFunc != null) { + var inputStream = inputStreamFunc(); var reader = new StreamReader(inputStream); long originalPosition = 0; if (inputStream.CanSeek) { @@ -252,5 +289,23 @@ namespace DotNetOpenAuth.Messaging { return new NameValueCollection(); } + +#if CLR4 + /// <summary> + /// Adds HTTP headers to a <see cref="NameValueCollection"/>. + /// </summary> + /// <param name="collectionToFill">The collection to be modified with added entries.</param> + /// <param name="headers">The collection to read from.</param> + private static void AddHeaders(NameValueCollection collectionToFill, HttpHeaders headers) { + Requires.NotNull(collectionToFill, "collectionToFill"); + Requires.NotNull(headers, "headers"); + + foreach (var header in headers) { + foreach (var value in header.Value) { + collectionToFill.Add(header.Key, value); + } + } + } +#endif } } diff --git a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs index 2d049c1..7c03555 100644 --- a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs +++ b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs @@ -15,6 +15,9 @@ namespace DotNetOpenAuth.Messaging { using System.IO.Compression; using System.Linq; using System.Net; +#if CLR4 + using System.Net.Http; +#endif using System.Net.Mime; using System.Runtime.Serialization.Json; using System.Security; @@ -161,6 +164,28 @@ namespace DotNetOpenAuth.Messaging { return new OutgoingWebResponseActionResult(response); } +#if CLR4 + /// <summary> + /// Transforms an OutgoingWebResponse to a Web API-friendly HttpResponseMessage. + /// </summary> + /// <param name="outgoingResponse">The response to send to the user agent.</param> + /// <returns>The <see cref="HttpResponseMessage"/> instance to be returned by the Web API method.</returns> + public static HttpResponseMessage AsHttpResponseMessage(this OutgoingWebResponse outgoingResponse) { + HttpResponseMessage response = new HttpResponseMessage(outgoingResponse.Status) { + Content = new StreamContent(outgoingResponse.ResponseStream) + }; + + var responseHeaders = outgoingResponse.Headers; + foreach (var header in responseHeaders.AllKeys) { + if (!response.Headers.TryAddWithoutValidation(header, responseHeaders[header])) { + response.Content.Headers.TryAddWithoutValidation(header, responseHeaders[header]); + } + } + + return response; + } +#endif + /// <summary> /// Gets the original request URL, as seen from the browser before any URL rewrites on the server if any. /// Cookieless session directory (if applicable) is also included. @@ -357,6 +382,28 @@ namespace DotNetOpenAuth.Messaging { } /// <summary> + /// Creates the XML reader settings to use for reading XML from untrusted sources. + /// </summary> + /// <returns> + /// The new instance of <see cref="XmlReaderSettings"/>. + /// </returns> + /// <remarks> + /// The default values set here are based on recommendations from + /// http://msdn.microsoft.com/en-us/magazine/ee335713.aspx + /// </remarks> + internal static XmlReaderSettings CreateUntrustedXmlReaderSettings() { + return new XmlReaderSettings { + MaxCharactersFromEntities = 1024, + XmlResolver = null, +#if CLR4 + DtdProcessing = DtdProcessing.Prohibit, +#else + ProhibitDtd = true, +#endif + }; + } + + /// <summary> /// Clears any existing elements in a collection and fills the collection with a given set of values. /// </summary> /// <typeparam name="T">The type of value kept in the collection.</typeparam> diff --git a/src/DotNetOpenAuth.Core/Properties/AssemblyInfo.cs b/src/DotNetOpenAuth.Core/Properties/AssemblyInfo.cs index 91d27f5..21cbb94 100644 --- a/src/DotNetOpenAuth.Core/Properties/AssemblyInfo.cs +++ b/src/DotNetOpenAuth.Core/Properties/AssemblyInfo.cs @@ -20,15 +20,7 @@ using System.Web.UI; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("DotNetOpenAuth")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("DotNetOpenAuth")] -[assembly: AssemblyCopyright("Copyright © 2011 Outercurve Foundation")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: NeutralResourcesLanguage("en-US")] +[assembly: AssemblyCopyright("Copyright © 2012 Outercurve Foundation")] [assembly: CLSCompliant(true)] // Setting ComVisible to false makes the types in this assembly not visible |