summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs42
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/BearerTokenHttpMessageHandler.cs6
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs25
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs35
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs5
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/UserAgentClient.cs22
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs38
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/OAuth2ChannelBase.cs5
-rw-r--r--src/DotNetOpenAuth.OAuth2/DefaultOAuth2HostFactories.cs50
-rw-r--r--src/DotNetOpenAuth.OAuth2/DotNetOpenAuth.OAuth2.csproj3
-rw-r--r--src/DotNetOpenAuth.OAuth2/OAuth2/OAuthUtilities.cs8
-rw-r--r--src/DotNetOpenAuth.OAuth2/packages.config1
-rw-r--r--src/DotNetOpenAuth.OpenId/OpenId/OpenIdUtilities.cs21
13 files changed, 168 insertions, 93 deletions
diff --git a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs
index d9fedf2..4b04052 100644
--- a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs
@@ -15,6 +15,7 @@ namespace DotNetOpenAuth.Messaging {
using System.Linq;
using System.Net;
using System.Net.Http;
+ using System.Net.Http.Headers;
using System.Net.Mime;
using System.Runtime.Serialization.Json;
using System.Security;
@@ -625,6 +626,26 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Adds a Set-Cookie HTTP header for the specified cookie.
+ /// WARNING: support for cookie properties is currently VERY LIMITED.
+ /// </summary>
+ internal static void SetCookie(this HttpResponseHeaders headers, Cookie cookie) {
+ Requires.NotNull(headers, "headers");
+ Requires.NotNull(cookie, "cookie");
+
+ var cookieBuilder = new StringBuilder(HttpUtility.UrlEncode(cookie.Name) + "=" + HttpUtility.UrlEncode(cookie.Value));
+ if (cookie.HttpOnly) {
+ cookieBuilder.Append("; HttpOnly");
+ }
+
+ if (cookie.Secure) {
+ cookieBuilder.Append("; Secure");
+ }
+
+ headers.Add("Set-Cookie", cookieBuilder.ToString());
+ }
+
+ /// <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>
@@ -1525,6 +1546,27 @@ namespace DotNetOpenAuth.Messaging {
}
}
+ internal static Uri GetDirectUriRequest(this HttpResponseMessage response) {
+ Requires.NotNull(response, "response");
+ Requires.Argument(
+ response.StatusCode == HttpStatusCode.Redirect || response.StatusCode == HttpStatusCode.RedirectKeepVerb
+ || response.StatusCode == HttpStatusCode.RedirectMethod || response.StatusCode == HttpStatusCode.TemporaryRedirect,
+ "response",
+ "Redirecting response expected.");
+ Requires.Argument(response.Headers.Location != null, "response", "Redirect URL header expected.");
+ Requires.Argument(response.Content == null || response.Content is FormUrlEncodedContent, "response", "FormUrlEncodedContent expected");
+
+ var builder = new UriBuilder(response.Headers.Location);
+ if (response.Content != null) {
+ var content = response.Content.ReadAsStringAsync();
+ Assumes.True(content.IsCompleted); // cached in memory, so it should never complete asynchronously.
+ var formFields = HttpUtility.ParseQueryString(content.Result).ToDictionary();
+ MessagingUtilities.AppendQueryArgs(builder, formFields);
+ }
+
+ return builder.Uri;
+ }
+
/// <summary>
/// Collects a sequence of key=value pairs into a dictionary.
/// </summary>
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/BearerTokenHttpMessageHandler.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/BearerTokenHttpMessageHandler.cs
index da4c869..9ebca32 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/BearerTokenHttpMessageHandler.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/BearerTokenHttpMessageHandler.cs
@@ -72,21 +72,21 @@ namespace DotNetOpenAuth.OAuth2 {
/// <returns>
/// Returns <see cref="T:System.Threading.Tasks.Task`1" />. The task object representing the asynchronous operation.
/// </returns>
- protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
+ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
string bearerToken = this.BearerToken;
if (bearerToken == null) {
ErrorUtilities.VerifyProtocol(!this.Authorization.AccessTokenExpirationUtc.HasValue || this.Authorization.AccessTokenExpirationUtc < DateTime.UtcNow || this.Authorization.RefreshToken != null, ClientStrings.AuthorizationExpired);
if (this.Authorization.AccessTokenExpirationUtc.HasValue && this.Authorization.AccessTokenExpirationUtc.Value < DateTime.UtcNow) {
ErrorUtilities.VerifyProtocol(this.Authorization.RefreshToken != null, ClientStrings.AccessTokenRefreshFailed);
- this.Client.RefreshAuthorization(this.Authorization);
+ await this.Client.RefreshAuthorizationAsync(this.Authorization, cancellationToken: cancellationToken);
}
bearerToken = this.Authorization.AccessToken;
}
request.Headers.Authorization = new AuthenticationHeaderValue(Protocol.BearerHttpAuthorizationScheme, bearerToken);
- return base.SendAsync(request, cancellationToken);
+ return await base.SendAsync(request, cancellationToken);
}
}
}
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs
index cf57618..fc1731d 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs
@@ -9,9 +9,11 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Net;
+ using System.Net.Http;
+ using System.Threading;
+ using System.Threading.Tasks;
using System.Web;
using System.Xml;
-
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth2.Messages;
@@ -67,8 +69,8 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
/// This method must be overridden by a derived class, unless the <see cref="Channel.RequestCore"/> method
/// is overridden and does not require this method.
/// </remarks>
- protected override HttpWebRequest CreateHttpRequest(IDirectedProtocolMessage request) {
- HttpWebRequest httpRequest;
+ protected override HttpRequestMessage CreateHttpRequest(IDirectedProtocolMessage request) {
+ HttpRequestMessage httpRequest;
if ((request.HttpMethods & HttpDeliveryMethods.GetRequest) != 0) {
httpRequest = InitializeRequestAsGet(request);
} else if ((request.HttpMethods & HttpDeliveryMethods.PostRequest) != 0) {
@@ -88,16 +90,17 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
/// The deserialized message parts, if found. Null otherwise.
/// </returns>
/// <exception cref="ProtocolException">Thrown when the response is not valid.</exception>
- protected override IDictionary<string, string> ReadFromResponseCore(IncomingWebResponse response) {
+ protected override async Task<IDictionary<string, string>> ReadFromResponseCoreAsync(HttpResponseMessage response) {
// The spec says direct responses should be JSON objects, but Facebook uses HttpFormUrlEncoded instead, calling it text/plain
// Others return text/javascript. Again bad.
- string body = response.GetResponseReader().ReadToEnd();
- if (response.ContentType.MediaType == JsonEncoded || response.ContentType.MediaType == JsonTextEncoded) {
+ string body = await response.Content.ReadAsStringAsync();
+ var contentType = response.Content.Headers.ContentType.MediaType;
+ if (contentType == JsonEncoded || contentType == JsonTextEncoded) {
return this.DeserializeFromJson(body);
- } else if (response.ContentType.MediaType == HttpFormUrlEncoded || response.ContentType.MediaType == PlainTextEncoded) {
+ } else if (contentType == HttpFormUrlEncoded || contentType == PlainTextEncoded) {
return HttpUtility.ParseQueryString(body).ToDictionary();
} else {
- throw ErrorUtilities.ThrowProtocol(ClientStrings.UnexpectedResponseContentType, response.ContentType.MediaType);
+ throw ErrorUtilities.ThrowProtocol(ClientStrings.UnexpectedResponseContentType, contentType);
}
}
@@ -108,7 +111,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
/// <returns>
/// The deserialized message, if one is found. Null otherwise.
/// </returns>
- protected override IDirectedProtocolMessage ReadFromRequestCore(HttpRequestBase request) {
+ protected override IDirectedProtocolMessage ReadFromRequestCore(HttpRequestBase request, CancellationToken cancellationToken) {
Logger.Channel.DebugFormat("Incoming HTTP request: {0} {1}", request.HttpMethod, request.GetPublicFacingUrl().AbsoluteUri);
var fields = request.GetQueryStringBeforeRewriting().ToDictionary();
@@ -146,7 +149,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
/// <remarks>
/// This method implements spec OAuth V1.0 section 5.3.
/// </remarks>
- protected override OutgoingWebResponse PrepareDirectResponse(IProtocolMessage response) {
+ protected override HttpResponseMessage PrepareDirectResponse(IProtocolMessage response) {
// Clients don't ever send direct responses.
throw new NotImplementedException();
}
@@ -155,7 +158,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
/// Performs additional processing on an outgoing web request before it is sent to the remote server.
/// </summary>
/// <param name="request">The request.</param>
- protected override void PrepareHttpWebRequest(HttpWebRequest request) {
+ protected override void PrepareHttpWebRequest(HttpRequestMessage request) {
base.PrepareHttpWebRequest(request);
if (this.ClientCredentialApplicator != null) {
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs
index d66f4fd..05bcb57 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs
@@ -13,8 +13,9 @@ namespace DotNetOpenAuth.OAuth2 {
using System.Net.Http;
using System.Security;
using System.Text;
+ using System.Threading;
+ using System.Threading.Tasks;
using System.Xml;
-
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth2.ChannelElements;
using DotNetOpenAuth.OAuth2.Messages;
@@ -116,11 +117,11 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <param name="request">The request for protected resources from the service provider.</param>
/// <param name="authorization">The authorization for this request previously obtained via OAuth.</param>
- public void AuthorizeRequest(HttpWebRequest request, IAuthorizationState authorization) {
+ public Task AuthorizeRequestAsync(HttpWebRequest request, IAuthorizationState authorization, CancellationToken cancellationToken) {
Requires.NotNull(request, "request");
Requires.NotNull(authorization, "authorization");
- this.AuthorizeRequest(request.Headers, authorization);
+ return this.AuthorizeRequestAsync(request.Headers, authorization, cancellationToken);
}
/// <summary>
@@ -129,7 +130,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <param name="requestHeaders">The headers on the request for protected resources from the service provider.</param>
/// <param name="authorization">The authorization for this request previously obtained via OAuth.</param>
- public void AuthorizeRequest(WebHeaderCollection requestHeaders, IAuthorizationState authorization) {
+ public async Task AuthorizeRequestAsync(WebHeaderCollection requestHeaders, IAuthorizationState authorization, CancellationToken cancellationToken) {
Requires.NotNull(requestHeaders, "requestHeaders");
Requires.NotNull(authorization, "authorization");
Requires.That(!string.IsNullOrEmpty(authorization.AccessToken), "authorization", "AccessToken required.");
@@ -137,7 +138,7 @@ namespace DotNetOpenAuth.OAuth2 {
if (authorization.AccessTokenExpirationUtc.HasValue && authorization.AccessTokenExpirationUtc.Value < DateTime.UtcNow) {
ErrorUtilities.VerifyProtocol(authorization.RefreshToken != null, ClientStrings.AccessTokenRefreshFailed);
- this.RefreshAuthorization(authorization);
+ await this.RefreshAuthorizationAsync(authorization, cancellationToken: cancellationToken);
}
AuthorizeRequest(requestHeaders, authorization.AccessToken);
@@ -180,7 +181,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// the <paramref name="authorization"/> parameter if the authorization server has cycled out your refresh token.
/// If the parameter value was updated, this method calls <see cref="IAuthorizationState.SaveChanges"/> on that instance.
/// </remarks>
- public bool RefreshAuthorization(IAuthorizationState authorization, TimeSpan? skipIfUsefulLifeExceeds = null) {
+ public async Task<bool> RefreshAuthorizationAsync(IAuthorizationState authorization, TimeSpan? skipIfUsefulLifeExceeds = null, CancellationToken cancellationToken = default(CancellationToken)) {
Requires.NotNull(authorization, "authorization");
Requires.That(!string.IsNullOrEmpty(authorization.RefreshToken), "authorization", "RefreshToken required.");
@@ -200,7 +201,7 @@ namespace DotNetOpenAuth.OAuth2 {
this.ApplyClientCredential(request);
- var response = this.Channel.Request<AccessTokenSuccessResponse>(request);
+ var response = await this.Channel.RequestAsync<AccessTokenSuccessResponse>(request, cancellationToken);
UpdateAuthorizationWithResponse(authorization, response);
return true;
}
@@ -216,7 +217,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// If the return value includes a new refresh token, the old refresh token should be discarded and
/// replaced with the new one.
/// </remarks>
- public IAuthorizationState GetScopedAccessToken(string refreshToken, HashSet<string> scope) {
+ public async Task<IAuthorizationState> GetScopedAccessTokenAsync(string refreshToken, HashSet<string> scope, CancellationToken cancellationToken) {
Requires.NotNullOrEmpty(refreshToken, "refreshToken");
Requires.NotNull(scope, "scope");
@@ -227,7 +228,7 @@ namespace DotNetOpenAuth.OAuth2 {
this.ApplyClientCredential(request);
- var response = this.Channel.Request<AccessTokenSuccessResponse>(request);
+ var response = await this.Channel.RequestAsync<AccessTokenSuccessResponse>(request, cancellationToken);
var authorization = new AuthorizationState();
UpdateAuthorizationWithResponse(authorization, response);
@@ -241,7 +242,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// <param name="password">The resource owner's account password.</param>
/// <param name="scopes">The desired scope of access.</param>
/// <returns>The result, containing the tokens if successful.</returns>
- public IAuthorizationState ExchangeUserCredentialForToken(string userName, string password, IEnumerable<string> scopes = null) {
+ public Task<IAuthorizationState> ExchangeUserCredentialForTokenAsync(string userName, string password, IEnumerable<string> scopes = null, CancellationToken cancellationToken = default(CancellationToken)) {
Requires.NotNullOrEmpty(userName, "userName");
Requires.NotNull(password, "password");
@@ -250,7 +251,7 @@ namespace DotNetOpenAuth.OAuth2 {
Password = password,
};
- return this.RequestAccessToken(request, scopes);
+ return this.RequestAccessTokenAsync(request, scopes, cancellationToken);
}
/// <summary>
@@ -258,9 +259,9 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <param name="scopes">The desired scopes.</param>
/// <returns>The result of the authorization request.</returns>
- public IAuthorizationState GetClientAccessToken(IEnumerable<string> scopes = null) {
+ public Task<IAuthorizationState> GetClientAccessTokenAsync(IEnumerable<string> scopes = null, CancellationToken cancellationToken = default(CancellationToken)) {
var request = new AccessTokenClientCredentialsRequest(this.AuthorizationServer.TokenEndpoint, this.AuthorizationServer.Version);
- return this.RequestAccessToken(request, scopes);
+ return this.RequestAccessTokenAsync(request, scopes, cancellationToken);
}
/// <summary>
@@ -322,7 +323,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <param name="authorizationState">The authorization state to update.</param>
/// <param name="authorizationSuccess">The authorization success message obtained from the authorization server.</param>
- internal void UpdateAuthorizationWithResponse(IAuthorizationState authorizationState, EndUserAuthorizationSuccessAuthCodeResponse authorizationSuccess) {
+ internal async Task UpdateAuthorizationWithResponseAsync(IAuthorizationState authorizationState, EndUserAuthorizationSuccessAuthCodeResponse authorizationSuccess, CancellationToken cancellationToken) {
Requires.NotNull(authorizationState, "authorizationState");
Requires.NotNull(authorizationSuccess, "authorizationSuccess");
@@ -332,7 +333,7 @@ namespace DotNetOpenAuth.OAuth2 {
AuthorizationCode = authorizationSuccess.AuthorizationCode,
};
this.ApplyClientCredential(accessTokenRequest);
- IProtocolMessage accessTokenResponse = this.Channel.Request(accessTokenRequest);
+ IProtocolMessage accessTokenResponse = await this.Channel.RequestAsync(accessTokenRequest, cancellationToken);
var accessTokenSuccess = accessTokenResponse as AccessTokenSuccessResponse;
var failedAccessTokenResponse = accessTokenResponse as AccessTokenFailedResponse;
if (accessTokenSuccess != null) {
@@ -388,7 +389,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// <param name="request">The request message.</param>
/// <param name="scopes">The scopes requested by the client.</param>
/// <returns>The result of the request.</returns>
- private IAuthorizationState RequestAccessToken(ScopedAccessTokenRequest request, IEnumerable<string> scopes = null) {
+ private async Task<IAuthorizationState> RequestAccessTokenAsync(ScopedAccessTokenRequest request, IEnumerable<string> scopes, CancellationToken cancellationToken) {
Requires.NotNull(request, "request");
var authorizationState = new AuthorizationState(scopes);
@@ -397,7 +398,7 @@ namespace DotNetOpenAuth.OAuth2 {
this.ApplyClientCredential(request);
request.Scope.UnionWith(authorizationState.Scope);
- var response = this.Channel.Request(request);
+ var response = await this.Channel.RequestAsync(request, cancellationToken);
var success = response as AccessTokenSuccessResponse;
var failure = response as AccessTokenFailedResponse;
ErrorUtilities.VerifyProtocol(success != null || failure != null, MessagingStrings.UnexpectedMessageReceivedOfMany);
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs
index 39ba1cb..769cf56 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs
@@ -9,6 +9,7 @@ namespace DotNetOpenAuth.OAuth2 {
using System.Collections.Generic;
using System.Linq;
using System.Net;
+ using System.Net.Http;
using System.Text;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth2.Messages;
@@ -75,7 +76,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <param name="clientIdentifier">The identifier by which the authorization server should recognize this client.</param>
/// <param name="request">The outbound message to apply authentication information to.</param>
- public virtual void ApplyClientCredential(string clientIdentifier, HttpWebRequest request) {
+ public virtual void ApplyClientCredential(string clientIdentifier, HttpRequestMessage request) {
}
/// <summary>
@@ -126,7 +127,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <param name="clientIdentifier">The identifier by which the authorization server should recognize this client.</param>
/// <param name="request">The outbound message to apply authentication information to.</param>
- public override void ApplyClientCredential(string clientIdentifier, HttpWebRequest request) {
+ public override void ApplyClientCredential(string clientIdentifier, HttpRequestMessage request) {
if (clientIdentifier != null) {
if (this.credential != null) {
ErrorUtilities.VerifyHost(
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/UserAgentClient.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/UserAgentClient.cs
index dcb3826..e87ecaa 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/UserAgentClient.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/UserAgentClient.cs
@@ -9,8 +9,9 @@ namespace DotNetOpenAuth.OAuth2 {
using System.Collections.Generic;
using System.Linq;
using System.Text;
+ using System.Threading;
+ using System.Threading.Tasks;
using System.Web;
-
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth2.Messages;
using Validation;
@@ -80,12 +81,12 @@ namespace DotNetOpenAuth.OAuth2 {
/// <returns>
/// A fully-qualified URL suitable to initiate the authorization flow.
/// </returns>
- public Uri RequestUserAuthorization(IEnumerable<string> scope = null, string state = null, Uri returnTo = null) {
+ public Task<Uri> RequestUserAuthorizationAsync(IEnumerable<string> scope = null, string state = null, Uri returnTo = null, CancellationToken cancellationToken = default(CancellationToken)) {
var authorization = new AuthorizationState(scope) {
Callback = returnTo,
};
- return this.RequestUserAuthorization(authorization, state: state);
+ return this.RequestUserAuthorizationAsync(authorization, state: state, cancellationToken: cancellationToken);
}
/// <summary>
@@ -101,12 +102,13 @@ namespace DotNetOpenAuth.OAuth2 {
/// <returns>
/// A fully-qualified URL suitable to initiate the authorization flow.
/// </returns>
- public Uri RequestUserAuthorization(IAuthorizationState authorization, bool implicitResponseType = false, string state = null) {
+ public async Task<Uri> RequestUserAuthorizationAsync(IAuthorizationState authorization, bool implicitResponseType = false, string state = null, CancellationToken cancellationToken = default(CancellationToken)) {
Requires.NotNull(authorization, "authorization");
RequiresEx.ValidState(!string.IsNullOrEmpty(this.ClientIdentifier));
var request = this.PrepareRequestUserAuthorization(authorization, implicitResponseType, state);
- return this.Channel.PrepareResponse(request).GetDirectUriRequest(this.Channel);
+ var response = await this.Channel.PrepareResponseAsync(request, cancellationToken);
+ return response.GetDirectUriRequest();
}
/// <summary>
@@ -115,7 +117,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// <param name="actualRedirectUrl">The actual URL of the incoming HTTP request.</param>
/// <param name="authorizationState">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 authorizationState = null) {
+ public async Task<IAuthorizationState> ProcessUserAuthorizationAsync(Uri actualRedirectUrl, IAuthorizationState authorizationState = null, CancellationToken cancellationToken = default(CancellationToken)) {
Requires.NotNull(actualRedirectUrl, "actualRedirectUrl");
if (authorizationState == null) {
@@ -123,12 +125,12 @@ namespace DotNetOpenAuth.OAuth2 {
}
var carrier = new HttpRequestInfo("GET", actualRedirectUrl);
- IDirectedProtocolMessage response = this.Channel.ReadFromRequest(carrier);
+ IDirectedProtocolMessage response = await this.Channel.ReadFromRequestAsync(carrier, cancellationToken);
if (response == null) {
return null;
}
- return this.ProcessUserAuthorization(authorizationState, response);
+ return await this.ProcessUserAuthorizationAsync(authorizationState, response, cancellationToken);
}
/// <summary>
@@ -139,7 +141,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// <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>
- internal IAuthorizationState ProcessUserAuthorization(IAuthorizationState authorizationState, IDirectedProtocolMessage response) {
+ internal async Task<IAuthorizationState> ProcessUserAuthorizationAsync(IAuthorizationState authorizationState, IDirectedProtocolMessage response, CancellationToken cancellationToken) {
Requires.NotNull(authorizationState, "authorizationState");
Requires.NotNull(response, "response");
@@ -148,7 +150,7 @@ namespace DotNetOpenAuth.OAuth2 {
if ((accessTokenSuccess = response as EndUserAuthorizationSuccessAccessTokenResponse) != null) {
UpdateAuthorizationWithResponse(authorizationState, accessTokenSuccess);
} else if ((authCodeSuccess = response as EndUserAuthorizationSuccessAuthCodeResponse) != null) {
- this.UpdateAuthorizationWithResponse(authorizationState, authCodeSuccess);
+ await this.UpdateAuthorizationWithResponseAsync(authorizationState, authCodeSuccess, cancellationToken);
} else if (response is EndUserAuthorizationFailedResponse) {
authorizationState.Delete();
return null;
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
index 63d96e1..dd7aff8 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
@@ -10,10 +10,12 @@ namespace DotNetOpenAuth.OAuth2 {
using System.Globalization;
using System.Linq;
using System.Net;
+ using System.Net.Http;
using System.Text;
+ using System.Threading;
+ using System.Threading.Tasks;
using System.Web;
using System.Web.Security;
-
using DotNetOpenAuth.Configuration;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth2.Messages;
@@ -60,26 +62,14 @@ namespace DotNetOpenAuth.OAuth2 {
/// <summary>
/// Prepares a request for user authorization from an authorization server.
/// </summary>
- /// <param name="scope">The scope of authorized access requested.</param>
- /// <param name="returnTo">The URL the authorization server should redirect the browser (typically on this site) to when the authorization is completed. If null, the current request's URL will be used.</param>
- public void RequestUserAuthorization(IEnumerable<string> scope = null, Uri returnTo = null) {
- var authorizationState = new AuthorizationState(scope) {
- Callback = returnTo,
- };
- this.PrepareRequestUserAuthorization(authorizationState).Send();
- }
-
- /// <summary>
- /// Prepares a request for user authorization from an authorization server.
- /// </summary>
/// <param name="scopes">The scope of authorized access requested.</param>
/// <param name="returnTo">The URL the authorization server should redirect the browser (typically on this site) to when the authorization is completed. If null, the current request's URL will be used.</param>
/// <returns>The authorization request.</returns>
- public OutgoingWebResponse PrepareRequestUserAuthorization(IEnumerable<string> scopes = null, Uri returnTo = null) {
+ public Task<HttpResponseMessage> PrepareRequestUserAuthorizationAsync(IEnumerable<string> scopes = null, Uri returnTo = null, CancellationToken cancellationToken = default(CancellationToken)) {
var authorizationState = new AuthorizationState(scopes) {
Callback = returnTo,
};
- return this.PrepareRequestUserAuthorization(authorizationState);
+ return this.PrepareRequestUserAuthorizationAsync(authorizationState, cancellationToken);
}
/// <summary>
@@ -87,7 +77,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <param name="authorization">The authorization state to associate with this particular request.</param>
/// <returns>The authorization request.</returns>
- public OutgoingWebResponse PrepareRequestUserAuthorization(IAuthorizationState authorization) {
+ public async Task<HttpResponseMessage> PrepareRequestUserAuthorizationAsync(IAuthorizationState authorization, CancellationToken cancellationToken) {
Requires.NotNull(authorization, "authorization");
RequiresEx.ValidState(authorization.Callback != null || (HttpContext.Current != null && HttpContext.Current.Request != null), MessagingStrings.HttpContextRequired);
RequiresEx.ValidState(!string.IsNullOrEmpty(this.ClientIdentifier), Strings.RequiredPropertyNotYetPreset, "ClientIdentifier");
@@ -108,12 +98,12 @@ namespace DotNetOpenAuth.OAuth2 {
// Mitigate XSRF attacks by including a state value that would be unpredictable between users, but
// verifiable for the same user/session.
// If the host is implementing the authorization tracker though, they're handling this protection themselves.
- HttpCookie cookie = null;
+ Cookie cookie = null;
if (this.AuthorizationTracker == null) {
var context = this.Channel.GetHttpContext();
string xsrfKey = MessagingUtilities.GetNonCryptoRandomDataAsBase64(16);
- cookie = new HttpCookie(XsrfCookieName, xsrfKey) {
+ cookie = new Cookie(XsrfCookieName, xsrfKey) {
HttpOnly = true,
Secure = FormsAuthentication.RequireSSL,
////Expires = DateTime.Now.Add(OAuth2ClientSection.Configuration.MaxAuthorizationTime), // we prefer session cookies to persistent ones
@@ -121,9 +111,9 @@ namespace DotNetOpenAuth.OAuth2 {
request.ClientState = xsrfKey;
}
- var response = this.Channel.PrepareResponse(request);
+ var response = await this.Channel.PrepareResponseAsync(request, cancellationToken);
if (cookie != null) {
- response.Cookies.Add(cookie);
+ response.Headers.SetCookie(cookie);
}
return response;
@@ -134,7 +124,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <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(HttpRequestBase request = null) {
+ public async Task<IAuthorizationState> ProcessUserAuthorizationAsync(HttpRequestBase request = null, CancellationToken cancellationToken = default(CancellationToken)) {
RequiresEx.ValidState(!string.IsNullOrEmpty(this.ClientIdentifier), Strings.RequiredPropertyNotYetPreset, "ClientIdentifier");
RequiresEx.ValidState(this.ClientCredentialApplicator != null, Strings.RequiredPropertyNotYetPreset, "ClientCredentialApplicator");
@@ -142,8 +132,8 @@ namespace DotNetOpenAuth.OAuth2 {
request = this.Channel.GetRequestFromContext();
}
- IMessageWithClientState response;
- if (this.Channel.TryReadFromRequest<IMessageWithClientState>(request, out response)) {
+ var response = await this.Channel.TryReadFromRequestAsync<IMessageWithClientState>(cancellationToken, request);
+ if (response != null) {
Uri callback = MessagingUtilities.StripMessagePartsFromQueryString(request.GetPublicFacingUrl(), this.Channel.MessageDescriptions.Get(response));
IAuthorizationState authorizationState;
if (this.AuthorizationTracker != null) {
@@ -160,7 +150,7 @@ namespace DotNetOpenAuth.OAuth2 {
var failure = response as EndUserAuthorizationFailedResponse;
ErrorUtilities.VerifyProtocol(success != null || failure != null, MessagingStrings.UnexpectedMessageReceivedOfMany);
if (success != null) {
- this.UpdateAuthorizationWithResponse(authorizationState, success);
+ await this.UpdateAuthorizationWithResponseAsync(authorizationState, success, cancellationToken);
} else { // failure
Logger.OAuth.Info("User refused to grant the requested authorization at the Authorization Server.");
authorizationState.Delete();
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/OAuth2ChannelBase.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/OAuth2ChannelBase.cs
index e6be1c4..1c2c990 100644
--- a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/OAuth2ChannelBase.cs
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/OAuth2ChannelBase.cs
@@ -12,6 +12,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth2.Messages;
+
using Validation;
/// <summary>
@@ -31,8 +32,8 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
/// The binding elements to use in sending and receiving messages.
/// The order they are provided is used for outgoing messgaes, and reversed for incoming messages.
/// </param>
- internal OAuth2ChannelBase(Type[] messageTypes, params IChannelBindingElement[] channelBindingElements)
- : base(Requires.NotNull(messageTypes, "messageTypes"), Versions, channelBindingElements) {
+ internal OAuth2ChannelBase(Type[] messageTypes, IChannelBindingElement[] channelBindingElements = null, IHostFactories hostFactories = null)
+ : base(Requires.NotNull(messageTypes, "messageTypes"), Versions, channelBindingElements ?? new IChannelBindingElement[0], hostFactories ?? new DefaultOAuth2HostFactories()) {
}
/// <summary>
diff --git a/src/DotNetOpenAuth.OAuth2/DefaultOAuth2HostFactories.cs b/src/DotNetOpenAuth.OAuth2/DefaultOAuth2HostFactories.cs
new file mode 100644
index 0000000..cc6aefc
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2/DefaultOAuth2HostFactories.cs
@@ -0,0 +1,50 @@
+//-----------------------------------------------------------------------
+// <copyright file="DefaultOAuth2HostFactories.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.Net.Cache;
+ using System.Net.Http;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ /// <summary>
+ /// Creates default instances of required dependencies.
+ /// </summary>
+ public class DefaultOAuth2HostFactories : IHostFactories {
+ /// <summary>
+ /// Initializes a new instance of a concrete derivation of <see cref="HttpMessageHandler" />
+ /// to be used for outbound HTTP traffic.
+ /// </summary>
+ /// <returns>An instance of <see cref="HttpMessageHandler"/>.</returns>
+ /// <remarks>
+ /// An instance of <see cref="WebRequestHandler" /> is recommended where available;
+ /// otherwise an instance of <see cref="HttpClientHandler" /> is recommended.
+ /// </remarks>
+ public virtual HttpMessageHandler CreateHttpMessageHandler() {
+ var handler = new HttpClientHandler();
+ return handler;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="HttpClient" /> class
+ /// to be used for outbound HTTP traffic.
+ /// </summary>
+ /// <param name="handler">The handler to pass to the <see cref="HttpClient" /> constructor.
+ /// May be null to use the default that would be provided by <see cref="CreateHttpMessageHandler" />.</param>
+ /// <returns>
+ /// An instance of <see cref="HttpClient" />.
+ /// </returns>
+ public HttpClient CreateHttpClient(HttpMessageHandler handler) {
+ handler = handler ?? this.CreateHttpMessageHandler();
+ var client = new HttpClient(handler);
+ client.DefaultRequestHeaders.UserAgent.Add(Util.LibraryVersionHeader);
+ return client;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2/DotNetOpenAuth.OAuth2.csproj b/src/DotNetOpenAuth.OAuth2/DotNetOpenAuth.OAuth2.csproj
index c570242..555915a 100644
--- a/src/DotNetOpenAuth.OAuth2/DotNetOpenAuth.OAuth2.csproj
+++ b/src/DotNetOpenAuth.OAuth2/DotNetOpenAuth.OAuth2.csproj
@@ -20,6 +20,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="Configuration\OAuth2SectionGroup.cs" />
+ <Compile Include="DefaultOAuth2HostFactories.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="OAuth2\AccessToken.cs" />
<Compile Include="OAuth2\ChannelElements\AuthorizationDataBag.cs" />
@@ -59,6 +60,8 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Net.Http.WebRequest" />
<Reference Include="Validation">
<HintPath>..\packages\Validation.2.0.1.12362\lib\portable-windows8+net40+sl5+windowsphone8\Validation.dll</HintPath>
<Private>True</Private>
diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthUtilities.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthUtilities.cs
index f2acf79..13ea287 100644
--- a/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthUtilities.cs
+++ b/src/DotNetOpenAuth.OAuth2/OAuth2/OAuthUtilities.cs
@@ -10,10 +10,13 @@ namespace DotNetOpenAuth.OAuth2 {
using System.Globalization;
using System.Linq;
using System.Net;
+ using System.Net.Http.Headers;
using System.Text;
using DotNetOpenAuth.Messaging;
using Validation;
+ using HttpRequestHeaders = DotNetOpenAuth.Messaging.HttpRequestHeaders;
+
/// <summary>
/// Some common utility methods for OAuth 2.0.
/// </summary>
@@ -161,7 +164,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// <param name="headers">The headers collection to set the authorization header to.</param>
/// <param name="userName">The username. Cannot be empty.</param>
/// <param name="password">The password. Cannot be null.</param>
- internal static void ApplyHttpBasicAuth(WebHeaderCollection headers, string userName, string password) {
+ internal static void ApplyHttpBasicAuth(System.Net.Http.Headers.HttpRequestHeaders headers, string userName, string password) {
Requires.NotNull(headers, "headers");
Requires.NotNullOrEmpty(userName, "userName");
Requires.NotNull(password, "password");
@@ -169,8 +172,7 @@ namespace DotNetOpenAuth.OAuth2 {
string concat = userName + ":" + password;
byte[] bits = HttpBasicEncoding.GetBytes(concat);
string base64 = Convert.ToBase64String(bits);
- string header = HttpBasicAuthScheme + base64;
- headers[HttpRequestHeader.Authorization] = header;
+ headers.Authorization = new AuthenticationHeaderValue(HttpBasicAuthScheme, base64);
}
/// <summary>
diff --git a/src/DotNetOpenAuth.OAuth2/packages.config b/src/DotNetOpenAuth.OAuth2/packages.config
index 58890d8..1d93cf5 100644
--- a/src/DotNetOpenAuth.OAuth2/packages.config
+++ b/src/DotNetOpenAuth.OAuth2/packages.config
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="Microsoft.Net.Http" version="2.0.20710.0" targetFramework="net45" />
<package id="Validation" version="2.0.1.12362" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/DotNetOpenAuth.OpenId/OpenId/OpenIdUtilities.cs b/src/DotNetOpenAuth.OpenId/OpenId/OpenIdUtilities.cs
index b656150..7b65a88 100644
--- a/src/DotNetOpenAuth.OpenId/OpenId/OpenIdUtilities.cs
+++ b/src/DotNetOpenAuth.OpenId/OpenId/OpenIdUtilities.cs
@@ -231,27 +231,6 @@ namespace DotNetOpenAuth.OpenId {
return hostFactories.CreateHttpClient(rootHandler);
}
- internal static Uri GetDirectUriRequest(this HttpResponseMessage response) {
- Requires.NotNull(response, "response");
- Requires.Argument(
- response.StatusCode == HttpStatusCode.Redirect || response.StatusCode == HttpStatusCode.RedirectKeepVerb
- || response.StatusCode == HttpStatusCode.RedirectMethod || response.StatusCode == HttpStatusCode.TemporaryRedirect,
- "response",
- "Redirecting response expected.");
- Requires.Argument(response.Headers.Location != null, "response", "Redirect URL header expected.");
- Requires.Argument(response.Content == null || response.Content is FormUrlEncodedContent, "response", "FormUrlEncodedContent expected");
-
- var builder = new UriBuilder(response.Headers.Location);
- if (response.Content != null) {
- var content = response.Content.ReadAsStringAsync();
- Assumes.True(content.IsCompleted); // cached in memory, so it should never complete asynchronously.
- var formFields = HttpUtility.ParseQueryString(content.Result).ToDictionary();
- MessagingUtilities.AppendQueryArgs(builder, formFields);
- }
-
- return builder.Uri;
- }
-
/// <summary>
/// Gets the extension factories from the extension aggregator on an OpenID channel.
/// </summary>