summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OAuth2.Client/OAuth2
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2013-03-26 11:19:06 -0700
committerAndrew Arnott <andrewarnott@gmail.com>2013-03-26 11:19:06 -0700
commit3d37ff45cab6838d80b22e6b782a0b9b4c2f4aeb (patch)
treec15816c3d7f6e74334553f2ff98605ce1c22c538 /src/DotNetOpenAuth.OAuth2.Client/OAuth2
parent5e9014f36b2d53b8e419918675df636540ea24e2 (diff)
parente6f7409f4caceb7bc2a5b4ddbcb1a4097af340f2 (diff)
downloadDotNetOpenAuth-3d37ff45cab6838d80b22e6b782a0b9b4c2f4aeb.zip
DotNetOpenAuth-3d37ff45cab6838d80b22e6b782a0b9b4c2f4aeb.tar.gz
DotNetOpenAuth-3d37ff45cab6838d80b22e6b782a0b9b4c2f4aeb.tar.bz2
Move to HttpClient throughout library.
Diffstat (limited to 'src/DotNetOpenAuth.OAuth2.Client/OAuth2')
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/BearerTokenHttpMessageHandler.cs8
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs47
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs68
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs5
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/UserAgentClient.cs55
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs105
6 files changed, 166 insertions, 122 deletions
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/BearerTokenHttpMessageHandler.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/BearerTokenHttpMessageHandler.cs
index da4c869..92f882f 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);
+ 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..aba0290 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs
@@ -9,12 +9,16 @@ 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;
+ using Validation;
+
/// <summary>
/// The messaging channel used by OAuth 2.0 Clients.
/// </summary>
@@ -32,10 +36,11 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
};
/// <summary>
- /// Initializes a new instance of the <see cref="OAuth2ClientChannel"/> class.
+ /// Initializes a new instance of the <see cref="OAuth2ClientChannel" /> class.
/// </summary>
- internal OAuth2ClientChannel()
- : base(MessageTypes) {
+ /// <param name="hostFactories">The host factories.</param>
+ internal OAuth2ClientChannel(IHostFactories hostFactories)
+ : base(MessageTypes, hostFactories: hostFactories) {
}
/// <summary>
@@ -64,11 +69,11 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
/// The <see cref="HttpWebRequest"/> prepared to send the request.
/// </returns>
/// <remarks>
- /// This method must be overridden by a derived class, unless the <see cref="Channel.RequestCore"/> method
+ /// This method must be overridden by a derived class, unless the <see cref="Channel.RequestCoreAsync"/> 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 +93,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, CancellationToken cancellationToken) {
// 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);
}
}
@@ -105,21 +111,24 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
/// Gets the protocol message that may be embedded in the given HTTP request.
/// </summary>
/// <param name="request">The request to search for an embedded message.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// The deserialized message, if one is found. Null otherwise.
/// </returns>
- protected override IDirectedProtocolMessage ReadFromRequestCore(HttpRequestBase request) {
- Logger.Channel.DebugFormat("Incoming HTTP request: {0} {1}", request.HttpMethod, request.GetPublicFacingUrl().AbsoluteUri);
+ protected override async Task<IDirectedProtocolMessage> ReadFromRequestCoreAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
+ Requires.NotNull(request, "request");
+
+ Logger.Channel.DebugFormat("Incoming HTTP request: {0} {1}", request.Method, request.RequestUri.AbsoluteUri);
- var fields = request.GetQueryStringBeforeRewriting().ToDictionary();
+ var fields = HttpUtility.ParseQueryString(request.RequestUri.Query).ToDictionary();
// Also read parameters from the fragment, if it's available.
// Typically the fragment is not available because the browser doesn't send it to a web server
// but this request may have been fabricated by an installed desktop app, in which case
// the fragment is available.
- string fragment = request.GetPublicFacingUrl().Fragment;
+ string fragment = request.RequestUri.Fragment;
if (!string.IsNullOrEmpty(fragment)) {
- foreach (var pair in HttpUtility.ParseQueryString(fragment.Substring(1)).ToDictionary()) {
+ foreach (var pair in HttpUtility.ParseQueryString(fragment.Substring(1)).AsKeyValuePairs()) {
fields.Add(pair.Key, pair.Value);
}
}
@@ -146,7 +155,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 +164,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..9730321 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;
@@ -33,10 +34,10 @@ namespace DotNetOpenAuth.OAuth2 {
/// The tool to use to apply client credentials to authenticated requests to the Authorization Server.
/// May be <c>null</c> for clients with no secret or other means of authentication.
/// </param>
- protected ClientBase(AuthorizationServerDescription authorizationServer, string clientIdentifier = null, ClientCredentialApplicator clientCredentialApplicator = null) {
+ protected ClientBase(AuthorizationServerDescription authorizationServer, string clientIdentifier = null, ClientCredentialApplicator clientCredentialApplicator = null, IHostFactories hostFactories = null) {
Requires.NotNull(authorizationServer, "authorizationServer");
this.AuthorizationServer = authorizationServer;
- this.Channel = new OAuth2ClientChannel();
+ this.Channel = new OAuth2ClientChannel(hostFactories);
this.ClientIdentifier = clientIdentifier;
this.ClientCredentialApplicator = clientCredentialApplicator;
}
@@ -116,11 +117,15 @@ 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) {
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// A task that completes with the asynchronous operation.
+ /// </returns>
+ 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 +134,11 @@ 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) {
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// A task that completes with the asynchronous operation.
+ /// </returns>
+ 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 +146,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);
@@ -174,13 +183,14 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <param name="authorization">The authorization to update.</param>
/// <param name="skipIfUsefulLifeExceeds">If given, the access token will <em>not</em> be refreshed if its remaining lifetime exceeds this value.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A value indicating whether the access token was actually renewed; <c>true</c> if it was renewed, or <c>false</c> if it still had useful life remaining.</returns>
/// <remarks>
/// This method may modify the value of the <see cref="IAuthorizationState.RefreshToken"/> property on
/// 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 +210,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;
}
@@ -211,12 +221,13 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <param name="refreshToken">The refresh token.</param>
/// <param name="scope">The scope subset desired in the access token.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A description of the obtained access token, and possibly a new refresh token.</returns>
/// <remarks>
/// 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 +238,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);
@@ -240,8 +251,11 @@ namespace DotNetOpenAuth.OAuth2 {
/// <param name="userName">The resource owner's username, as it is known by the authorization server.</param>
/// <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) {
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// The result, containing the tokens if successful.
+ /// </returns>
+ 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,17 +264,20 @@ namespace DotNetOpenAuth.OAuth2 {
Password = password,
};
- return this.RequestAccessToken(request, scopes);
+ return this.RequestAccessTokenAsync(request, scopes, cancellationToken);
}
/// <summary>
/// Obtains an access token for accessing client-controlled resources on the resource server.
/// </summary>
/// <param name="scopes">The desired scopes.</param>
- /// <returns>The result of the authorization request.</returns>
- public IAuthorizationState GetClientAccessToken(IEnumerable<string> scopes = null) {
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// The result of the authorization request.
+ /// </returns>
+ 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 +339,11 @@ 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) {
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// A task that completes with the asynchronous operation.
+ /// </returns>
+ internal async Task UpdateAuthorizationWithResponseAsync(IAuthorizationState authorizationState, EndUserAuthorizationSuccessAuthCodeResponse authorizationSuccess, CancellationToken cancellationToken) {
Requires.NotNull(authorizationState, "authorizationState");
Requires.NotNull(authorizationSuccess, "authorizationSuccess");
@@ -332,7 +353,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) {
@@ -387,8 +408,11 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <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) {
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// The result of the request.
+ /// </returns>
+ private async Task<IAuthorizationState> RequestAccessTokenAsync(ScopedAccessTokenRequest request, IEnumerable<string> scopes, CancellationToken cancellationToken) {
Requires.NotNull(request, "request");
var authorizationState = new AuthorizationState(scopes);
@@ -397,7 +421,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..7a52c0f 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/UserAgentClient.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/UserAgentClient.cs
@@ -8,9 +8,11 @@ namespace DotNetOpenAuth.OAuth2 {
using System;
using System.Collections.Generic;
using System.Linq;
+ using System.Net.Http;
using System.Text;
+ using System.Threading;
+ using System.Threading.Tasks;
using System.Web;
-
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth2.Messages;
using Validation;
@@ -26,8 +28,8 @@ namespace DotNetOpenAuth.OAuth2 {
/// <param name="authorizationServer">The token issuer.</param>
/// <param name="clientIdentifier">The client identifier.</param>
/// <param name="clientSecret">The client secret.</param>
- public UserAgentClient(AuthorizationServerDescription authorizationServer, string clientIdentifier = null, string clientSecret = null)
- : this(authorizationServer, clientIdentifier, DefaultSecretApplicator(clientSecret)) {
+ public UserAgentClient(AuthorizationServerDescription authorizationServer, string clientIdentifier = null, string clientSecret = null, IHostFactories hostFactories = null)
+ : this(authorizationServer, clientIdentifier, DefaultSecretApplicator(clientSecret), hostFactories) {
}
/// <summary>
@@ -37,8 +39,8 @@ namespace DotNetOpenAuth.OAuth2 {
/// <param name="tokenEndpoint">The token endpoint.</param>
/// <param name="clientIdentifier">The client identifier.</param>
/// <param name="clientSecret">The client secret.</param>
- public UserAgentClient(Uri authorizationEndpoint, Uri tokenEndpoint, string clientIdentifier = null, string clientSecret = null)
- : this(authorizationEndpoint, tokenEndpoint, clientIdentifier, DefaultSecretApplicator(clientSecret)) {
+ public UserAgentClient(Uri authorizationEndpoint, Uri tokenEndpoint, string clientIdentifier = null, string clientSecret = null, IHostFactories hostFactories = null)
+ : this(authorizationEndpoint, tokenEndpoint, clientIdentifier, DefaultSecretApplicator(clientSecret), hostFactories) {
}
/// <summary>
@@ -51,8 +53,8 @@ namespace DotNetOpenAuth.OAuth2 {
/// The tool to use to apply client credentials to authenticated requests to the Authorization Server.
/// May be <c>null</c> for clients with no secret or other means of authentication.
/// </param>
- public UserAgentClient(Uri authorizationEndpoint, Uri tokenEndpoint, string clientIdentifier, ClientCredentialApplicator clientCredentialApplicator)
- : this(new AuthorizationServerDescription { AuthorizationEndpoint = authorizationEndpoint, TokenEndpoint = tokenEndpoint }, clientIdentifier, clientCredentialApplicator) {
+ public UserAgentClient(Uri authorizationEndpoint, Uri tokenEndpoint, string clientIdentifier, ClientCredentialApplicator clientCredentialApplicator, IHostFactories hostFactories = null)
+ : this(new AuthorizationServerDescription { AuthorizationEndpoint = authorizationEndpoint, TokenEndpoint = tokenEndpoint }, clientIdentifier, clientCredentialApplicator, hostFactories) {
Requires.NotNull(authorizationEndpoint, "authorizationEndpoint");
Requires.NotNull(tokenEndpoint, "tokenEndpoint");
}
@@ -66,8 +68,8 @@ namespace DotNetOpenAuth.OAuth2 {
/// The tool to use to apply client credentials to authenticated requests to the Authorization Server.
/// May be <c>null</c> for clients with no secret or other means of authentication.
/// </param>
- public UserAgentClient(AuthorizationServerDescription authorizationServer, string clientIdentifier, ClientCredentialApplicator clientCredentialApplicator)
- : base(authorizationServer, clientIdentifier, clientCredentialApplicator) {
+ public UserAgentClient(AuthorizationServerDescription authorizationServer, string clientIdentifier, ClientCredentialApplicator clientCredentialApplicator, IHostFactories hostFactories = null)
+ : base(authorizationServer, clientIdentifier, clientCredentialApplicator, hostFactories) {
}
/// <summary>
@@ -77,15 +79,16 @@ namespace DotNetOpenAuth.OAuth2 {
/// <param name="scope">The scope of authorized access requested.</param>
/// <param name="state">The client state that should be returned with the authorization response.</param>
/// <param name="returnTo">The URL that the authorization response should be sent to via a user-agent redirect.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
/// <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>
@@ -93,20 +96,20 @@ namespace DotNetOpenAuth.OAuth2 {
/// this client to access protected data at some resource server.
/// </summary>
/// <param name="authorization">The authorization state that is tracking this particular request. Optional.</param>
- /// <param name="implicitResponseType">
- /// <c>true</c> to request an access token in the fragment of the response's URL;
- /// <c>false</c> to authenticate to the authorization server and acquire the access token (and possibly a refresh token) via a private channel.
- /// </param>
+ /// <param name="implicitResponseType"><c>true</c> to request an access token in the fragment of the response's URL;
+ /// <c>false</c> to authenticate to the authorization server and acquire the access token (and possibly a refresh token) via a private channel.</param>
/// <param name="state">The client state that should be returned with the authorization response.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
/// <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>
@@ -114,21 +117,24 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <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) {
+ /// <param name="cancellationToken">The cancellation token.</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 async Task<IAuthorizationState> ProcessUserAuthorizationAsync(Uri actualRedirectUrl, IAuthorizationState authorizationState = null, CancellationToken cancellationToken = default(CancellationToken)) {
Requires.NotNull(actualRedirectUrl, "actualRedirectUrl");
if (authorizationState == null) {
authorizationState = new AuthorizationState();
}
- var carrier = new HttpRequestInfo("GET", actualRedirectUrl);
- IDirectedProtocolMessage response = this.Channel.ReadFromRequest(carrier);
+ var carrier = new HttpRequestMessage(HttpMethod.Get, actualRedirectUrl);
+ 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>
@@ -136,10 +142,11 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <param name="authorizationState">The authorization.</param>
/// <param name="response">The incoming authorization response message.</param>
+ /// <param name="cancellationToken">The cancellation token.</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>
- 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 +155,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..2b5a80a 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
@@ -10,10 +10,13 @@ namespace DotNetOpenAuth.OAuth2 {
using System.Globalization;
using System.Linq;
using System.Net;
+ using System.Net.Http;
+ using System.Net.Http.Headers;
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;
@@ -29,26 +32,26 @@ namespace DotNetOpenAuth.OAuth2 {
private const string XsrfCookieName = "DotNetOpenAuth.WebServerClient.XSRF-Session";
/// <summary>
- /// Initializes a new instance of the <see cref="WebServerClient"/> class.
+ /// Initializes a new instance of the <see cref="WebServerClient" /> class.
/// </summary>
/// <param name="authorizationServer">The authorization server.</param>
/// <param name="clientIdentifier">The client identifier.</param>
/// <param name="clientSecret">The client secret.</param>
- public WebServerClient(AuthorizationServerDescription authorizationServer, string clientIdentifier = null, string clientSecret = null)
- : this(authorizationServer, clientIdentifier, DefaultSecretApplicator(clientSecret)) {
+ /// <param name="hostFactories">The host factories.</param>
+ public WebServerClient(AuthorizationServerDescription authorizationServer, string clientIdentifier = null, string clientSecret = null, IHostFactories hostFactories = null)
+ : this(authorizationServer, clientIdentifier, DefaultSecretApplicator(clientSecret), hostFactories) {
}
/// <summary>
- /// Initializes a new instance of the <see cref="WebServerClient"/> class.
+ /// Initializes a new instance of the <see cref="WebServerClient" /> class.
/// </summary>
/// <param name="authorizationServer">The authorization server.</param>
/// <param name="clientIdentifier">The client identifier.</param>
- /// <param name="clientCredentialApplicator">
- /// The tool to use to apply client credentials to authenticated requests to the Authorization Server.
- /// May be <c>null</c> for clients with no secret or other means of authentication.
- /// </param>
- public WebServerClient(AuthorizationServerDescription authorizationServer, string clientIdentifier, ClientCredentialApplicator clientCredentialApplicator)
- : base(authorizationServer, clientIdentifier, clientCredentialApplicator) {
+ /// <param name="clientCredentialApplicator">The tool to use to apply client credentials to authenticated requests to the Authorization Server.
+ /// May be <c>null</c> for clients with no secret or other means of authentication.</param>
+ /// <param name="hostFactories"></param>
+ public WebServerClient(AuthorizationServerDescription authorizationServer, string clientIdentifier, ClientCredentialApplicator clientCredentialApplicator, IHostFactories hostFactories = null)
+ : base(authorizationServer, clientIdentifier, clientCredentialApplicator, hostFactories) {
}
/// <summary>
@@ -60,34 +63,28 @@ 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) {
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// The authorization request.
+ /// </returns>
+ 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>
/// Prepares a request for user authorization from an authorization server.
/// </summary>
/// <param name="authorization">The authorization state to associate with this particular request.</param>
- /// <returns>The authorization request.</returns>
- public OutgoingWebResponse PrepareRequestUserAuthorization(IAuthorizationState authorization) {
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// The authorization request.
+ /// </returns>
+ public async Task<HttpResponseMessage> PrepareRequestUserAuthorizationAsync(IAuthorizationState authorization, CancellationToken cancellationToken = default(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,23 +105,18 @@ 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;
+ var cookies = new List<CookieHeaderValue>();
if (this.AuthorizationTracker == null) {
- var context = this.Channel.GetHttpContext();
-
string xsrfKey = MessagingUtilities.GetNonCryptoRandomDataAsBase64(16);
- cookie = new HttpCookie(XsrfCookieName, xsrfKey) {
+ cookies.Add(new CookieHeaderValue(XsrfCookieName, xsrfKey) {
HttpOnly = true,
Secure = FormsAuthentication.RequireSSL,
- ////Expires = DateTime.Now.Add(OAuth2ClientSection.Configuration.MaxAuthorizationTime), // we prefer session cookies to persistent ones
- };
+ });
request.ClientState = xsrfKey;
}
- var response = this.Channel.PrepareResponse(request);
- if (cookie != null) {
- response.Cookies.Add(cookie);
- }
+ var response = await this.Channel.PrepareResponseAsync(request, cancellationToken);
+ response.Headers.AddCookies(cookies);
return response;
}
@@ -133,34 +125,45 @@ namespace DotNetOpenAuth.OAuth2 {
/// Processes the authorization response from an authorization server, if available.
/// </summary>
/// <param name="request">The incoming HTTP request that may carry an authorization response.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The authorization state that contains the details of the authorization.</returns>
- public IAuthorizationState ProcessUserAuthorization(HttpRequestBase request = null) {
+ public Task<IAuthorizationState> ProcessUserAuthorizationAsync(
+ HttpRequestBase request = null, CancellationToken cancellationToken = default(CancellationToken)) {
+ request = request ?? this.Channel.GetRequestFromContext();
+ return this.ProcessUserAuthorizationAsync(request.AsHttpRequestMessage(), cancellationToken);
+ }
+
+ /// <summary>
+ /// Processes the authorization response from an authorization server, if available.
+ /// </summary>
+ /// <param name="request">The incoming HTTP request that may carry an authorization response.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>The authorization state that contains the details of the authorization.</returns>
+ public async Task<IAuthorizationState> ProcessUserAuthorizationAsync(HttpRequestMessage request, CancellationToken cancellationToken = default(CancellationToken)) {
+ Requires.NotNull(request, "request");
RequiresEx.ValidState(!string.IsNullOrEmpty(this.ClientIdentifier), Strings.RequiredPropertyNotYetPreset, "ClientIdentifier");
RequiresEx.ValidState(this.ClientCredentialApplicator != null, Strings.RequiredPropertyNotYetPreset, "ClientCredentialApplicator");
- if (request == null) {
- request = this.Channel.GetRequestFromContext();
- }
-
- IMessageWithClientState response;
- if (this.Channel.TryReadFromRequest<IMessageWithClientState>(request, out response)) {
- Uri callback = MessagingUtilities.StripMessagePartsFromQueryString(request.GetPublicFacingUrl(), this.Channel.MessageDescriptions.Get(response));
+ var response = await this.Channel.TryReadFromRequestAsync<IMessageWithClientState>(request, cancellationToken);
+ if (response != null) {
+ Uri callback = request.RequestUri.StripMessagePartsFromQueryString(this.Channel.MessageDescriptions.Get(response));
IAuthorizationState authorizationState;
if (this.AuthorizationTracker != null) {
authorizationState = this.AuthorizationTracker.GetAuthorizationState(callback, response.ClientState);
ErrorUtilities.VerifyProtocol(authorizationState != null, ClientStrings.AuthorizationResponseUnexpectedMismatch);
} else {
- var context = this.Channel.GetHttpContext();
-
- HttpCookie cookie = request.Cookies[XsrfCookieName];
- ErrorUtilities.VerifyProtocol(cookie != null && string.Equals(response.ClientState, cookie.Value, StringComparison.Ordinal), ClientStrings.AuthorizationResponseUnexpectedMismatch);
+ var xsrfCookieValue = (from cookieHeader in request.Headers.GetCookies()
+ from cookie in cookieHeader.Cookies
+ where cookie.Name == XsrfCookieName
+ select cookie.Value).FirstOrDefault();
+ ErrorUtilities.VerifyProtocol(xsrfCookieValue != null && string.Equals(response.ClientState, xsrfCookieValue, StringComparison.Ordinal), ClientStrings.AuthorizationResponseUnexpectedMismatch);
authorizationState = new AuthorizationState { Callback = callback };
}
var success = response as EndUserAuthorizationSuccessAuthCodeResponse;
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();