summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2012-12-26 08:05:32 -0800
committerAndrew Arnott <andrewarnott@gmail.com>2012-12-26 08:05:32 -0800
commit3787e3dac06df104a8fbe4b2c2df02abadd63d74 (patch)
treea216be8fe66ba273c508a3b3f77e1e49a2557a50 /src
parent162f450a2cfb861ca5fcb36410625a7b3326494e (diff)
parent06fdacd94eb1a337b6822680336317357885ab48 (diff)
downloadDotNetOpenAuth-3787e3dac06df104a8fbe4b2c2df02abadd63d74.zip
DotNetOpenAuth-3787e3dac06df104a8fbe4b2c2df02abadd63d74.tar.gz
DotNetOpenAuth-3787e3dac06df104a8fbe4b2c2df02abadd63d74.tar.bz2
Merge branch 'v4.2'
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs21
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs172
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs2
-rw-r--r--src/DotNetOpenAuth.Test/Mocks/CoordinatingChannel.cs19
-rw-r--r--src/DotNetOpenAuth.Test/Mocks/CoordinatingHttpRequestInfo.cs19
-rw-r--r--src/DotNetOpenAuth.Test/Mocks/CoordinatingOutgoingWebResponse.cs7
-rw-r--r--src/DotNetOpenAuth.Test/OAuth2/AuthorizationServerTests.cs23
7 files changed, 168 insertions, 95 deletions
diff --git a/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs b/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs
index 4b4a3fe..d0f6f63 100644
--- a/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs
@@ -61,6 +61,11 @@ namespace DotNetOpenAuth.Messaging {
private readonly NameValueCollection serverVariables;
/// <summary>
+ /// The backing field for the <see cref="Cookies"/> property.
+ /// </summary>
+ private readonly HttpCookieCollection cookies;
+
+ /// <summary>
/// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
/// </summary>
/// <param name="request">The request.</param>
@@ -75,6 +80,7 @@ namespace DotNetOpenAuth.Messaging {
this.form = new NameValueCollection();
this.queryString = HttpUtility.ParseQueryString(requestUri.Query);
this.serverVariables = new NameValueCollection();
+ this.cookies = new HttpCookieCollection();
Reporting.RecordRequestStatistics(this);
}
@@ -86,7 +92,8 @@ namespace DotNetOpenAuth.Messaging {
/// <param name="requestUri">The request URI.</param>
/// <param name="form">The form variables.</param>
/// <param name="headers">The HTTP headers.</param>
- internal HttpRequestInfo(string httpMethod, Uri requestUri, NameValueCollection form = null, NameValueCollection headers = null) {
+ /// <param name="cookies">The cookies in the request.</param>
+ internal HttpRequestInfo(string httpMethod, Uri requestUri, NameValueCollection form = null, NameValueCollection headers = null, HttpCookieCollection cookies = null) {
Requires.NotNullOrEmpty(httpMethod, "httpMethod");
Requires.NotNull(requestUri, "requestUri");
@@ -96,6 +103,7 @@ namespace DotNetOpenAuth.Messaging {
this.queryString = HttpUtility.ParseQueryString(requestUri.Query);
this.headers = headers ?? new WebHeaderCollection();
this.serverVariables = new NameValueCollection();
+ this.cookies = cookies ?? new HttpCookieCollection();
}
/// <summary>
@@ -111,6 +119,7 @@ namespace DotNetOpenAuth.Messaging {
this.headers = listenerRequest.Headers;
this.form = ParseFormData(listenerRequest.HttpMethod, listenerRequest.Headers, () => listenerRequest.InputStream);
this.serverVariables = new NameValueCollection();
+ this.cookies = new HttpCookieCollection();
Reporting.RecordRequestStatistics(this);
}
@@ -131,6 +140,7 @@ namespace DotNetOpenAuth.Messaging {
AddHeaders(this.headers, request.Content.Headers);
this.form = ParseFormData(this.httpMethod, this.headers, () => request.Content.ReadAsStreamAsync().Result);
this.serverVariables = new NameValueCollection();
+ this.cookies = new HttpCookieCollection();
Reporting.RecordRequestStatistics(this);
}
@@ -153,6 +163,7 @@ namespace DotNetOpenAuth.Messaging {
this.queryString = HttpUtility.ParseQueryString(requestUri.Query);
this.form = ParseFormData(httpMethod, headers, () => inputStream);
this.serverVariables = new NameValueCollection();
+ this.cookies = new HttpCookieCollection();
Reporting.RecordRequestStatistics(this);
}
@@ -207,6 +218,14 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Gets the collection of cookies that were sent by the client.
+ /// </summary>
+ /// <returns>The client's cookies.</returns>
+ public override HttpCookieCollection Cookies {
+ get { return this.cookies; }
+ }
+
+ /// <summary>
/// Creates an <see cref="HttpRequestBase"/> instance that describes the specified HTTP request.
/// </summary>
/// <param name="request">The request.</param>
diff --git a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs
index 2e72c97..bbe28ab 100644
--- a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs
@@ -22,6 +22,7 @@ namespace DotNetOpenAuth.Messaging {
using System.Runtime.Serialization.Json;
using System.Security;
using System.Security.Cryptography;
+ using System.Threading;
using System.Text;
using System.Web;
using System.Web.Mvc;
@@ -41,9 +42,11 @@ namespace DotNetOpenAuth.Messaging {
internal static readonly RandomNumberGenerator CryptoRandomDataGenerator = new RNGCryptoServiceProvider();
/// <summary>
- /// A pseudo-random data generator (NOT cryptographically strong random data)
+ /// Gets a random number generator for use on the current thread only.
/// </summary>
- internal static readonly Random NonCryptoRandomDataGenerator = new Random();
+ internal static Random NonCryptoRandomDataGenerator {
+ get { return ThreadSafeRandom.RandomNumberGenerator; }
+ }
/// <summary>
/// The uppercase alphabet.
@@ -367,63 +370,63 @@ namespace DotNetOpenAuth.Messaging {
}
return result == 0;
- }
-
- /// <summary>
- /// Gets the public facing URL for the given incoming HTTP request.
- /// </summary>
- /// <param name="request">The incoming request. Cannot be <c>null</c>.</param>
- /// <param name="serverVariables">The server variables to consider part of the request. Cannot be <c>null</c>.</param>
- /// <returns>
- /// The URI that the outside world used to create this request.
- /// </returns>
- /// <remarks>
- /// Although the <paramref name="serverVariables"/> value can be obtained from
- /// <see cref="HttpRequest.ServerVariables"/>, it's useful to be able to pass them
- /// in so we can simulate injected values from our unit tests since the actual property
- /// is a read-only kind of <see cref="NameValueCollection"/>.
- /// </remarks>
- public static Uri GetPublicFacingUrl(this HttpRequestBase request, NameValueCollection serverVariables) {
- Requires.NotNull(request, "request");
- Requires.NotNull(serverVariables, "serverVariables");
-
- // Due to URL rewriting, cloud computing (i.e. Azure)
- // and web farms, etc., we have to be VERY careful about what
- // we consider the incoming URL. We want to see the URL as it would
- // appear on the public-facing side of the hosting web site.
- // HttpRequest.Url gives us the internal URL in a cloud environment,
- // So we use a variable that (at least from what I can tell) gives us
- // the public URL:
- if (serverVariables["HTTP_HOST"] != null) {
- ErrorUtilities.VerifySupported(request.Url.Scheme == Uri.UriSchemeHttps || request.Url.Scheme == Uri.UriSchemeHttp, "Only HTTP and HTTPS are supported protocols.");
- string scheme = serverVariables["HTTP_X_FORWARDED_PROTO"] ?? request.Url.Scheme;
- Uri hostAndPort = new Uri(scheme + Uri.SchemeDelimiter + serverVariables["HTTP_HOST"]);
- UriBuilder publicRequestUri = new UriBuilder(request.Url);
- publicRequestUri.Scheme = scheme;
- publicRequestUri.Host = hostAndPort.Host;
- publicRequestUri.Port = hostAndPort.Port; // CC missing Uri.Port contract that's on UriBuilder.Port
- return publicRequestUri.Uri;
- } else {
- // Failover to the method that works for non-web farm enviroments.
- // We use Request.Url for the full path to the server, and modify it
- // with Request.RawUrl to capture both the cookieless session "directory" if it exists
- // and the original path in case URL rewriting is going on. We don't want to be
- // fooled by URL rewriting because we're comparing the actual URL with what's in
- // the return_to parameter in some cases.
- // Response.ApplyAppPathModifier(builder.Path) would have worked for the cookieless
- // session, but not the URL rewriting problem.
- return new Uri(request.Url, request.RawUrl);
- }
- }
-
- /// <summary>
- /// Gets the public facing URL for the given incoming HTTP request.
- /// </summary>
- /// <param name="request">The incoming request. Cannot be <c>null</c>. Server variables are read from this request.</param>
- /// <returns>The URI that the outside world used to create this request.</returns>
- public static Uri GetPublicFacingUrl(this HttpRequestBase request) {
- Requires.NotNull(request, "request");
- return GetPublicFacingUrl(request, request.ServerVariables);
+ }
+
+ /// <summary>
+ /// Gets the public facing URL for the given incoming HTTP request.
+ /// </summary>
+ /// <param name="request">The incoming request. Cannot be <c>null</c>.</param>
+ /// <param name="serverVariables">The server variables to consider part of the request. Cannot be <c>null</c>.</param>
+ /// <returns>
+ /// The URI that the outside world used to create this request.
+ /// </returns>
+ /// <remarks>
+ /// Although the <paramref name="serverVariables"/> value can be obtained from
+ /// <see cref="HttpRequest.ServerVariables"/>, it's useful to be able to pass them
+ /// in so we can simulate injected values from our unit tests since the actual property
+ /// is a read-only kind of <see cref="NameValueCollection"/>.
+ /// </remarks>
+ public static Uri GetPublicFacingUrl(this HttpRequestBase request, NameValueCollection serverVariables) {
+ Requires.NotNull(request, "request");
+ Requires.NotNull(serverVariables, "serverVariables");
+
+ // Due to URL rewriting, cloud computing (i.e. Azure)
+ // and web farms, etc., we have to be VERY careful about what
+ // we consider the incoming URL. We want to see the URL as it would
+ // appear on the public-facing side of the hosting web site.
+ // HttpRequest.Url gives us the internal URL in a cloud environment,
+ // So we use a variable that (at least from what I can tell) gives us
+ // the public URL:
+ if (serverVariables["HTTP_HOST"] != null) {
+ ErrorUtilities.VerifySupported(request.Url.Scheme == Uri.UriSchemeHttps || request.Url.Scheme == Uri.UriSchemeHttp, "Only HTTP and HTTPS are supported protocols.");
+ string scheme = serverVariables["HTTP_X_FORWARDED_PROTO"] ?? request.Url.Scheme;
+ Uri hostAndPort = new Uri(scheme + Uri.SchemeDelimiter + serverVariables["HTTP_HOST"]);
+ UriBuilder publicRequestUri = new UriBuilder(request.Url);
+ publicRequestUri.Scheme = scheme;
+ publicRequestUri.Host = hostAndPort.Host;
+ publicRequestUri.Port = hostAndPort.Port; // CC missing Uri.Port contract that's on UriBuilder.Port
+ return publicRequestUri.Uri;
+ } else {
+ // Failover to the method that works for non-web farm enviroments.
+ // We use Request.Url for the full path to the server, and modify it
+ // with Request.RawUrl to capture both the cookieless session "directory" if it exists
+ // and the original path in case URL rewriting is going on. We don't want to be
+ // fooled by URL rewriting because we're comparing the actual URL with what's in
+ // the return_to parameter in some cases.
+ // Response.ApplyAppPathModifier(builder.Path) would have worked for the cookieless
+ // session, but not the URL rewriting problem.
+ return new Uri(request.Url, request.RawUrl);
+ }
+ }
+
+ /// <summary>
+ /// Gets the public facing URL for the given incoming HTTP request.
+ /// </summary>
+ /// <param name="request">The incoming request. Cannot be <c>null</c>. Server variables are read from this request.</param>
+ /// <returns>The URI that the outside world used to create this request.</returns>
+ public static Uri GetPublicFacingUrl(this HttpRequestBase request) {
+ Requires.NotNull(request, "request");
+ return GetPublicFacingUrl(request, request.ServerVariables);
}
/// <summary>
@@ -662,7 +665,7 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
- /// Gets a cryptographically strong random sequence of values.
+ /// Gets a cryptographically strong random string of base64 characters.
/// </summary>
/// <param name="binaryLength">The length of the byte sequence to generate.</param>
/// <returns>A base64 encoding of the generated random data,
@@ -674,6 +677,18 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Gets a NON-cryptographically strong random string of base64 characters.
+ /// </summary>
+ /// <param name="binaryLength">The length of the byte sequence to generate.</param>
+ /// <returns>A base64 encoding of the generated random data,
+ /// whose length in characters will likely be greater than <paramref name="binaryLength"/>.</returns>
+ internal static string GetNonCryptoRandomDataAsBase64(int binaryLength) {
+ byte[] uniq_bytes = GetNonCryptoRandomData(binaryLength);
+ string uniq = Convert.ToBase64String(uniq_bytes);
+ return uniq;
+ }
+
+ /// <summary>
/// Gets a random string made up of a given set of allowable characters.
/// </summary>
/// <param name="length">The length of the desired random string.</param>
@@ -684,8 +699,9 @@ namespace DotNetOpenAuth.Messaging {
Requires.True(allowableCharacters != null && allowableCharacters.Length >= 2, "allowableCharacters");
char[] randomString = new char[length];
+ var random = NonCryptoRandomDataGenerator;
for (int i = 0; i < length; i++) {
- randomString[i] = allowableCharacters[NonCryptoRandomDataGenerator.Next(allowableCharacters.Length)];
+ randomString[i] = allowableCharacters[random.Next(allowableCharacters.Length)];
}
return new string(randomString);
@@ -1545,9 +1561,9 @@ namespace DotNetOpenAuth.Messaging {
return HttpDeliveryMethods.DeleteRequest;
} else if (httpVerb == "HEAD") {
return HttpDeliveryMethods.HeadRequest;
- } else if (httpVerb == "PATCH") {
+ } else if (httpVerb == "PATCH") {
return HttpDeliveryMethods.PatchRequest;
- } else if (httpVerb == "OPTIONS") {
+ } else if (httpVerb == "OPTIONS") {
return HttpDeliveryMethods.OptionsRequest;
} else {
throw ErrorUtilities.ThrowArgumentNamed("httpVerb", MessagingStrings.UnsupportedHttpVerb, httpVerb);
@@ -1570,9 +1586,9 @@ namespace DotNetOpenAuth.Messaging {
return "DELETE";
} else if ((httpMethod & HttpDeliveryMethods.HttpVerbMask) == HttpDeliveryMethods.HeadRequest) {
return "HEAD";
- } else if ((httpMethod & HttpDeliveryMethods.HttpVerbMask) == HttpDeliveryMethods.PatchRequest) {
+ } else if ((httpMethod & HttpDeliveryMethods.HttpVerbMask) == HttpDeliveryMethods.PatchRequest) {
return "PATCH";
- } else if ((httpMethod & HttpDeliveryMethods.HttpVerbMask) == HttpDeliveryMethods.OptionsRequest) {
+ } else if ((httpMethod & HttpDeliveryMethods.HttpVerbMask) == HttpDeliveryMethods.OptionsRequest) {
return "OPTIONS";
} else if ((httpMethod & HttpDeliveryMethods.AuthorizationHeaderRequest) != 0) {
return "GET"; // if AuthorizationHeaderRequest is specified without an explicit HTTP verb, assume GET.
@@ -2032,5 +2048,31 @@ namespace DotNetOpenAuth.Messaging {
#endregion
}
+
+ /// <summary>
+ /// A thread-safe, non-crypto random number generator.
+ /// </summary>
+ private static class ThreadSafeRandom {
+ /// <summary>
+ /// The initializer of all new <see cref="Random"/> instances.
+ /// </summary>
+ private static readonly Random threadRandomInitializer = new Random();
+
+ /// <summary>
+ /// A thread-local instance of <see cref="Random"/>
+ /// </summary>
+ private static readonly ThreadLocal<Random> threadRandom = new ThreadLocal<Random>(delegate {
+ lock (threadRandomInitializer) {
+ return new Random(threadRandomInitializer.Next());
+ }
+ });
+
+ /// <summary>
+ /// Gets a random number generator for use on the current thread only.
+ /// </summary>
+ public static Random RandomNumberGenerator {
+ get { return threadRandom.Value; }
+ }
+ }
}
}
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
index 4fc8687..1fdd372 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
@@ -113,7 +113,7 @@ namespace DotNetOpenAuth.OAuth2 {
if (this.AuthorizationTracker == null) {
var context = this.Channel.GetHttpContext();
- string xsrfKey = (new Random()).Next().ToString(CultureInfo.InvariantCulture);
+ string xsrfKey = MessagingUtilities.GetNonCryptoRandomDataAsBase64(16);
cookie = new HttpCookie(XsrfCookieName, xsrfKey) {
HttpOnly = true,
Secure = FormsAuthentication.RequireSSL,
diff --git a/src/DotNetOpenAuth.Test/Mocks/CoordinatingChannel.cs b/src/DotNetOpenAuth.Test/Mocks/CoordinatingChannel.cs
index 2e09943..50eff97 100644
--- a/src/DotNetOpenAuth.Test/Mocks/CoordinatingChannel.cs
+++ b/src/DotNetOpenAuth.Test/Mocks/CoordinatingChannel.cs
@@ -88,6 +88,11 @@ namespace DotNetOpenAuth.Test.Mocks {
private Action<IProtocolMessage> outgoingMessageFilter;
/// <summary>
+ /// The simulated clients cookies.
+ /// </summary>
+ private HttpCookieCollection cookies = new HttpCookieCollection();
+
+ /// <summary>
/// Initializes a new instance of the <see cref="CoordinatingChannel"/> class.
/// </summary>
/// <param name="wrappedChannel">The wrapped channel. Must not be null.</param>
@@ -158,15 +163,23 @@ namespace DotNetOpenAuth.Test.Mocks {
this.incomingMessageSignal.Set();
}
+ internal void SaveCookies(HttpCookieCollection cookies) {
+ Requires.NotNull(cookies, "cookies");
+ foreach (string cookieName in cookies) {
+ var cookie = cookies[cookieName];
+ this.cookies.Set(cookie);
+ }
+ }
+
protected internal override HttpRequestBase GetRequestFromContext() {
MessageReceivingEndpoint recipient;
WebHeaderCollection headers;
var messageData = this.AwaitIncomingMessage(out recipient, out headers);
CoordinatingHttpRequestInfo result;
if (messageData != null) {
- result = new CoordinatingHttpRequestInfo(this, this.MessageFactory, messageData, recipient);
+ result = new CoordinatingHttpRequestInfo(this, this.MessageFactory, messageData, recipient, this.cookies);
} else {
- result = new CoordinatingHttpRequestInfo(recipient);
+ result = new CoordinatingHttpRequestInfo(recipient, this.cookies);
}
if (headers != null) {
@@ -207,7 +220,7 @@ namespace DotNetOpenAuth.Test.Mocks {
protected override OutgoingWebResponse PrepareDirectResponse(IProtocolMessage response) {
this.ProcessMessageFilter(response, true);
- return new CoordinatingOutgoingWebResponse(response, this.RemoteChannel);
+ return new CoordinatingOutgoingWebResponse(response, this.RemoteChannel, this);
}
protected override OutgoingWebResponse PrepareIndirectResponse(IDirectedProtocolMessage message) {
diff --git a/src/DotNetOpenAuth.Test/Mocks/CoordinatingHttpRequestInfo.cs b/src/DotNetOpenAuth.Test/Mocks/CoordinatingHttpRequestInfo.cs
index a1f5cf5..d53d8c9 100644
--- a/src/DotNetOpenAuth.Test/Mocks/CoordinatingHttpRequestInfo.cs
+++ b/src/DotNetOpenAuth.Test/Mocks/CoordinatingHttpRequestInfo.cs
@@ -6,10 +6,12 @@
namespace DotNetOpenAuth.Test.Mocks {
using System;
-using System.Collections.Generic;
-using System.Diagnostics.Contracts;
-using System.Net;
-using DotNetOpenAuth.Messaging;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using System.Net;
+ using System.Web;
+
+ using DotNetOpenAuth.Messaging;
internal class CoordinatingHttpRequestInfo : HttpRequestInfo {
private readonly Channel channel;
@@ -34,8 +36,9 @@ using DotNetOpenAuth.Messaging;
Channel channel,
IMessageFactory messageFactory,
IDictionary<string, string> messageData,
- MessageReceivingEndpoint recipient)
- : this(recipient) {
+ MessageReceivingEndpoint recipient,
+ HttpCookieCollection cookies)
+ : this(recipient, cookies) {
Contract.Requires(channel != null);
Contract.Requires(messageFactory != null);
Contract.Requires(messageData != null);
@@ -49,8 +52,8 @@ using DotNetOpenAuth.Messaging;
/// that will not generate any message.
/// </summary>
/// <param name="recipient">The recipient.</param>
- internal CoordinatingHttpRequestInfo(MessageReceivingEndpoint recipient)
- : base(GetHttpVerb(recipient), recipient != null ? recipient.Location : new Uri("http://host/path")) {
+ internal CoordinatingHttpRequestInfo(MessageReceivingEndpoint recipient, HttpCookieCollection cookies)
+ : base(GetHttpVerb(recipient), recipient != null ? recipient.Location : new Uri("http://host/path"), cookies: cookies) {
this.recipient = recipient;
}
diff --git a/src/DotNetOpenAuth.Test/Mocks/CoordinatingOutgoingWebResponse.cs b/src/DotNetOpenAuth.Test/Mocks/CoordinatingOutgoingWebResponse.cs
index 8d2c1e7..326cc74 100644
--- a/src/DotNetOpenAuth.Test/Mocks/CoordinatingOutgoingWebResponse.cs
+++ b/src/DotNetOpenAuth.Test/Mocks/CoordinatingOutgoingWebResponse.cs
@@ -16,16 +16,20 @@ namespace DotNetOpenAuth.Test.Mocks {
internal class CoordinatingOutgoingWebResponse : OutgoingWebResponse {
private CoordinatingChannel receivingChannel;
+ private CoordinatingChannel sendingChannel;
+
/// <summary>
/// Initializes a new instance of the <see cref="CoordinatingOutgoingWebResponse"/> class.
/// </summary>
/// <param name="message">The direct response message to send to the remote channel. This message will be cloned.</param>
/// <param name="receivingChannel">The receiving channel.</param>
- internal CoordinatingOutgoingWebResponse(IProtocolMessage message, CoordinatingChannel receivingChannel) {
+ internal CoordinatingOutgoingWebResponse(IProtocolMessage message, CoordinatingChannel receivingChannel, CoordinatingChannel sendingChannel) {
Requires.NotNull(message, "message");
Requires.NotNull(receivingChannel, "receivingChannel");
+ Requires.NotNull(sendingChannel, "sendingChannel");
this.receivingChannel = receivingChannel;
+ this.sendingChannel = sendingChannel;
this.OriginalMessage = message;
}
@@ -35,6 +39,7 @@ namespace DotNetOpenAuth.Test.Mocks {
}
public override void Respond() {
+ this.sendingChannel.SaveCookies(this.Cookies);
this.receivingChannel.PostMessage(this.OriginalMessage);
}
}
diff --git a/src/DotNetOpenAuth.Test/OAuth2/AuthorizationServerTests.cs b/src/DotNetOpenAuth.Test/OAuth2/AuthorizationServerTests.cs
index e1af8a5..e8f7172 100644
--- a/src/DotNetOpenAuth.Test/OAuth2/AuthorizationServerTests.cs
+++ b/src/DotNetOpenAuth.Test/OAuth2/AuthorizationServerTests.cs
@@ -168,33 +168,24 @@ namespace DotNetOpenAuth.Test.OAuth2 {
Assert.That(req.User, Is.EqualTo(ResourceOwnerUsername));
return true;
});
- var refreshTokenSource = new TaskCompletionSource<string>();
var coordinator = new OAuth2Coordinator<WebServerClient>(
AuthorizationServerDescription,
authServerMock.Object,
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();
- }
+ 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);
},
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();
}