diff options
Diffstat (limited to 'src/DotNetOAuth/ChannelElements')
8 files changed, 624 insertions, 0 deletions
diff --git a/src/DotNetOAuth/ChannelElements/IOAuthProtocolDirectedMessage.cs b/src/DotNetOAuth/ChannelElements/IOAuthProtocolDirectedMessage.cs new file mode 100644 index 0000000..6399c9c --- /dev/null +++ b/src/DotNetOAuth/ChannelElements/IOAuthProtocolDirectedMessage.cs @@ -0,0 +1,19 @@ +//-----------------------------------------------------------------------
+// <copyright file="IOAuthProtocolDirectedMessage.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.ChannelElements {
+ using DotNetOAuth.Messaging;
+
+ /// <summary>
+ /// Additional properties that apply specifically to OAuth messages.
+ /// </summary>
+ internal interface IOAuthProtocolDirectedMessage {
+ /// <summary>
+ /// Gets the preferred method of transport for the message.
+ /// </summary>
+ MessageScheme PreferredScheme { get; }
+ }
+}
diff --git a/src/DotNetOAuth/ChannelElements/ITamperResistantOAuthMessage.cs b/src/DotNetOAuth/ChannelElements/ITamperResistantOAuthMessage.cs new file mode 100644 index 0000000..c00ff8b --- /dev/null +++ b/src/DotNetOAuth/ChannelElements/ITamperResistantOAuthMessage.cs @@ -0,0 +1,19 @@ +//-----------------------------------------------------------------------
+// <copyright file="ITamperResistantOAuthMessage.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.ChannelElements {
+ using DotNetOAuth.Messaging.Bindings;
+
+ /// <summary>
+ /// An interface that OAuth messages implement to support signing.
+ /// </summary>
+ internal interface ITamperResistantOAuthMessage : ITamperResistantProtocolMessage {
+ /// <summary>
+ /// Gets or sets the method used to sign the message.
+ /// </summary>
+ string SignatureMethod { get; set; }
+ }
+}
diff --git a/src/DotNetOAuth/ChannelElements/IWebRequestHandler.cs b/src/DotNetOAuth/ChannelElements/IWebRequestHandler.cs new file mode 100644 index 0000000..13b57c7 --- /dev/null +++ b/src/DotNetOAuth/ChannelElements/IWebRequestHandler.cs @@ -0,0 +1,31 @@ +//-----------------------------------------------------------------------
+// <copyright file="IWebRequestHandler.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.ChannelElements {
+ using System.IO;
+ using System.Net;
+ using DotNetOAuth.Messaging;
+
+ /// <summary>
+ /// A contract for <see cref="HttpWebRequest"/> handling.
+ /// </summary>
+ internal interface IWebRequestHandler {
+ /// <summary>
+ /// Prepares an <see cref="HttpWebRequest"/> that contains an POST entity for sending the entity.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param>
+ /// <returns>The writer the caller should write out the entity data to.</returns>
+ TextWriter GetRequestStream(HttpWebRequest request);
+
+ /// <summary>
+ /// Processes an <see cref="HttpWebRequest"/> and converts the
+ /// <see cref="HttpWebResponse"/> to a <see cref="Response"/> instance.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> to handle.</param>
+ /// <returns>An instance of <see cref="Response"/> describing the response.</returns>
+ Response GetResponse(HttpWebRequest request);
+ }
+}
diff --git a/src/DotNetOAuth/ChannelElements/OAuthChannel.cs b/src/DotNetOAuth/ChannelElements/OAuthChannel.cs new file mode 100644 index 0000000..7a91a98 --- /dev/null +++ b/src/DotNetOAuth/ChannelElements/OAuthChannel.cs @@ -0,0 +1,268 @@ +//-----------------------------------------------------------------------
+// <copyright file="OAuthChannel.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Net;
+ using System.Text;
+ using System.Web;
+ using DotNetOAuth.Messaging;
+using DotNetOAuth.Messaging.Bindings;
+
+ /// <summary>
+ /// An OAuth-specific implementation of the <see cref="Channel"/> class.
+ /// </summary>
+ internal class OAuthChannel : Channel {
+ /// <summary>
+ /// The object that will transmit <see cref="HttpWebRequest"/> instances
+ /// and return their responses.
+ /// </summary>
+ private IWebRequestHandler webRequestHandler;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuthChannel"/> class.
+ /// </summary>
+ /// <param name="signingBindingElement">The binding element to use for signing.</param>
+ /// <param name="store">The web application store to use for nonces.</param>
+ internal OAuthChannel(SigningBindingElementBase signingBindingElement, INonceStore store)
+ : this(signingBindingElement, store, new OAuthMessageTypeProvider(), new StandardWebRequestHandler()) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuthChannel"/> class.
+ /// </summary>
+ /// <param name="signingBindingElement">The binding element to use for signing.</param>
+ /// <param name="store">The web application store to use for nonces.</param>
+ /// <param name="messageTypeProvider">
+ /// An injected message type provider instance.
+ /// Except for mock testing, this should always be <see cref="OAuthMessageTypeProvider"/>.
+ /// </param>
+ /// <param name="webRequestHandler">
+ /// An instance to a <see cref="IWebRequestHandler"/> that will be used when submitting HTTP
+ /// requests and waiting for responses.
+ /// </param>
+ /// <remarks>
+ /// This overload for testing purposes only.
+ /// </remarks>
+ internal OAuthChannel(SigningBindingElementBase signingBindingElement, INonceStore store, IMessageTypeProvider messageTypeProvider, IWebRequestHandler webRequestHandler)
+ : base(messageTypeProvider, signingBindingElement, new StandardExpirationBindingElement(), new StandardReplayProtectionBindingElement(store)) {
+ if (webRequestHandler == null) {
+ throw new ArgumentNullException("webRequestHandler");
+ }
+
+ this.webRequestHandler = webRequestHandler;
+ this.PreferredTransmissionScheme = MessageScheme.AuthorizationHeaderRequest;
+ }
+
+ /// <summary>
+ /// Gets or sets the method used in direct requests to transmit the message payload.
+ /// </summary>
+ internal MessageScheme PreferredTransmissionScheme { get; set; }
+
+ /// <summary>
+ /// Searches an incoming HTTP request for data that could be used to assemble
+ /// a protocol request message.
+ /// </summary>
+ /// <param name="request">The HTTP request to search.</param>
+ /// <returns>A dictionary of data in the request. Should never be null, but may be empty.</returns>
+ protected override IProtocolMessage ReadFromRequestInternal(HttpRequestInfo request) {
+ if (request == null) {
+ throw new ArgumentNullException("request");
+ }
+
+ // First search the Authorization header. Use it exclusively if it's present.
+ string authorization = request.Headers[HttpRequestHeader.Authorization];
+ if (authorization != null) {
+ string[] authorizationSections = authorization.Split(';'); // TODO: is this the right delimiter?
+ string oauthPrefix = Protocol.Default.AuthorizationHeaderScheme + " ";
+
+ // The Authorization header may have multiple uses, and OAuth may be just one of them.
+ // Go through each one looking for an OAuth one.
+ foreach (string auth in authorizationSections) {
+ string trimmedAuth = auth.Trim();
+ if (trimmedAuth.StartsWith(oauthPrefix, StringComparison.Ordinal)) {
+ // We found an Authorization: OAuth header.
+ // Parse it according to the rules in section 5.4.1 of the V1.0 spec.
+ var fields = new Dictionary<string, string>();
+ foreach (string stringPair in trimmedAuth.Substring(oauthPrefix.Length).Split(',')) {
+ string[] keyValueStringPair = stringPair.Trim().Split('=');
+ string key = Uri.UnescapeDataString(keyValueStringPair[0]);
+ string value = Uri.UnescapeDataString(keyValueStringPair[1].Trim('"'));
+ fields.Add(key, value);
+ }
+
+ return this.Receive(fields);
+ }
+ }
+ }
+
+ // We didn't find an OAuth authorization header. Revert to other payload methods.
+ return base.ReadFromRequestInternal(request);
+ }
+
+ /// <summary>
+ /// Gets the protocol message that may be in the given HTTP response stream.
+ /// </summary>
+ /// <param name="responseStream">The response that is anticipated to contain an OAuth message.</param>
+ /// <returns>The deserialized message, if one is found. Null otherwise.</returns>
+ protected override IProtocolMessage ReadFromResponseInternal(Stream responseStream) {
+ if (responseStream == null) {
+ throw new ArgumentNullException("responseStream");
+ }
+
+ using (StreamReader reader = new StreamReader(responseStream)) {
+ string response = reader.ReadToEnd();
+ var fields = HttpUtility.ParseQueryString(response).ToDictionary();
+ return Receive(fields);
+ }
+ }
+
+ /// <summary>
+ /// Sends a direct message to a remote party and waits for the response.
+ /// </summary>
+ /// <param name="request">The message to send.</param>
+ /// <returns>The remote party's response.</returns>
+ protected override IProtocolMessage RequestInternal(IDirectedProtocolMessage request) {
+ if (request == null) {
+ throw new ArgumentNullException("request");
+ }
+ if (request.Recipient == null) {
+ throw new ArgumentException(MessagingStrings.DirectedMessageMissingRecipient, "request");
+ }
+
+ HttpWebRequest httpRequest;
+
+ MessageScheme transmissionMethod = this.PreferredTransmissionScheme;
+ switch (transmissionMethod) {
+ case MessageScheme.AuthorizationHeaderRequest:
+ httpRequest = InitializeRequestAsAuthHeader(request);
+ break;
+ case MessageScheme.PostRequest:
+ httpRequest = this.InitializeRequestAsPost(request);
+ break;
+ case MessageScheme.GetRequest:
+ httpRequest = InitializeRequestAsGet(request);
+ break;
+ default:
+ throw new NotSupportedException();
+ }
+
+ Response response = this.webRequestHandler.GetResponse(httpRequest);
+ if (response.Body == null) {
+ return null;
+ }
+ var responseFields = HttpUtility.ParseQueryString(response.Body).ToDictionary();
+ Type messageType = this.MessageTypeProvider.GetResponseMessageType(request, responseFields);
+ if (messageType == null) {
+ return null;
+ }
+ var responseSerialize = MessageSerializer.Get(messageType);
+ var responseMessage = responseSerialize.Deserialize(responseFields);
+
+ return responseMessage;
+ }
+
+ /// <summary>
+ /// Queues a message for sending in the response stream where the fields
+ /// are sent in the response stream in querystring style.
+ /// </summary>
+ /// <param name="response">The message to send as a response.</param>
+ /// <remarks>
+ /// This method implements spec V1.0 section 5.3.
+ /// </remarks>
+ protected override void SendDirectMessageResponse(IProtocolMessage response) {
+ MessageSerializer serializer = MessageSerializer.Get(response.GetType());
+ var fields = serializer.Serialize(response);
+ string responseBody = MessagingUtilities.CreateQueryString(fields);
+
+ Response encodedResponse = new Response {
+ Body = responseBody,
+ OriginalMessage = response,
+ Status = HttpStatusCode.OK,
+ Headers = new System.Net.WebHeaderCollection(),
+ };
+ this.QueueIndirectOrResponseMessage(encodedResponse);
+ }
+
+ /// <summary>
+ /// Prepares to send a request to the Service Provider via the Authorization header.
+ /// </summary>
+ /// <param name="requestMessage">The message to be transmitted to the ServiceProvider.</param>
+ /// <returns>The web request ready to send.</returns>
+ /// <remarks>
+ /// This method implements OAuth 1.0 section 5.2, item #1 (described in section 5.4).
+ /// </remarks>
+ private static HttpWebRequest InitializeRequestAsAuthHeader(IDirectedProtocolMessage requestMessage) {
+ var serializer = MessageSerializer.Get(requestMessage.GetType());
+ var fields = serializer.Serialize(requestMessage);
+ var protocol = Protocol.Lookup(requestMessage.ProtocolVersion);
+
+ HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(requestMessage.Recipient);
+
+ StringBuilder authorization = new StringBuilder();
+ authorization.Append(protocol.AuthorizationHeaderScheme);
+ authorization.Append(" ");
+ foreach (var pair in fields) {
+ string key = Uri.EscapeDataString(pair.Key);
+ string value = Uri.EscapeDataString(pair.Value);
+ authorization.Append(key);
+ authorization.Append("=\"");
+ authorization.Append(value);
+ authorization.Append("\",");
+ }
+ authorization.Length--; // remove trailing comma
+
+ httpRequest.Headers.Add(HttpRequestHeader.Authorization, authorization.ToString());
+
+ return httpRequest;
+ }
+
+ /// <summary>
+ /// Prepares to send a request to the Service Provider as the query string in a GET request.
+ /// </summary>
+ /// <param name="requestMessage">The message to be transmitted to the ServiceProvider.</param>
+ /// <returns>The web request ready to send.</returns>
+ /// <remarks>
+ /// This method implements OAuth 1.0 section 5.2, item #3.
+ /// </remarks>
+ private static HttpWebRequest InitializeRequestAsGet(IDirectedProtocolMessage requestMessage) {
+ var serializer = MessageSerializer.Get(requestMessage.GetType());
+ var fields = serializer.Serialize(requestMessage);
+
+ UriBuilder builder = new UriBuilder(requestMessage.Recipient);
+ MessagingUtilities.AppendQueryArgs(builder, fields);
+ HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(builder.Uri);
+
+ return httpRequest;
+ }
+
+ /// <summary>
+ /// Prepares to send a request to the Service Provider as the payload of a POST request.
+ /// </summary>
+ /// <param name="requestMessage">The message to be transmitted to the ServiceProvider.</param>
+ /// <returns>The web request ready to send.</returns>
+ /// <remarks>
+ /// This method implements OAuth 1.0 section 5.2, item #2.
+ /// </remarks>
+ private HttpWebRequest InitializeRequestAsPost(IDirectedProtocolMessage requestMessage) {
+ var serializer = MessageSerializer.Get(requestMessage.GetType());
+ var fields = serializer.Serialize(requestMessage);
+
+ HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(requestMessage.Recipient);
+ httpRequest.Method = "POST";
+ httpRequest.ContentType = "application/x-www-form-urlencoded";
+ string requestBody = MessagingUtilities.CreateQueryString(fields);
+ httpRequest.ContentLength = requestBody.Length;
+ using (TextWriter writer = this.webRequestHandler.GetRequestStream(httpRequest)) {
+ writer.Write(requestBody);
+ }
+
+ return httpRequest;
+ }
+ }
+}
diff --git a/src/DotNetOAuth/ChannelElements/OAuthMessageTypeProvider.cs b/src/DotNetOAuth/ChannelElements/OAuthMessageTypeProvider.cs new file mode 100644 index 0000000..0d30ec1 --- /dev/null +++ b/src/DotNetOAuth/ChannelElements/OAuthMessageTypeProvider.cs @@ -0,0 +1,112 @@ +//-----------------------------------------------------------------------
+// <copyright file="OAuthMessageTypeProvider.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using DotNetOAuth.Messages;
+ using DotNetOAuth.Messaging;
+
+ /// <summary>
+ /// An OAuth-protocol specific implementation of the <see cref="IMessageTypeProvider"/>
+ /// interface.
+ /// </summary>
+ internal class OAuthMessageTypeProvider : IMessageTypeProvider {
+ #region IMessageTypeProvider Members
+
+ /// <summary>
+ /// Analyzes an incoming request message payload to discover what kind of
+ /// message is embedded in it and returns the type, or null if no match is found.
+ /// </summary>
+ /// <param name="fields">The name/value pairs that make up the message payload.</param>
+ /// <remarks>
+ /// The request messages are:
+ /// RequestTokenMessage
+ /// RequestAccessTokenMessage
+ /// DirectUserToServiceProviderMessage
+ /// AccessProtectedResourcesMessage
+ /// </remarks>
+ /// <returns>
+ /// The <see cref="IProtocolMessage"/>-derived concrete class that this message can
+ /// deserialize to. Null if the request isn't recognized as a valid protocol message.
+ /// </returns>
+ public Type GetRequestMessageType(IDictionary<string, string> fields) {
+ if (fields == null) {
+ throw new ArgumentNullException("fields");
+ }
+
+ if (fields.ContainsKey("oauth_consumer_key") &&
+ !fields.ContainsKey("oauth_token")) {
+ return typeof(RequestTokenMessage);
+ }
+
+ if (fields.ContainsKey("oauth_consumer_key") &&
+ fields.ContainsKey("oauth_token")) {
+ // Discern between RequestAccessToken and AccessProtectedResources,
+ // which have all the same parameters, by figuring out what type of token
+ // is in the token parameter.
+ bool tokenTypeIsAccessToken = false; // TODO
+
+ return tokenTypeIsAccessToken ? typeof(AccessProtectedResourcesMessage) :
+ typeof(RequestAccessTokenMessage);
+ }
+
+ // fail over to the message with no required fields at all.
+ return typeof(DirectUserToServiceProviderMessage);
+ }
+
+ /// <summary>
+ /// Analyzes an incoming request message payload to discover what kind of
+ /// message is embedded in it and returns the type, or null if no match is found.
+ /// </summary>
+ /// <param name="request">
+ /// The message that was sent as a request that resulted in the response.
+ /// Null on a Consumer site that is receiving an indirect message from the Service Provider.
+ /// </param>
+ /// <param name="fields">The name/value pairs that make up the message payload.</param>
+ /// <returns>
+ /// The <see cref="IProtocolMessage"/>-derived concrete class that this message can
+ /// deserialize to. Null if the request isn't recognized as a valid protocol message.
+ /// </returns>
+ /// <remarks>
+ /// The response messages are:
+ /// UnauthorizedRequestTookenMessage
+ /// DirectUserToConsumerMessage
+ /// GrantAccessTokenMessage
+ /// </remarks>
+ public Type GetResponseMessageType(IProtocolMessage request, IDictionary<string, string> fields) {
+ if (fields == null) {
+ throw new ArgumentNullException("fields");
+ }
+
+ // All response messages have the oauth_token field.
+ if (!fields.ContainsKey("oauth_token")) {
+ return null;
+ }
+
+ if (request == null) {
+ return typeof(DirectUserToConsumerMessage);
+ }
+
+ // All direct message responses should haev the oauth_token_secret field.
+ if (!fields.ContainsKey("oauth_token_secret")) {
+ Logger.Error("An OAuth message was expected to contain an oauth_token_secret but didn't.");
+ return null;
+ }
+
+ if (request is RequestTokenMessage) {
+ return typeof(UnauthorizedRequestTokenMessage);
+ } else if (request is RequestAccessTokenMessage) {
+ return typeof(GrantAccessTokenMessage);
+ } else {
+ Logger.ErrorFormat("Unexpected response message given the request type {0}", request.GetType().Name);
+ throw new ProtocolException(Strings.InvalidIncomingMessage);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOAuth/ChannelElements/RsaSha1SigningBindingElement.cs b/src/DotNetOAuth/ChannelElements/RsaSha1SigningBindingElement.cs new file mode 100644 index 0000000..9b25cd0 --- /dev/null +++ b/src/DotNetOAuth/ChannelElements/RsaSha1SigningBindingElement.cs @@ -0,0 +1,37 @@ +//-----------------------------------------------------------------------
+// <copyright file="RsaSha1SigningBindingElement.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOAuth.Messaging;
+ using DotNetOAuth.Messaging.Bindings;
+
+ /// <summary>
+ /// A binding element that signs outgoing messages and verifies the signature on incoming messages.
+ /// </summary>
+ internal class RsaSha1SigningBindingElement : SigningBindingElementBase {
+ /// <summary>
+ /// Applies a signature to the message.
+ /// </summary>
+ /// <param name="message">The message to sign.</param>
+ protected override void Sign(ITamperResistantOAuthMessage message) {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Validates the signature on a message.
+ /// Does NOT throw an exception on failing signature verification.
+ /// </summary>
+ /// <param name="message">The message with a signature to verify.</param>
+ /// <returns>True if the signature is valid. False otherwise.</returns>
+ protected override bool IsSignatureValid(ITamperResistantOAuthMessage message) {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs b/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs new file mode 100644 index 0000000..369c844 --- /dev/null +++ b/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs @@ -0,0 +1,78 @@ +//-----------------------------------------------------------------------
+// <copyright file="SigningBindingElementBase.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOAuth.Messaging;
+ using DotNetOAuth.Messaging.Bindings;
+
+ /// <summary>
+ /// A binding element that signs outgoing messages and verifies the signature on incoming messages.
+ /// </summary>
+ internal abstract class SigningBindingElementBase : IChannelBindingElement {
+ #region IChannelBindingElement Members
+
+ /// <summary>
+ /// Gets the message protection provided by this binding element.
+ /// </summary>
+ public MessageProtection Protection {
+ get { return MessageProtection.TamperProtection; }
+ }
+
+ /// <summary>
+ /// Signs the outgoing message.
+ /// </summary>
+ /// <param name="message">The message to sign.</param>
+ /// <returns>True if the message was signed. False otherwise.</returns>
+ public bool PrepareMessageForSending(IProtocolMessage message) {
+ var signedMessage = message as ITamperResistantOAuthMessage;
+ if (signedMessage != null) {
+ this.Sign(signedMessage);
+ return true;
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Verifies the signature on an incoming message.
+ /// </summary>
+ /// <param name="message">The message whose signature should be verified.</param>
+ /// <returns>True if the signature was verified. False if the message had no signature.</returns>
+ /// <exception cref="InvalidSignatureException">Thrown if the signature is invalid.</exception>
+ public bool PrepareMessageForReceiving(IProtocolMessage message) {
+ var signedMessage = message as ITamperResistantOAuthMessage;
+ if (signedMessage != null) {
+ if (!this.IsSignatureValid(signedMessage)) {
+ throw new InvalidSignatureException(message);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Applies a signature to the message.
+ /// </summary>
+ /// <param name="message">The message to sign.</param>
+ protected abstract void Sign(ITamperResistantOAuthMessage message);
+
+ /// <summary>
+ /// Validates the signature on a message.
+ /// Does NOT throw an exception on failing signature verification.
+ /// </summary>
+ /// <param name="message">The message with a signature to verify.</param>
+ /// <returns>True if the signature is valid. False otherwise.</returns>
+ protected abstract bool IsSignatureValid(ITamperResistantOAuthMessage message);
+ }
+}
diff --git a/src/DotNetOAuth/ChannelElements/StandardWebRequestHandler.cs b/src/DotNetOAuth/ChannelElements/StandardWebRequestHandler.cs new file mode 100644 index 0000000..8d0adb2 --- /dev/null +++ b/src/DotNetOAuth/ChannelElements/StandardWebRequestHandler.cs @@ -0,0 +1,60 @@ +//-----------------------------------------------------------------------
+// <copyright file="StandardWebRequestHandler.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.ChannelElements {
+ using System;
+ using System.IO;
+ using System.Net;
+ using DotNetOAuth.Messaging;
+
+ /// <summary>
+ /// The default handler for transmitting <see cref="HttpWebRequest"/> instances
+ /// and returning the responses.
+ /// </summary>
+ internal class StandardWebRequestHandler : IWebRequestHandler {
+ #region IWebRequestHandler Members
+
+ /// <summary>
+ /// Prepares a POST <see cref="HttpWebRequest"/> and returns the request stream
+ /// for writing out the POST entity data.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param>
+ /// <returns>The stream the caller should write out the entity data to.</returns>
+ public TextWriter GetRequestStream(HttpWebRequest request) {
+ if (request == null) {
+ throw new ArgumentNullException("request");
+ }
+
+ try {
+ return new StreamWriter(request.GetRequestStream());
+ } catch (WebException ex) {
+ throw new ProtocolException(MessagingStrings.ErrorInRequestReplyMessage, ex);
+ }
+ }
+
+ /// <summary>
+ /// Processes an <see cref="HttpWebRequest"/> and converts the
+ /// <see cref="HttpWebResponse"/> to a <see cref="Response"/> instance.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> to handle.</param>
+ /// <returns>An instance of <see cref="Response"/> describing the response.</returns>
+ public Response GetResponse(HttpWebRequest request) {
+ if (request == null) {
+ throw new ArgumentNullException("request");
+ }
+
+ try {
+ using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
+ return new Response(response);
+ }
+ } catch (WebException ex) {
+ throw new ProtocolException(MessagingStrings.ErrorInRequestReplyMessage, ex);
+ }
+ }
+
+ #endregion
+ }
+}
|