//----------------------------------------------------------------------- // // Copyright (c) Andrew Arnott. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOAuth { using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text; using System.Web; using DotNetOAuth.Messaging; /// /// An OAuth-specific implementation of the class. /// internal class OAuthChannel : Channel { /// /// Initializes a new instance of the class. /// /// /// A class prepared to analyze incoming messages and indicate what concrete /// message types can deserialize from it. /// internal OAuthChannel(IMessageTypeProvider messageTypeProvider) : base(messageTypeProvider) { } /// /// Queues a message for sending in the response stream where the fields /// are sent in the response stream in querystring style. /// /// The message to send as a response. /// /// This method implements spec V1.0 section 5.3. /// 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 = Encoding.UTF8.GetBytes(responseBody), OriginalMessage = response, Status = System.Net.HttpStatusCode.OK, Headers = new System.Net.WebHeaderCollection(), }; this.QueueIndirectOrResponseMessage(encodedResponse); } /// /// Sends a direct message to a remote party and waits for the response. /// /// The message to send. /// The remote party's response. protected override IProtocolMessage Request(IDirectedProtocolMessage request) { if (request == null) { throw new ArgumentNullException("request"); } HttpWebRequest httpRequest; MessageScheme transmissionMethod = MessageScheme.AuthorizationHeaderRequest; switch (transmissionMethod) { case MessageScheme.AuthorizationHeaderRequest: httpRequest = this.InitializeRequestAsAuthHeader(request); break; case MessageScheme.PostRequest: httpRequest = this.InitializeRequestAsPost(request); break; case MessageScheme.GetRequest: httpRequest = this.InitializeRequestAsGet(request); break; default: throw new NotSupportedException(); } // Submit the request and await the reply. Dictionary responseFields; try { using (HttpWebResponse response = (HttpWebResponse)httpRequest.GetResponse()) { using (StreamReader reader = new StreamReader(response.GetResponseStream())) { string queryString = reader.ReadToEnd(); responseFields = HttpUtility.ParseQueryString(queryString).ToDictionary(); } } } catch (WebException ex) { throw new ProtocolException(MessagingStrings.ErrorInRequestReplyMessage, ex); } Type messageType = this.MessageTypeProvider.GetResponseMessageType(request, responseFields); var responseSerialize = MessageSerializer.Get(messageType); var responseMessage = responseSerialize.Deserialize(responseFields); return responseMessage; } /// /// Reports an error to the user via the user agent. /// /// The error information. protected override void ReportErrorToUser(ProtocolException exception) { throw new NotImplementedException(); } /// /// Sends an error result directly to the calling remote party according to the /// rules of the protocol. /// /// The error information. protected override void ReportErrorAsDirectResponse(ProtocolException exception) { throw new NotImplementedException(); } /// /// Prepares to send a request to the Service Provider via the Authorization header. /// /// The message to be transmitted to the ServiceProvider. /// The web request ready to send. /// /// This method implements OAuth 1.0 section 5.2, item #1 (described in section 5.4). /// private HttpWebRequest InitializeRequestAsAuthHeader(IDirectedProtocolMessage requestMessage) { var serializer = MessageSerializer.Get(requestMessage.GetType()); var fields = serializer.Serialize(requestMessage); HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(requestMessage.Recipient); StringBuilder authorization = new StringBuilder(); authorization.Append(requestMessage.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; } /// /// Prepares to send a request to the Service Provider as the payload of a POST request. /// /// The message to be transmitted to the ServiceProvider. /// The web request ready to send. /// /// This method implements OAuth 1.0 section 5.2, item #2. /// 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 (StreamWriter writer = new StreamWriter(httpRequest.GetRequestStream())) { writer.Write(requestBody); } return httpRequest; } /// /// Prepares to send a request to the Service Provider as the query string in a GET request. /// /// The message to be transmitted to the ServiceProvider. /// The web request ready to send. /// /// This method implements OAuth 1.0 section 5.2, item #3. /// private 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; } } }