diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2010-07-03 21:55:07 -0700 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2010-07-03 21:55:07 -0700 |
commit | 43f5260542eb1b1b15c7f46f95c6034e8796d20e (patch) | |
tree | fb61b6aacadadabf5b0f068e62ca3b2d32342f64 | |
parent | 44702bffda183696c367de01eaf364912bcd96a8 (diff) | |
download | DotNetOpenAuth-43f5260542eb1b1b15c7f46f95c6034e8796d20e.zip DotNetOpenAuth-43f5260542eb1b1b15c7f46f95c6034e8796d20e.tar.gz DotNetOpenAuth-43f5260542eb1b1b15c7f46f95c6034e8796d20e.tar.bz2 |
Lots more work toward OAuth 2.0 draft 09 compliance.
Still doesn't compile.
20 files changed, 216 insertions, 78 deletions
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj index 6dbc3a0..20749dd 100644 --- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj +++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj @@ -323,7 +323,7 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="OAuth2\ChannelElements\RefreshToken.cs" /> <Compile Include="OAuth2\ChannelElements\DataBag.cs" /> <Compile Include="OAuth2\ChannelElements\TimestampEncoder.cs" /> - <Compile Include="OAuth2\ChannelElements\VerificationCode.cs" /> + <Compile Include="OAuth2\ChannelElements\AuthorizationCode.cs" /> <Compile Include="OAuth2\ChannelElements\WebServerVerificationCodeBindingElement.cs" /> <Compile Include="OAuth2\ChannelElements\AuthServerAllFlowsBindingElement.cs" /> <Compile Include="OAuth2\IAccessTokenAnalyzer.cs" /> @@ -337,9 +337,11 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="OAuth2\Messages\AccessTokenBasicCredentialsRequest.cs" /> <Compile Include="OAuth2\Messages\AccessTokenRequestBase.cs" /> <Compile Include="OAuth2\Messages\AccessTokenClientCredentialsRequest.cs" /> + <Compile Include="OAuth2\Messages\EndUserAuthorizationFailedResponse.cs" /> <Compile Include="OAuth2\Messages\GrantType.cs" /> <Compile Include="OAuth2\Messages\AccessTokenRefreshRequest.cs" /> <Compile Include="OAuth2\Messages\EndUserAuthorizationResponseType.cs" /> + <Compile Include="OAuth2\Messages\IMessageWithClientState.cs" /> <Compile Include="OAuth2\Messages\UnauthorizedResponse.cs" /> <Compile Include="OAuth2\Messages\AccessTokenFailedResponse.cs" /> <Compile Include="OAuth2\Messages\AccessTokenSuccessResponse.cs" /> diff --git a/src/DotNetOpenAuth/OAuth2/AuthorizationServerBase.cs b/src/DotNetOpenAuth/OAuth2/AuthorizationServerBase.cs index 84e4604..b23ca9d 100644 --- a/src/DotNetOpenAuth/OAuth2/AuthorizationServerBase.cs +++ b/src/DotNetOpenAuth/OAuth2/AuthorizationServerBase.cs @@ -58,7 +58,7 @@ namespace DotNetOpenAuth.OAuth2 { /// <param name="accessTokenLifetime">The access token's lifetime.</param> /// <param name="includeRefreshToken">If set to <c>true</c>, the response will include a long-lived refresh token.</param> /// <returns>The response message to send to the client.</returns> - public virtual IDirectResponseProtocolMessage PrepareAccessTokenResponse(IAccessTokenRequest request, RSAParameters accessTokenEncryptingPublicKey, TimeSpan? accessTokenLifetime = null, bool includeRefreshToken = true) { + public virtual IDirectResponseProtocolMessage PrepareAccessTokenResponse(AccessTokenRequestBase request, RSAParameters accessTokenEncryptingPublicKey, TimeSpan? accessTokenLifetime = null, bool includeRefreshToken = true) { Contract.Requires<ArgumentNullException>(request != null, "request"); var tokenRequest = (ITokenCarryingRequest)request; diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/AccessRequestBindingElement.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/AccessRequestBindingElement.cs index 45e0fd4..b71b66d 100644 --- a/src/DotNetOpenAuth/OAuth2/ChannelElements/AccessRequestBindingElement.cs +++ b/src/DotNetOpenAuth/OAuth2/ChannelElements/AccessRequestBindingElement.cs @@ -11,6 +11,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { using System.Text; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.Messaging.Bindings; + using DotNetOpenAuth.OAuth2.Messages; /// <summary> /// Decodes verification codes, refresh tokens and access tokens on incoming messages. @@ -53,9 +54,9 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { public override MessageProtections? ProcessOutgoingMessage(IProtocolMessage message) { var tokenRequest = message as ITokenCarryingRequest; if (tokenRequest != null) { - ErrorUtilities.VerifyInternal(tokenRequest.CodeOrTokenType == CodeOrTokenType.VerificationCode, "Only verification codes are expected here."); - var tokenBag = (VerificationCode)tokenRequest.AuthorizationDescription; - var formatter = VerificationCode.CreateFormatter(this.AuthorizationServer); + ErrorUtilities.VerifyInternal(tokenRequest.CodeOrTokenType == CodeOrTokenType.AuthorizationCode, "Only verification codes are expected here."); + var tokenBag = (AuthorizationCode)tokenRequest.AuthorizationDescription; + var formatter = AuthorizationCode.CreateFormatter(this.AuthorizationServer); tokenRequest.CodeOrToken = formatter.Serialize(tokenBag); return MessageProtections.None; @@ -86,8 +87,8 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { if (tokenRequest != null) { try { switch (tokenRequest.CodeOrTokenType) { - case CodeOrTokenType.VerificationCode: - var verificationCodeFormatter = VerificationCode.CreateFormatter(this.AuthorizationServer); + case CodeOrTokenType.AuthorizationCode: + var verificationCodeFormatter = AuthorizationCode.CreateFormatter(this.AuthorizationServer); var verificationCode = verificationCodeFormatter.Deserialize(message, tokenRequest.CodeOrToken); tokenRequest.AuthorizationDescription = verificationCode; break; @@ -103,7 +104,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { throw ErrorUtilities.Wrap(ex, Protocol.authorization_expired); } - var accessRequest = tokenRequest as IAccessTokenRequest; + var accessRequest = tokenRequest as AccessTokenRequestBase; if (accessRequest != null) { // Make sure the client sending us this token is the client we issued the token to. ErrorUtilities.VerifyProtocol(string.Equals(accessRequest.ClientIdentifier, tokenRequest.AuthorizationDescription.ClientIdentifier, StringComparison.Ordinal), Protocol.incorrect_client_credentials); diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/VerificationCode.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/AuthorizationCode.cs index b920c2c..04f83ac 100644 --- a/src/DotNetOpenAuth/OAuth2/ChannelElements/VerificationCode.cs +++ b/src/DotNetOpenAuth/OAuth2/ChannelElements/AuthorizationCode.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// <copyright file="VerificationCode.cs" company="Andrew Arnott"> +// <copyright file="AuthorizationCode.cs" company="Andrew Arnott"> // Copyright (c) Andrew Arnott. All rights reserved. // </copyright> //----------------------------------------------------------------------- @@ -13,29 +13,29 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { using DotNetOpenAuth.Messaging.Bindings; /// <summary> - /// Represents the verification code created when a user approves authorization that + /// Represents the authorization code created when a user approves authorization that /// allows the client to request an access/refresh token. /// </summary> - internal class VerificationCode : AuthorizationDataBag { + internal class AuthorizationCode : AuthorizationDataBag { /// <summary> /// The hash algorithm used on the callback URI. /// </summary> private readonly HashAlgorithm hasher = new SHA256Managed(); /// <summary> - /// Initializes a new instance of the <see cref="VerificationCode"/> class. + /// Initializes a new instance of the <see cref="AuthorizationCode"/> class. /// </summary> - public VerificationCode() { + public AuthorizationCode() { } /// <summary> - /// Initializes a new instance of the <see cref="VerificationCode"/> class. + /// Initializes a new instance of the <see cref="AuthorizationCode"/> class. /// </summary> /// <param name="clientIdentifier">The client identifier.</param> /// <param name="callback">The callback the client used to obtain authorization.</param> /// <param name="scope">The scope.</param> /// <param name="username">The name on the account that authorized access.</param> - internal VerificationCode(string clientIdentifier, Uri callback, string scope, string username) { + internal AuthorizationCode(string clientIdentifier, Uri callback, string scope, string username) { Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(clientIdentifier)); Contract.Requires<ArgumentNullException>(callback != null, "callback"); @@ -51,11 +51,11 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { [MessagePart("cb")] private byte[] CallbackHash { get; set; } - internal static IDataBagFormatter<VerificationCode> CreateFormatter(IAuthorizationServer authorizationServer) { + internal static IDataBagFormatter<AuthorizationCode> CreateFormatter(IAuthorizationServer authorizationServer) { Contract.Requires<ArgumentNullException>(authorizationServer != null, "authorizationServer"); - Contract.Ensures(Contract.Result<IDataBagFormatter<VerificationCode>>() != null); + Contract.Ensures(Contract.Result<IDataBagFormatter<AuthorizationCode>>() != null); - return new UriStyleMessageFormatter<VerificationCode>( + return new UriStyleMessageFormatter<AuthorizationCode>( authorizationServer.Secret, true, true, diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuthWrapAuthorizationServerChannel.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuthWrapAuthorizationServerChannel.cs index ecc2cb3..6547b8b 100644 --- a/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuthWrapAuthorizationServerChannel.cs +++ b/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuthWrapAuthorizationServerChannel.cs @@ -29,27 +29,17 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { /// The messages receivable by this channel. /// </summary> private static readonly Type[] MessageTypes = new Type[] { - typeof(Messages.RefreshAccessTokenRequest), - typeof(Messages.AccessTokenSuccessResponse), - typeof(Messages.AccessTokenFailedResponse), - typeof(Messages.UnauthorizedResponse), - typeof(Messages.AssertionRequest), - typeof(Messages.ClientCredentialsRequest), - typeof(Messages.DeviceRequest), - typeof(Messages.DeviceResponse), - typeof(Messages.DeviceAccessTokenRequest), - typeof(Messages.UserNamePasswordRequest), - typeof(Messages.UserNamePasswordSuccessResponse), - typeof(Messages.UserNamePasswordVerificationResponse), - typeof(Messages.UserNamePasswordFailedResponse), - typeof(Messages.UsernamePasswordCaptchaResponse), - typeof(Messages.WebServerRequest), - typeof(Messages.WebServerSuccessResponse), - typeof(Messages.WebServerFailedResponse), - typeof(Messages.WebServerAccessTokenRequest), - typeof(Messages.UserAgentRequest), - typeof(Messages.UserAgentSuccessResponse), - typeof(Messages.UserAgentFailedResponse), + typeof(AccessTokenRefreshRequest), + typeof(AccessTokenAuthorizationCodeRequest), + typeof(AccessTokenBasicCredentialsRequest), + typeof(AccessTokenAssertionRequest), + typeof(AccessTokenClientCredentialsRequest), + typeof(AccessTokenSuccessResponse), + typeof(AccessTokenFailedResponse), + typeof(EndUserAuthorizationRequest), + typeof(EndUserAuthorizationSuccessResponse), + typeof(EndUserAuthorizationFailedResponse), + typeof(UnauthorizedResponse), }; /// <summary> diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/WebServerVerificationCodeBindingElement.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/WebServerVerificationCodeBindingElement.cs index 7b50c9c..5eb35ba 100644 --- a/src/DotNetOpenAuth/OAuth2/ChannelElements/WebServerVerificationCodeBindingElement.cs +++ b/src/DotNetOpenAuth/OAuth2/ChannelElements/WebServerVerificationCodeBindingElement.cs @@ -55,12 +55,12 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable. /// </remarks> public override MessageProtections? ProcessOutgoingMessage(IProtocolMessage message) { - var response = message as WebServerSuccessResponse; + var response = message as EndUserAuthorizationSuccessResponse; if (response != null) { var directResponse = (IDirectResponseProtocolMessage)response; var request = (EndUserAuthorizationRequest)directResponse.OriginatingRequest; ITokenCarryingRequest tokenCarryingResponse = response; - tokenCarryingResponse.AuthorizationDescription = new VerificationCode(request.ClientIdentifier, request.Callback, request.Scope, response.AuthorizingUsername); + tokenCarryingResponse.AuthorizationDescription = new AuthorizationCode(request.ClientIdentifier, request.Callback, request.Scope, response.AuthorizingUsername); return MessageProtections.None; } @@ -86,10 +86,10 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable. /// </remarks> public override MessageProtections? ProcessIncomingMessage(IProtocolMessage message) { - var request = message as WebServerAccessTokenRequest; + var request = message as AccessTokenAuthorizationCodeRequest; if (request != null) { ITokenCarryingRequest tokenRequest = request; - ((VerificationCode)tokenRequest.AuthorizationDescription).VerifyCallback(request.Callback); + ((AuthorizationCode)tokenRequest.AuthorizationDescription).VerifyCallback(request.Callback); return MessageProtections.None; } diff --git a/src/DotNetOpenAuth/OAuth2/ClientBase.cs b/src/DotNetOpenAuth/OAuth2/ClientBase.cs index 93e1c47..9be1cee 100644 --- a/src/DotNetOpenAuth/OAuth2/ClientBase.cs +++ b/src/DotNetOpenAuth/OAuth2/ClientBase.cs @@ -103,7 +103,7 @@ namespace DotNetOpenAuth.OAuth2 { } } - var request = new RefreshAccessTokenRequest(this.AuthorizationServer) { + var request = new AccessTokenRefreshRequest(this.AuthorizationServer) { ClientIdentifier = this.ClientIdentifier, ClientSecret = this.ClientSecret, RefreshToken = authorization.RefreshToken, diff --git a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenAssertionRequest.cs b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenAssertionRequest.cs index d3abf54..d81733b 100644 --- a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenAssertionRequest.cs +++ b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenAssertionRequest.cs @@ -29,5 +29,9 @@ namespace DotNetOpenAuth.OAuth2.Messages { /// <value>The assertion.</value> [MessagePart(Protocol.assertion, IsRequired = true, AllowEmpty = false)] internal string Assertion { get; set; } + + internal override GrantType GrantType { + get { return GrantType.Assertion; } + } } } diff --git a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenAuthorizationCodeRequest.cs b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenAuthorizationCodeRequest.cs index 3e679e6..cea7148 100644 --- a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenAuthorizationCodeRequest.cs +++ b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenAuthorizationCodeRequest.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.OAuth2.Messages { using System; using System.Collections.Generic; + using System.Diagnostics.Contracts; using System.Linq; using System.Text; @@ -17,10 +18,17 @@ namespace DotNetOpenAuth.OAuth2.Messages { /// <summary> /// Initializes a new instance of the <see cref="AccessTokenAuthorizationCodeRequest"/> class. /// </summary> - /// <param name="accessTokenEndpoint">The Authorization Server's access token endpoint URL.</param> + /// <param name="tokenEndpoint">The Authorization Server's access token endpoint URL.</param> /// <param name="version">The version.</param> - internal AccessTokenAuthorizationCodeRequest(Uri accessTokenEndpoint, Version version) - : base(accessTokenEndpoint, version) { + internal AccessTokenAuthorizationCodeRequest(Uri tokenEndpoint, Version version) + : base(tokenEndpoint, version) { + } + + + internal AccessTokenAuthorizationCodeRequest(AuthorizationServerDescription authorizationServer) + : this(authorizationServer.TokenEndpoint, authorizationServer.Version) + { + Contract.Requires<ArgumentNullException>(authorizationServer != null, "authorizationServer"); } internal override GrantType GrantType { diff --git a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenFailedResponse.cs b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenFailedResponse.cs index 28bcefe..90c5e67 100644 --- a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenFailedResponse.cs +++ b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenFailedResponse.cs @@ -46,7 +46,7 @@ namespace DotNetOpenAuth.OAuth2.Messages { /// <summary> /// Gets or sets the error. /// </summary> - /// <value>One of the values given in <see cref="Protocol.ErrorCodes"/>.</value> + /// <value>One of the values given in <see cref="Protocol.AccessTokenRequestErrorCodes"/>.</value> [MessagePart(Protocol.error, IsRequired = true, AllowEmpty = false)] internal string Error { get; set; } diff --git a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenRequestBase.cs b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenRequestBase.cs index 86ec216..4ebd6b7 100644 --- a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenRequestBase.cs +++ b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenRequestBase.cs @@ -13,7 +13,7 @@ namespace DotNetOpenAuth.OAuth2.Messages { using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OAuth2.ChannelElements; - internal abstract class AccessTokenRequestBase : MessageBase, IAccessTokenRequest { + public abstract class AccessTokenRequestBase : MessageBase { /// <summary> /// Initializes a new instance of the <see cref="AccessTokenRequestBase"/> class. /// </summary> diff --git a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenSuccessResponse.cs b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenSuccessResponse.cs index a38081d..85db387 100644 --- a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenSuccessResponse.cs +++ b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenSuccessResponse.cs @@ -22,7 +22,7 @@ namespace DotNetOpenAuth.OAuth2.Messages { /// Initializes a new instance of the <see cref="AccessTokenSuccessResponse"/> class. /// </summary> /// <param name="request">The request.</param> - internal AccessTokenSuccessResponse(IAccessTokenRequest request) + internal AccessTokenSuccessResponse(AccessTokenRequestBase request) : base(request) { } diff --git a/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationFailedResponse.cs b/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationFailedResponse.cs new file mode 100644 index 0000000..e2f4b37 --- /dev/null +++ b/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationFailedResponse.cs @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------- +// <copyright file="EndUserAuthorizationFailedResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth2.Messages { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.Linq; + using System.Runtime.Remoting.Messaging; + using System.Text; + using DotNetOpenAuth.Messaging; + + internal class EndUserAuthorizationFailedResponse : MessageBase, IMessageWithClientState { + /// <summary> + /// Initializes a new instance of the <see cref="EndUserAuthorizationSuccessResponse"/> class. + /// </summary> + /// <param name="clientCallback">The URL to redirect to so the client receives the message. This may not be built into the request message if the client pre-registered the URL with the authorization server.</param> + /// <param name="version">The protocol version.</param> + internal EndUserAuthorizationFailedResponse(Uri clientCallback, Version version) + : base(version, MessageTransport.Indirect, clientCallback) { + Contract.Requires<ArgumentNullException>(version != null); + Contract.Requires<ArgumentNullException>(clientCallback != null); + } + + /// <summary> + /// Initializes a new instance of the <see cref="EndUserAuthorizationFailedResponse"/> class. + /// </summary> + /// <param name="clientCallback">The URL to redirect to so the client receives the message. This may not be built into the request message if the client pre-registered the URL with the authorization server.</param> + /// <param name="request">The authorization request from the user agent on behalf of the client.</param> + internal EndUserAuthorizationFailedResponse(Uri clientCallback, EndUserAuthorizationRequest request) + : base(((IProtocolMessage)request).Version, MessageTransport.Indirect, clientCallback) { + Contract.Requires<ArgumentNullException>(request != null, "request"); + ((IMessageWithClientState)this).ClientState = request.ClientState; + } + + /// <summary> + /// Gets or sets the error. + /// </summary> + /// <value>One of the values given in <see cref="Protocol.EndUserAuthorizationRequestErrorCodes"/>.</value> + [MessagePart(Protocol.error, IsRequired = true, AllowEmpty = false)] + public string Error { get; set; } + + /// <summary> + /// Gets or sets a human readable description of the error. + /// </summary> + /// <value>Human-readable text providing additional information, used to assist in the understanding and resolution of the error that occurred.</value> + [MessagePart(Protocol.error_description, AllowEmpty = true, IsRequired = false)] + public string ErrorDescription { get; set; } + + /// <summary> + /// Gets or sets the location of the web page that describes the error and possible resolution. + /// </summary> + /// <value>A URI identifying a human-readable web page with information about the error, used to provide the end-user with additional information about the error.</value> + [MessagePart(Protocol.error_uri, AllowEmpty = false, IsRequired = false)] + public Uri ErrorUri { get; set; } + + /// <summary> + /// Gets or sets some state as provided by the client in the authorization request. + /// </summary> + /// <value>An opaque value defined by the client.</value> + /// <remarks> + /// REQUIRED if the Client sent the value in the <see cref="EndUserAuthorizationRequest"/>. + /// </remarks> + [MessagePart(Protocol.state, IsRequired = false, AllowEmpty = true)] + string IMessageWithClientState.ClientState { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationRequest.cs b/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationRequest.cs index 71a3e82..2faa33b 100644 --- a/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationRequest.cs +++ b/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationRequest.cs @@ -16,7 +16,7 @@ namespace DotNetOpenAuth.OAuth2.Messages { /// to issue an access token to the Consumer if permission is granted. /// </summary> [Serializable] - public abstract class EndUserAuthorizationRequest : MessageBase { + public class EndUserAuthorizationRequest : MessageBase { /// <summary> /// Initializes a new instance of the <see cref="EndUserAuthorizationRequest"/> class. /// </summary> @@ -27,6 +27,7 @@ namespace DotNetOpenAuth.OAuth2.Messages { Contract.Requires<ArgumentNullException>(authorizationEndpoint != null); Contract.Requires<ArgumentNullException>(version != null); this.HttpMethods = HttpDeliveryMethods.GetRequest; + this.ResponseType = EndUserAuthorizationResponseType.AuthorizationCode; } /// <summary> diff --git a/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationSuccessResponse.cs b/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationSuccessResponse.cs index c0b7038..8a90572 100644 --- a/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationSuccessResponse.cs +++ b/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationSuccessResponse.cs @@ -15,11 +15,11 @@ namespace DotNetOpenAuth.OAuth2.Messages { /// to indicate that user authorization was granted, and to return the user /// to the Client where they started their experience. /// </summary> - internal class EndUserAuthorizationSuccessResponse : MessageBase { + internal class EndUserAuthorizationSuccessResponse : MessageBase, IMessageWithClientState { /// <summary> /// Initializes a new instance of the <see cref="EndUserAuthorizationSuccessResponse"/> class. /// </summary> - /// <param name="clientCallback">The client callback.</param> + /// <param name="clientCallback">The URL to redirect to so the client receives the message. This may not be built into the request message if the client pre-registered the URL with the authorization server.</param> /// <param name="version">The protocol version.</param> internal EndUserAuthorizationSuccessResponse(Uri clientCallback, Version version) : base(version, MessageTransport.Indirect, clientCallback) { @@ -30,13 +30,13 @@ namespace DotNetOpenAuth.OAuth2.Messages { /// <summary> /// Initializes a new instance of the <see cref="EndUserAuthorizationSuccessResponse"/> class. /// </summary> - /// <param name="clientCallback">The client callback.</param> - /// <param name="request">The request.</param> + /// <param name="clientCallback">The URL to redirect to so the client receives the message. This may not be built into the request message if the client pre-registered the URL with the authorization server.</param> + /// <param name="request">The authorization request from the user agent on behalf of the client.</param> internal EndUserAuthorizationSuccessResponse(Uri clientCallback, EndUserAuthorizationRequest request) : base(request, clientCallback) { Contract.Requires<ArgumentNullException>(clientCallback != null, "clientCallback"); Contract.Requires<ArgumentNullException>(request != null, "request"); - ((IMessageWithClientState)this).ClientState = ((IMessageWithClientState)request).ClientState; + ((IMessageWithClientState)this).ClientState = request.ClientState; } [MessagePart(Protocol.code, AllowEmpty = false, IsRequired = false)] diff --git a/src/DotNetOpenAuth/OAuth2/Messages/IMessageWithClientState.cs b/src/DotNetOpenAuth/OAuth2/Messages/IMessageWithClientState.cs new file mode 100644 index 0000000..fa371ae --- /dev/null +++ b/src/DotNetOpenAuth/OAuth2/Messages/IMessageWithClientState.cs @@ -0,0 +1,21 @@ +//----------------------------------------------------------------------- +// <copyright file="IMessageWithClientState.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth2.Messages { + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A message carrying client state the authorization server should preserve on behalf of the client + /// during an authorization. + /// </summary> + internal interface IMessageWithClientState : IProtocolMessage { + /// <summary> + /// Gets or sets the state of the client. + /// </summary> + /// <value>The state of the client.</value> + string ClientState { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuth2/Protocol.cs b/src/DotNetOpenAuth/OAuth2/Protocol.cs index 5819cac..c33f79c 100644 --- a/src/DotNetOpenAuth/OAuth2/Protocol.cs +++ b/src/DotNetOpenAuth/OAuth2/Protocol.cs @@ -253,7 +253,7 @@ namespace DotNetOpenAuth.OAuth2 { /// <summary> /// Error codes that an authorization server can return to a client in response to a malformed or unsupported access token request. /// </summary> - internal static class ErrorCodes + internal static class AccessTokenRequestErrorCodes { /// <summary> /// The request is missing a required parameter, includes an unknown parameter or parameter value, repeats a parameter, includes multiple credentials, utilizes more than one mechanism for authenticating the client, or is otherwise malformed. @@ -285,5 +285,46 @@ namespace DotNetOpenAuth.OAuth2 { /// </summary> internal const string InvalidScope = "invalid-scope"; } + + /// <summary> + /// Error codes that an authorization server can return to a client in response to a malformed or unsupported end user authorization request. + /// </summary> + internal static class EndUserAuthorizationRequestErrorCodes + { + /// <summary> + /// The request is missing a required parameter, includes an unknown parameter or parameter value, or is otherwise malformed. + /// </summary> + internal const string InvalidRequest = "invalid-request"; + + /// <summary> + /// The client identifier provided is invalid. + /// </summary> + internal const string InvalidClientId = "invalid-client-id"; + + /// <summary> + /// The client is not authorized to use the requested response type. + /// </summary> + internal const string UnauthorizedClient = "unauthorized-client"; + + /// <summary> + /// The redirection URI provided does not match a pre-registered value. + /// </summary> + internal const string RedirectUriMismatch = "redirect-uri-mismatch"; + + /// <summary> + /// The end-user or authorization server denied the request. + /// </summary> + internal const string AccessDenied = "access-denied"; + + /// <summary> + /// The requested response type is not supported by the authorization server. + /// </summary> + internal const string UnsupportedResponseType = "unsupported-response-type"; + + /// <summary> + /// The requested scope is invalid, unknown, or malformed. + /// </summary> + internal const string InvalidScope = "invalid_scope"; + } } } diff --git a/src/DotNetOpenAuth/OAuth2/UserAgentClient.cs b/src/DotNetOpenAuth/OAuth2/UserAgentClient.cs index 42e359c..f68393b 100644 --- a/src/DotNetOpenAuth/OAuth2/UserAgentClient.cs +++ b/src/DotNetOpenAuth/OAuth2/UserAgentClient.cs @@ -42,7 +42,7 @@ namespace DotNetOpenAuth.OAuth2 { /// <param name="authorization">The authorization state that is tracking this particular request. Optional.</param> /// <param name="immediate">If set to <c>true</c>, the authorization server will return immediately instead of interacting with the user. Authorization will only be granted if the authorization server determines it is safe to do so without asking the user first.</param> /// <returns>A fully-qualified URL suitable to initiate the authorization flow.</returns> - public Uri RequestUserAuthorization(IAuthorizationState authorization = null, bool immediate = false) { + public Uri RequestUserAuthorization(IAuthorizationState authorization = null) { Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(this.ClientIdentifier)); if (authorization == null) { @@ -53,11 +53,10 @@ namespace DotNetOpenAuth.OAuth2 { authorization.Callback = new Uri("http://localhost/"); } - var request = new UserAgentRequest(this.AuthorizationServer) { + var request = new EndUserAuthorizationRequest(this.AuthorizationServer) { ClientIdentifier = this.ClientIdentifier, Scope = authorization.Scope, Callback = authorization.Callback, - Immediate = immediate, }; return this.Channel.PrepareResponse(request).GetDirectUriRequest(this.Channel); @@ -82,11 +81,11 @@ namespace DotNetOpenAuth.OAuth2 { return null; } - UserAgentSuccessResponse success; - UserAgentFailedResponse failure; - if ((success = response as UserAgentSuccessResponse) != null) { + EndUserAuthorizationSuccessResponse success; + EndUserAuthorizationFailedResponse failure; + if ((success = response as EndUserAuthorizationSuccessResponse) != null) { this.UpdateAuthorizationWithResponse(authorization, success); - } else if ((failure = response as UserAgentFailedResponse) != null) { + } else if ((failure = response as EndUserAuthorizationFailedResponse) != null) { authorization.Delete(); return null; } else { diff --git a/src/DotNetOpenAuth/OAuth2/WebServerAuthorizationServer.cs b/src/DotNetOpenAuth/OAuth2/WebServerAuthorizationServer.cs index 63a999f..2aa96b3 100644 --- a/src/DotNetOpenAuth/OAuth2/WebServerAuthorizationServer.cs +++ b/src/DotNetOpenAuth/OAuth2/WebServerAuthorizationServer.cs @@ -79,38 +79,38 @@ namespace DotNetOpenAuth.OAuth2 { return false; } - public IAccessTokenRequest ReadAccessTokenRequest(HttpRequestInfo requestInfo = null) { + public AccessTokenRequestBase ReadAccessTokenRequest(HttpRequestInfo requestInfo = null) { if (requestInfo == null) { requestInfo = this.Channel.GetRequestFromContext(); } - IAccessTokenRequest request; + AccessTokenRequestBase request; this.Channel.TryReadFromRequest(requestInfo, out request); return request; } - internal WebServerFailedResponse PrepareRejectAuthorizationRequest(EndUserAuthorizationRequest authorizationRequest, Uri callback = null) { + internal EndUserAuthorizationFailedResponse PrepareRejectAuthorizationRequest(EndUserAuthorizationRequest authorizationRequest, Uri callback = null) { Contract.Requires<ArgumentNullException>(authorizationRequest != null, "authorizationRequest"); - Contract.Ensures(Contract.Result<WebServerFailedResponse>() != null); + Contract.Ensures(Contract.Result<EndUserAuthorizationFailedResponse>() != null); if (callback == null) { callback = this.GetCallback(authorizationRequest); } - var response = new WebServerFailedResponse(callback, authorizationRequest); + var response = new EndUserAuthorizationFailedResponse(callback, authorizationRequest); return response; } - internal WebServerSuccessResponse PrepareApproveAuthorizationRequest(EndUserAuthorizationRequest authorizationRequest, Uri callback = null) { + internal EndUserAuthorizationSuccessResponse PrepareApproveAuthorizationRequest(EndUserAuthorizationRequest authorizationRequest, Uri callback = null) { Contract.Requires<ArgumentNullException>(authorizationRequest != null, "authorizationRequest"); - Contract.Ensures(Contract.Result<WebServerSuccessResponse>() != null); + Contract.Ensures(Contract.Result<EndUserAuthorizationSuccessResponse>() != null); if (callback == null) { callback = this.GetCallback(authorizationRequest); } var client = this.AuthorizationServer.GetClientOrThrow(authorizationRequest.ClientIdentifier); - var response = new WebServerSuccessResponse(callback, authorizationRequest); + var response = new EndUserAuthorizationSuccessResponse(callback, authorizationRequest); return response; } diff --git a/src/DotNetOpenAuth/OAuth2/WebServerClient.cs b/src/DotNetOpenAuth/OAuth2/WebServerClient.cs index ea3ebfd..1d98d7c 100644 --- a/src/DotNetOpenAuth/OAuth2/WebServerClient.cs +++ b/src/DotNetOpenAuth/OAuth2/WebServerClient.cs @@ -56,11 +56,12 @@ namespace DotNetOpenAuth.OAuth2 { if (authorization.Callback == null) { authorization.Callback = this.Channel.GetRequestFromContext().UrlBeforeRewriting - .StripMessagePartsFromQueryString(this.Channel.MessageDescriptions.Get(typeof(WebServerSuccessResponse), Protocol.Default.Version)); + .StripMessagePartsFromQueryString(this.Channel.MessageDescriptions.Get(typeof(EndUserAuthorizationSuccessResponse), Protocol.Default.Version)) + .StripMessagePartsFromQueryString(this.Channel.MessageDescriptions.Get(typeof(EndUserAuthorizationFailedResponse), Protocol.Default.Version)); authorization.SaveChanges(); } - var request = new WebServerRequest(this.AuthorizationServer) { + var request = new EndUserAuthorizationRequest(this.AuthorizationServer) { ClientIdentifier = this.ClientIdentifier, Callback = authorization.Callback, Scope = authorization.Scope, @@ -88,15 +89,15 @@ namespace DotNetOpenAuth.OAuth2 { Uri callback = MessagingUtilities.StripMessagePartsFromQueryString(request.UrlBeforeRewriting, this.Channel.MessageDescriptions.Get(response)); IAuthorizationState authorizationState = this.TokenManager.GetAuthorizationState(callback, 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 WebServerSuccessResponse; - var failure = response as WebServerFailedResponse; + var success = response as EndUserAuthorizationSuccessResponse; + var failure = response as EndUserAuthorizationFailedResponse; ErrorUtilities.VerifyProtocol(success != null || failure != null, MessagingStrings.UnexpectedMessageReceivedOfMany); if (success != null) { - var accessTokenRequest = new WebServerAccessTokenRequest(this.AuthorizationServer) { + var accessTokenRequest = new AccessTokenAuthorizationCodeRequest(this.AuthorizationServer) { ClientIdentifier = this.ClientIdentifier, ClientSecret = this.ClientSecret, Callback = authorizationState.Callback, - VerificationCode = success.VerificationCode, + AuthorizationCode = success.AuthorizationCode, }; IProtocolMessage accessTokenResponse = this.Channel.Request(accessTokenRequest); var accessTokenSuccess = accessTokenResponse as AccessTokenSuccessResponse; |