summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OAuth2.Client/OAuth2
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth.OAuth2.Client/OAuth2')
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/IOAuth2ChannelWithClient.cs27
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs28
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs60
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs165
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/UserAgentClient.cs31
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs17
6 files changed, 312 insertions, 16 deletions
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/IOAuth2ChannelWithClient.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/IOAuth2ChannelWithClient.cs
new file mode 100644
index 0000000..c802be6
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/IOAuth2ChannelWithClient.cs
@@ -0,0 +1,27 @@
+//-----------------------------------------------------------------------
+// <copyright file="IOAuth2ChannelWithClient.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ /// <summary>
+ /// An interface that defines the OAuth2 client specific channel additions.
+ /// </summary>
+ internal interface IOAuth2ChannelWithClient {
+ /// <summary>
+ /// Gets or sets the identifier by which this client is known to the Authorization Server.
+ /// </summary>
+ string ClientIdentifier { get; set; }
+
+ /// <summary>
+ /// Gets or sets the client credentials applicator extension to use.
+ /// </summary>
+ ClientCredentialApplicator ClientCredentialApplicator { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs
index 54fc110..8ad2ed9 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs
@@ -18,7 +18,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
/// <summary>
/// The messaging channel used by OAuth 2.0 Clients.
/// </summary>
- internal class OAuth2ClientChannel : OAuth2ChannelBase {
+ internal class OAuth2ClientChannel : OAuth2ChannelBase, IOAuth2ChannelWithClient {
/// <summary>
/// The messages receivable by this channel.
/// </summary>
@@ -34,10 +34,22 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
/// <summary>
/// Initializes a new instance of the <see cref="OAuth2ClientChannel"/> class.
/// </summary>
- internal OAuth2ClientChannel() : base(MessageTypes) {
+ internal OAuth2ClientChannel()
+ : base(MessageTypes) {
}
/// <summary>
+ /// Gets or sets the identifier by which this client is known to the Authorization Server.
+ /// </summary>
+ public string ClientIdentifier { get; set; }
+
+ /// <summary>
+ /// Gets or sets the tool to use to apply client credentials to authenticated requests to the Authorization Server.
+ /// </summary>
+ /// <value>May be <c>null</c> if this client has no client secret.</value>
+ public ClientCredentialApplicator ClientCredentialApplicator { get; set; }
+
+ /// <summary>
/// Prepares an HTTP request that carries a given message.
/// </summary>
/// <param name="request">The message to send.</param>
@@ -131,5 +143,17 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
// Clients don't ever send direct responses.
throw new NotImplementedException();
}
+
+ /// <summary>
+ /// 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) {
+ base.PrepareHttpWebRequest(request);
+
+ if (this.ClientCredentialApplicator != null) {
+ this.ClientCredentialApplicator.ApplyClientCredential(this.ClientIdentifier, request);
+ }
+ }
}
}
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs
index 77b9cc6..5f377ae 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs
@@ -26,13 +26,16 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <param name="authorizationServer">The token issuer.</param>
/// <param name="clientIdentifier">The client identifier.</param>
- /// <param name="clientSecret">The client secret.</param>
- protected ClientBase(AuthorizationServerDescription authorizationServer, string clientIdentifier = null, string clientSecret = null) {
+ /// <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>
+ protected ClientBase(AuthorizationServerDescription authorizationServer, string clientIdentifier = null, ClientCredentialApplicator clientCredentialApplicator = null) {
Requires.NotNull(authorizationServer, "authorizationServer");
this.AuthorizationServer = authorizationServer;
this.Channel = new OAuth2ClientChannel();
this.ClientIdentifier = clientIdentifier;
- this.ClientSecret = clientSecret;
+ this.ClientCredentialApplicator = clientCredentialApplicator;
}
/// <summary>
@@ -50,12 +53,26 @@ namespace DotNetOpenAuth.OAuth2 {
/// <summary>
/// Gets or sets the identifier by which this client is known to the Authorization Server.
/// </summary>
- public string ClientIdentifier { get; set; }
+ public string ClientIdentifier {
+ get { return this.OAuthChannel.ClientIdentifier; }
+ set { this.OAuthChannel.ClientIdentifier = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the tool to use to apply client credentials to authenticated requests to the Authorization Server.
+ /// </summary>
+ /// <value>May be <c>null</c> if this client has no client secret.</value>
+ public ClientCredentialApplicator ClientCredentialApplicator {
+ get { return this.OAuthChannel.ClientCredentialApplicator; }
+ set { this.OAuthChannel.ClientCredentialApplicator = value; }
+ }
/// <summary>
- /// Gets or sets the client secret shared with the Authorization Server.
+ /// Gets the OAuth client channel.
/// </summary>
- public string ClientSecret { get; set; }
+ internal IOAuth2ChannelWithClient OAuthChannel {
+ get { return (IOAuth2ChannelWithClient)this.Channel; }
+ }
/// <summary>
/// Adds the necessary HTTP Authorization header to an HTTP request for protected resources
@@ -118,10 +135,11 @@ namespace DotNetOpenAuth.OAuth2 {
var request = new AccessTokenRefreshRequestC(this.AuthorizationServer) {
ClientIdentifier = this.ClientIdentifier,
- ClientSecret = this.ClientSecret,
RefreshToken = authorization.RefreshToken,
};
+ this.ApplyClientCredential(request);
+
var response = this.Channel.Request<AccessTokenSuccessResponse>(request);
UpdateAuthorizationWithResponse(authorization, response);
return true;
@@ -145,10 +163,11 @@ namespace DotNetOpenAuth.OAuth2 {
var request = new AccessTokenRefreshRequestC(this.AuthorizationServer) {
ClientIdentifier = this.ClientIdentifier,
- ClientSecret = this.ClientSecret,
RefreshToken = refreshToken,
};
+ this.ApplyClientCredential(request);
+
var response = this.Channel.Request<AccessTokenSuccessResponse>(request);
var authorization = new AuthorizationState();
UpdateAuthorizationWithResponse(authorization, response);
@@ -250,10 +269,10 @@ namespace DotNetOpenAuth.OAuth2 {
var accessTokenRequest = new AccessTokenAuthorizationCodeRequestC(this.AuthorizationServer) {
ClientIdentifier = this.ClientIdentifier,
- ClientSecret = this.ClientSecret,
Callback = authorizationState.Callback,
AuthorizationCode = authorizationSuccess.AuthorizationCode,
};
+ this.ApplyClientCredential(accessTokenRequest);
IProtocolMessage accessTokenResponse = this.Channel.Request(accessTokenRequest);
var accessTokenSuccess = accessTokenResponse as AccessTokenSuccessResponse;
var failedAccessTokenResponse = accessTokenResponse as AccessTokenFailedResponse;
@@ -267,6 +286,27 @@ namespace DotNetOpenAuth.OAuth2 {
}
/// <summary>
+ /// Applies the default client authentication mechanism given a client secret.
+ /// </summary>
+ /// <param name="secret">The client secret. May be <c>null</c></param>
+ /// <returns>The client credential applicator.</returns>
+ protected static ClientCredentialApplicator DefaultSecretApplicator(string secret) {
+ return secret == null ? ClientCredentialApplicator.NoSecret() : ClientCredentialApplicator.NetworkCredential(secret);
+ }
+
+ /// <summary>
+ /// Applies any applicable client credential to an authenticated outbound request to the authorization server.
+ /// </summary>
+ /// <param name="request">The request to apply authentication information to.</param>
+ protected void ApplyClientCredential(AuthenticatedClientRequestBase request) {
+ Requires.NotNull(request, "request");
+
+ if (this.ClientCredentialApplicator != null) {
+ this.ClientCredentialApplicator.ApplyClientCredential(this.ClientIdentifier, request);
+ }
+ }
+
+ /// <summary>
/// Calculates the fraction of life remaining in an access token.
/// </summary>
/// <param name="authorization">The authorization to measure.</param>
@@ -295,7 +335,7 @@ namespace DotNetOpenAuth.OAuth2 {
var authorizationState = new AuthorizationState(scopes);
request.ClientIdentifier = this.ClientIdentifier;
- request.ClientSecret = this.ClientSecret;
+ this.ApplyClientCredential(request);
request.Scope.UnionWith(authorizationState.Scope);
var response = this.Channel.Request(request);
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs
new file mode 100644
index 0000000..2a9a8a7
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs
@@ -0,0 +1,165 @@
+//-----------------------------------------------------------------------
+// <copyright file="ClientCredentialApplicator.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;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.Messages;
+
+ /// <summary>
+ /// A base class for extensions that apply client authentication to messages for the authorization server in specific ways.
+ /// </summary>
+ public abstract class ClientCredentialApplicator {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ClientCredentialApplicator"/> class.
+ /// </summary>
+ protected ClientCredentialApplicator() {
+ }
+
+ /// <summary>
+ /// Transmits the secret the client shares with the authorization server as a parameter in the POST entity payload.
+ /// </summary>
+ /// <param name="clientSecret">The secret the client shares with the authorization server.</param>
+ /// <returns>The credential applicator to provide to the <see cref="ClientBase"/> instance.</returns>
+ public static ClientCredentialApplicator PostParameter(string clientSecret) {
+ Requires.NotNullOrEmpty(clientSecret, "clientSecret");
+ return new PostParameterApplicator(clientSecret);
+ }
+
+ /// <summary>
+ /// Transmits the client identifier and secret in the HTTP Authorization header via HTTP Basic authentication.
+ /// </summary>
+ /// <param name="credential">The client id and secret.</param>
+ /// <returns>The credential applicator to provide to the <see cref="ClientBase"/> instance.</returns>
+ public static ClientCredentialApplicator NetworkCredential(NetworkCredential credential) {
+ Requires.NotNull(credential, "credential");
+ return new NetworkCredentialApplicator(credential);
+ }
+
+ /// <summary>
+ /// Transmits the client identifier and secret in the HTTP Authorization header via HTTP Basic authentication.
+ /// </summary>
+ /// <param name="clientSecret">The secret the client shares with the authorization server.</param>
+ /// <returns>The credential applicator to provide to the <see cref="ClientBase"/> instance.</returns>
+ public static ClientCredentialApplicator NetworkCredential(string clientSecret) {
+ Requires.NotNullOrEmpty(clientSecret, "clientSecret");
+ return new NetworkCredentialApplicator(clientSecret);
+ }
+
+ /// <summary>
+ /// Never transmits a secret. Useful for anonymous clients or clients unable to keep a secret.
+ /// </summary>
+ /// <returns>The credential applicator to provide to the <see cref="ClientBase"/> instance.</returns>
+ public static ClientCredentialApplicator NoSecret() {
+ return null;
+ }
+
+ /// <summary>
+ /// Applies the client identifier and (when applicable) the client authentication to an outbound message.
+ /// </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, AuthenticatedClientRequestBase request) {
+ }
+
+ /// <summary>
+ /// Applies the client identifier and (when applicable) the client authentication to an outbound message.
+ /// </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) {
+ }
+
+ /// <summary>
+ /// Authenticates the client via HTTP Basic.
+ /// </summary>
+ private class NetworkCredentialApplicator : ClientCredentialApplicator {
+ /// <summary>
+ /// The client identifier and secret.
+ /// </summary>
+ private readonly NetworkCredential credential;
+
+ /// <summary>
+ /// The client secret.
+ /// </summary>
+ private readonly string clientSecret;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="NetworkCredentialApplicator"/> class.
+ /// </summary>
+ /// <param name="clientSecret">The client secret.</param>
+ internal NetworkCredentialApplicator(string clientSecret) {
+ Requires.NotNullOrEmpty(clientSecret, "clientSecret");
+ this.clientSecret = clientSecret;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="NetworkCredentialApplicator"/> class.
+ /// </summary>
+ /// <param name="credential">The client credential.</param>
+ internal NetworkCredentialApplicator(NetworkCredential credential) {
+ Requires.NotNull(credential, "credential");
+ this.credential = credential;
+ }
+
+ /// <summary>
+ /// Applies the client identifier and (when applicable) the client authentication to an outbound message.
+ /// </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, AuthenticatedClientRequestBase request) {
+ // When using network credentials, the client authentication is not done as standard message parts.
+ request.ClientIdentifier = null;
+ request.ClientSecret = null;
+ }
+
+ /// <summary>
+ /// Applies the client identifier and (when applicable) the client authentication to an outbound message.
+ /// </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) {
+ if (this.credential != null && this.credential.UserName == clientIdentifier) {
+ ErrorUtilities.VerifyHost(false, "Client identifiers \"{0}\" and \"{1}\" do not match.", this.credential.UserName, clientIdentifier);
+ }
+
+ request.Credentials = this.credential ?? new NetworkCredential(clientIdentifier, this.clientSecret);
+ }
+ }
+
+ /// <summary>
+ /// Authenticates the client via a client_secret parameter in the message.
+ /// </summary>
+ private class PostParameterApplicator : ClientCredentialApplicator {
+ /// <summary>
+ /// The client secret.
+ /// </summary>
+ private readonly string secret;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PostParameterApplicator"/> class.
+ /// </summary>
+ /// <param name="clientSecret">The client secret.</param>
+ internal PostParameterApplicator(string clientSecret) {
+ Requires.NotNullOrEmpty(clientSecret, "clientSecret");
+ this.secret = clientSecret;
+ }
+
+ /// <summary>
+ /// Applies the client identifier and (when applicable) the client authentication to an outbound message.
+ /// </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, AuthenticatedClientRequestBase request) {
+ request.ClientSecret = this.secret;
+ }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/UserAgentClient.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/UserAgentClient.cs
index 9834985..edde2a9 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/UserAgentClient.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/UserAgentClient.cs
@@ -27,7 +27,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// <param name="clientIdentifier">The client identifier.</param>
/// <param name="clientSecret">The client secret.</param>
public UserAgentClient(AuthorizationServerDescription authorizationServer, string clientIdentifier = null, string clientSecret = null)
- : base(authorizationServer, clientIdentifier, clientSecret) {
+ : this(authorizationServer, clientIdentifier, DefaultSecretApplicator(clientSecret)) {
}
/// <summary>
@@ -38,12 +38,39 @@ namespace DotNetOpenAuth.OAuth2 {
/// <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(new AuthorizationServerDescription { AuthorizationEndpoint = authorizationEndpoint, TokenEndpoint = tokenEndpoint }, clientIdentifier, clientSecret) {
+ : this(authorizationEndpoint, tokenEndpoint, clientIdentifier, DefaultSecretApplicator(clientSecret)) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="UserAgentClient"/> class.
+ /// </summary>
+ /// <param name="authorizationEndpoint">The authorization endpoint.</param>
+ /// <param name="tokenEndpoint">The token endpoint.</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 UserAgentClient(Uri authorizationEndpoint, Uri tokenEndpoint, string clientIdentifier, ClientCredentialApplicator clientCredentialApplicator)
+ : this(new AuthorizationServerDescription { AuthorizationEndpoint = authorizationEndpoint, TokenEndpoint = tokenEndpoint }, clientIdentifier, clientCredentialApplicator) {
Requires.NotNull(authorizationEndpoint, "authorizationEndpoint");
Requires.NotNull(tokenEndpoint, "tokenEndpoint");
}
/// <summary>
+ /// Initializes a new instance of the <see cref="UserAgentClient"/> class.
+ /// </summary>
+ /// <param name="authorizationServer">The token issuer.</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 UserAgentClient(AuthorizationServerDescription authorizationServer, string clientIdentifier, ClientCredentialApplicator clientCredentialApplicator)
+ : base(authorizationServer, clientIdentifier, clientCredentialApplicator) {
+ }
+
+ /// <summary>
/// Generates a URL that the user's browser can be directed to in order to authorize
/// this client to access protected data at some resource server.
/// </summary>
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
index 5a86bef..c19757f 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
@@ -26,7 +26,20 @@ namespace DotNetOpenAuth.OAuth2 {
/// <param name="clientIdentifier">The client identifier.</param>
/// <param name="clientSecret">The client secret.</param>
public WebServerClient(AuthorizationServerDescription authorizationServer, string clientIdentifier = null, string clientSecret = null)
- : base(authorizationServer, clientIdentifier, clientSecret) {
+ : this(authorizationServer, clientIdentifier, DefaultSecretApplicator(clientSecret)) {
+ }
+
+ /// <summary>
+ /// 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) {
}
/// <summary>
@@ -106,7 +119,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// <returns>The authorization state that contains the details of the authorization.</returns>
public IAuthorizationState ProcessUserAuthorization(HttpRequestBase request = null) {
Requires.ValidState(!string.IsNullOrEmpty(this.ClientIdentifier), ClientStrings.RequiredPropertyNotYetPreset, "ClientIdentifier");
- Requires.ValidState(!string.IsNullOrEmpty(this.ClientSecret), ClientStrings.RequiredPropertyNotYetPreset, "ClientSecret");
+ Requires.ValidState(this.ClientCredentialApplicator != null, ClientStrings.RequiredPropertyNotYetPreset, "ClientCredentialApplicator");
if (request == null) {
request = this.Channel.GetRequestFromContext();