summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.Core
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth.Core')
-rw-r--r--src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuth.xsd89
-rw-r--r--src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj2
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/Channel.cs25
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs16
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/HttpRequestHeaders.cs5
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs2
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/IHttpDirectRequest.cs22
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/IHttpDirectRequestContract.cs75
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/OutgoingWebResponseActionResult.cs5
-rw-r--r--src/DotNetOpenAuth.Core/Requires.cs5
10 files changed, 234 insertions, 12 deletions
diff --git a/src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuth.xsd b/src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuth.xsd
index d193776..74d4db4 100644
--- a/src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuth.xsd
+++ b/src/DotNetOpenAuth.Core/Configuration/DotNetOpenAuth.xsd
@@ -479,12 +479,19 @@
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="add">
<xs:complexType>
- <xs:attribute name="name" type="xs:string" use="required" />
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ The fully-qualified name of the type that implements the IIdentifierDiscoveryService 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="name" type="xs:string" use="required" />
+ <xs:attribute name="type" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
<xs:element name="clear">
@@ -898,6 +905,84 @@
</xs:choice>
</xs:complexType>
</xs:element>
+ <xs:element name="oauth2">
+ <xs:annotation>
+ <xs:documentation>
+ Settings OAuth 2 clients, authorization servers and resource servers.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="client">
+ <xs:annotation>
+ <xs:documentation>
+ Settings applicable to OAuth 2 Clients.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="authorizationServer">
+ <xs:annotation>
+ <xs:documentation>
+ Settings applicable to OAuth 2 Authorization Servers.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="clientAuthenticationModules">
+ <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 ClientAuthenticationModule-derived type.
+ </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 ClientAuthenticationModule-derived type.
+ </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:complexType>
+ </xs:element>
+ <xs:element name="resourceServer">
+ <xs:annotation>
+ <xs:documentation>
+ Settings applicable to OAuth 2 Resource Servers.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
<xs:element name="reporting">
<xs:annotation>
<xs:documentation>
diff --git a/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj b/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
index 447a3c5..65dee44 100644
--- a/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
+++ b/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
@@ -29,6 +29,8 @@
<Compile Include="Messaging\ChannelContract.cs" />
<Compile Include="Messaging\DataBagFormatterBase.cs" />
<Compile Include="Messaging\HttpRequestHeaders.cs" />
+ <Compile Include="Messaging\IHttpDirectRequest.cs" />
+ <Compile Include="Messaging\IHttpDirectRequestContract.cs" />
<Compile Include="Messaging\IHttpIndirectResponse.cs" />
<Compile Include="Messaging\IMessageOriginalPayload.cs" />
<Compile Include="Messaging\DirectWebRequestOptions.cs" />
diff --git a/src/DotNetOpenAuth.Core/Messaging/Channel.cs b/src/DotNetOpenAuth.Core/Messaging/Channel.cs
index 016a2b6..235c41b 100644
--- a/src/DotNetOpenAuth.Core/Messaging/Channel.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/Channel.cs
@@ -478,6 +478,14 @@ namespace DotNetOpenAuth.Messaging {
IDirectedProtocolMessage requestMessage = this.ReadFromRequestCore(httpRequest);
if (requestMessage != null) {
Logger.Channel.DebugFormat("Incoming request received: {0}", requestMessage.GetType().Name);
+
+ var directRequest = requestMessage as IHttpDirectRequest;
+ if (directRequest != null) {
+ foreach (string header in httpRequest.Headers) {
+ directRequest.Headers[header] = httpRequest.Headers[header];
+ }
+ }
+
this.ProcessIncomingMessage(requestMessage);
}
@@ -717,6 +725,13 @@ namespace DotNetOpenAuth.Messaging {
Requires.True(request.Recipient != null, "request", MessagingStrings.DirectedMessageMissingRecipient);
HttpWebRequest webRequest = this.CreateHttpRequest(request);
+ var directRequest = request as IHttpDirectRequest;
+ if (directRequest != null) {
+ foreach (string header in directRequest.Headers) {
+ webRequest.Headers[header] = directRequest.Headers[header];
+ }
+ }
+
IDictionary<string, string> responseFields;
IDirectResponseProtocolMessage responseMessage;
@@ -1082,6 +1097,7 @@ namespace DotNetOpenAuth.Messaging {
UriBuilder builder = new UriBuilder(requestMessage.Recipient);
MessagingUtilities.AppendQueryArgs(builder, fields);
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(builder.Uri);
+ this.PrepareHttpWebRequest(httpRequest);
return httpRequest;
}
@@ -1122,6 +1138,7 @@ namespace DotNetOpenAuth.Messaging {
var fields = messageAccessor.Serialize();
var httpRequest = (HttpWebRequest)WebRequest.Create(requestMessage.Recipient);
+ this.PrepareHttpWebRequest(httpRequest);
httpRequest.CachePolicy = this.CachePolicy;
httpRequest.Method = "POST";
@@ -1299,6 +1316,14 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Performs additional processing on an outgoing web request before it is sent to the remote server.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ protected virtual void PrepareHttpWebRequest(HttpWebRequest request) {
+ Requires.NotNull(request, "request");
+ }
+
+ /// <summary>
/// Customizes the binding element order for outgoing and incoming messages.
/// </summary>
/// <param name="outgoingOrder">The outgoing order.</param>
diff --git a/src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs b/src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs
index f499d67..2237cc7 100644
--- a/src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs
@@ -193,17 +193,17 @@ namespace DotNetOpenAuth.Messaging {
/// Throws a <see cref="ProtocolException"/> if some <paramref name="condition"/> evaluates to false.
/// </summary>
/// <param name="condition">True to do nothing; false to throw the exception.</param>
- /// <param name="message">The error message for the exception.</param>
+ /// <param name="unformattedMessage">The error message for the exception.</param>
/// <param name="args">The string formatting arguments, if any.</param>
/// <exception cref="ProtocolException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception>
[Pure]
- internal static void VerifyProtocol(bool condition, string message, params object[] args) {
+ internal static void VerifyProtocol(bool condition, string unformattedMessage, params object[] args) {
Requires.NotNull(args, "args");
Contract.Ensures(condition);
Contract.EnsuresOnThrow<ProtocolException>(!condition);
- Contract.Assume(message != null);
+ Contract.Assume(unformattedMessage != null);
if (!condition) {
- var exception = new ProtocolException(string.Format(CultureInfo.CurrentCulture, message, args));
+ var exception = new ProtocolException(string.Format(CultureInfo.CurrentCulture, unformattedMessage, args));
if (Logger.Messaging.IsErrorEnabled) {
Logger.Messaging.Error(
string.Format(
@@ -220,7 +220,7 @@ namespace DotNetOpenAuth.Messaging {
/// <summary>
/// Throws a <see cref="ProtocolException"/>.
/// </summary>
- /// <param name="message">The message to set in the exception.</param>
+ /// <param name="unformattedMessage">The message to set in the exception.</param>
/// <param name="args">The formatting arguments of the message.</param>
/// <returns>
/// An InternalErrorException, which may be "thrown" by the caller in order
@@ -229,10 +229,10 @@ namespace DotNetOpenAuth.Messaging {
/// </returns>
/// <exception cref="ProtocolException">Always thrown.</exception>
[Pure]
- internal static Exception ThrowProtocol(string message, params object[] args) {
+ internal static Exception ThrowProtocol(string unformattedMessage, params object[] args) {
Requires.NotNull(args, "args");
- Contract.Assume(message != null);
- VerifyProtocol(false, message, args);
+ Contract.Assume(unformattedMessage != null);
+ VerifyProtocol(false, unformattedMessage, args);
// we never reach here, but this allows callers to "throw" this method.
return new InternalErrorException();
diff --git a/src/DotNetOpenAuth.Core/Messaging/HttpRequestHeaders.cs b/src/DotNetOpenAuth.Core/Messaging/HttpRequestHeaders.cs
index 9579a81..dad6bf6 100644
--- a/src/DotNetOpenAuth.Core/Messaging/HttpRequestHeaders.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/HttpRequestHeaders.cs
@@ -20,6 +20,11 @@ namespace DotNetOpenAuth.Messaging {
internal const string Authorization = "Authorization";
/// <summary>
+ /// The WWW-Authenticate header, which is included in HTTP 401 Unauthorized responses to help the client know which authorization schemes are supported.
+ /// </summary>
+ internal const string WwwAuthenticate = "WWW-Authenticate";
+
+ /// <summary>
/// The Content-Type header, which specifies the MIME type of the accompanying body data.
/// </summary>
internal const string ContentType = "Content-Type";
diff --git a/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs b/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs
index 0f60e04..f613dc5 100644
--- a/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs
@@ -90,7 +90,7 @@ namespace DotNetOpenAuth.Messaging {
this.requestUri = requestUri;
this.form = form ?? new NameValueCollection();
this.queryString = HttpUtility.ParseQueryString(requestUri.Query);
- this.headers = headers ?? new NameValueCollection();
+ this.headers = headers ?? new WebHeaderCollection();
this.serverVariables = new NameValueCollection();
}
diff --git a/src/DotNetOpenAuth.Core/Messaging/IHttpDirectRequest.cs b/src/DotNetOpenAuth.Core/Messaging/IHttpDirectRequest.cs
new file mode 100644
index 0000000..7153334
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Messaging/IHttpDirectRequest.cs
@@ -0,0 +1,22 @@
+//-----------------------------------------------------------------------
+// <copyright file="IHttpDirectRequest.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Messaging {
+ using System.Diagnostics.Contracts;
+ using System.Net;
+
+ /// <summary>
+ /// An interface that allows direct request messages to capture the details of the HTTP request they arrived on.
+ /// </summary>
+ [ContractClass(typeof(IHttpDirectRequestContract))]
+ public interface IHttpDirectRequest : IMessage {
+ /// <summary>
+ /// Gets the HTTP headers of the request.
+ /// </summary>
+ /// <value>May be an empty collection, but must not be <c>null</c>.</value>
+ WebHeaderCollection Headers { get; }
+ }
+}
diff --git a/src/DotNetOpenAuth.Core/Messaging/IHttpDirectRequestContract.cs b/src/DotNetOpenAuth.Core/Messaging/IHttpDirectRequestContract.cs
new file mode 100644
index 0000000..cfde6cf
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Messaging/IHttpDirectRequestContract.cs
@@ -0,0 +1,75 @@
+//-----------------------------------------------------------------------
+// <copyright file="IHttpDirectRequestContract.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Messaging {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using System.Net;
+ using System.Text;
+
+ /// <summary>
+ /// Contract class for the <see cref="IHttpDirectRequest"/> interface.
+ /// </summary>
+ [ContractClassFor(typeof(IHttpDirectRequest))]
+ public abstract class IHttpDirectRequestContract : IHttpDirectRequest {
+ #region IHttpDirectRequest Members
+
+ /// <summary>
+ /// Gets the HTTP headers of the request.
+ /// </summary>
+ /// <value>May be an empty collection, but must not be <c>null</c>.</value>
+ WebHeaderCollection IHttpDirectRequest.Headers {
+ get {
+ Contract.Ensures(Contract.Result<WebHeaderCollection>() != null);
+ 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 { 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 { 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.Core/Messaging/OutgoingWebResponseActionResult.cs b/src/DotNetOpenAuth.Core/Messaging/OutgoingWebResponseActionResult.cs
index a5fe782..7691cc4 100644
--- a/src/DotNetOpenAuth.Core/Messaging/OutgoingWebResponseActionResult.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/OutgoingWebResponseActionResult.cs
@@ -35,6 +35,11 @@ namespace DotNetOpenAuth.Messaging {
/// <param name="context">The context in which to set the response.</param>
public override void ExecuteResult(ControllerContext context) {
this.response.Respond(context.HttpContext);
+
+ // MVC likes to muck with our response. For example, when returning contrived 401 Unauthorized responses
+ // MVC will rewrite our response and turn it into a redirect, which breaks OAuth 2 authorization server token endpoints.
+ // It turns out we can prevent this unwanted behavior by flushing the response before returning from this method.
+ context.HttpContext.Response.Flush();
}
}
}
diff --git a/src/DotNetOpenAuth.Core/Requires.cs b/src/DotNetOpenAuth.Core/Requires.cs
index 7a196a3..7d4d5be 100644
--- a/src/DotNetOpenAuth.Core/Requires.cs
+++ b/src/DotNetOpenAuth.Core/Requires.cs
@@ -43,14 +43,17 @@ namespace DotNetOpenAuth {
/// </summary>
/// <param name="value">The value.</param>
/// <param name="parameterName">Name of the parameter.</param>
+ /// <returns>The validated value.</returns>
#if !CLR4
[ContractArgumentValidator]
#endif
[Pure, DebuggerStepThrough]
- internal static void NotNullOrEmpty(string value, string parameterName) {
+ internal static string NotNullOrEmpty(string value, string parameterName) {
NotNull(value, parameterName);
True(value.Length > 0, parameterName, Strings.EmptyStringNotAllowed);
+ Contract.Ensures(Contract.Result<string>() == value);
Contract.EndContractBlock();
+ return value;
}
/// <summary>