diff options
16 files changed, 96 insertions, 46 deletions
diff --git a/samples/OAuthConsumer/SampleWcf2.aspx.cs b/samples/OAuthConsumer/SampleWcf2.aspx.cs index 6b6ced2..a4f0f1c 100644 --- a/samples/OAuthConsumer/SampleWcf2.aspx.cs +++ b/samples/OAuthConsumer/SampleWcf2.aspx.cs @@ -31,7 +31,8 @@ } } - if (Authorization != null) { + // Refresh the access token if it expires and if its lifetime is too short to be of use. + if (Authorization != null && Authorization.AccessTokenExpirationUtc.HasValue) { client.RefreshToken(Authorization, TimeSpan.FromMinutes(1)); } } diff --git a/samples/OAuthServiceProvider/Code/DatabaseNonceStore.cs b/samples/OAuthServiceProvider/Code/DatabaseNonceStore.cs index 1f8f56e..f0c10d1 100644 --- a/samples/OAuthServiceProvider/Code/DatabaseNonceStore.cs +++ b/samples/OAuthServiceProvider/Code/DatabaseNonceStore.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Web; using DotNetOpenAuth.Messaging.Bindings; + using System.Data.SqlClient; /// <summary> /// A database-persisted nonce store. @@ -47,6 +48,8 @@ return true; } catch (System.Data.Linq.DuplicateKeyException) { return false; + } catch (SqlException) { + return false; } } diff --git a/samples/OAuthServiceProvider/OAuth2.ashx.cs b/samples/OAuthServiceProvider/OAuth2.ashx.cs index 259803a..62aa680 100644 --- a/samples/OAuthServiceProvider/OAuth2.ashx.cs +++ b/samples/OAuthServiceProvider/OAuth2.ashx.cs @@ -38,11 +38,6 @@ throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request."); } - // This sample doesn't implement support for immediate mode. - if (!request.IsUserInteractionAllowed) { - Global.AuthorizationServer.RejectAuthorizationRequest(request); - } - // Redirect the user to a page that requires the user to be logged in. Global.PendingOAuth2Authorization = request; context.Response.Redirect("~/Members/Authorize2.aspx"); diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj index 20749dd..2b2a069 100644 --- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj +++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj @@ -324,7 +324,7 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="OAuth2\ChannelElements\DataBag.cs" /> <Compile Include="OAuth2\ChannelElements\TimestampEncoder.cs" /> <Compile Include="OAuth2\ChannelElements\AuthorizationCode.cs" /> - <Compile Include="OAuth2\ChannelElements\WebServerVerificationCodeBindingElement.cs" /> + <Compile Include="OAuth2\ChannelElements\AuthorizationCodeBindingElement.cs" /> <Compile Include="OAuth2\ChannelElements\AuthServerAllFlowsBindingElement.cs" /> <Compile Include="OAuth2\IAccessTokenAnalyzer.cs" /> <Compile Include="OAuth2\IAuthorizationServer.cs" /> diff --git a/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs b/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs index 21fd53a..e34dc03 100644 --- a/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs +++ b/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. -// Runtime Version:4.0.30426.0 +// Runtime Version:4.0.30319.1 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -133,6 +133,15 @@ namespace DotNetOpenAuth.Messaging { } /// <summary> + /// Looks up a localized string similar to Unable to instantiate the message part encoder/decoder type {0}.. + /// </summary> + internal static string EncoderInstantiationFailed { + get { + return ResourceManager.GetString("EncoderInstantiationFailed", resourceCulture); + } + } + + /// <summary> /// Looks up a localized string similar to Error while deserializing message {0}.. /// </summary> internal static string ErrorDeserializingMessage { diff --git a/src/DotNetOpenAuth/Messaging/MessagingStrings.resx b/src/DotNetOpenAuth/Messaging/MessagingStrings.resx index 3a265f1..d7d0b01 100644 --- a/src/DotNetOpenAuth/Messaging/MessagingStrings.resx +++ b/src/DotNetOpenAuth/Messaging/MessagingStrings.resx @@ -309,4 +309,7 @@ <data name="RequiredMessagePartConstantIncorrect" xml:space="preserve"> <value>The following message parts had constant value requirements that were unsatisfied: {0}</value> </data> + <data name="EncoderInstantiationFailed" xml:space="preserve"> + <value>Unable to instantiate the message part encoder/decoder type {0}.</value> + </data> </root>
\ No newline at end of file diff --git a/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs b/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs index 462bb3c..df6dc73 100644 --- a/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs +++ b/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs @@ -361,7 +361,11 @@ namespace DotNetOpenAuth.Messaging.Reflection { IMessagePartEncoder encoder; if (!encoders.TryGetValue(messagePartEncoder, out encoder)) { - encoder = encoders[messagePartEncoder] = (IMessagePartEncoder)Activator.CreateInstance(messagePartEncoder); + try { + encoder = encoders[messagePartEncoder] = (IMessagePartEncoder)Activator.CreateInstance(messagePartEncoder); + } catch (MissingMethodException ex) { + throw ErrorUtilities.Wrap(ex, MessagingStrings.EncoderInstantiationFailed, messagePartEncoder.FullName); + } } return encoder; diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/AuthorizationCode.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/AuthorizationCode.cs index 04f83ac..c4257aa 100644 --- a/src/DotNetOpenAuth/OAuth2/ChannelElements/AuthorizationCode.cs +++ b/src/DotNetOpenAuth/OAuth2/ChannelElements/AuthorizationCode.cs @@ -60,7 +60,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { true, true, false, - WebServerVerificationCodeBindingElement.MaximumMessageAge, + AuthorizationCodeBindingElement.MaximumMessageAge, authorizationServer.VerificationCodeNonceStore); } diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/WebServerVerificationCodeBindingElement.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/AuthorizationCodeBindingElement.cs index 5eb35ba..869a48c 100644 --- a/src/DotNetOpenAuth/OAuth2/ChannelElements/WebServerVerificationCodeBindingElement.cs +++ b/src/DotNetOpenAuth/OAuth2/ChannelElements/AuthorizationCodeBindingElement.cs @@ -15,13 +15,13 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { /// <summary> /// A binding element for OAuth 2.0 authorization servers that create/verify - /// issued verification codes as part of obtaining access/refresh tokens. + /// issued authorization codes as part of obtaining access/refresh tokens. /// </summary> - internal class WebServerVerificationCodeBindingElement : AuthServerBindingElementBase { + internal class AuthorizationCodeBindingElement : AuthServerBindingElementBase { /// <summary> - /// Initializes a new instance of the <see cref="WebServerVerificationCodeBindingElement"/> class. + /// Initializes a new instance of the <see cref="AuthorizationCodeBindingElement"/> class. /// </summary> - internal WebServerVerificationCodeBindingElement() { + internal AuthorizationCodeBindingElement() { } /// <summary> diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/EndUserAuthorizationResponseTypeEncoder.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/EndUserAuthorizationResponseTypeEncoder.cs index 491ace9..7ad6940 100644 --- a/src/DotNetOpenAuth/OAuth2/ChannelElements/EndUserAuthorizationResponseTypeEncoder.cs +++ b/src/DotNetOpenAuth/OAuth2/ChannelElements/EndUserAuthorizationResponseTypeEncoder.cs @@ -14,7 +14,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { /// <summary> /// Initializes a new instance of the <see cref="EndUserAuthorizationResponseTypeEncoder"/> class. /// </summary> - internal EndUserAuthorizationResponseTypeEncoder() { + public EndUserAuthorizationResponseTypeEncoder() { } #region IMessagePartEncoder Members diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/GrantTypeEncoder.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/GrantTypeEncoder.cs index 5414793..f39eecd 100644 --- a/src/DotNetOpenAuth/OAuth2/ChannelElements/GrantTypeEncoder.cs +++ b/src/DotNetOpenAuth/OAuth2/ChannelElements/GrantTypeEncoder.cs @@ -14,7 +14,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { /// <summary> /// Initializes a new instance of the <see cref="GrantTypeEncoder"/> class. /// </summary> - internal GrantTypeEncoder() { + public GrantTypeEncoder() { } #region IMessagePartEncoder Members diff --git a/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuthWrapAuthorizationServerChannel.cs b/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuthWrapAuthorizationServerChannel.cs index 6547b8b..dd3d02c 100644 --- a/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuthWrapAuthorizationServerChannel.cs +++ b/src/DotNetOpenAuth/OAuth2/ChannelElements/OAuthWrapAuthorizationServerChannel.cs @@ -160,7 +160,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { if (authorizationServer != null) { bindingElements.Add(new AuthServerAllFlowsBindingElement()); - bindingElements.Add(new WebServerVerificationCodeBindingElement()); + bindingElements.Add(new AuthorizationCodeBindingElement()); bindingElements.Add(new AccessRequestBindingElement()); } diff --git a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenAuthorizationCodeRequest.cs b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenAuthorizationCodeRequest.cs index cea7148..d898862 100644 --- a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenAuthorizationCodeRequest.cs +++ b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenAuthorizationCodeRequest.cs @@ -59,7 +59,7 @@ namespace DotNetOpenAuth.OAuth2.Messages { /// <summary> /// Gets or sets the verification code previously communicated to the Client - /// in <see cref="WebServerSuccessResponse.VerificationCode"/>. + /// in <see cref="EndUserAuthorizationSuccessResponse.AuthorizationCode"/>. /// </summary> /// <value>The verification code received from the authorization server.</value> [MessagePart(Protocol.code, IsRequired = true, AllowEmpty = false)] @@ -73,22 +73,5 @@ namespace DotNetOpenAuth.OAuth2.Messages { /// </value> [MessagePart(Protocol.redirect_uri, IsRequired = true, AllowEmpty = false)] internal Uri Callback { get; set; } - - /// <summary> - /// 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)] - public 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)] - public string ClientSecret { get; set; } } } diff --git a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenRequestBase.cs b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenRequestBase.cs index 4ebd6b7..09866cd 100644 --- a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenRequestBase.cs +++ b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenRequestBase.cs @@ -44,7 +44,7 @@ namespace DotNetOpenAuth.OAuth2.Messages { [MessagePart(Protocol.grant_type, IsRequired = true, AllowEmpty = false, Encoder = typeof(GrantTypeEncoder))] internal abstract GrantType GrantType { get; } - [MessagePart(Protocol.scope, IsRequired = true, AllowEmpty = true)] + [MessagePart(Protocol.scope, IsRequired = false, AllowEmpty = true)] internal string Scope { get; set; } /// <summary> diff --git a/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationSuccessResponse.cs b/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationSuccessResponse.cs index 8a90572..6d4ce40 100644 --- a/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationSuccessResponse.cs +++ b/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationSuccessResponse.cs @@ -15,7 +15,7 @@ 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, IMessageWithClientState { + internal class EndUserAuthorizationSuccessResponse : MessageBase, IMessageWithClientState, ITokenCarryingRequest { /// <summary> /// Initializes a new instance of the <see cref="EndUserAuthorizationSuccessResponse"/> class. /// </summary> @@ -39,7 +39,7 @@ namespace DotNetOpenAuth.OAuth2.Messages { ((IMessageWithClientState)this).ClientState = request.ClientState; } - [MessagePart(Protocol.code, AllowEmpty = false, IsRequired = false)] + [MessagePart(Protocol.code, AllowEmpty = false, IsRequired = true)] // TODO: this isn't required when the access_token part is present. internal string AuthorizationCode { get; set; } [MessagePart(Protocol.access_token, AllowEmpty = false, IsRequired = false)] @@ -73,5 +73,43 @@ namespace DotNetOpenAuth.OAuth2.Messages { /// Gets or sets the authorizing user's account name. /// </summary> internal string AuthorizingUsername { get; set; } + + #region ITokenCarryingRequest Members + + string ITokenCarryingRequest.CodeOrToken { + get { return this.AuthorizationCode; } + set { this.AuthorizationCode = value;} + } + + CodeOrTokenType ITokenCarryingRequest.CodeOrTokenType { + get { return CodeOrTokenType.AuthorizationCode; } + } + + IAuthorizationDescription ITokenCarryingRequest.AuthorizationDescription { get; set; } + + #endregion + + /// <summary> + /// Checks the message state for conformity to the protocol specification + /// and throws an exception if the message is invalid. + /// </summary> + /// <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> + /// </remarks> + /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception> + protected override void EnsureValidMessage() + { + base.EnsureValidMessage(); + + ErrorUtilities.VerifyProtocol( + !string.IsNullOrEmpty(this.AuthorizationCode) || !string.IsNullOrEmpty(this.AccessToken), + MessagingStrings.RequiredParametersMissing, + this.GetType().Name, + string.Join(", ", new string[] { Protocol.code,Protocol.access_token})); + } } } diff --git a/src/DotNetOpenAuth/OAuth2/UserAgentClient.cs b/src/DotNetOpenAuth/OAuth2/UserAgentClient.cs index f68393b..7815858 100644 --- a/src/DotNetOpenAuth/OAuth2/UserAgentClient.cs +++ b/src/DotNetOpenAuth/OAuth2/UserAgentClient.cs @@ -68,11 +68,11 @@ namespace DotNetOpenAuth.OAuth2 { /// <param name="actualRedirectUrl">The actual URL of the incoming HTTP request.</param> /// <param name="authorization">The authorization.</param> /// <returns>The granted authorization, or <c>null</c> if the incoming HTTP request did not contain an authorization server response or authorization was rejected.</returns> - public IAuthorizationState ProcessUserAuthorization(Uri actualRedirectUrl, IAuthorizationState authorization = null) { + public IAuthorizationState ProcessUserAuthorization(Uri actualRedirectUrl, IAuthorizationState authorizationState = null) { Contract.Requires<ArgumentNullException>(actualRedirectUrl != null, "actualRedirectUrl"); - if (authorization == null) { - authorization = new AuthorizationState(); + if (authorizationState == null) { + authorizationState = new AuthorizationState(); } var carrier = new HttpRequestInfo("GET", actualRedirectUrl, actualRedirectUrl.PathAndQuery, new System.Net.WebHeaderCollection(), null); @@ -84,15 +84,29 @@ namespace DotNetOpenAuth.OAuth2 { EndUserAuthorizationSuccessResponse success; EndUserAuthorizationFailedResponse failure; if ((success = response as EndUserAuthorizationSuccessResponse) != null) { - this.UpdateAuthorizationWithResponse(authorization, success); + var accessTokenRequest = new AccessTokenAuthorizationCodeRequest(this.AuthorizationServer) { + ClientIdentifier = this.ClientIdentifier, + ClientSecret = this.ClientSecret, + Callback = authorizationState.Callback, + AuthorizationCode = success.AuthorizationCode, + }; + IProtocolMessage accessTokenResponse = this.Channel.Request(accessTokenRequest); + var accessTokenSuccess = accessTokenResponse as AccessTokenSuccessResponse; + var failedAccessTokenResponse = accessTokenResponse as AccessTokenFailedResponse; + if (accessTokenSuccess != null) { + this.UpdateAuthorizationWithResponse(authorizationState, accessTokenSuccess); + } else if (failedAccessTokenResponse != null) { + authorizationState.Delete(); + return null; + } else { + ErrorUtilities.ThrowProtocol(MessagingStrings.UnexpectedMessageReceivedOfMany); + } } else if ((failure = response as EndUserAuthorizationFailedResponse) != null) { - authorization.Delete(); + authorizationState.Delete(); return null; - } else { - ErrorUtilities.ThrowProtocol(MessagingStrings.UnexpectedMessageReceivedOfMany); } - return authorization; + return authorizationState; } } } |