diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2012-10-29 21:49:39 -0700 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2012-10-29 21:49:39 -0700 |
commit | a7915417b94037f1cc9a17590787f88d88be2559 (patch) | |
tree | 49ec536de4387def04a4eef8ac30c03636679fd6 | |
parent | 1a9aa9dc9ec85d32e771f2f2fd863304a60e29d2 (diff) | |
parent | 6dba07eda990f75dfea0999b06aba9c2e61fa442 (diff) | |
download | DotNetOpenAuth-a7915417b94037f1cc9a17590787f88d88be2559.zip DotNetOpenAuth-a7915417b94037f1cc9a17590787f88d88be2559.tar.gz DotNetOpenAuth-a7915417b94037f1cc9a17590787f88d88be2559.tar.bz2 |
Merge remote-tracking branch 'aarnott/master'
16 files changed, 118 insertions, 31 deletions
diff --git a/src/DotNetOpenAuth.Core/Messaging/Bindings/ExpiredMessageException.cs b/src/DotNetOpenAuth.Core/Messaging/Bindings/ExpiredMessageException.cs index 5126897..88b8fed 100644 --- a/src/DotNetOpenAuth.Core/Messaging/Bindings/ExpiredMessageException.cs +++ b/src/DotNetOpenAuth.Core/Messaging/Bindings/ExpiredMessageException.cs @@ -22,7 +22,6 @@ namespace DotNetOpenAuth.Messaging.Bindings { public ExpiredMessageException(DateTime utcExpirationDate, IProtocolMessage faultedMessage) : base(string.Format(CultureInfo.CurrentCulture, MessagingStrings.ExpiredMessage, utcExpirationDate.ToLocalTime(), DateTime.Now), faultedMessage) { Requires.True(utcExpirationDate.Kind == DateTimeKind.Utc, "utcExpirationDate"); - Requires.NotNull(faultedMessage, "faultedMessage"); } /// <summary> diff --git a/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs b/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs index 69ee8dc..377e6d8 100644 --- a/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs +++ b/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs @@ -193,20 +193,18 @@ namespace DotNetOpenAuth.Messaging { /// Deserializes a <see cref="DataBag"/>, including decompression, decryption, signature and nonce validation where applicable. /// </summary> /// <param name="message">The instance to initialize with deserialized data.</param> - /// <param name="containingMessage">The message that contains the <see cref="DataBag"/> serialized value. Must not be null.</param> /// <param name="value">The serialized form of the <see cref="DataBag"/> to deserialize. Must not be null or empty.</param> - /// <param name="messagePartName">The name of the parameter whose value is to be deserialized. Used for error message generation.</param> + /// <param name="containingMessage">The message that contains the <see cref="DataBag"/> serialized value. May be null if no carrying message is applicable.</param> + /// <param name="messagePartName">The name of the parameter whose value is to be deserialized. Used for error message generation, but may be <c>null</c>.</param> [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "No apparent problem. False positive?")] - public void Deserialize(T message, IProtocolMessage containingMessage, string value, string messagePartName) { + public void Deserialize(T message, string value, IProtocolMessage containingMessage, string messagePartName) { Requires.NotNull(message, "message"); - Requires.NotNull(containingMessage, "containingMessage"); Requires.NotNullOrEmpty(value, "value"); - Requires.NotNullOrEmpty(messagePartName, "messagePartName"); string symmetricSecretHandle = null; if (this.encrypted && this.cryptoKeyStore != null) { string valueWithoutHandle; - MessagingUtilities.ExtractKeyHandleAndPayload(containingMessage, messagePartName, value, out symmetricSecretHandle, out valueWithoutHandle); + MessagingUtilities.ExtractKeyHandleAndPayload(messagePartName, value, out symmetricSecretHandle, out valueWithoutHandle); value = valueWithoutHandle; } diff --git a/src/DotNetOpenAuth.Core/Messaging/IDataBagFormatter.cs b/src/DotNetOpenAuth.Core/Messaging/IDataBagFormatter.cs index 923773e..0d1ab03 100644 --- a/src/DotNetOpenAuth.Core/Messaging/IDataBagFormatter.cs +++ b/src/DotNetOpenAuth.Core/Messaging/IDataBagFormatter.cs @@ -25,10 +25,10 @@ namespace DotNetOpenAuth.Messaging { /// Deserializes a <see cref="DataBag"/>. /// </summary> /// <param name="message">The instance to deserialize into</param> - /// <param name="containingMessage">The message that contains the <see cref="DataBag"/> serialized value. Must not be null.</param> /// <param name="data">The serialized form of the <see cref="DataBag"/> to deserialize. Must not be null or empty.</param> - /// <param name="messagePartName">The name of the parameter whose value is to be deserialized. Used for error message generation.</param> - void Deserialize(T message, IProtocolMessage containingMessage, string data, string messagePartName); + /// <param name="containingMessage">The message that contains the <see cref="DataBag"/> serialized value. May be null if no carrying message is applicable.</param> + /// <param name="messagePartName">The name of the parameter whose value is to be deserialized. Used for error message generation, but may be <c>null</c>.</param> + void Deserialize(T message, string data, IProtocolMessage containingMessage = null, string messagePartName = null); } /// <summary> @@ -61,10 +61,10 @@ namespace DotNetOpenAuth.Messaging { /// Deserializes a <see cref="DataBag"/>. /// </summary> /// <param name="message">The instance to deserialize into</param> - /// <param name="containingMessage">The message that contains the <see cref="DataBag"/> serialized value. Must not be nulll.</param> /// <param name="data">The serialized form of the <see cref="DataBag"/> to deserialize. Must not be null or empty.</param> + /// <param name="containingMessage">The message that contains the <see cref="DataBag"/> serialized value. Must not be nulll.</param> /// <param name="messagePartName">Name of the message part whose value is to be deserialized. Used for exception messages.</param> - void IDataBagFormatter<T>.Deserialize(T message, IProtocolMessage containingMessage, string data, string messagePartName) { + void IDataBagFormatter<T>.Deserialize(T message, string data, IProtocolMessage containingMessage, string messagePartName) { Requires.NotNull(message, "message"); Requires.NotNull(containingMessage, "containingMessage"); Requires.NotNullOrEmpty(data, "data"); diff --git a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs index 6d8db24..d6df26c 100644 --- a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs +++ b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs @@ -625,18 +625,15 @@ namespace DotNetOpenAuth.Messaging { /// <summary> /// Extracts the key handle and encrypted blob from a string previously returned from <see cref="CombineKeyHandleAndPayload"/>. /// </summary> - /// <param name="containingMessage">The containing message.</param> - /// <param name="messagePart">The message part.</param> + /// <param name="messagePart">The message part. May be null if not applicable.</param> /// <param name="keyHandleAndBlob">The value previously returned from <see cref="CombineKeyHandleAndPayload"/>.</param> /// <param name="handle">The crypto key handle.</param> /// <param name="dataBlob">The encrypted/signed data.</param> - internal static void ExtractKeyHandleAndPayload(IProtocolMessage containingMessage, string messagePart, string keyHandleAndBlob, out string handle, out string dataBlob) { - Requires.NotNull(containingMessage, "containingMessage"); - Requires.NotNullOrEmpty(messagePart, "messagePart"); + internal static void ExtractKeyHandleAndPayload(string messagePart, string keyHandleAndBlob, out string handle, out string dataBlob) { Requires.NotNullOrEmpty(keyHandleAndBlob, "keyHandleAndBlob"); int privateHandleIndex = keyHandleAndBlob.IndexOf('!'); - ErrorUtilities.VerifyProtocol(privateHandleIndex > 0, MessagingStrings.UnexpectedMessagePartValue, messagePart, keyHandleAndBlob); + ErrorUtilities.VerifyProtocol(privateHandleIndex > 0, MessagingStrings.UnexpectedMessagePartValue, messagePart ?? "<unknown>", keyHandleAndBlob); handle = keyHandleAndBlob.Substring(0, privateHandleIndex); dataBlob = keyHandleAndBlob.Substring(privateHandleIndex + 1); } diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/DotNetOpenAuth.OAuth2.AuthorizationServer.csproj b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/DotNetOpenAuth.OAuth2.AuthorizationServer.csproj index 34d59ee..bb782f0 100644 --- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/DotNetOpenAuth.OAuth2.AuthorizationServer.csproj +++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/DotNetOpenAuth.OAuth2.AuthorizationServer.csproj @@ -42,6 +42,7 @@ <Compile Include="OAuth2\IAuthorizationServerHost.cs" /> <Compile Include="OAuth2\Messages\AccessTokenAuthorizationCodeRequestAS.cs" /> <Compile Include="OAuth2\Messages\AccessTokenRefreshRequestAS.cs" /> + <Compile Include="OAuth2\Messages\AccessTokenResult.cs" /> <Compile Include="OAuth2\Messages\EndUserAuthorizationSuccessAuthCodeResponseAS.cs" /> <Compile Include="OAuth2\Messages\IAuthorizationCodeCarryingRequest.cs" /> <Compile Include="OAuth2\Messages\IRefreshTokenCarryingRequest.cs" /> diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs index 6a96c2d..7d829c5 100644 --- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs +++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs @@ -251,6 +251,25 @@ namespace DotNetOpenAuth.OAuth2 { } /// <summary> + /// Decodes a refresh token into its authorization details. + /// </summary> + /// <param name="refreshToken">The encoded refresh token as it would appear to the client.</param> + /// <returns>A description of the authorization represented by the refresh token.</returns> + /// <exception cref="ProtocolException">Thrown if the refresh token is not valid due to expiration, corruption or not being authentic.</exception> + /// <remarks> + /// This can be useful if the authorization server supports the client revoking its own access (on uninstall, for example). + /// Outside the scope of the OAuth 2 spec, the client may contact the authorization server host requesting that its refresh + /// token be revoked. The authorization server would need to decode the refresh token so it knows which authorization in + /// the database to delete. + /// </remarks> + public IAuthorizationDescription DecodeRefreshToken(string refreshToken) { + var refreshTokenFormatter = RefreshToken.CreateFormatter(this.AuthorizationServerServices.CryptoKeyStore); + var token = new RefreshToken(); + refreshTokenFormatter.Deserialize(token, refreshToken); + return token; + } + + /// <summary> /// Gets the redirect URL to use for a particular authorization request. /// </summary> /// <param name="authorizationRequest">The authorization request.</param> diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/TokenCodeSerializationBindingElement.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/TokenCodeSerializationBindingElement.cs index 494a10b..5a1dbae 100644 --- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/TokenCodeSerializationBindingElement.cs +++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/TokenCodeSerializationBindingElement.cs @@ -103,7 +103,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { if (authCodeCarrier != null) { var authorizationCodeFormatter = AuthorizationCode.CreateFormatter(this.AuthorizationServer); var authorizationCode = new AuthorizationCode(); - authorizationCodeFormatter.Deserialize(authorizationCode, message, authCodeCarrier.Code, Protocol.code); + authorizationCodeFormatter.Deserialize(authorizationCode, authCodeCarrier.Code, message, Protocol.code); authCodeCarrier.AuthorizationDescription = authorizationCode; } @@ -111,7 +111,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { if (refreshTokenCarrier != null) { var refreshTokenFormatter = RefreshToken.CreateFormatter(this.AuthorizationServer.CryptoKeyStore); var refreshToken = new RefreshToken(); - refreshTokenFormatter.Deserialize(refreshToken, message, refreshTokenCarrier.RefreshToken, Protocol.refresh_token); + refreshTokenFormatter.Deserialize(refreshToken, refreshTokenCarrier.RefreshToken, message, Protocol.refresh_token); refreshTokenCarrier.AuthorizationDescription = refreshToken; } diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenResult.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/Messages/AccessTokenResult.cs index 11e486b..4297165 100644 --- a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenResult.cs +++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/Messages/AccessTokenResult.cs @@ -14,12 +14,12 @@ namespace DotNetOpenAuth.OAuth2 { /// <summary> /// Describes the parameters to be fed into creating a response to an access token request. /// </summary> - public class AccessTokenResult { + public class AccessTokenResult : IAccessTokenResult { /// <summary> /// Initializes a new instance of the <see cref="AccessTokenResult"/> class. /// </summary> /// <param name="accessToken">The access token to include in this result.</param> - public AccessTokenResult(AccessToken accessToken) { + public AccessTokenResult(AuthorizationServerAccessToken accessToken) { Requires.NotNull(accessToken, "accessToken"); this.AllowRefreshToken = true; this.AccessToken = accessToken; @@ -38,6 +38,13 @@ namespace DotNetOpenAuth.OAuth2 { /// <summary> /// Gets the access token. /// </summary> - public AccessToken AccessToken { get; private set; } + public AuthorizationServerAccessToken AccessToken { get; private set; } + + /// <summary> + /// Gets the access token. + /// </summary> + AccessToken IAccessTokenResult.AccessToken { + get { return this.AccessToken; } + } } } diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/DotNetOpenAuth.OAuth2.ClientAuthorization.csproj b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/DotNetOpenAuth.OAuth2.ClientAuthorization.csproj index 2a08dbf..c3ed569 100644 --- a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/DotNetOpenAuth.OAuth2.ClientAuthorization.csproj +++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/DotNetOpenAuth.OAuth2.ClientAuthorization.csproj @@ -34,7 +34,7 @@ <Compile Include="OAuth2\Messages\AccessTokenRefreshRequest.cs" /> <Compile Include="OAuth2\Messages\AccessTokenRequestBase.cs" /> <Compile Include="OAuth2\Messages\AccessTokenResourceOwnerPasswordCredentialsRequest.cs" /> - <Compile Include="OAuth2\Messages\AccessTokenResult.cs" /> + <Compile Include="OAuth2\Messages\IAccessTokenResult.cs" /> <Compile Include="OAuth2\Messages\AccessTokenSuccessResponse.cs" /> <Compile Include="OAuth2\Messages\AuthenticatedClientRequestBase.cs" /> <Compile Include="OAuth2\Messages\EndUserAuthorizationFailedResponse.cs" /> diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenRequestBase.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenRequestBase.cs index e6bbc34..9ab6837 100644 --- a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenRequestBase.cs +++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenRequestBase.cs @@ -45,7 +45,7 @@ namespace DotNetOpenAuth.OAuth2.Messages { /// <summary> /// Gets or sets the result of calling the authorization server host's access token creation method. /// </summary> - AccessTokenResult IAccessTokenRequestInternal.AccessTokenResult { get; set; } + IAccessTokenResult IAccessTokenRequestInternal.AccessTokenResult { get; set; } /// <summary> /// Gets the type of the grant. diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationImplicitRequest.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationImplicitRequest.cs index 4b662cd..8932cd3 100644 --- a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationImplicitRequest.cs +++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationImplicitRequest.cs @@ -45,7 +45,7 @@ namespace DotNetOpenAuth.OAuth2.Messages { /// <summary> /// Gets or sets the result of calling the authorization server host's access token creation method. /// </summary> - AccessTokenResult IAccessTokenRequestInternal.AccessTokenResult { get; set; } + IAccessTokenResult IAccessTokenRequestInternal.AccessTokenResult { get; set; } /// <summary> /// Gets a value indicating whether the client requesting the access token has authenticated itself. diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenRequestInternal.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenRequestInternal.cs index 44af074..b79d566 100644 --- a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenRequestInternal.cs +++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenRequestInternal.cs @@ -17,6 +17,6 @@ namespace DotNetOpenAuth.OAuth2.Messages { /// <summary> /// Gets or sets the result of calling the authorization server host's access token creation method. /// </summary> - AccessTokenResult AccessTokenResult { get; set; } + IAccessTokenResult AccessTokenResult { get; set; } } } diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenResult.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenResult.cs new file mode 100644 index 0000000..1719984 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenResult.cs @@ -0,0 +1,33 @@ +//----------------------------------------------------------------------- +// <copyright file="IAccessTokenResult.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth2 { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Security.Cryptography; + using System.Text; + + /// <summary> + /// Describes the parameters to be fed into creating a response to an access token request. + /// </summary> + public interface IAccessTokenResult { + /// <summary> + /// Gets or sets a value indicating whether to provide the client with a refresh token, when applicable. + /// </summary> + /// <value>The default value is <c>true</c>.</value> + /// <remarks>> + /// The refresh token will never be provided when this value is false. + /// The refresh token <em>may</em> be provided when this value is true. + /// </remarks> + bool AllowRefreshToken { get; set; } + + /// <summary> + /// Gets the access token. + /// </summary> + AccessToken AccessToken { get; } + } +} diff --git a/src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/StandardAccessTokenAnalyzer.cs b/src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/StandardAccessTokenAnalyzer.cs index 54d86ff..a03bdab 100644 --- a/src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/StandardAccessTokenAnalyzer.cs +++ b/src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/StandardAccessTokenAnalyzer.cs @@ -51,7 +51,7 @@ namespace DotNetOpenAuth.OAuth2 { public virtual AccessToken DeserializeAccessToken(IDirectedProtocolMessage message, string accessToken) { var accessTokenFormatter = AccessToken.CreateFormatter(this.AuthorizationServerPublicSigningKey, this.ResourceServerPrivateEncryptionKey); var token = new AccessToken(); - accessTokenFormatter.Deserialize(token, message, accessToken, Protocol.access_token); + accessTokenFormatter.Deserialize(token, accessToken, message, Protocol.access_token); return token; } } diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/ProviderAssociationHandleEncoder.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/ProviderAssociationHandleEncoder.cs index 5c39c5e..897b4f8 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/ProviderAssociationHandleEncoder.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/ProviderAssociationHandleEncoder.cs @@ -70,7 +70,7 @@ namespace DotNetOpenAuth.OpenId.Provider { var formatter = AssociationDataBag.CreateFormatter(this.cryptoKeyStore, AssociationHandleEncodingSecretBucket); AssociationDataBag bag = new AssociationDataBag(); try { - formatter.Deserialize(bag, containingMessage, handle, Protocol.Default.openid.assoc_handle); + formatter.Deserialize(bag, handle, containingMessage, Protocol.Default.openid.assoc_handle); } catch (ProtocolException ex) { Logger.OpenId.Error("Rejecting an association because deserialization of the encoded handle failed.", ex); return null; diff --git a/src/DotNetOpenAuth.Test/OAuth2/AuthorizationServerTests.cs b/src/DotNetOpenAuth.Test/OAuth2/AuthorizationServerTests.cs index 3791e28..251cd67 100644 --- a/src/DotNetOpenAuth.Test/OAuth2/AuthorizationServerTests.cs +++ b/src/DotNetOpenAuth.Test/OAuth2/AuthorizationServerTests.cs @@ -9,6 +9,7 @@ namespace DotNetOpenAuth.Test.OAuth2 { using System.Collections.Generic; using System.Linq; using System.Text; + using System.Threading.Tasks; using DotNetOpenAuth.OAuth2; using DotNetOpenAuth.OAuth2.Messages; using NUnit.Framework; @@ -28,8 +29,7 @@ namespace DotNetOpenAuth.Test.OAuth2 { AuthorizationServerMock, new UserAgentClient(AuthorizationServerDescription), client => { - var request = new AccessTokenAuthorizationCodeRequestC(AuthorizationServerDescription) - { ClientIdentifier = ClientId, ClientSecret = ClientSecret, AuthorizationCode = "foo" }; + var request = new AccessTokenAuthorizationCodeRequestC(AuthorizationServerDescription) { ClientIdentifier = ClientId, ClientSecret = ClientSecret, AuthorizationCode = "foo" }; var response = client.Channel.Request<AccessTokenFailedResponse>(request); Assert.That(response.Error, Is.Not.Null.And.Not.Empty); @@ -40,5 +40,38 @@ namespace DotNetOpenAuth.Test.OAuth2 { }); coordinator.Run(); } + + [Test] + public void DecodeRefreshToken() { + var refreshTokenSource = new TaskCompletionSource<string>(); + var coordinator = new OAuth2Coordinator<WebServerClient>( + AuthorizationServerDescription, + AuthorizationServerMock, + new WebServerClient(AuthorizationServerDescription), + client => { + try { + var authState = new AuthorizationState(TestScopes) { + Callback = ClientCallback, + }; + client.PrepareRequestUserAuthorization(authState).Respond(); + var result = client.ProcessUserAuthorization(); + Assert.That(result.AccessToken, Is.Not.Null.And.Not.Empty); + Assert.That(result.RefreshToken, Is.Not.Null.And.Not.Empty); + refreshTokenSource.SetResult(result.RefreshToken); + } catch { + refreshTokenSource.TrySetCanceled(); + } + }, + server => { + var request = server.ReadAuthorizationRequest(); + Assert.That(request, Is.Not.Null); + server.ApproveAuthorizationRequest(request, ResourceOwnerUsername); + server.HandleTokenRequest().Respond(); + var authorization = server.DecodeRefreshToken(refreshTokenSource.Task.Result); + Assert.That(authorization, Is.Not.Null); + Assert.That(authorization.User, Is.EqualTo(ResourceOwnerUsername)); + }); + coordinator.Run(); + } } } |