diff options
Diffstat (limited to 'src')
9 files changed, 70 insertions, 24 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 c9ceb81..c39d7fd 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 e821953..f39698a 100644 --- a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs +++ b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs @@ -521,18 +521,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/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.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(); + } } } |