diff options
37 files changed, 499 insertions, 391 deletions
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj b/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj index 28c4ff4..c808070 100644 --- a/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj +++ b/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj @@ -68,6 +68,7 @@ <Reference Include="System.Core"> <RequiredTargetFramework>3.5</RequiredTargetFramework> </Reference> + <Reference Include="System.Web" /> <Reference Include="System.Xml.Linq"> <RequiredTargetFramework>3.5</RequiredTargetFramework> </Reference> @@ -81,8 +82,10 @@ <Compile Include="CustomExtensions\Acme.cs" /> <Compile Include="CustomExtensions\AcmeRequest.cs" /> <Compile Include="CustomExtensions\AcmeResponse.cs" /> + <Compile Include="FacebookClient.cs" /> <Compile Include="GoogleConsumer.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="TokenManager.cs" /> <Compile Include="TwitterConsumer.cs" /> <Compile Include="Util.cs" /> </ItemGroup> diff --git a/samples/DotNetOpenAuth.ApplicationBlock/FacebookClient.cs b/samples/DotNetOpenAuth.ApplicationBlock/FacebookClient.cs new file mode 100644 index 0000000..be4df21 --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/FacebookClient.cs @@ -0,0 +1,24 @@ +using System.Web; +using DotNetOpenAuth.OAuthWrap; + +namespace DotNetOpenAuth.ApplicationBlock { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + + public class FacebookClient : WebAppClient { + private static readonly AuthorizationServerDescription FacebookDescription = new AuthorizationServerDescription { + TokenEndpoint = new Uri("https://graph.facebook.com/oauth/access_token"), + AuthorizationEndpoint = new Uri("https://graph.facebook.com/oauth/authorize"), + }; + + /// <summary> + /// Initializes a new instance of the <see cref="FacebookClient"/> class. + /// </summary> + public FacebookClient() : base(FacebookDescription) { + this.TokenManager = new TokenManager(); + } + } +} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/TokenManager.cs b/samples/DotNetOpenAuth.ApplicationBlock/TokenManager.cs new file mode 100644 index 0000000..22099a3 --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/TokenManager.cs @@ -0,0 +1,18 @@ +//----------------------------------------------------------------------- +// <copyright file="TokenManager.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.ApplicationBlock { + using System; + using DotNetOpenAuth.OAuthWrap; + + public class TokenManager : IClientTokenManager { + public IAuthorizationState GetAuthorizationState(Uri callbackUrl, string clientState) { + return new AuthorizationState { + Callback = callbackUrl, + }; + } + } +} diff --git a/samples/OAuthConsumer/Facebook.aspx b/samples/OAuthConsumer/Facebook.aspx new file mode 100644 index 0000000..536540e --- /dev/null +++ b/samples/OAuthConsumer/Facebook.aspx @@ -0,0 +1,16 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Facebook.aspx.cs" Inherits="Facebook" %> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server"> + <div> + Welcome, + <asp:Label Text="[name]" ID="nameLabel" runat="server" /> + </div> + </form> +</body> +</html> diff --git a/samples/OAuthConsumer/Facebook.aspx.cs b/samples/OAuthConsumer/Facebook.aspx.cs new file mode 100644 index 0000000..ba08920 --- /dev/null +++ b/samples/OAuthConsumer/Facebook.aspx.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; +using DotNetOpenAuth.ApplicationBlock; +using DotNetOpenAuth.OAuthWrap; +using System.Net; +using System.IO; + +public partial class Facebook : System.Web.UI.Page { + private static readonly FacebookClient client = new FacebookClient { + ClientIdentifier = ConfigurationManager.AppSettings["facebookAppID"], + ClientSecret = ConfigurationManager.AppSettings["facebookAppSecret"], + }; + + protected void Page_Load(object sender, EventArgs e) + { + IAuthorizationState authorization = client.ProcessUserAuthorization(); + if (authorization == null) + { + // Kick off authorization request + client.Channel.Send(client.PrepareRequestUserAuthorization()); + } + else + { + var request = WebRequest.Create("https://graph.facebook.com/me?access_token=" + Uri.EscapeDataString(authorization.AccessToken)); + using (var response = request.GetResponse()) { + using (var responseReader = new StreamReader(response.GetResponseStream())) { + string data = responseReader.ReadToEnd(); + } + } + nameLabel.Text = "Success! Access token: " + HttpUtility.HtmlEncode(authorization.AccessToken); + } + } +}
\ No newline at end of file diff --git a/samples/OAuthConsumer/Web.config b/samples/OAuthConsumer/Web.config index 496da95..05eb6a8 100644 --- a/samples/OAuthConsumer/Web.config +++ b/samples/OAuthConsumer/Web.config @@ -50,6 +50,9 @@ <!-- Google sign-up: https://www.google.com/accounts/ManageDomains --> <add key="googleConsumerKey" value=""/> <add key="googleConsumerSecret" value=""/> + <!-- Facebook sign-up: http://developers.facebook.com/setup/ --> + <add key="facebookAppID" value=""/> + <add key="facebookAppSecret" value=""/> </appSettings> <connectionStrings/> diff --git a/src/DotNetOpenAuth.Test/OAuthWrap/MessageFactoryTests.cs b/src/DotNetOpenAuth.Test/OAuthWrap/MessageFactoryTests.cs index 6f8ad06..805e1e3 100644 --- a/src/DotNetOpenAuth.Test/OAuthWrap/MessageFactoryTests.cs +++ b/src/DotNetOpenAuth.Test/OAuthWrap/MessageFactoryTests.cs @@ -35,7 +35,7 @@ namespace DotNetOpenAuth.Test.OAuthWrap { [TestCase] public void RefreshAccessTokenRequest() { var fields = new Dictionary<string, string> { - { Protocol.wrap_refresh_token, "abc" }, + { Protocol.refresh_token, "abc" }, }; IDirectedProtocolMessage request = this.messageFactory.GetNewRequestMessage(this.recipient, fields); Assert.IsInstanceOf(typeof(RefreshAccessTokenRequest), request); @@ -44,11 +44,11 @@ namespace DotNetOpenAuth.Test.OAuthWrap { [TestCase] public void RefreshAccessTokenSuccessResponse() { var fields = new Dictionary<string, string> { - { Protocol.wrap_access_token, "abc" }, + { Protocol.access_token, "abc" }, }; var request = new RefreshAccessTokenRequest(this.recipient.Location, Protocol.Default.Version); Assert.IsInstanceOf( - typeof(RefreshAccessTokenSuccessResponse), + typeof(AccessTokenSuccessResponse), this.messageFactory.GetNewResponseMessage(request, fields)); } @@ -58,7 +58,7 @@ namespace DotNetOpenAuth.Test.OAuthWrap { }; var request = new RefreshAccessTokenRequest(this.recipient.Location, Protocol.Default.Version); Assert.IsInstanceOf( - typeof(RefreshAccessTokenFailedResponse), + typeof(AccessTokenFailedResponse), this.messageFactory.GetNewResponseMessage(request, fields)); } @@ -69,8 +69,8 @@ namespace DotNetOpenAuth.Test.OAuthWrap { [TestCase] public void WebAppRequestRequest() { var fields = new Dictionary<string, string> { - { Protocol.wrap_client_id, "abc" }, - { Protocol.wrap_callback, "abc" }, + { Protocol.client_id, "abc" }, + { Protocol.redirect_uri, "abc" }, }; IDirectedProtocolMessage request = this.messageFactory.GetNewRequestMessage(this.recipient, fields); Assert.IsInstanceOf(typeof(WebAppRequest), request); @@ -79,7 +79,7 @@ namespace DotNetOpenAuth.Test.OAuthWrap { [TestCase] public void WebAppFailedResponse() { var fields = new Dictionary<string, string> { - { Protocol.wrap_error_reason, "user_denied" }, + { Protocol.error, "user_denied" }, }; var request = new WebAppRequest(this.recipient.Location, Protocol.Default.Version); Assert.IsInstanceOf( @@ -90,7 +90,7 @@ namespace DotNetOpenAuth.Test.OAuthWrap { [TestCase] public void WebAppSuccessResponse() { var fields = new Dictionary<string, string> { - { Protocol.wrap_verification_code, "abc" }, + { Protocol.code, "abc" }, }; var request = new WebAppRequest(this.recipient.Location, Protocol.Default.Version); Assert.IsInstanceOf( @@ -101,10 +101,10 @@ namespace DotNetOpenAuth.Test.OAuthWrap { [TestCase] public void WebAppAccessTokenRequest() { var fields = new Dictionary<string, string> { - { Protocol.wrap_client_id, "abc" }, - { Protocol.wrap_client_secret, "abc" }, - { Protocol.wrap_verification_code, "abc" }, - { Protocol.wrap_callback, "abc" }, + { Protocol.client_id, "abc" }, + { Protocol.client_secret, "abc" }, + { Protocol.code, "abc" }, + { Protocol.redirect_uri, "abc" }, }; IDirectedProtocolMessage request = this.messageFactory.GetNewRequestMessage(this.recipient, fields); Assert.IsInstanceOf(typeof(WebAppAccessTokenRequest), request); @@ -121,18 +121,6 @@ namespace DotNetOpenAuth.Test.OAuthWrap { // WWW-Authenticate: WRAP } - [TestCase] - public void WebAppAccessTokenSuccessResponse() { - var fields = new Dictionary<string, string> { - { Protocol.wrap_refresh_token, "abc" }, - { Protocol.wrap_access_token, "abc" }, - }; - var request = new WebAppAccessTokenRequest(this.recipient.Location, Protocol.Default.Version); - Assert.IsInstanceOf( - typeof(WebAppAccessTokenSuccessResponse), - this.messageFactory.GetNewResponseMessage(request, fields)); - } - #endregion #region Username and Password profile messages @@ -140,7 +128,7 @@ namespace DotNetOpenAuth.Test.OAuthWrap { [TestCase] public void UserNamePasswordRequest() { var fields = new Dictionary<string, string> { - { Protocol.wrap_client_id, "abc" }, + { Protocol.client_id, "abc" }, { Protocol.wrap_username, "abc" }, { Protocol.wrap_password, "abc" }, }; @@ -151,7 +139,7 @@ namespace DotNetOpenAuth.Test.OAuthWrap { [TestCase] public void UserNamePasswordSuccessResponse() { var fields = new Dictionary<string, string> { - { Protocol.wrap_access_token, "abc" }, + { Protocol.access_token, "abc" }, }; var request = new UserNamePasswordRequest(this.recipient.Location, Protocol.Default.Version); Assert.IsInstanceOf( @@ -197,16 +185,16 @@ namespace DotNetOpenAuth.Test.OAuthWrap { public void RichAppRequest() { // include just required parameters var fields = new Dictionary<string, string> { - { Protocol.wrap_client_id, "abc" }, + { Protocol.client_id, "abc" }, }; IDirectedProtocolMessage request = this.messageFactory.GetNewRequestMessage(this.recipient, fields); Assert.IsInstanceOf(typeof(RichAppRequest), request); // including optional parts fields = new Dictionary<string, string> { - { Protocol.wrap_client_id, "abc" }, - { Protocol.wrap_callback, "abc" }, - { Protocol.wrap_client_state, "abc" }, + { Protocol.client_id, "abc" }, + { Protocol.redirect_uri, "abc" }, + { Protocol.state, "abc" }, { Protocol.wrap_scope, "abc" }, }; request = this.messageFactory.GetNewRequestMessage(this.recipient, fields); @@ -216,8 +204,8 @@ namespace DotNetOpenAuth.Test.OAuthWrap { [TestCase] public void RichAppResponse() { var fields = new Dictionary<string, string> { - { Protocol.wrap_refresh_token, "abc" }, - { Protocol.wrap_access_token, "abc" }, + { Protocol.refresh_token, "abc" }, + { Protocol.access_token, "abc" }, }; IDirectedProtocolMessage request = this.messageFactory.GetNewRequestMessage(this.recipient, fields); Assert.IsInstanceOf(typeof(RichAppResponse), request); @@ -227,8 +215,8 @@ namespace DotNetOpenAuth.Test.OAuthWrap { public void RichAppAccessTokenRequest() { // include just required parameters var fields = new Dictionary<string, string> { - { Protocol.wrap_client_id, "abc" }, - { Protocol.wrap_verification_code, "abc" }, + { Protocol.client_id, "abc" }, + { Protocol.code, "abc" }, }; IDirectedProtocolMessage request = this.messageFactory.GetNewRequestMessage(this.recipient, fields); Assert.IsInstanceOf(typeof(RichAppAccessTokenRequest), request); @@ -237,8 +225,8 @@ namespace DotNetOpenAuth.Test.OAuthWrap { [TestCase] public void RichAppAccessTokenSuccessResponse() { var fields = new Dictionary<string, string> { - { Protocol.wrap_refresh_token, "abc" }, - { Protocol.wrap_access_token, "abc" }, + { Protocol.refresh_token, "abc" }, + { Protocol.access_token, "abc" }, }; var request = new RichAppAccessTokenRequest(this.recipient.Location, Protocol.Default.Version); Assert.IsInstanceOf( @@ -275,8 +263,8 @@ namespace DotNetOpenAuth.Test.OAuthWrap { [TestCase] public void ClientAccountUsernamePasswordSuccessResponse() { var fields = new Dictionary<string, string> { - { Protocol.wrap_refresh_token, "abc" }, - { Protocol.wrap_access_token, "abc" }, + { Protocol.refresh_token, "abc" }, + { Protocol.access_token, "abc" }, }; var request = new ClientAccountUsernamePasswordRequest(this.recipient.Location, Protocol.Default.Version); Assert.IsInstanceOf( @@ -313,7 +301,7 @@ namespace DotNetOpenAuth.Test.OAuthWrap { [TestCase] public void AssertionSuccessResponse() { var fields = new Dictionary<string, string> { - { Protocol.wrap_access_token, "abc" }, + { Protocol.access_token, "abc" }, }; var request = new AssertionRequest(this.recipient.Location, Protocol.Default.Version); Assert.IsInstanceOf( diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj index 70f4ecc..292da82 100644 --- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj +++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj @@ -304,27 +304,26 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="Messaging\Reflection\IMessagePartNullEncoder.cs" /> <Compile Include="Messaging\Reflection\MessageDescriptionCollection.cs" /> <Compile Include="Messaging\StandardMessageFactory.cs" /> + <Compile Include="OAuthWrap\AuthorizationState.cs" /> <Compile Include="OAuthWrap\IClientTokenManager.cs" /> <Compile Include="OAuthWrap\Messages\Assertion\AssertionRequest.cs" /> <Compile Include="OAuthWrap\Messages\Assertion\AssertionFailedResponse.cs" /> - <Compile Include="OAuthWrap\Messages\ClientAccountAndPassword\ClientAccountUsernamePasswordFailedResponse.cs" /> - <Compile Include="OAuthWrap\Messages\ClientAccountAndPassword\ClientAccountUsernamePasswordRequest.cs" /> - <Compile Include="OAuthWrap\Messages\ClientAccountAndPassword\ClientAccountUsernamePasswordSuccessResponse.cs" /> + <Compile Include="OAuthWrap\Messages\ClientCredentials\ClientAccountUsernamePasswordFailedResponse.cs" /> + <Compile Include="OAuthWrap\Messages\ClientCredentials\ClientAccountUsernamePasswordRequest.cs" /> + <Compile Include="OAuthWrap\Messages\ClientCredentials\ClientAccountUsernamePasswordSuccessResponse.cs" /> <Compile Include="OAuthWrap\Messages\Assertion\AssertionSuccessResponse.cs" /> <Compile Include="OAuthWrap\Messages\IMessageWithClientState.cs" /> - <Compile Include="OAuthWrap\Messages\RichApp\RichAppAccessTokenRequest.cs" /> - <Compile Include="OAuthWrap\Messages\RichApp\RichAppRequest.cs" /> - <Compile Include="OAuthWrap\Messages\RichApp\RichAppResponse.cs" /> - <Compile Include="OAuthWrap\Messages\RichApp\RichAppAccessTokenSuccessResponse.cs" /> - <Compile Include="OAuthWrap\Messages\RichApp\RichAppAccessTokenFailedResponse.cs" /> - <Compile Include="OAuthWrap\Messages\UnauthorizedResponse.cs" /> - <Compile Include="OAuthWrap\Messages\RefreshAccessTokenFailedResponse.cs" /> - <Compile Include="OAuthWrap\Messages\RefreshAccessTokenSuccessResponse.cs" /> <Compile Include="OAuthWrap\Messages\RefreshAccessTokenRequest.cs" /> + <Compile Include="OAuthWrap\Messages\UserAgent\RichAppAccessTokenRequest.cs" /> + <Compile Include="OAuthWrap\Messages\UserAgent\RichAppRequest.cs" /> + <Compile Include="OAuthWrap\Messages\UserAgent\RichAppResponse.cs" /> + <Compile Include="OAuthWrap\Messages\UserAgent\RichAppAccessTokenSuccessResponse.cs" /> + <Compile Include="OAuthWrap\Messages\UserAgent\RichAppAccessTokenFailedResponse.cs" /> + <Compile Include="OAuthWrap\Messages\UnauthorizedResponse.cs" /> + <Compile Include="OAuthWrap\Messages\AccessTokenFailedResponse.cs" /> + <Compile Include="OAuthWrap\Messages\AccessTokenSuccessResponse.cs" /> <Compile Include="OAuthWrap\Messages\UsernameAndPassword\UserNamePasswordCaptchaResponse.cs" /> <Compile Include="OAuthWrap\Messages\UsernameAndPassword\UserNamePasswordVerificationResponse.cs" /> - <Compile Include="OAuthWrap\Messages\WebApp\WebAppAccessTokenBadClientResponse.cs" /> - <Compile Include="OAuthWrap\Messages\WebApp\WebAppAccessTokenFailedResponse.cs" /> <Compile Include="OAuthWrap\WrapUtilities.cs" /> <Compile Include="OAuth\ChannelElements\ICombinedOpenIdProviderTokenManager.cs" /> <Compile Include="OAuth\ChannelElements\IConsumerDescription.cs" /> @@ -612,12 +611,11 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="Reporting.cs" /> <Compile Include="OAuthWrap\ChannelElements\OAuthWrapChannel.cs" /> <Compile Include="OAuthWrap\ClientBase.cs" /> - <Compile Include="OAuthWrap\Messages\WebApp\WebAppAccessTokenSuccessResponse.cs" /> <Compile Include="OAuthWrap\Messages\MessageBase.cs" /> - <Compile Include="OAuthWrap\Messages\WebApp\WebAppAccessTokenRequest.cs" /> - <Compile Include="OAuthWrap\Messages\WebApp\WebAppFailedResponse.cs" /> - <Compile Include="OAuthWrap\Messages\WebApp\WebAppRequest.cs" /> - <Compile Include="OAuthWrap\Messages\WebApp\WebAppSuccessResponse.cs" /> + <Compile Include="OAuthWrap\Messages\WebServer\WebAppAccessTokenRequest.cs" /> + <Compile Include="OAuthWrap\Messages\WebServer\WebAppFailedResponse.cs" /> + <Compile Include="OAuthWrap\Messages\WebServer\WebAppRequest.cs" /> + <Compile Include="OAuthWrap\Messages\WebServer\WebAppSuccessResponse.cs" /> <Compile Include="OAuthWrap\Messages\UsernameAndPassword\UserNamePasswordFailedResponse.cs" /> <Compile Include="OAuthWrap\Messages\UsernameAndPassword\UserNamePasswordRequest.cs" /> <Compile Include="OAuthWrap\Messages\UsernameAndPassword\UserNamePasswordSuccessResponse.cs" /> @@ -775,31 +773,21 @@ http://opensource.org/licenses/ms-pl.html </BootstrapperPackage> <Content Include="DotNetOpenAuth.ico" /> </ItemGroup> - <ItemGroup> <SignDependsOn Include="BuildUnifiedProduct" /> - <DelaySignedAssemblies Include="$(ILMergeOutputAssembly); - $(OutputPath)$(ProductName).Contracts.dll; - " /> + <DelaySignedAssemblies Include="$(ILMergeOutputAssembly);
 $(OutputPath)$(ProductName).Contracts.dll;
 " /> + </ItemGroup> + <ItemGroup> + <Folder Include="OAuthWrap\Messages\Device\" /> </ItemGroup> - <PropertyGroup> - <!-- Don't sign the non-unified version of the assembly. --> - <SuppressTargetPathDelaySignedAssembly>true</SuppressTargetPathDelaySignedAssembly> - </PropertyGroup> - - <Target Name="BuildUnifiedProduct" - DependsOnTargets="Build" - Inputs="@(ILMergeInputAssemblies)" - Outputs="$(ILMergeOutputAssembly)"> + <PropertyGroup> + <!-- Don't sign the non-unified version of the assembly. --> + <SuppressTargetPathDelaySignedAssembly>true</SuppressTargetPathDelaySignedAssembly> + </PropertyGroup> + <Target Name="BuildUnifiedProduct" DependsOnTargets="Build" Inputs="@(ILMergeInputAssemblies)" Outputs="$(ILMergeOutputAssembly)"> <MakeDir Directories="$(ILMergeOutputAssemblyDirectory)" /> - <ILMerge ExcludeFile="$(ProjectRoot)ILMergeInternalizeExceptions.txt" - InputAssemblies="@(ILMergeInputAssemblies)" - OutputFile="$(ILMergeOutputAssembly)" - KeyFile="$(PublicKeyFile)" - DelaySign="true" - /> + <ILMerge ExcludeFile="$(ProjectRoot)ILMergeInternalizeExceptions.txt" InputAssemblies="@(ILMergeInputAssemblies)" OutputFile="$(ILMergeOutputAssembly)" KeyFile="$(PublicKeyFile)" DelaySign="true" /> </Target> - <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(ProjectRoot)tools\DotNetOpenAuth.targets" /> -</Project> +</Project>
\ No newline at end of file diff --git a/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerDescription.cs b/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerDescription.cs index c04cec0..93cc1e1 100644 --- a/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerDescription.cs +++ b/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerDescription.cs @@ -22,31 +22,29 @@ namespace DotNetOpenAuth.OAuthWrap { } /// <summary> - /// Gets or sets the Authorization Server URL at which an Access Token is requested by the Client. - /// A refresh token may also be returned to the Client. + /// Gets or sets the Authorization Server URL from which an Access Token is requested by the Client. /// </summary> /// <value>An HTTPS URL.</value> /// <remarks> - /// Messages sent to this URL must always be sent by the POST HTTP method. + /// <para>After obtaining authorization from the resource owner, clients request an access token from the authorization server's token endpoint.</para> + /// <para>The URI of the token endpoint can be found in the service documentation, or can be obtained by the client by making an unauthorized protected resource request (from the WWW-Authenticate response header token-uri (The 'authorization-uri' Attribute) attribute).</para> + /// <para>The token endpoint advertised by the resource server MAY include a query component as defined by [RFC3986] (Berners-Lee, T., Fielding, R., and L. Masinter, “Uniform Resource Identifier (URI): Generic Syntax,” January 2005.) section 3.</para> + /// <para>Since requests to the token endpoint result in the transmission of plain text credentials in the HTTP request and response, the authorization server MUST require the use of a transport-layer mechanism such as TLS/SSL (or a secure channel with equivalent protections) when sending requests to the token endpoints. </para> /// </remarks> - public Uri AccessTokenEndpoint { get; set; } - - /// <summary> - /// Gets or sets the Authorization Server URL at which a Refresh Token is presented in exchange - /// for a new Access Token. - /// </summary> - /// <value>An HTTPS URL.</value> - /// <remarks> - /// Messages sent to this URL must always be sent by the POST HTTP method. - /// </remarks> - public Uri RefreshTokenEndpoint { get; set; } + public Uri TokenEndpoint { get; set; } /// <summary> /// Gets or sets the Authorization Server URL where the Client (re)directs the User /// to make an authorization request. /// </summary> /// <value>An HTTP or HTTPS URL.</value> - public Uri UserAuthorizationEndpoint { get; set; } + /// <remarks> + /// <para>Clients direct the resource owner to the authorization endpoint to approve their access request. Before granting access, the resource owner first authenticates with the authorization server. The way in which the authorization server authenticates the end-user (e.g. username and password login, OpenID, session cookies) and in which the authorization server obtains the end-user's authorization, including whether it uses a secure channel such as TLS/SSL, is beyond the scope of this specification. However, the authorization server MUST first verify the identity of the end-user.</para> + /// <para>The URI of the authorization endpoint can be found in the service documentation, or can be obtained by the client by making an unauthorized protected resource request (from the WWW-Authenticate response header auth-uri (The 'authorization-uri' Attribute) attribute).</para> + /// <para>The authorization endpoint advertised by the resource server MAY include a query component as defined by [RFC3986] (Berners-Lee, T., Fielding, R., and L. Masinter, “Uniform Resource Identifier (URI): Generic Syntax,” January 2005.) section 3.</para> + /// <para>Since requests to the authorization endpoint result in user authentication and the transmission of sensitive values, the authorization server SHOULD require the use of a transport-layer mechanism such as TLS/SSL (or a secure channel with equivalent protections) when sending requests to the authorization endpoints.</para> + /// </remarks> + public Uri AuthorizationEndpoint { get; set; } /// <summary> /// Gets or sets the OAuth WRAP version supported by the Authorization Server. diff --git a/src/DotNetOpenAuth/OAuthWrap/AuthorizationState.cs b/src/DotNetOpenAuth/OAuthWrap/AuthorizationState.cs new file mode 100644 index 0000000..a19f523 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/AuthorizationState.cs @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------- +// <copyright file="AuthorizationState.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap { + using System; + + /// <summary> + /// A simple memory-only copy of an authorization state. + /// </summary> + public class AuthorizationState : IAuthorizationState { + /// <summary> + /// Initializes a new instance of the <see cref="AuthorizationState"/> class. + /// </summary> + public AuthorizationState() { + } + + public Uri Callback { get; set; } + + public string RefreshToken { get; set; } + + public string AccessToken { get; set; } + + public string AccessTokenSecret { get; set; } + + public DateTime? AccessTokenExpirationUtc { get; set; } + + public string Scope { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether this instance is deleted. + /// </summary> + /// <value> + /// <c>true</c> if this instance is deleted; otherwise, <c>false</c>. + /// </value> + public bool IsDeleted { get; set; } + + public void Delete() { + this.IsDeleted = true; + } + + public void SaveChanges() { + } + } +}
\ No newline at end of file diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapChannel.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapChannel.cs index 01ef028..fc1108f 100644 --- a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapChannel.cs +++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapChannel.cs @@ -81,8 +81,8 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements { var messageTypes = new Type[] { typeof(Messages.RefreshAccessTokenRequest), - typeof(Messages.RefreshAccessTokenSuccessResponse), - typeof(Messages.RefreshAccessTokenFailedResponse), + typeof(Messages.AccessTokenSuccessResponse), + typeof(Messages.AccessTokenFailedResponse), typeof(Messages.UnauthorizedResponse), typeof(Messages.AssertionRequest), typeof(Messages.AssertionSuccessResponse), @@ -104,9 +104,7 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements { typeof(Messages.WebAppSuccessResponse), typeof(Messages.WebAppFailedResponse), typeof(Messages.WebAppAccessTokenRequest), - typeof(Messages.WebAppAccessTokenSuccessResponse), - typeof(Messages.WebAppAccessTokenBadClientResponse), - typeof(Messages.WebAppAccessTokenFailedResponse), + typeof(Messages.RefreshAccessTokenRequest), }; // Get all the MessageDescription objects through the standard cache, diff --git a/src/DotNetOpenAuth/OAuthWrap/ClientBase.cs b/src/DotNetOpenAuth/OAuthWrap/ClientBase.cs index fefa005..e96b1f7 100644 --- a/src/DotNetOpenAuth/OAuthWrap/ClientBase.cs +++ b/src/DotNetOpenAuth/OAuthWrap/ClientBase.cs @@ -57,7 +57,7 @@ namespace DotNetOpenAuth.OAuthWrap { /// </summary> /// <param name="request">The request for protected resources from the service provider.</param> /// <param name="authorization">The authorization for this request previously obtained via OAuth WRAP.</param> - public static void AuthorizeRequest(HttpWebRequest request, IWrapAuthorization authorization) { + public static void AuthorizeRequest(HttpWebRequest request, IAuthorizationState authorization) { Contract.Requires<ArgumentNullException>(request != null); Contract.Requires<ArgumentNullException>(authorization != null); Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(authorization.AccessToken)); diff --git a/src/DotNetOpenAuth/OAuthWrap/IClientTokenManager.cs b/src/DotNetOpenAuth/OAuthWrap/IClientTokenManager.cs index 8627c4d..42b7e01 100644 --- a/src/DotNetOpenAuth/OAuthWrap/IClientTokenManager.cs +++ b/src/DotNetOpenAuth/OAuthWrap/IClientTokenManager.cs @@ -6,10 +6,7 @@ namespace DotNetOpenAuth.OAuthWrap { using System; - using System.Collections.Generic; using System.Diagnostics.Contracts; - using System.Linq; - using System.Text; [ContractClass(typeof(IClientTokenManagerContract))] public interface IClientTokenManager { @@ -19,7 +16,7 @@ namespace DotNetOpenAuth.OAuthWrap { /// <param name="callbackUrl">The callback URL.</param> /// <param name="clientState">State of the client stored at the beginning of an authorization request.</param> /// <returns>The authorization state; may be <c>null</c> if no authorization state matches.</returns> - IWrapAuthorization GetAuthorizationState(Uri callbackUrl, string clientState); + IAuthorizationState GetAuthorizationState(Uri callbackUrl, string clientState); } /// <summary> @@ -32,7 +29,7 @@ namespace DotNetOpenAuth.OAuthWrap { #region IClientTokenManager Members - IWrapAuthorization IClientTokenManager.GetAuthorizationState(Uri callbackUrl, string clientState) { + IAuthorizationState IClientTokenManager.GetAuthorizationState(Uri callbackUrl, string clientState) { Contract.Requires<ArgumentNullException>(callbackUrl != null); throw new NotImplementedException(); } @@ -43,7 +40,7 @@ namespace DotNetOpenAuth.OAuthWrap { /// <summary> /// Provides access to a persistent object that tracks the state of an authorization. /// </summary> - public interface IWrapAuthorization { + public interface IAuthorizationState { /// <summary> /// Gets or sets the callback URL used to obtain authorization. /// </summary> @@ -63,6 +60,12 @@ namespace DotNetOpenAuth.OAuthWrap { string AccessToken { get; set; } /// <summary> + /// Gets or sets the access token secret. + /// </summary> + /// <value>The access token secret.</value> + string AccessTokenSecret { get; set; } + + /// <summary> /// Gets or sets the access token UTC expiration date. /// </summary> DateTime? AccessTokenExpirationUtc { get; set; } @@ -74,7 +77,7 @@ namespace DotNetOpenAuth.OAuthWrap { string Scope { get; set; } /// <summary> - /// Deletes this authorization, including access token and refresh token were applicable. + /// Deletes this authorization, including access token and refresh token where applicable. /// </summary> /// <remarks> /// This method is invoked when an authorization attempt fails, is rejected, is revoked, or diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenFailedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenFailedResponse.cs index 5463791..9455d53 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenFailedResponse.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenFailedResponse.cs @@ -4,6 +4,8 @@ // </copyright> //----------------------------------------------------------------------- +using DotNetOpenAuth.Messaging; + namespace DotNetOpenAuth.OAuthWrap.Messages { /// <summary> /// A response from the Authorization Server to the Client to indicate that a @@ -13,13 +15,23 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// <remarks> /// This message type is shared by the Web App, Rich App, and Username/Password profiles. /// </remarks> - internal class RefreshAccessTokenFailedResponse : UnauthorizedResponse { + internal class AccessTokenFailedResponse : UnauthorizedResponse { /// <summary> - /// Initializes a new instance of the <see cref="RefreshAccessTokenFailedResponse"/> class. + /// Initializes a new instance of the <see cref="AccessTokenFailedResponse"/> class. /// </summary> /// <param name="request">The request.</param> - internal RefreshAccessTokenFailedResponse(RefreshAccessTokenRequest request) + internal AccessTokenFailedResponse(IDirectedProtocolMessage request) : base(request) { } + + /// <summary> + /// Gets or sets the error. + /// </summary> + /// <value>The error.</value> + /// <remarks> + /// REQUIRED. The parameter value MUST be set to one of the values specified by each flow. + /// </remarks> + [MessagePart(Protocol.error, IsRequired = true, AllowEmpty = false)] + internal string Error { get; set; } } } diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenSuccessResponse.cs new file mode 100644 index 0000000..ad59483 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenSuccessResponse.cs @@ -0,0 +1,84 @@ +//----------------------------------------------------------------------- +// <copyright file="AccessTokenSuccessResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +using System.Net; + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A response from the Authorization Server to the Consumer containing a delegation code + /// that the Consumer should use to obtain an access token. + /// </summary> + /// <remarks> + /// This message type is shared by the Web App, Rich App, and Username/Password profiles. + /// </remarks> + internal class AccessTokenSuccessResponse : MessageBase, IHttpDirectResponse { + /// <summary> + /// Initializes a new instance of the <see cref="AccessTokenSuccessResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal AccessTokenSuccessResponse(IDirectedProtocolMessage request) + : base(request) { + } + + /// <summary> + /// Gets or sets the access token. + /// </summary> + /// <value>The access token.</value> + [MessagePart(Protocol.access_token, IsRequired = true, AllowEmpty = false)] + internal string AccessToken { get; set; } + + /// <summary> + /// Gets or sets the lifetime of the access token. + /// </summary> + /// <value>The lifetime.</value> + [MessagePart(Protocol.expires_in, IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))] + internal TimeSpan? Lifetime { get; set; } + + /// <summary> + /// Gets or sets the refresh token. + /// </summary> + /// <value>The refresh token.</value> + /// <remarks> + /// OPTIONAL. The refresh token used to obtain new access tokens using the same end-user access grant as described in Section 6 (Refreshing an Access Token). + /// </remarks> + [MessagePart(Protocol.refresh_token, IsRequired = false, AllowEmpty = false)] + internal string RefreshToken { get; set; } + + /// <summary> + /// Gets or sets the access token secret. + /// </summary> + /// <value>The access token secret.</value> + /// <remarks> + /// REQUIRED if requested by the client. The corresponding access token secret as requested by the client. + /// </remarks> + [MessagePart(Protocol.access_token_secret, IsRequired = false, AllowEmpty = false)] + internal string AccessTokenSecret { get; set; } + + /// <summary> + /// Gets the HTTP status code that the direct response should be sent with. + /// </summary> + /// <value>HttpStatusCode.OK</value> + HttpStatusCode IHttpDirectResponse.HttpStatusCode { + get { return HttpStatusCode.OK; } + } + + /// <summary> + /// Gets the HTTP headers to add to the response. + /// </summary> + /// <value>May be an empty collection, but must not be <c>null</c>.</value> + WebHeaderCollection IHttpDirectResponse.Headers { + get { + return new WebHeaderCollection + { + { HttpResponseHeader.CacheControl, "no-store" }, + }; + } + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/Assertion/AssertionSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/Assertion/AssertionSuccessResponse.cs index f42e1f6..d1deaa9 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/Assertion/AssertionSuccessResponse.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/Assertion/AssertionSuccessResponse.cs @@ -27,14 +27,14 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// Gets or sets the access token. /// </summary> /// <value>The access token.</value> - [MessagePart(Protocol.wrap_access_token, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.access_token, IsRequired = true, AllowEmpty = false)] internal string AccessToken { get; set; } /// <summary> /// Gets or sets the lifetime of the access token. /// </summary> /// <value>The lifetime.</value> - [MessagePart(Protocol.wrap_access_token_expires_in, IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))] + [MessagePart(Protocol.expires_in, IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))] internal TimeSpan? Lifetime { get; set; } } } diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordFailedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/ClientCredentials/ClientAccountUsernamePasswordFailedResponse.cs index 57ce588..57ce588 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordFailedResponse.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/ClientCredentials/ClientAccountUsernamePasswordFailedResponse.cs diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/ClientCredentials/ClientAccountUsernamePasswordRequest.cs index 9f47c57..9f47c57 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordRequest.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/ClientCredentials/ClientAccountUsernamePasswordRequest.cs diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/ClientCredentials/ClientAccountUsernamePasswordSuccessResponse.cs index c53bdea..8bd6620 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordSuccessResponse.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/ClientCredentials/ClientAccountUsernamePasswordSuccessResponse.cs @@ -27,21 +27,21 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// Gets or sets the refresh token. /// </summary> /// <value>The token.</value> - [MessagePart(Protocol.wrap_refresh_token, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.refresh_token, IsRequired = true, AllowEmpty = false)] internal string RefreshToken { get; set; } /// <summary> /// Gets or sets the access token. /// </summary> /// <value>The access token.</value> - [MessagePart(Protocol.wrap_access_token, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.access_token, IsRequired = true, AllowEmpty = false)] internal string AccessToken { get; set; } /// <summary> /// Gets or sets the lifetime of the access token. /// </summary> /// <value>The lifetime.</value> - [MessagePart(Protocol.wrap_access_token_expires_in, IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))] + [MessagePart(Protocol.expires_in, IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))] internal TimeSpan? Lifetime { get; set; } } } diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenRequest.cs index a5de51a..b895f20 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenRequest.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenRequest.cs @@ -6,52 +6,57 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; using DotNetOpenAuth.Messaging; /// <summary> - /// A request from the client to the authorization server for a new access token - /// using a refresh token, after a previously supplied access token has expired. + /// A request from the client to the token endpoint for a new access token + /// in exchange for a refresh token that the client has previously obtained. /// </summary> - /// <remarks> - /// This message type is shared by the Web App, Rich App, and Username/Password profiles. - /// </remarks> internal class RefreshAccessTokenRequest : MessageBase { /// <summary> /// Initializes a new instance of the <see cref="RefreshAccessTokenRequest"/> class. /// </summary> - /// <param name="refreshTokenEndpoint">The authorization server's Refresh Token endpoint.</param> + /// <param name="tokenEndpoint">The token endpoint.</param> /// <param name="version">The version.</param> - internal RefreshAccessTokenRequest(Uri refreshTokenEndpoint, Version version) - : base(version, MessageTransport.Direct, refreshTokenEndpoint) { - this.HttpMethods = HttpDeliveryMethods.PostRequest; + internal RefreshAccessTokenRequest(Uri tokenEndpoint, Version version) + : base(version, MessageTransport.Direct, tokenEndpoint) { } /// <summary> - /// Gets or sets the refresh token that was received in - /// <see cref="UserNamePasswordSuccessResponse.RefreshToken"/>. + /// Gets or sets the identifier by which this client is known to the Authorization Server. + /// </summary> + /// <value>The client identifier.</value> + [MessagePart(Protocol.client_id, IsRequired = true, AllowEmpty = false)] + internal string ClientIdentifier { get; set; } + + /// <summary> + /// Gets or sets the client secret. + /// </summary> + /// <value>The client secret.</value> + /// <remarks> + /// REQUIRED if the client identifier has a matching secret. The client secret as described in Section 3.4 (Client Credentials). + /// </remarks> + [MessagePart(Protocol.client_secret, IsRequired = false, AllowEmpty = true)] + internal string ClientSecret { get; set; } + + /// <summary> + /// Gets or sets the refresh token. /// </summary> /// <value>The refresh token.</value> - [MessagePart(Protocol.wrap_refresh_token, IsRequired = true, AllowEmpty = false)] + /// <remarks> + /// REQUIRED. The refresh token associated with the access token to be refreshed. + /// </remarks> + [MessagePart(Protocol.refresh_token, IsRequired = true, AllowEmpty = false)] internal string RefreshToken { get; set; } /// <summary> - /// Checks the message state for conformity to the protocol specification - /// and throws an exception if the message is invalid. + /// Gets or sets the type of the secret. /// </summary> + /// <value>The type of the secret.</value> /// <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> + /// OPTIONAL. The access token secret type as described by Section 5.3 (Cryptographic Tokens Requests). If omitted, the authorization server will issue a bearer token (an access token without a matching secret) as described by Section 5.2 (Bearer Token Requests). /// </remarks> - /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception> - protected override void EnsureValidMessage() { - base.EnsureValidMessage(); - ErrorUtilities.VerifyProtocol(this.Recipient.IsTransportSecure(), OAuthWrapStrings.HttpsRequired); - } + [MessagePart(Protocol.secret_type, IsRequired = false, AllowEmpty = false)] + internal string SecretType { get; set; } } } diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenSuccessResponse.cs deleted file mode 100644 index 36a98e5..0000000 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenSuccessResponse.cs +++ /dev/null @@ -1,44 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="RefreshAccessTokenSuccessResponse.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuthWrap.Messages { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - using DotNetOpenAuth.Messaging; - - /// <summary> - /// A response from the Authorization Server to the Consumer containing a delegation code - /// that the Consumer should use to obtain an access token. - /// </summary> - /// <remarks> - /// This message type is shared by the Web App, Rich App, and Username/Password profiles. - /// </remarks> - internal class RefreshAccessTokenSuccessResponse : MessageBase { - /// <summary> - /// Initializes a new instance of the <see cref="RefreshAccessTokenSuccessResponse"/> class. - /// </summary> - /// <param name="request">The request.</param> - internal RefreshAccessTokenSuccessResponse(RefreshAccessTokenRequest request) - : base(request) { - } - - /// <summary> - /// Gets or sets the access token. - /// </summary> - /// <value>The access token.</value> - [MessagePart(Protocol.wrap_access_token, IsRequired = true, AllowEmpty = false)] - internal string AccessToken { get; set; } - - /// <summary> - /// Gets or sets the lifetime of the access token. - /// </summary> - /// <value>The lifetime.</value> - [MessagePart(Protocol.wrap_access_token_expires_in, IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))] - internal TimeSpan? Lifetime { get; set; } - } -} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenFailedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAgent/RichAppAccessTokenFailedResponse.cs index be4f001..be4f001 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenFailedResponse.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAgent/RichAppAccessTokenFailedResponse.cs diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAgent/RichAppAccessTokenRequest.cs index f0ad943..015ef54 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenRequest.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAgent/RichAppAccessTokenRequest.cs @@ -30,7 +30,7 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// Gets or sets the identifier by which this client is known to the Authorization Server. /// </summary> /// <value>The client identifier.</value> - [MessagePart(Protocol.wrap_client_id, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.client_id, IsRequired = true, AllowEmpty = false)] internal string ClientIdentifier { get; set; } /// <summary> @@ -38,7 +38,7 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// in <see cref="RichAppResponse.VerificationCode"/>. /// </summary> /// <value>The verification code.</value> - [MessagePart(Protocol.wrap_verification_code, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.code, IsRequired = true, AllowEmpty = false)] internal string VerificationCode { get; set; } /// <summary> diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAgent/RichAppAccessTokenSuccessResponse.cs index 8330176..17979e4 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenSuccessResponse.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAgent/RichAppAccessTokenSuccessResponse.cs @@ -25,21 +25,21 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// Gets or sets the refresh token. /// </summary> /// <value>The token.</value> - [MessagePart(Protocol.wrap_refresh_token, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.refresh_token, IsRequired = true, AllowEmpty = false)] internal string RefreshToken { get; set; } /// <summary> /// Gets or sets the access token. /// </summary> /// <value>The token.</value> - [MessagePart(Protocol.wrap_access_token, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.access_token, IsRequired = true, AllowEmpty = false)] internal string AccessToken { get; set; } /// <summary> /// Gets or sets the lifetime of the access token. /// </summary> /// <value>The lifetime.</value> - [MessagePart(Protocol.wrap_access_token_expires_in, IsRequired = false, AllowEmpty = false, Encoder = typeof(TimespanSecondsEncoder))] + [MessagePart(Protocol.expires_in, IsRequired = false, AllowEmpty = false, Encoder = typeof(TimespanSecondsEncoder))] internal TimeSpan? Lifetime { get; set; } } } diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAgent/RichAppRequest.cs index 9856687..49ded9a 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppRequest.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAgent/RichAppRequest.cs @@ -29,7 +29,7 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// Gets or sets the client identifier previously obtained from the Authorization Server. /// </summary> /// <value>The client identifier.</value> - [MessagePart(Protocol.wrap_client_id, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.client_id, IsRequired = true, AllowEmpty = false)] internal string ClientIdentifier { get; set; } /// <summary> @@ -43,7 +43,7 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// Authorization Servers MAY require that the wrap_callback URL match the previously /// registered value for the Client Identifier. /// </remarks> - [MessagePart(Protocol.wrap_callback, IsRequired = false, AllowEmpty = false)] + [MessagePart(Protocol.redirect_uri, IsRequired = false, AllowEmpty = false)] internal Uri Callback { get; set; } /// <summary> @@ -55,7 +55,7 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// <remarks> /// If this value is present, the Authorization Server MUST return it to the Client's Callback URL. /// </remarks> - [MessagePart(Protocol.wrap_client_state, IsRequired = false, AllowEmpty = true)] + [MessagePart(Protocol.state, IsRequired = false, AllowEmpty = true)] internal string ClientState { get; set; } /// <summary> diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAgent/RichAppResponse.cs index 678d956..48561cf 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppResponse.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAgent/RichAppResponse.cs @@ -32,7 +32,7 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// The long-lived credential assigned by the Authorization Server to this Client for /// use in accessing the authorizing user's protected resources. /// </value> - [MessagePart(Protocol.wrap_verification_code, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.code, IsRequired = true, AllowEmpty = false)] internal string VerificationCode { get; set; } /// <summary> @@ -44,7 +44,7 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// <remarks> /// This parameter is required if the Client included it in <see cref="RichAppRequest.ClientState"/>. /// </remarks> - [MessagePart(Protocol.wrap_client_state, IsRequired = false, AllowEmpty = true)] + [MessagePart(Protocol.state, IsRequired = false, AllowEmpty = true)] internal string ClientState { get; set; } /// <summary> diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordRequest.cs index b4a72ff..212611a 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordRequest.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordRequest.cs @@ -34,7 +34,7 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// Gets or sets the client identifier previously obtained from the Authorization Server. /// </summary> /// <value>The client identifier.</value> - [MessagePart(Protocol.wrap_client_id, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.client_id, IsRequired = true, AllowEmpty = false)] internal string ClientIdentifier { get; set; } /// <summary> diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordSuccessResponse.cs index 7afe7da..db3a7d2 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordSuccessResponse.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordSuccessResponse.cs @@ -31,21 +31,21 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// The long-lived credential assigned by the Authorization Server to this Client for /// use in accessing the authorizing user's protected resources. /// </value> - [MessagePart(Protocol.wrap_refresh_token, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.refresh_token, IsRequired = true, AllowEmpty = false)] internal string RefreshToken { get; set; } /// <summary> /// Gets or sets the access token. /// </summary> /// <value>The access token.</value> - [MessagePart(Protocol.wrap_access_token, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.access_token, IsRequired = true, AllowEmpty = false)] internal string AccessToken { get; set; } /// <summary> /// Gets or sets the lifetime of the access token. /// </summary> /// <value>The lifetime.</value> - [MessagePart(Protocol.wrap_access_token_expires_in, IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))] + [MessagePart(Protocol.expires_in, IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))] internal TimeSpan? Lifetime { get; set; } } } diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenBadClientResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenBadClientResponse.cs deleted file mode 100644 index 6758e93..0000000 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenBadClientResponse.cs +++ /dev/null @@ -1,22 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="WebAppAccessTokenBadClientResponse.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuthWrap.Messages { - /// <summary> - /// A response from the Authorization Server to the Client in the event - /// that the <see cref="WebAppAccessTokenRequest"/> message had an - /// invalid Client Identifier and Client Secret combination. - /// </summary> - internal class WebAppAccessTokenBadClientResponse : UnauthorizedResponse { - /// <summary> - /// Initializes a new instance of the <see cref="WebAppAccessTokenBadClientResponse"/> class. - /// </summary> - /// <param name="request">The request.</param> - internal WebAppAccessTokenBadClientResponse(WebAppAccessTokenRequest request) - : base(request) { - } - } -} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenFailedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenFailedResponse.cs deleted file mode 100644 index 7cdc2a9..0000000 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenFailedResponse.cs +++ /dev/null @@ -1,56 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="WebAppAccessTokenFailedResponse.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuthWrap.Messages { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Net; - using System.Text; - using DotNetOpenAuth.Messaging; - - /// <summary> - /// A response from the Authorization Server to the Client in the event - /// that the <see cref="WebAppAccessTokenRequest"/> message had an - /// invalid calback URL or verification code. - /// </summary> - internal class WebAppAccessTokenFailedResponse : MessageBase, IHttpDirectResponse { - /// <summary> - /// Initializes a new instance of the <see cref="WebAppAccessTokenFailedResponse"/> class. - /// </summary> - /// <param name="request">The request.</param> - internal WebAppAccessTokenFailedResponse(WebAppAccessTokenRequest request) - : base(request) { - } - - #region IHttpDirectResponse Members - - /// <summary> - /// Gets the HTTP status code that the direct response should be sent with. - /// </summary> - /// <value></value> - HttpStatusCode IHttpDirectResponse.HttpStatusCode { - get { return System.Net.HttpStatusCode.BadRequest; } - } - - /// <summary> - /// Gets the HTTP headers to add to the response. - /// </summary> - /// <value>May be an empty collection, but must not be <c>null</c>.</value> - WebHeaderCollection IHttpDirectResponse.Headers { - get { return new WebHeaderCollection(); } - } - - #endregion - - /// <summary> - /// Gets or sets the error reason. - /// </summary> - /// <value>"expired_verification_code" or "invalid_callback".</value> - [MessagePart(Protocol.wrap_error_reason, IsRequired = false, AllowEmpty = true)] - internal string ErrorReason { get; set; } - } -} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenSuccessResponse.cs deleted file mode 100644 index ec44712..0000000 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenSuccessResponse.cs +++ /dev/null @@ -1,45 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="WebAppAccessTokenSuccessResponse.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuthWrap.Messages { - using System; - using DotNetOpenAuth.Messaging; - - /// <summary> - /// The direct response message that contains the access token from the Authorization Server - /// to the Client. - /// </summary> - internal class WebAppAccessTokenSuccessResponse : MessageBase { - /// <summary> - /// Initializes a new instance of the <see cref="WebAppAccessTokenSuccessResponse"/> class. - /// </summary> - /// <param name="request">The request.</param> - internal WebAppAccessTokenSuccessResponse(WebAppAccessTokenRequest request) - : base(request) { - } - - /// <summary> - /// Gets or sets the refresh token. - /// </summary> - /// <value>The token.</value> - [MessagePart(Protocol.wrap_refresh_token, IsRequired = true, AllowEmpty = false)] - internal string RefreshToken { get; set; } - - /// <summary> - /// Gets or sets the access token. - /// </summary> - /// <value>The token.</value> - [MessagePart(Protocol.wrap_access_token, IsRequired = true, AllowEmpty = false)] - internal string AccessToken { get; set; } - - /// <summary> - /// Gets or sets the lifetime of the access token. - /// </summary> - /// <value>The lifetime.</value> - [MessagePart(Protocol.wrap_access_token_expires_in, IsRequired = false, AllowEmpty = false, Encoder = typeof(TimespanSecondsEncoder))] - internal TimeSpan? Lifetime { get; set; } - } -} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppAccessTokenRequest.cs index f64a0d2..de3ef40 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenRequest.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppAccessTokenRequest.cs @@ -19,6 +19,12 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// </remarks> internal class WebAppAccessTokenRequest : MessageBase { /// <summary> + /// The type of message. + /// </summary> + [MessagePart(Protocol.type, IsRequired = true)] + private const string Type = "web_server"; + + /// <summary> /// Initializes a new instance of the <see cref="WebAppAccessTokenRequest"/> class. /// </summary> /// <param name="accessTokenEndpoint">The Authorization Server's access token endpoint URL.</param> @@ -33,32 +39,35 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// </summary> /// <param name="authorizationServer">The authorization server.</param> internal WebAppAccessTokenRequest(AuthorizationServerDescription authorizationServer) - : this(authorizationServer.AccessTokenEndpoint, authorizationServer.Version) { + : this(authorizationServer.TokenEndpoint, authorizationServer.Version) { Contract.Requires<ArgumentNullException>(authorizationServer != null); Contract.Requires<ArgumentException>(authorizationServer.Version != null); - Contract.Requires<ArgumentException>(authorizationServer.AccessTokenEndpoint != null); + Contract.Requires<ArgumentException>(authorizationServer.TokenEndpoint != null); } /// <summary> /// Gets or sets the identifier by which this client is known to the Authorization Server. /// </summary> /// <value>The client identifier.</value> - [MessagePart(Protocol.wrap_client_id, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.client_id, IsRequired = true, AllowEmpty = false)] internal string ClientIdentifier { get; set; } /// <summary> /// Gets or sets the client secret. /// </summary> /// <value>The client secret.</value> - [MessagePart(Protocol.wrap_client_secret, IsRequired = true, AllowEmpty = false)] + /// <remarks> + /// REQUIRED if the client identifier has a matching secret. The client secret as described in Section 3.4 (Client Credentials). + /// </remarks> + [MessagePart(Protocol.client_secret, IsRequired = false, AllowEmpty = true)] internal string ClientSecret { get; set; } /// <summary> /// Gets or sets the verification code previously communicated to the Client /// in <see cref="WebAppSuccessResponse.VerificationCode"/>. /// </summary> - /// <value>The verification code.</value> - [MessagePart(Protocol.wrap_verification_code, IsRequired = true, AllowEmpty = false)] + /// <value>The verification code received from the authorization server.</value> + [MessagePart(Protocol.code, IsRequired = true, AllowEmpty = false)] internal string VerificationCode { get; set; } /// <summary> @@ -67,10 +76,20 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// <value> /// The Callback URL used to obtain the Verification Code. /// </value> - [MessagePart(Protocol.wrap_callback, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.redirect_uri, IsRequired = true, AllowEmpty = false)] internal Uri Callback { get; set; } /// <summary> + /// Gets or sets the type of the secret. + /// </summary> + /// <value>The type of the secret.</value> + /// <remarks> + /// OPTIONAL. The access token secret type as described by Section 5.3 (Cryptographic Tokens Requests). If omitted, the authorization server will issue a bearer token (an access token without a matching secret) as described by Section 5.2 (Bearer Token Requests). + /// </remarks> + [MessagePart(Protocol.secret_type, IsRequired = false, AllowEmpty = false)] + internal string SecretType { get; set; } + + /// <summary> /// Checks the message state for conformity to the protocol specification /// and throws an exception if the message is invalid. /// </summary> diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppFailedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppFailedResponse.cs index ea7b0b7..be00f52 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppFailedResponse.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppFailedResponse.cs @@ -18,7 +18,7 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// <summary> /// A constant parameter that indicates the user refused to grant the requested authorization. /// </summary> - [MessagePart(Protocol.wrap_error_reason, IsRequired = true)] + [MessagePart(Protocol.error, IsRequired = true)] private const string ErrorReason = Protocol.user_denied; /// <summary> @@ -41,7 +41,7 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// <remarks> /// If this value is present, the Authorization Server MUST return it to the Client's callback URL. /// </remarks> - [MessagePart(Protocol.wrap_client_state, IsRequired = false, AllowEmpty = true)] + [MessagePart(Protocol.state, IsRequired = false, AllowEmpty = true)] public string ClientState { get; set; } } } diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppRequest.cs index 229ebd4..d8338df 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppRequest.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppRequest.cs @@ -17,6 +17,12 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// </summary> public class WebAppRequest : MessageBase, IMessageWithClientState { /// <summary> + /// The type of message. + /// </summary> + [MessagePart(Protocol.type, IsRequired = true)] + private const string Type = "web_server"; + + /// <summary> /// Initializes a new instance of the <see cref="WebAppRequest"/> class. /// </summary> /// <param name="userAuthorizationEndpoint">The Authorization Server's user authorization URL to direct the user to.</param> @@ -32,10 +38,10 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// </summary> /// <param name="authorizationServer">The authorization server.</param> internal WebAppRequest(AuthorizationServerDescription authorizationServer) - : this(authorizationServer.UserAuthorizationEndpoint, authorizationServer.Version) { + : this(authorizationServer.AuthorizationEndpoint, authorizationServer.Version) { Contract.Requires<ArgumentNullException>(authorizationServer != null); Contract.Requires<ArgumentException>(authorizationServer.Version != null); - Contract.Requires<ArgumentException>(authorizationServer.UserAuthorizationEndpoint != null); + Contract.Requires<ArgumentException>(authorizationServer.AuthorizationEndpoint != null); } /// <summary> @@ -45,15 +51,15 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// An opaque value that Clients can use to maintain state associated with this request. /// </value> /// <remarks> - /// If this value is present, the Authorization Server MUST return it to the Client's Callback URL. + /// REQUIRED. The client identifier as described in Section 3.4 (Client Credentials). /// </remarks> - [MessagePart(Protocol.wrap_client_state, IsRequired = false, AllowEmpty = true)] + [MessagePart(Protocol.state, IsRequired = false, AllowEmpty = true)] public string ClientState { get; set; } /// <summary> /// Gets or sets the identifier by which this client is known to the Authorization Server. /// </summary> - [MessagePart(Protocol.wrap_client_id, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.client_id, IsRequired = true, AllowEmpty = false)] internal string ClientIdentifier { get; set; } /// <summary> @@ -64,17 +70,19 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// the user has approved the authorization request. /// </value> /// <remarks> - /// Authorization Servers MAY require that the wrap_callback URL match the previously - /// registered value for the Client Identifier. + /// REQUIRED unless a redirection URI has been established between the client and authorization server via other means. An absolute URI to which the authorization server will redirect the user-agent to when the end-user authorization step is completed. The authorization server MAY require the client to pre-register their redirection URI. The redirection URI MUST NOT include a query component as defined by [RFC3986] (Berners-Lee, T., Fielding, R., and L. Masinter, “Uniform Resource Identifier (URI): Generic Syntax,” January 2005.) section 3 if the state parameter is present. /// </remarks> - [MessagePart(Protocol.wrap_callback, IsRequired = true, AllowEmpty = false)] + [MessagePart(Protocol.redirect_uri, IsRequired = false, AllowEmpty = false)] internal Uri Callback { get; set; } /// <summary> - /// Gets or sets the scope. + /// Gets or sets a value indicating whether the authorization server is + /// required to redirect the browser back to the client immediately. /// </summary> - /// <value>The Authorization Server MAY define authorization scope values for the Client to include.</value> - [MessagePart(Protocol.wrap_scope, IsRequired = false, AllowEmpty = true)] - internal string Scope { get; set; } + /// <remarks> + /// OPTIONAL. The parameter value must be set to true or false. If set to true, the authorization server MUST NOT prompt the end-user to authenticate or approve access. Instead, the authorization server attempts to establish the end-user's identity via other means (e.g. browser cookies) and checks if the end-user has previously approved an identical access request by the same client and if that access grant is still active. If the authorization server does not support an immediate check or if it is unable to establish the end-user's identity or approval status, it MUST deny the request without prompting the end-user. Defaults to false if omitted. + /// </remarks> + [MessagePart(Protocol.immediate, IsRequired = false, AllowEmpty = false)] + internal bool Immediate { get; set; } } } diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppSuccessResponse.cs index 3bbc59e..abc99bb 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppSuccessResponse.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppSuccessResponse.cs @@ -33,7 +33,7 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// <remarks> /// REQUIRED if the Client sent the value in the <see cref="WebAppRequest"/>. /// </remarks> - [MessagePart(Protocol.wrap_client_state, IsRequired = false, AllowEmpty = true)] + [MessagePart(Protocol.state, IsRequired = false, AllowEmpty = true)] public string ClientState { get; set; } /// <summary> @@ -43,7 +43,7 @@ namespace DotNetOpenAuth.OAuthWrap.Messages { /// The long-lived credential assigned by the Authorization Server to this Consumer for /// use in accessing the authorizing user's protected resources. /// </value> - [MessagePart(Protocol.wrap_verification_code, IsRequired = true, AllowEmpty = true)] + [MessagePart(Protocol.code, IsRequired = true, AllowEmpty = true)] internal string VerificationCode { get; set; } } } diff --git a/src/DotNetOpenAuth/OAuthWrap/Protocol.cs b/src/DotNetOpenAuth/OAuthWrap/Protocol.cs index b8e3962..8882aea 100644 --- a/src/DotNetOpenAuth/OAuthWrap/Protocol.cs +++ b/src/DotNetOpenAuth/OAuthWrap/Protocol.cs @@ -14,9 +14,9 @@ namespace DotNetOpenAuth.OAuthWrap { /// </summary> public enum ProtocolVersion { /// <summary> - /// The OAuth WRAP 1.0 specification. + /// The OAuth 2.0 specification. /// </summary> - V10, + V20, } /// <summary> @@ -34,19 +34,24 @@ namespace DotNetOpenAuth.OAuthWrap { internal const string HttpAuthorizationHeaderFormat = "WRAP access_token=\"{0}\""; /// <summary> - /// The "wrap_client_state" string. + /// The "type" string. /// </summary> - internal const string wrap_client_state = "wrap_client_state"; + internal const string type = "type"; /// <summary> - /// The "wrap_callback" string. + /// The "state" string. /// </summary> - internal const string wrap_callback = "wrap_callback"; + internal const string state = "state"; /// <summary> - /// The "wrap_client_id" string. + /// The "redirect_uri" string. /// </summary> - internal const string wrap_client_id = "wrap_client_id"; + internal const string redirect_uri = "redirect_uri"; + + /// <summary> + /// The "client_id" string. + /// </summary> + internal const string client_id = "client_id"; /// <summary> /// The "wrap_scope" string. @@ -54,14 +59,19 @@ namespace DotNetOpenAuth.OAuthWrap { internal const string wrap_scope = "wrap_scope"; /// <summary> - /// The "wrap_client_secret" string. + /// The "immediate" string. + /// </summary> + internal const string immediate = "immediate"; + + /// <summary> + /// The "client_secret" string. /// </summary> - internal const string wrap_client_secret = "wrap_client_secret"; + internal const string client_secret = "client_secret"; /// <summary> /// The "wrap_verification_code" string. /// </summary> - internal const string wrap_verification_code = "wrap_verification_code"; + internal const string code = "code"; /// <summary> /// The "wrap_verification_url" string. @@ -69,24 +79,29 @@ namespace DotNetOpenAuth.OAuthWrap { internal const string wrap_verification_url = "wrap_verification_url"; /// <summary> - /// The "wrap_error_reason" string. + /// The "error" string. /// </summary> - internal const string wrap_error_reason = "wrap_error_reason"; + internal const string error = "error"; /// <summary> - /// The "wrap_access_token" string. + /// The "access_token" string. /// </summary> - internal const string wrap_access_token = "wrap_access_token"; + internal const string access_token = "access_token"; /// <summary> - /// The "wrap_refresh_token" string. + /// The "access_token_secret" string. /// </summary> - internal const string wrap_refresh_token = "wrap_refresh_token"; + internal const string access_token_secret = "access_token_secret"; /// <summary> - /// The "wrap_access_token_expires_in" string. + /// The "refresh_token" string. /// </summary> - internal const string wrap_access_token_expires_in = "wrap_access_token_expires_in"; + internal const string refresh_token = "refresh_token"; + + /// <summary> + /// The "expires_in" string. + /// </summary> + internal const string expires_in = "expires_in"; /// <summary> /// The "expired_delegation_code" string. @@ -144,17 +159,22 @@ namespace DotNetOpenAuth.OAuthWrap { internal const string user_denied = "user_denied"; /// <summary> + /// The "secret_type" string. + /// </summary> + internal const string secret_type = "secret_type"; + + /// <summary> /// Gets the <see cref="Protocol"/> instance with values initialized for V1.0 of the protocol. /// </summary> - internal static readonly Protocol V10 = new Protocol { - Version = new Version(1, 0), - ProtocolVersion = ProtocolVersion.V10, + internal static readonly Protocol V20 = new Protocol { + Version = new Version(2, 0), + ProtocolVersion = ProtocolVersion.V20, }; /// <summary> /// A list of all supported OAuth versions, in order starting from newest version. /// </summary> - internal static readonly List<Protocol> AllVersions = new List<Protocol>() { V10 }; + internal static readonly List<Protocol> AllVersions = new List<Protocol>() { V20 }; /// <summary> /// The default (or most recent) supported version of the OpenID protocol. @@ -180,7 +200,7 @@ namespace DotNetOpenAuth.OAuthWrap { /// <returns>A matching <see cref="Protocol"/> instance.</returns> public static Protocol Lookup(ProtocolVersion version) { switch (version) { - case ProtocolVersion.V10: return Protocol.V10; + case ProtocolVersion.V20: return Protocol.V20; default: throw new ArgumentOutOfRangeException("version"); } } diff --git a/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs b/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs index d0ebb09..83bf48b 100644 --- a/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs +++ b/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs @@ -4,6 +4,8 @@ // </copyright> //----------------------------------------------------------------------- +using System.Net; + namespace DotNetOpenAuth.OAuthWrap { using System; using System.Collections.Generic; @@ -38,66 +40,67 @@ namespace DotNetOpenAuth.OAuthWrap { public IClientTokenManager TokenManager { get; set; } - public WebAppRequest PrepareRequestUserAuthorization(IWrapAuthorization authorizationState) { - Contract.Requires<ArgumentNullException>(authorizationState != null); - Contract.Requires<InvalidOperationException>(authorizationState.Callback != null || (HttpContext.Current != null && HttpContext.Current.Request != null), MessagingStrings.HttpContextRequired); + public WebAppRequest PrepareRequestUserAuthorization() { + return PrepareRequestUserAuthorization(new AuthorizationState()); + } + + public WebAppRequest PrepareRequestUserAuthorization(IAuthorizationState authorization) { + Contract.Requires<ArgumentNullException>(authorization != null); + Contract.Requires<InvalidOperationException>(authorization.Callback != null || (HttpContext.Current != null && HttpContext.Current.Request != null), MessagingStrings.HttpContextRequired); Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(this.ClientIdentifier)); Contract.Ensures(Contract.Result<WebAppRequest>() != null); - Contract.Ensures(Contract.Result<WebAppRequest>().Callback == authorizationState.Callback); Contract.Ensures(Contract.Result<WebAppRequest>().ClientIdentifier == this.ClientIdentifier); + Contract.Ensures(Contract.Result<WebAppRequest>().Callback == authorization.Callback); - if (authorizationState.Callback == null) { - authorizationState.Callback = this.Channel.GetRequestFromContext().UrlBeforeRewriting; - authorizationState.SaveChanges(); + if (authorization.Callback == null) { + authorization.Callback = this.Channel.GetRequestFromContext().UrlBeforeRewriting; + authorization.SaveChanges(); } var request = new WebAppRequest(this.AuthorizationServer) { ClientIdentifier = this.ClientIdentifier, - Callback = authorizationState.Callback, - Scope = authorizationState.Scope, + Callback = authorization.Callback, }; return request; } - public IWrapAuthorization ProcessUserAuthorization() { + public IAuthorizationState ProcessUserAuthorization() { Contract.Requires<InvalidOperationException>(HttpContext.Current != null && HttpContext.Current.Request != null, MessagingStrings.HttpContextRequired); return this.ProcessUserAuthorization(this.Channel.GetRequestFromContext()); } - public IWrapAuthorization ProcessUserAuthorization(HttpRequestInfo request) { + public IAuthorizationState ProcessUserAuthorization(HttpRequestInfo request) { Contract.Requires<ArgumentNullException>(request != null); Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(this.ClientIdentifier)); Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(this.ClientSecret)); + var response = this.Channel.ReadFromRequest<IMessageWithClientState>(request); if (response != null) { - IWrapAuthorization authorizationState = this.TokenManager.GetAuthorizationState(request.UrlBeforeRewriting, response.ClientState); - ErrorUtilities.VerifyProtocol(authorizationState != null, "Unexpected OAuth WRAP authorization response received with callback and client state that does not match an expected value."); + IAuthorizationState authorizationState = this.TokenManager.GetAuthorizationState(request.UrlBeforeRewriting, response.ClientState); + ErrorUtilities.VerifyProtocol(authorizationState != null, "Unexpected OAuth authorization response received with callback and client state that does not match an expected value."); var success = response as WebAppSuccessResponse; var failure = response as WebAppFailedResponse; ErrorUtilities.VerifyProtocol(success != null || failure != null, MessagingStrings.UnexpectedMessageReceivedOfMany); if (success != null) { var accessTokenRequest = new WebAppAccessTokenRequest(this.AuthorizationServer) { - ClientSecret = this.ClientSecret, ClientIdentifier = this.ClientIdentifier, + ClientSecret = this.ClientSecret, Callback = authorizationState.Callback, VerificationCode = success.VerificationCode, }; IProtocolMessage accessTokenResponse = this.Channel.Request(accessTokenRequest); - var accessTokenSuccess = accessTokenResponse as WebAppAccessTokenSuccessResponse; - var badClientAccessTokenResponse = accessTokenResponse as WebAppAccessTokenBadClientResponse; - var failedAccessTokenResponse = accessTokenResponse as WebAppAccessTokenFailedResponse; + var accessTokenSuccess = accessTokenResponse as AccessTokenSuccessResponse; + var failedAccessTokenResponse = accessTokenResponse as AccessTokenFailedResponse; if (accessTokenSuccess != null) { authorizationState.AccessToken = accessTokenSuccess.AccessToken; + authorizationState.AccessTokenSecret = accessTokenSuccess.AccessTokenSecret; authorizationState.RefreshToken = accessTokenSuccess.RefreshToken; authorizationState.AccessTokenExpirationUtc = DateTime.UtcNow + accessTokenSuccess.Lifetime; authorizationState.SaveChanges(); - } else if (badClientAccessTokenResponse != null) { - authorizationState.Delete(); - ErrorUtilities.ThrowProtocol(OAuthWrapStrings.InvalidClientCredentials); - } else { // failedAccessTokenResponse != null + } else { authorizationState.Delete(); - ErrorUtilities.ThrowProtocol(OAuthWrapStrings.CannotObtainAccessTokenWithReason, failedAccessTokenResponse.ErrorReason); + ErrorUtilities.ThrowProtocol(OAuthWrapStrings.CannotObtainAccessTokenWithReason, failedAccessTokenResponse.Error); } } else { // failure Logger.Wrap.Info("User refused to grant the requested authorization at the Authorization Server."); |