diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2010-07-09 08:35:42 -0700 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2010-07-09 08:35:42 -0700 |
commit | 07047811a7dfd1218de8f20393a282391e2f35cc (patch) | |
tree | c33caa391a349f108d3de2989e183cf7e9c316d7 | |
parent | 1b8bd07ddd70b8c1f9dc0ae45068a0f7ee7fd82d (diff) | |
download | DotNetOpenAuth-07047811a7dfd1218de8f20393a282391e2f35cc.zip DotNetOpenAuth-07047811a7dfd1218de8f20393a282391e2f35cc.tar.gz DotNetOpenAuth-07047811a7dfd1218de8f20393a282391e2f35cc.tar.bz2 |
A bit of OAuth2 channel refactoring.
15 files changed, 281 insertions, 197 deletions
diff --git a/samples/OAuthConsumerWpf/MainWindow.xaml b/samples/OAuthConsumerWpf/MainWindow.xaml index 4488fab..b4a6959 100644 --- a/samples/OAuthConsumerWpf/MainWindow.xaml +++ b/samples/OAuthConsumerWpf/MainWindow.xaml @@ -157,15 +157,12 @@ <Label Grid.Row="2">User Authorization URL</Label> <TextBox Grid.Row="2" Grid.Column="1" x:Name="wrapAuthorizationUrlBox" Text="https://graph.facebook.com/oauth/authorize?display=popup" /> <Label Grid.Row="2" Grid.Column="2">GET</Label> - <Label Grid.Row="0">Flow</Label> - <ComboBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" x:Name="flowBox" SelectedIndex="1"> + <Label Grid.Row="0">Grant Type</Label> + <ComboBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" x:Name="flowBox" SelectedIndex="0"> <ComboBox.Items> - <ComboBoxItem>Web Server</ComboBoxItem> - <ComboBoxItem>User Agent</ComboBoxItem> - <ComboBoxItem>Device</ComboBoxItem> - <ComboBoxItem>Username and Password</ComboBoxItem> - <ComboBoxItem>Assertion</ComboBoxItem> - <ComboBoxItem>Client Credentials</ComboBoxItem> + <ComboBoxItem>Authorization Code</ComboBoxItem> + <ComboBoxItem>Resource Owner Basic Credentials</ComboBoxItem> + <ComboBoxItem>Access Code (direct)</ComboBoxItem> </ComboBox.Items> </ComboBox> <Label Grid.Row="3">Resource URL</Label> diff --git a/src/DotNetOpenAuth.Test/OAuth2/MessageFactoryTests.cs b/src/DotNetOpenAuth.Test/OAuth2/MessageFactoryTests.cs index b6b8994..bd830c8 100644 --- a/src/DotNetOpenAuth.Test/OAuth2/MessageFactoryTests.cs +++ b/src/DotNetOpenAuth.Test/OAuth2/MessageFactoryTests.cs @@ -20,13 +20,13 @@ namespace DotNetOpenAuth.Test.OAuth2 { /// </summary> public class MessageFactoryTests : OAuth2TestBase { private readonly MessageReceivingEndpoint recipient = new MessageReceivingEndpoint("http://who", HttpDeliveryMethods.PostRequest); - private OAuthWrapAuthorizationServerChannel channel; + private OAuth2AuthorizationServerChannel channel; private IMessageFactory messageFactory; public override void SetUp() { base.SetUp(); - this.channel = new OAuthWrapAuthorizationServerChannel(); + this.channel = new OAuth2AuthorizationServerChannel(); this.messageFactory = OAuthWrapAuthorizationServerChannel_Accessor.AttachShadow(this.channel).MessageFactory; } diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj index af24fa3..150006f 100644 --- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj +++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj @@ -315,10 +315,12 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="OAuth2\ChannelElements\GrantTypeEncoder.cs" /> <Compile Include="OAuth2\ChannelElements\EndUserAuthorizationResponseTypeEncoder.cs" /> <Compile Include="OAuth2\ChannelElements\IDataBagFormatter.cs" /> + <Compile Include="OAuth2\ChannelElements\OAuth2ChannelBase.cs" /> + <Compile Include="OAuth2\ChannelElements\OAuth2ClientChannel.cs" /> <Compile Include="OAuth2\ChannelElements\UriStyleMessageFormatter.cs" /> <Compile Include="OAuth2\ChannelElements\IAuthorizationDescription.cs" /> <Compile Include="OAuth2\ChannelElements\ITokenCarryingRequest.cs" /> - <Compile Include="OAuth2\ChannelElements\OAuthWrapResourceServerChannel.cs" /> + <Compile Include="OAuth2\ChannelElements\OAuth2ResourceServerChannel.cs" /> <Compile Include="Messaging\StandardMessageFactoryChannel.cs" /> <Compile Include="OAuth2\ChannelElements\RefreshToken.cs" /> <Compile Include="OAuth2\ChannelElements\DataBag.cs" /> @@ -637,7 +639,7 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="Messaging\StandardWebRequestHandler.cs" /> <Compile Include="Messaging\MessageReceivingEndpoint.cs" /> <Compile Include="Reporting.cs" /> - <Compile Include="OAuth2\ChannelElements\OAuthWrapAuthorizationServerChannel.cs" /> + <Compile Include="OAuth2\ChannelElements\OAuth2AuthorizationServerChannel.cs" /> <Compile Include="OAuth2\ClientBase.cs" /> <Compile Include="OAuth2\Messages\MessageBase.cs" /> <Compile Include="OAuth2\Messages\EndUserAuthorizationRequest.cs" /> diff --git a/src/DotNetOpenAuth/Messaging/Channel.cs b/src/DotNetOpenAuth/Messaging/Channel.cs index 0767a4c..0633cd4 100644 --- a/src/DotNetOpenAuth/Messaging/Channel.cs +++ b/src/DotNetOpenAuth/Messaging/Channel.cs @@ -618,7 +618,7 @@ namespace DotNetOpenAuth.Messaging { try { recipient = request.GetRecipient(); } catch (ArgumentException ex) { - Logger.Messaging.WarnFormat("Unrecognized HTTP request: " + ex.ToString()); + Logger.Messaging.WarnFormat("Unrecognized HTTP request: {0}", ex); return null; } diff --git a/src/DotNetOpenAuth/OAuth2/AuthorizationServerBase.cs b/src/DotNetOpenAuth/OAuth2/AuthorizationServerBase.cs index b23ca9d..93790b6 100644 --- a/src/DotNetOpenAuth/OAuth2/AuthorizationServerBase.cs +++ b/src/DotNetOpenAuth/OAuth2/AuthorizationServerBase.cs @@ -26,7 +26,7 @@ namespace DotNetOpenAuth.OAuth2 { /// <param name="authorizationServer">The authorization server.</param> protected AuthorizationServerBase(IAuthorizationServer authorizationServer) { Contract.Requires<ArgumentNullException>(authorizationServer != null, "authorizationServer"); - this.OAuthChannel = new OAuthWrapAuthorizationServerChannel(authorizationServer); + this.OAuthChannel = new OAuth2AuthorizationServerChannel(authorizationServer); } /// <summary> @@ -48,7 +48,7 @@ namespace DotNetOpenAuth.OAuth2 { /// <summary> /// Gets the channel. /// </summary> - internal OAuthWrapAuthorizationServerChannel OAuthChannel { get; private set; } + internal OAuth2AuthorizationServerChannel OAuthChannel { get; private set; } /// <summary> /// Prepares the response to an access token request. diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/AuthServerBindingElementBase.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/AuthServerBindingElementBase.cs index b117fa3..9d3e78f 100644 --- a/src/DotNetOpenAuth/OAuth2/ChannelElements/AuthServerBindingElementBase.cs +++ b/src/DotNetOpenAuth/OAuth2/ChannelElements/AuthServerBindingElementBase.cs @@ -44,8 +44,8 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { /// <remarks> /// This property is set by the channel when it is first constructed. /// </remarks> - protected OAuthWrapAuthorizationServerChannel OAuthChannel { - get { return (OAuthWrapAuthorizationServerChannel)this.Channel; } + protected OAuth2AuthorizationServerChannel OAuthChannel { + get { return (OAuth2AuthorizationServerChannel)this.Channel; } } /// <summary> diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuth2AuthorizationServerChannel.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuth2AuthorizationServerChannel.cs new file mode 100644 index 0000000..5ecf01c --- /dev/null +++ b/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuth2AuthorizationServerChannel.cs @@ -0,0 +1,107 @@ +//----------------------------------------------------------------------- +// <copyright file="OAuth2AuthorizationServerChannel.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth2.ChannelElements { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.Net.Mime; + using System.Web; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// The channel for the OAuth protocol. + /// </summary> + internal class OAuth2AuthorizationServerChannel : OAuth2ChannelBase { + /// <summary> + /// Initializes a new instance of the <see cref="OAuth2AuthorizationServerChannel"/> class. + /// </summary> + /// <param name="authorizationServer">The authorization server.</param> + protected internal OAuth2AuthorizationServerChannel(IAuthorizationServer authorizationServer) + : base(InitializeBindingElements(authorizationServer)) { + Contract.Requires<ArgumentNullException>(authorizationServer != null, "authorizationServer"); + this.AuthorizationServer = authorizationServer; + } + + /// <summary> + /// Gets the authorization server. + /// </summary> + /// <value>The authorization server.</value> + public IAuthorizationServer AuthorizationServer { get; private set; } + + /// <summary> + /// Gets the protocol message that may be in the given HTTP response. + /// </summary> + /// <param name="response">The response that is anticipated to contain an protocol message.</param> + /// <returns> + /// The deserialized message parts, if found. Null otherwise. + /// </returns> + /// <exception cref="ProtocolException">Thrown when the response is not valid.</exception> + protected override IDictionary<string, string> ReadFromResponseCore(IncomingWebResponse response) { + throw new NotImplementedException(); + } + + /// <summary> + /// Queues a message for sending in the response stream. + /// </summary> + /// <param name="response">The message to send as a response.</param> + /// <returns> + /// The pending user agent redirect based message to be sent as an HttpResponse. + /// </returns> + /// <remarks> + /// This method implements spec OAuth V1.0 section 5.3. + /// </remarks> + protected override OutgoingWebResponse PrepareDirectResponse(IProtocolMessage response) { + var webResponse = new OutgoingWebResponse(); + string json = this.SerializeAsJson(response); + webResponse.SetResponse(json, new ContentType(JsonEncoded)); + return webResponse; + } + + /// <summary> + /// Gets the protocol message that may be embedded in the given HTTP request. + /// </summary> + /// <param name="request">The request to search for an embedded message.</param> + /// <returns> + /// The deserialized message, if one is found. Null otherwise. + /// </returns> + protected override IDirectedProtocolMessage ReadFromRequestCore(HttpRequestInfo request) { + if (!string.IsNullOrEmpty(request.Url.Fragment)) { + var fields = HttpUtility.ParseQueryString(request.Url.Fragment.Substring(1)).ToDictionary(); + + MessageReceivingEndpoint recipient; + try { + recipient = request.GetRecipient(); + } catch (ArgumentException ex) { + Logger.Messaging.WarnFormat("Unrecognized HTTP request: " + ex.ToString()); + return null; + } + + return (IDirectedProtocolMessage)this.Receive(fields, recipient); + } + + return base.ReadFromRequestCore(request); + } + + /// <summary> + /// Initializes the binding elements for the OAuth channel. + /// </summary> + /// <param name="authorizationServer">The authorization server.</param> + /// <returns> + /// An array of binding elements used to initialize the channel. + /// </returns> + private static IChannelBindingElement[] InitializeBindingElements(IAuthorizationServer authorizationServer) { + Contract.Requires<ArgumentNullException>(authorizationServer != null, "authorizationServer"); + var bindingElements = new List<IChannelBindingElement>(); + + bindingElements.Add(new AuthServerAllFlowsBindingElement()); + bindingElements.Add(new AuthorizationCodeBindingElement()); + bindingElements.Add(new AccessRequestBindingElement()); + + return bindingElements.ToArray(); + } + } +} diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuth2ChannelBase.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuth2ChannelBase.cs new file mode 100644 index 0000000..56b0e7b --- /dev/null +++ b/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuth2ChannelBase.cs @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------- +// <copyright file="OAuth2ChannelBase.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth2.ChannelElements { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth2.Messages; + + internal abstract class OAuth2ChannelBase : StandardMessageFactoryChannel { + /// <summary> + /// The messages receivable by this channel. + /// </summary> + private static readonly Type[] MessageTypes = new Type[] { + typeof(AccessTokenRefreshRequest), + typeof(AccessTokenAuthorizationCodeRequest), + typeof(AccessTokenBasicCredentialsRequest), + typeof(AccessTokenAssertionRequest), + typeof(AccessTokenClientCredentialsRequest), + typeof(AccessTokenSuccessResponse), + typeof(AccessTokenFailedResponse), + typeof(EndUserAuthorizationRequest), + typeof(EndUserAuthorizationSuccessResponse), + typeof(EndUserAuthorizationFailedResponse), + typeof(UnauthorizedResponse), + }; + + /// <summary> + /// The protocol versions supported by this channel. + /// </summary> + private static readonly Version[] Versions = Protocol.AllVersions.Select(v => v.Version).ToArray(); + + /// <summary> + /// Initializes a new instance of the <see cref="OAuth2ChannelBase"/> class. + /// </summary> + /// <param name="channelBindingElements">The channel binding elements.</param> + internal OAuth2ChannelBase(params IChannelBindingElement[] channelBindingElements) + : base(MessageTypes, Versions, channelBindingElements) { + } + } +} diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuth2ClientChannel.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuth2ClientChannel.cs new file mode 100644 index 0000000..ec1dd27 --- /dev/null +++ b/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuth2ClientChannel.cs @@ -0,0 +1,91 @@ +//----------------------------------------------------------------------- +// <copyright file="OAuth2ClientChannel.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth2.ChannelElements { + using System; + using System.Collections.Generic; + using System.Collections.Specialized; + using System.Diagnostics.Contracts; + using System.Net; + using System.Web; + + using DotNetOpenAuth.Messaging; + + internal class OAuth2ClientChannel : OAuth2ChannelBase { + /// <summary> + /// Initializes a new instance of the <see cref="OAuth2ClientChannel"/> class. + /// </summary> + internal OAuth2ClientChannel() { + } + + /// <summary> + /// Prepares an HTTP request that carries a given message. + /// </summary> + /// <param name="request">The message to send.</param> + /// <returns> + /// The <see cref="HttpWebRequest"/> prepared to send the request. + /// </returns> + /// <remarks> + /// This method must be overridden by a derived class, unless the <see cref="Channel.RequestCore"/> method + /// is overridden and does not require this method. + /// </remarks> + protected override HttpWebRequest CreateHttpRequest(IDirectedProtocolMessage request) { + HttpWebRequest httpRequest; + if ((request.HttpMethods & HttpDeliveryMethods.GetRequest) != 0) { + httpRequest = InitializeRequestAsGet(request); + } else if ((request.HttpMethods & HttpDeliveryMethods.PostRequest) != 0) { + httpRequest = InitializeRequestAsPost(request); + } else { + throw new NotSupportedException(); + } + + return httpRequest; + } + + protected override IDictionary<string, string> ReadFromResponseCore(IncomingWebResponse response) { + // The spec says direct responses should be JSON objects, but Facebook uses HttpFormUrlEncoded instead, calling it text/plain + string body = response.GetResponseReader().ReadToEnd(); + if (response.ContentType.MediaType == JsonEncoded) { + return this.DeserializeFromJson(body); + } else if (response.ContentType.MediaType == HttpFormUrlEncoded || response.ContentType.MediaType == PlainTextEncoded) { + return HttpUtility.ParseQueryString(body).ToDictionary(); + } else { + throw ErrorUtilities.ThrowProtocol("Unexpected response Content-Type {0}", response.ContentType.MediaType); + } + } + + protected override IDirectedProtocolMessage ReadFromRequestCore(HttpRequestInfo request) { + Logger.Channel.DebugFormat("Incoming HTTP request: {0} {1}", request.HttpMethod, request.UrlBeforeRewriting.AbsoluteUri); + + var fields = request.QueryStringBeforeRewriting.ToDictionary(); + + // Also read parameters from the fragment, if it's available. + // Typically the fragment is not available because the browser doesn't send it to a web server + // but this request may have been fabricated by an installed desktop app, in which case + // the fragment is available. + string fragment = request.UrlBeforeRewriting.Fragment; + if (fragment != null) { + foreach (var pair in HttpUtility.ParseQueryString(fragment.Substring(1)).ToDictionary()) { + fields.Add(pair.Key, pair.Value); + } + } + + MessageReceivingEndpoint recipient; + try { + recipient = request.GetRecipient(); + } catch (ArgumentException ex) { + Logger.Messaging.WarnFormat("Unrecognized HTTP request: ", ex); + return null; + } + + return (IDirectedProtocolMessage)this.Receive(fields, recipient); + } + + protected override OutgoingWebResponse PrepareDirectResponse(IProtocolMessage response) { + throw new NotImplementedException(); + } + } +} diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuthWrapResourceServerChannel.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuth2ResourceServerChannel.cs index 56cc359..60e464c 100644 --- a/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuthWrapResourceServerChannel.cs +++ b/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuth2ResourceServerChannel.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// <copyright file="OAuthWrapResourceServerChannel.cs" company="Andrew Arnott"> +// <copyright file="OAuth2ResourceServerChannel.cs" company="Andrew Arnott"> // Copyright (c) Andrew Arnott. All rights reserved. // </copyright> //----------------------------------------------------------------------- @@ -20,7 +20,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { /// <summary> /// The channel for the OAuth protocol. /// </summary> - internal class OAuthWrapResourceServerChannel : StandardMessageFactoryChannel { + internal class OAuth2ResourceServerChannel : StandardMessageFactoryChannel { /// <summary> /// The messages receivable by this channel. /// </summary> @@ -34,9 +34,9 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { private static readonly Version[] Versions = Protocol.AllVersions.Select(v => v.Version).ToArray(); /// <summary> - /// Initializes a new instance of the <see cref="OAuthWrapResourceServerChannel"/> class. + /// Initializes a new instance of the <see cref="OAuth2ResourceServerChannel"/> class. /// </summary> - protected internal OAuthWrapResourceServerChannel() + protected internal OAuth2ResourceServerChannel() : base(MessageTypes, Versions) { // TODO: add signing (authenticated request) binding element. } diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuthWrapAuthorizationServerChannel.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuthWrapAuthorizationServerChannel.cs deleted file mode 100644 index dd3d02c..0000000 --- a/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuthWrapAuthorizationServerChannel.cs +++ /dev/null @@ -1,170 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="OAuthWrapAuthorizationServerChannel.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuth2.ChannelElements { - using System; - using System.Collections.Generic; - using System.Diagnostics.Contracts; - using System.Linq; - using System.Net; - using System.Net.Mime; - using System.Runtime.Serialization.Json; - using System.Security.Cryptography; - using System.Text; - using System.Web; - using System.Web.Script.Serialization; - using DotNetOpenAuth.Messaging; - using DotNetOpenAuth.Messaging.Bindings; - using DotNetOpenAuth.Messaging.Reflection; - using DotNetOpenAuth.OAuth2.Messages; - - /// <summary> - /// The channel for the OAuth protocol. - /// </summary> - internal class OAuthWrapAuthorizationServerChannel : StandardMessageFactoryChannel { - /// <summary> - /// The messages receivable by this channel. - /// </summary> - private static readonly Type[] MessageTypes = new Type[] { - typeof(AccessTokenRefreshRequest), - typeof(AccessTokenAuthorizationCodeRequest), - typeof(AccessTokenBasicCredentialsRequest), - typeof(AccessTokenAssertionRequest), - typeof(AccessTokenClientCredentialsRequest), - typeof(AccessTokenSuccessResponse), - typeof(AccessTokenFailedResponse), - typeof(EndUserAuthorizationRequest), - typeof(EndUserAuthorizationSuccessResponse), - typeof(EndUserAuthorizationFailedResponse), - typeof(UnauthorizedResponse), - }; - - /// <summary> - /// The protocol versions supported by this channel. - /// </summary> - private static readonly Version[] Versions = Protocol.AllVersions.Select(v => v.Version).ToArray(); - - /// <summary> - /// Initializes a new instance of the <see cref="OAuthWrapAuthorizationServerChannel"/> class. - /// </summary> - /// <param name="authorizationServer">The authorization server.</param> - protected internal OAuthWrapAuthorizationServerChannel(IAuthorizationServer authorizationServer = null) - : base(MessageTypes, Versions, InitializeBindingElements(authorizationServer)) { - this.AuthorizationServer = authorizationServer; - } - - /// <summary> - /// Gets the authorization server. - /// </summary> - /// <value>The authorization server. Will be null for channels serving clients.</value> - public IAuthorizationServer AuthorizationServer { get; private set; } - - /// <summary> - /// Prepares an HTTP request that carries a given message. - /// </summary> - /// <param name="request">The message to send.</param> - /// <returns> - /// The <see cref="HttpWebRequest"/> prepared to send the request. - /// </returns> - /// <remarks> - /// This method must be overridden by a derived class, unless the <see cref="Channel.RequestCore"/> method - /// is overridden and does not require this method. - /// </remarks> - protected override HttpWebRequest CreateHttpRequest(IDirectedProtocolMessage request) { - HttpWebRequest httpRequest; - if ((request.HttpMethods & HttpDeliveryMethods.GetRequest) != 0) { - httpRequest = InitializeRequestAsGet(request); - } else if ((request.HttpMethods & HttpDeliveryMethods.PostRequest) != 0) { - httpRequest = InitializeRequestAsPost(request); - } else { - throw new NotSupportedException(); - } - - return httpRequest; - } - - /// <summary> - /// Gets the protocol message that may be in the given HTTP response. - /// </summary> - /// <param name="response">The response that is anticipated to contain an protocol message.</param> - /// <returns> - /// The deserialized message parts, if found. Null otherwise. - /// </returns> - /// <exception cref="ProtocolException">Thrown when the response is not valid.</exception> - protected override IDictionary<string, string> ReadFromResponseCore(IncomingWebResponse response) { - // The spec says direct responses should be JSON objects, but Facebook uses HttpFormUrlEncoded instead, calling it text/plain - string body = response.GetResponseReader().ReadToEnd(); - if (response.ContentType.MediaType == JsonEncoded) { - return this.DeserializeFromJson(body); - } else if (response.ContentType.MediaType == HttpFormUrlEncoded || response.ContentType.MediaType == PlainTextEncoded) { - return HttpUtility.ParseQueryString(body).ToDictionary(); - } else { - throw ErrorUtilities.ThrowProtocol("Unexpected response Content-Type {0}", response.ContentType.MediaType); - } - } - - /// <summary> - /// Queues a message for sending in the response stream. - /// </summary> - /// <param name="response">The message to send as a response.</param> - /// <returns> - /// The pending user agent redirect based message to be sent as an HttpResponse. - /// </returns> - /// <remarks> - /// This method implements spec OAuth V1.0 section 5.3. - /// </remarks> - protected override OutgoingWebResponse PrepareDirectResponse(IProtocolMessage response) { - var webResponse = new OutgoingWebResponse(); - string json = this.SerializeAsJson(response); - webResponse.SetResponse(json, new ContentType(JsonEncoded)); - return webResponse; - } - - /// <summary> - /// Gets the protocol message that may be embedded in the given HTTP request. - /// </summary> - /// <param name="request">The request to search for an embedded message.</param> - /// <returns> - /// The deserialized message, if one is found. Null otherwise. - /// </returns> - protected override IDirectedProtocolMessage ReadFromRequestCore(HttpRequestInfo request) { - if (!string.IsNullOrEmpty(request.Url.Fragment)) { - var fields = HttpUtility.ParseQueryString(request.Url.Fragment.Substring(1)).ToDictionary(); - - MessageReceivingEndpoint recipient; - try { - recipient = request.GetRecipient(); - } catch (ArgumentException ex) { - Logger.Messaging.WarnFormat("Unrecognized HTTP request: " + ex.ToString()); - return null; - } - - return (IDirectedProtocolMessage)this.Receive(fields, recipient); - } - - return base.ReadFromRequestCore(request); - } - - /// <summary> - /// Initializes the binding elements for the OAuth channel. - /// </summary> - /// <param name="authorizationServer">The authorization server.</param> - /// <returns> - /// An array of binding elements used to initialize the channel. - /// </returns> - private static IChannelBindingElement[] InitializeBindingElements(IAuthorizationServer authorizationServer) { - var bindingElements = new List<IChannelBindingElement>(); - - if (authorizationServer != null) { - bindingElements.Add(new AuthServerAllFlowsBindingElement()); - bindingElements.Add(new AuthorizationCodeBindingElement()); - bindingElements.Add(new AccessRequestBindingElement()); - } - - return bindingElements.ToArray(); - } - } -} diff --git a/src/DotNetOpenAuth/OAuth2/ClientBase.cs b/src/DotNetOpenAuth/OAuth2/ClientBase.cs index a63fab3..1c5e09d 100644 --- a/src/DotNetOpenAuth/OAuth2/ClientBase.cs +++ b/src/DotNetOpenAuth/OAuth2/ClientBase.cs @@ -29,7 +29,7 @@ namespace DotNetOpenAuth.OAuth2 { protected ClientBase(AuthorizationServerDescription authorizationServer, string clientIdentifier = null, string clientSecret = null) { Contract.Requires<ArgumentNullException>(authorizationServer != null); this.AuthorizationServer = authorizationServer; - this.Channel = new OAuthWrapAuthorizationServerChannel(); + this.Channel = new OAuth2ClientChannel(); this.ClientIdentifier = clientIdentifier; this.ClientSecret = clientSecret; } @@ -54,7 +54,7 @@ namespace DotNetOpenAuth.OAuth2 { /// <summary> /// Gets or sets the client secret shared with the Authorization Server. /// </summary> - public string ClientSecret { get; set; } + protected internal string ClientSecret { get; set; } /// <summary> /// Adds the necessary HTTP Authorization header to an HTTP request for protected resources diff --git a/src/DotNetOpenAuth/OAuth2/ResourceServer.cs b/src/DotNetOpenAuth/OAuth2/ResourceServer.cs index 5b14623..534f741 100644 --- a/src/DotNetOpenAuth/OAuth2/ResourceServer.cs +++ b/src/DotNetOpenAuth/OAuth2/ResourceServer.cs @@ -29,7 +29,7 @@ namespace DotNetOpenAuth.OAuth2 { Contract.Requires<ArgumentNullException>(accessTokenAnalyzer != null, "accessTokenAnalyzer"); this.AccessTokenAnalyzer = accessTokenAnalyzer; - this.Channel = new OAuthWrapResourceServerChannel(); + this.Channel = new OAuth2ResourceServerChannel(); } /// <summary> @@ -53,7 +53,7 @@ namespace DotNetOpenAuth.OAuth2 { /// Gets the channel. /// </summary> /// <value>The channel.</value> - internal OAuthWrapResourceServerChannel Channel { get; private set; } + internal OAuth2ResourceServerChannel Channel { get; private set; } /// <summary> /// Discovers what access the client should have considering the access token in the current request. diff --git a/src/DotNetOpenAuth/OAuth2/UserAgentClient.cs b/src/DotNetOpenAuth/OAuth2/UserAgentClient.cs index 6040764..fc96e77 100644 --- a/src/DotNetOpenAuth/OAuth2/UserAgentClient.cs +++ b/src/DotNetOpenAuth/OAuth2/UserAgentClient.cs @@ -24,8 +24,8 @@ namespace DotNetOpenAuth.OAuth2 { /// <param name="authorizationServer">The token issuer.</param> /// <param name="clientIdentifier">The client identifier.</param> /// <param name="clientSecret">The client secret.</param> - public UserAgentClient(AuthorizationServerDescription authorizationServer, string clientIdentifier = null, string clientSecret = null) - : base(authorizationServer, clientIdentifier, clientSecret) { + public UserAgentClient(AuthorizationServerDescription authorizationServer, string clientIdentifier = null) + : base(authorizationServer, clientIdentifier) { } /// <summary> @@ -66,6 +66,7 @@ namespace DotNetOpenAuth.OAuth2 { ClientIdentifier = this.ClientIdentifier, Scope = authorization.Scope, Callback = authorization.Callback, + ResponseType = EndUserAuthorizationResponseType.AccessToken, }; return this.Channel.PrepareResponse(request).GetDirectUriRequest(this.Channel); diff --git a/src/DotNetOpenAuth/OAuth2/WebServerClient.cs b/src/DotNetOpenAuth/OAuth2/WebServerClient.cs index 0c5a90f..e307405 100644 --- a/src/DotNetOpenAuth/OAuth2/WebServerClient.cs +++ b/src/DotNetOpenAuth/OAuth2/WebServerClient.cs @@ -30,6 +30,15 @@ namespace DotNetOpenAuth.OAuth2 { } /// <summary> + /// Gets or sets the client secret shared with the Authorization Server. + /// </summary> + /// <value></value> + public new string ClientSecret { + get { return base.ClientSecret; } + set { base.ClientSecret = value; } + } + + /// <summary> /// Gets or sets an optional component that gives you greater control to record and influence the authorization process. /// </summary> /// <value>The authorization tracker.</value> |