diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2012-02-20 22:18:31 -0800 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2012-02-20 22:18:31 -0800 |
commit | 335402d6dda7a96acab14e7263ef16e06e637d12 (patch) | |
tree | 1f108e239c21dcdc99469d113224afde4ae3cade | |
parent | 234cf20e86b0ed1d65bca4a61eabb3277e8562c5 (diff) | |
download | DotNetOpenAuth-335402d6dda7a96acab14e7263ef16e06e637d12.zip DotNetOpenAuth-335402d6dda7a96acab14e7263ef16e06e637d12.tar.gz DotNetOpenAuth-335402d6dda7a96acab14e7263ef16e06e637d12.tar.bz2 |
Added scaffolding for OAuth2 unit tests and added the first test for client authorization.
22 files changed, 298 insertions, 55 deletions
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs index 5dee893..5429b60 100644 --- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs +++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs @@ -26,31 +26,24 @@ namespace DotNetOpenAuth.OAuth2 { /// <param name="authorizationServer">The authorization server.</param> public AuthorizationServer(IAuthorizationServer authorizationServer) { Requires.NotNull(authorizationServer, "authorizationServer"); - this.OAuthChannel = new OAuth2AuthorizationServerChannel(authorizationServer); + this.Channel = new OAuth2AuthorizationServerChannel(authorizationServer); } /// <summary> /// Gets the channel. /// </summary> /// <value>The channel.</value> - public Channel Channel { - get { return this.OAuthChannel; } - } + public Channel Channel { get; internal set; } /// <summary> /// Gets the authorization server. /// </summary> /// <value>The authorization server.</value> public IAuthorizationServer AuthorizationServerServices { - get { return this.OAuthChannel.AuthorizationServer; } + get { return ((IOAuth2ChannelWithAuthorizationServer)this.Channel).AuthorizationServer; } } /// <summary> - /// Gets the channel. - /// </summary> - internal OAuth2AuthorizationServerChannel OAuthChannel { get; private set; } - - /// <summary> /// Reads in a client's request for the Authorization Server to obtain permission from /// the user to authorize the Client's access of some protected resource(s). /// </summary> diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs index 6911452..8a681be 100644 --- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs +++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs @@ -44,7 +44,7 @@ namespace DotNetOpenAuth.OAuth2 { /// Gets the OAuth channel. /// </summary> /// <value>The channel.</value> - public Channel Channel { get; private set; } + public Channel Channel { get; internal set; } /// <summary> /// Gets or sets the identifier by which this client is known to the Authorization Server. diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/OAuth2Strings.Designer.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/OAuth2Strings.Designer.cs index 72701d3..d140b7e 100644 --- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/OAuth2Strings.Designer.cs +++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/OAuth2Strings.Designer.cs @@ -86,5 +86,14 @@ namespace DotNetOpenAuth.OAuth2 { return ResourceManager.GetString("AuthorizationResponseUnexpectedMismatch", resourceCulture); } } + + /// <summary> + /// Looks up a localized string similar to The property {0} must be set before this operation is allowed.. + /// </summary> + internal static string RequiredPropertyNotYetPreset { + get { + return ResourceManager.GetString("RequiredPropertyNotYetPreset", resourceCulture); + } + } } } diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/OAuth2Strings.resx b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/OAuth2Strings.resx index a78e397..114b3e8 100644 --- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/OAuth2Strings.resx +++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/OAuth2Strings.resx @@ -126,4 +126,7 @@ <data name="AuthorizationResponseUnexpectedMismatch" xml:space="preserve"> <value>Unexpected OAuth authorization response received with callback and client state that does not match an expected value.</value> </data> + <data name="RequiredPropertyNotYetPreset" xml:space="preserve"> + <value>The property {0} must be set before this operation is allowed.</value> + </data> </root>
\ No newline at end of file diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs index 09f471c..ffcc1ee 100644 --- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs +++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs @@ -71,7 +71,7 @@ namespace DotNetOpenAuth.OAuth2 { public OutgoingWebResponse PrepareRequestUserAuthorization(IAuthorizationState authorization, string state = null) { Requires.NotNull(authorization, "authorization"); Requires.ValidState(authorization.Callback != null || (HttpContext.Current != null && HttpContext.Current.Request != null), MessagingStrings.HttpContextRequired); - Requires.ValidState(!string.IsNullOrEmpty(this.ClientIdentifier)); + Requires.ValidState(!string.IsNullOrEmpty(this.ClientIdentifier), OAuth2Strings.RequiredPropertyNotYetPreset, "ClientIdentifier"); Contract.Ensures(Contract.Result<OutgoingWebResponse>() != null); if (authorization.Callback == null) { @@ -97,8 +97,8 @@ namespace DotNetOpenAuth.OAuth2 { /// <param name="request">The incoming HTTP request that may carry an authorization response.</param> /// <returns>The authorization state that contains the details of the authorization.</returns> public IAuthorizationState ProcessUserAuthorization(HttpRequestInfo request = null) { - Requires.ValidState(!string.IsNullOrEmpty(this.ClientIdentifier)); - Requires.ValidState(!string.IsNullOrEmpty(this.ClientSecret)); + Requires.ValidState(!string.IsNullOrEmpty(this.ClientIdentifier), OAuth2Strings.RequiredPropertyNotYetPreset, "ClientIdentifier"); + Requires.ValidState(!string.IsNullOrEmpty(this.ClientSecret), OAuth2Strings.RequiredPropertyNotYetPreset, "ClientSecret"); if (request == null) { request = this.Channel.GetRequestFromContext(); diff --git a/src/DotNetOpenAuth.OAuth2/DotNetOpenAuth.OAuth2.csproj b/src/DotNetOpenAuth.OAuth2/DotNetOpenAuth.OAuth2.csproj index 094d005..5c934b4 100644 --- a/src/DotNetOpenAuth.OAuth2/DotNetOpenAuth.OAuth2.csproj +++ b/src/DotNetOpenAuth.OAuth2/DotNetOpenAuth.OAuth2.csproj @@ -26,6 +26,7 @@ <Compile Include="OAuth2\ChannelElements\AuthServerBindingElementBase.cs" /> <Compile Include="OAuth2\ChannelElements\GrantTypeEncoder.cs" /> <Compile Include="OAuth2\ChannelElements\EndUserAuthorizationResponseTypeEncoder.cs" /> + <Compile Include="OAuth2\ChannelElements\IOAuth2ChannelWithAuthorizationServer.cs" /> <Compile Include="OAuth2\ChannelElements\OAuth2ChannelBase.cs" /> <Compile Include="OAuth2\ChannelElements\OAuth2ClientChannel.cs" /> <Compile Include="OAuth2\ChannelElements\ScopeEncoder.cs" /> @@ -36,6 +37,7 @@ <Compile Include="OAuth2\ChannelElements\AuthorizationCode.cs" /> <Compile Include="OAuth2\ChannelElements\AuthorizationCodeBindingElement.cs" /> <Compile Include="OAuth2\ChannelElements\AuthServerAllFlowsBindingElement.cs" /> + <Compile Include="OAuth2\ClientDescription.cs" /> <Compile Include="OAuth2\ClientType.cs" /> <Compile Include="OAuth2\IAccessTokenAnalyzer.cs" /> <Compile Include="OAuth2\IAuthorizationServer.cs" /> diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/AuthServerBindingElementBase.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/AuthServerBindingElementBase.cs index 6d24d38..49f820d 100644 --- a/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/AuthServerBindingElementBase.cs +++ b/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/AuthServerBindingElementBase.cs @@ -18,8 +18,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { /// <summary> /// Initializes a new instance of the <see cref="AuthServerBindingElementBase"/> class. /// </summary> - protected AuthServerBindingElementBase() - { + protected AuthServerBindingElementBase() { } /// <summary> @@ -39,21 +38,11 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { public abstract MessageProtections Protection { get; } /// <summary> - /// Gets the channel that this binding element belongs to. - /// </summary> - /// <remarks> - /// This property is set by the channel when it is first constructed. - /// </remarks> - protected OAuth2AuthorizationServerChannel OAuthChannel { - get { return (OAuth2AuthorizationServerChannel)this.Channel; } - } - - /// <summary> /// Gets the authorization server hosting this channel. /// </summary> /// <value>The authorization server.</value> protected IAuthorizationServer AuthorizationServer { - get { return this.OAuthChannel.AuthorizationServer; } + get { return ((IOAuth2ChannelWithAuthorizationServer)this.Channel).AuthorizationServer; } } /// <summary> diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/AuthorizationCode.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/AuthorizationCode.cs index 6199178..111c007 100644 --- a/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/AuthorizationCode.cs +++ b/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/AuthorizationCode.cs @@ -61,8 +61,11 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { Requires.NotNull(authorizationServer, "authorizationServer"); Contract.Ensures(Contract.Result<IDataBagFormatter<AuthorizationCode>>() != null); + var cryptoStore = authorizationServer.CryptoKeyStore; + ErrorUtilities.VerifyHost(cryptoStore != null, OAuthStrings.ResultShouldNotBeNull, authorizationServer.GetType(), "CryptoKeyStore"); + return new UriStyleMessageFormatter<AuthorizationCode>( - authorizationServer.CryptoKeyStore, + cryptoStore, AuthorizationCodeKeyBucket, signed: true, encrypted: true, diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/IOAuth2ChannelWithAuthorizationServer.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/IOAuth2ChannelWithAuthorizationServer.cs new file mode 100644 index 0000000..5fc73ce --- /dev/null +++ b/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/IOAuth2ChannelWithAuthorizationServer.cs @@ -0,0 +1,19 @@ +//----------------------------------------------------------------------- +// <copyright file="IOAuth2ChannelWithAuthorizationServer.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth2.ChannelElements { + /// <summary> + /// An interface on an OAuth 2 Authorization Server channel + /// to expose the host provided authorization server object. + /// </summary> + internal interface IOAuth2ChannelWithAuthorizationServer { + /// <summary> + /// Gets the authorization server. + /// </summary> + /// <value>The authorization server.</value> + IAuthorizationServer AuthorizationServer { get; } + } +} diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/OAuth2AuthorizationServerChannel.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/OAuth2AuthorizationServerChannel.cs index 295ee86..3375328 100644 --- a/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/OAuth2AuthorizationServerChannel.cs +++ b/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/OAuth2AuthorizationServerChannel.cs @@ -15,7 +15,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { /// <summary> /// The channel for the OAuth protocol. /// </summary> - internal class OAuth2AuthorizationServerChannel : OAuth2ChannelBase { + internal class OAuth2AuthorizationServerChannel : OAuth2ChannelBase, IOAuth2ChannelWithAuthorizationServer { /// <summary> /// Initializes a new instance of the <see cref="OAuth2AuthorizationServerChannel"/> class. /// </summary> diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/ClientDescription.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/ClientDescription.cs new file mode 100644 index 0000000..76c3ea6 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth2/OAuth2/ClientDescription.cs @@ -0,0 +1,71 @@ +//----------------------------------------------------------------------- +// <copyright file="ClientDescription.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth2 { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + + /// <summary> + /// A default implementation of the <see cref="IClientDescription"/> interface. + /// </summary> + public class ClientDescription : IClientDescription { + /// <summary> + /// A delegate that determines whether the callback is allowed. + /// </summary> + private readonly Func<Uri, bool> isCallbackAllowed; + + /// <summary> + /// Initializes a new instance of the <see cref="ClientDescription"/> class. + /// </summary> + /// <param name="secret">The secret.</param> + /// <param name="defaultCallback">The default callback.</param> + /// <param name="clientType">Type of the client.</param> + /// <param name="isCallbackAllowed">A delegate that determines whether the callback is allowed.</param> + public ClientDescription(string secret, Uri defaultCallback, ClientType clientType, Func<Uri, bool> isCallbackAllowed = null) { + this.Secret = secret; + this.DefaultCallback = defaultCallback; + this.ClientType = clientType; + this.isCallbackAllowed = isCallbackAllowed; + } + + /// <summary> + /// Gets the client secret. + /// </summary> + public string Secret { get; private set; } + + /// <summary> + /// Gets the callback to use when an individual authorization request + /// does not include an explicit callback URI. + /// </summary> + /// <value> + /// An absolute URL; or <c>null</c> if none is registered. + /// </value> + public Uri DefaultCallback { get; private set; } + + /// <summary> + /// Gets the type of the client. + /// </summary> + public ClientType ClientType { get; private set; } + + /// <summary> + /// Determines whether a callback URI included in a client's authorization request + /// is among those allowed callbacks for the registered client. + /// </summary> + /// <param name="callback">The absolute URI the client has requested the authorization result be received at.</param> + /// <returns> + /// <c>true</c> if the callback URL is allowable for this client; otherwise, <c>false</c>. + /// </returns> + public bool IsCallbackAllowed(Uri callback) { + if (this.isCallbackAllowed != null) { + return this.isCallbackAllowed(callback); + } + + return EqualityComparer<Uri>.Default.Equals(this.DefaultCallback, callback); + } + } +} diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/IAuthorizationServer.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/IAuthorizationServer.cs index 9c2888f..1732003 100644 --- a/src/DotNetOpenAuth.OAuth2/OAuth2/IAuthorizationServer.cs +++ b/src/DotNetOpenAuth.OAuth2/OAuth2/IAuthorizationServer.cs @@ -22,7 +22,7 @@ namespace DotNetOpenAuth.OAuth2 { [ContractClass(typeof(IAuthorizationServerContract))] public interface IAuthorizationServer { /// <summary> - /// Gets the store for storeing crypto keys used to symmetrically encrypt and sign authorization codes and refresh tokens. + /// Gets the store for storing crypto keys used to symmetrically encrypt and sign authorization codes and refresh tokens. /// </summary> /// <remarks> /// This store should be kept strictly confidential in the authorization server(s) diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthStrings.Designer.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthStrings.Designer.cs index 2167b5f..6ce3b53 100644 --- a/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthStrings.Designer.cs +++ b/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthStrings.Designer.cs @@ -169,6 +169,15 @@ namespace DotNetOpenAuth.OAuth2 { } /// <summary> + /// Looks up a localized string similar to The return value of {0}.{1} should never be null.. + /// </summary> + internal static string ResultShouldNotBeNull { + get { + return ResourceManager.GetString("ResultShouldNotBeNull", resourceCulture); + } + } + + /// <summary> /// Looks up a localized string similar to Individual scopes may not contain spaces.. /// </summary> internal static string ScopesMayNotContainSpaces { diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthStrings.resx b/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthStrings.resx index 6fad914..af1a955 100644 --- a/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthStrings.resx +++ b/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthStrings.resx @@ -153,6 +153,9 @@ <data name="RefreshTokenInappropriateForRequestType" xml:space="preserve"> <value>The request message type {0} should not be responded to with a refresh token.</value> </data> + <data name="ResultShouldNotBeNull" xml:space="preserve"> + <value>The return value of {0}.{1} should never be null.</value> + </data> <data name="ScopesMayNotContainSpaces" xml:space="preserve"> <value>Individual scopes may not contain spaces.</value> </data> diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthUtilities.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthUtilities.cs index 245779a..68ccc1d 100644 --- a/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthUtilities.cs +++ b/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthUtilities.cs @@ -141,7 +141,9 @@ namespace DotNetOpenAuth.OAuth2 { Contract.Ensures(Contract.Result<IClientDescription>() != null); try { - return authorizationServer.GetClient(clientIdentifier); + var result = authorizationServer.GetClient(clientIdentifier); + ErrorUtilities.VerifyHost(result != null, OAuthStrings.ResultShouldNotBeNull, authorizationServer.GetType().FullName, "GetClient(string)"); + return result; } catch (KeyNotFoundException ex) { throw ErrorUtilities.Wrap(ex, OAuthStrings.ClientOrTokenSecretNotFound); } catch (ArgumentException ex) { diff --git a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj index 46556f7..8fc4183 100644 --- a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj +++ b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj @@ -218,6 +218,7 @@ <Compile Include="Mocks\AssociateUnencryptedRequestNoSslCheck.cs" /> <Compile Include="Mocks\CoordinatingChannel.cs" /> <Compile Include="Mocks\CoordinatingHttpRequestInfo.cs" /> + <Compile Include="Mocks\CoordinatingOAuth2AuthServerChannel.cs" /> <Compile Include="Mocks\CoordinatingOutgoingWebResponse.cs" /> <Compile Include="Mocks\CoordinatingOAuthConsumerChannel.cs" /> <Compile Include="Mocks\InMemoryTokenManager.cs" /> @@ -242,7 +243,8 @@ <Compile Include="Mocks\TestMessage.cs" /> <Compile Include="Mocks\TestMessageFactory.cs" /> <Compile Include="OAuth2\MessageFactoryTests.cs" /> - <Compile Include="OAuth2\OAuth2ChannelTests.cs" /> + <Compile Include="OAuth2\AuthorizeTests.cs" /> + <Compile Include="OAuth2\OAuth2Coordinator.cs" /> <Compile Include="OAuth2\OAuth2TestBase.cs" /> <Compile Include="OAuth\ChannelElements\HmacSha1SigningBindingElementTests.cs" /> <Compile Include="OAuth\ChannelElements\OAuthChannelTests.cs" /> @@ -484,4 +486,4 @@ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(ProjectRoot)tools\DotNetOpenAuth.targets" /> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))\EnlistmentInfo.targets" Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))' != '' " /> -</Project> +</Project>
\ No newline at end of file diff --git a/src/DotNetOpenAuth.Test/Mocks/CoordinatingChannel.cs b/src/DotNetOpenAuth.Test/Mocks/CoordinatingChannel.cs index 054892a..8d5295b 100644 --- a/src/DotNetOpenAuth.Test/Mocks/CoordinatingChannel.cs +++ b/src/DotNetOpenAuth.Test/Mocks/CoordinatingChannel.cs @@ -142,7 +142,7 @@ namespace DotNetOpenAuth.Test.Mocks { ErrorUtilities.VerifyInternal(this.incomingMessage == null, "Oops, a message is already waiting for the remote party!"); this.incomingMessage = this.MessageDescriptions.GetAccessor(message).Serialize(); var directedMessage = message as IDirectedProtocolMessage; - this.incomingMessageRecipient = directedMessage != null ? new MessageReceivingEndpoint(directedMessage.Recipient, directedMessage.HttpMethods) : null; + this.incomingMessageRecipient = (directedMessage != null && directedMessage.Recipient != null) ? new MessageReceivingEndpoint(directedMessage.Recipient, directedMessage.HttpMethods) : null; this.incomingMessageSignal.Set(); } diff --git a/src/DotNetOpenAuth.Test/Mocks/CoordinatingOAuth2AuthServerChannel.cs b/src/DotNetOpenAuth.Test/Mocks/CoordinatingOAuth2AuthServerChannel.cs new file mode 100644 index 0000000..2b087fd --- /dev/null +++ b/src/DotNetOpenAuth.Test/Mocks/CoordinatingOAuth2AuthServerChannel.cs @@ -0,0 +1,28 @@ +//----------------------------------------------------------------------- +// <copyright file="CoordinatingOAuth2AuthServerChannel.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test.Mocks { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth2; + using DotNetOpenAuth.OAuth2.ChannelElements; + + internal class CoordinatingOAuth2AuthServerChannel : CoordinatingChannel, IOAuth2ChannelWithAuthorizationServer { + private OAuth2AuthorizationServerChannel wrappedChannel; + + internal CoordinatingOAuth2AuthServerChannel(Channel wrappedChannel, Action<IProtocolMessage> incomingMessageFilter, Action<IProtocolMessage> outgoingMessageFilter) + : base(wrappedChannel, incomingMessageFilter, outgoingMessageFilter) { + this.wrappedChannel = (OAuth2AuthorizationServerChannel)wrappedChannel; + } + + public IAuthorizationServer AuthorizationServer { + get { return this.wrappedChannel.AuthorizationServer; } + } + } +} diff --git a/src/DotNetOpenAuth.Test/OAuth2/AuthorizeTests.cs b/src/DotNetOpenAuth.Test/OAuth2/AuthorizeTests.cs new file mode 100644 index 0000000..0f0ad8b --- /dev/null +++ b/src/DotNetOpenAuth.Test/OAuth2/AuthorizeTests.cs @@ -0,0 +1,50 @@ +//----------------------------------------------------------------------- +// <copyright file="AuthorizeTests.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test.OAuth2 { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.Messaging.Bindings; + using DotNetOpenAuth.OAuth2; + using DotNetOpenAuth.OAuth2.ChannelElements; + using DotNetOpenAuth.OAuth2.Messages; + using Moq; + using NUnit.Framework; + + [TestFixture] + public class AuthorizeTests : OAuth2TestBase { + [TestCase] + public void Test1() { + var authHostMock = new Mock<IAuthorizationServer>(); + var cryptoStore = new MemoryCryptoKeyStore(); + authHostMock.Setup(m => m.GetClient(ClientId)).Returns(ClientDescription); + authHostMock.SetupGet(m => m.CryptoKeyStore).Returns(cryptoStore); + authHostMock.Setup(m => m.IsAuthorizationValid(It.Is<IAuthorizationDescription>(d => d.ClientIdentifier == ClientId && d.User == Username))).Returns(true); + var coordinator = new OAuth2Coordinator( + AuthorizationServerDescription, + authHostMock.Object, + client => { + var authState = new AuthorizationState { + Callback = ClientCallback, + }; + client.PrepareRequestUserAuthorization(authState).Respond(); + var result = client.ProcessUserAuthorization(); + Assert.IsNotNull(result.AccessToken); + }, + server => { + var request = server.ReadAuthorizationRequest(); + server.ApproveAuthorizationRequest(request, Username); + var tokenRequest = server.ReadAccessTokenRequest(); + var tokenResponse = server.PrepareAccessTokenResponse(tokenRequest); + server.Channel.Respond(tokenResponse); + }); + coordinator.Run(); + } + } +} diff --git a/src/DotNetOpenAuth.Test/OAuth2/OAuth2ChannelTests.cs b/src/DotNetOpenAuth.Test/OAuth2/OAuth2ChannelTests.cs deleted file mode 100644 index 309dfaf..0000000 --- a/src/DotNetOpenAuth.Test/OAuth2/OAuth2ChannelTests.cs +++ /dev/null @@ -1,21 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="OAuth2ChannelTests.cs" company="Outercurve Foundation"> -// Copyright (c) Outercurve Foundation. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.Test.OAuth2 { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - using DotNetOpenAuth.Messaging; - using DotNetOpenAuth.OAuth2; - using DotNetOpenAuth.OAuth2.ChannelElements; - using DotNetOpenAuth.OAuth2.Messages; - using NUnit.Framework; - - [TestFixture] - public class OAuth2ChannelTests : OAuth2TestBase { - } -} diff --git a/src/DotNetOpenAuth.Test/OAuth2/OAuth2Coordinator.cs b/src/DotNetOpenAuth.Test/OAuth2/OAuth2Coordinator.cs new file mode 100644 index 0000000..5af7fe8 --- /dev/null +++ b/src/DotNetOpenAuth.Test/OAuth2/OAuth2Coordinator.cs @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------- +// <copyright file="OAuth2Coordinator.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test.OAuth2 { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.OAuth2; + using DotNetOpenAuth.Test.Mocks; + + internal class OAuth2Coordinator : CoordinatorBase<WebServerClient, AuthorizationServer> { + private readonly AuthorizationServerDescription serverDescription; + private readonly IAuthorizationServer authServerHost; + + internal OAuth2Coordinator(AuthorizationServerDescription serverDescription, IAuthorizationServer authServerHost, Action<WebServerClient> clientAction, Action<AuthorizationServer> authServerAction) + : base(clientAction, authServerAction) { + Requires.NotNull(serverDescription, "serverDescription"); + Requires.NotNull(authServerHost, "authServerHost"); + this.serverDescription = serverDescription; + this.authServerHost = authServerHost; + } + + internal override void Run() { + var client = new WebServerClient(this.serverDescription) { + ClientIdentifier = OAuth2TestBase.ClientId, + ClientSecret = OAuth2TestBase.ClientSecret, + }; + var authServer = new AuthorizationServer(this.authServerHost); + + var rpCoordinatingChannel = new CoordinatingChannel(client.Channel, this.IncomingMessageFilter, this.OutgoingMessageFilter); + var opCoordinatingChannel = new CoordinatingOAuth2AuthServerChannel(authServer.Channel, this.IncomingMessageFilter, this.OutgoingMessageFilter); + rpCoordinatingChannel.RemoteChannel = opCoordinatingChannel; + opCoordinatingChannel.RemoteChannel = rpCoordinatingChannel; + + client.Channel = rpCoordinatingChannel; + authServer.Channel = opCoordinatingChannel; + + this.RunCore(client, authServer); + } + + private static Action<WebServerClient> WrapAction(Action<WebServerClient> action) { + Requires.NotNull(action, "action"); + + return client => { + action(client); + ((CoordinatingChannel)client.Channel).Close(); + }; + } + + private static Action<AuthorizationServer> WrapAction(Action<AuthorizationServer> action) { + Requires.NotNull(action, "action"); + + return authServer => { + action(authServer); + ((CoordinatingChannel)authServer.Channel).Close(); + }; + } + } +} diff --git a/src/DotNetOpenAuth.Test/OAuth2/OAuth2TestBase.cs b/src/DotNetOpenAuth.Test/OAuth2/OAuth2TestBase.cs index 49fc40b..32de525 100644 --- a/src/DotNetOpenAuth.Test/OAuth2/OAuth2TestBase.cs +++ b/src/DotNetOpenAuth.Test/OAuth2/OAuth2TestBase.cs @@ -9,7 +9,25 @@ namespace DotNetOpenAuth.Test.OAuth2 { using System.Collections.Generic; using System.Linq; using System.Text; + using DotNetOpenAuth.OAuth2; public class OAuth2TestBase : TestBase { + protected internal const string ClientId = "TestClientId"; + + protected internal const string ClientSecret = "TestClientSecret"; + + protected const string Username = "TestUser"; + + protected static readonly Uri ClientCallback = new Uri("http://client/callback"); + + protected static readonly AuthorizationServerDescription AuthorizationServerDescription = new AuthorizationServerDescription { + AuthorizationEndpoint = new Uri("https://authserver/authorize"), + TokenEndpoint = new Uri("https://authserver/token"), + }; + + protected static readonly IClientDescription ClientDescription = new ClientDescription( + ClientSecret, + ClientCallback, + ClientType.Confidential); } } |