//----------------------------------------------------------------------- // // Copyright (c) Andrew Arnott. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth.OAuth2 { using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Text; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OAuth2.Messages; using Validation; /// /// A base class for extensions that apply client authentication to messages for the authorization server in specific ways. /// public abstract class ClientCredentialApplicator { /// /// Initializes a new instance of the class. /// protected ClientCredentialApplicator() { } /// /// Transmits the secret the client shares with the authorization server as a parameter in the POST entity payload. /// /// The secret the client shares with the authorization server. /// The credential applicator to provide to the instance. public static ClientCredentialApplicator PostParameter(string clientSecret) { Requires.NotNullOrEmpty(clientSecret, "clientSecret"); return new PostParameterApplicator(clientSecret); } /// /// Transmits the client identifier and secret in the HTTP Authorization header via HTTP Basic authentication. /// /// The client id and secret. /// The credential applicator to provide to the instance. public static ClientCredentialApplicator NetworkCredential(NetworkCredential credential) { Requires.NotNull(credential, "credential"); return new NetworkCredentialApplicator(credential); } /// /// Transmits the client identifier and secret in the HTTP Authorization header via HTTP Basic authentication. /// /// The secret the client shares with the authorization server. /// The credential applicator to provide to the instance. public static ClientCredentialApplicator NetworkCredential(string clientSecret) { Requires.NotNullOrEmpty(clientSecret, "clientSecret"); return new NetworkCredentialApplicator(clientSecret); } /// /// Never transmits a secret. Useful for anonymous clients or clients unable to keep a secret. /// /// The credential applicator to provide to the instance. public static ClientCredentialApplicator NoSecret() { return null; } /// /// Applies the client identifier and (when applicable) the client authentication to an outbound message. /// /// The identifier by which the authorization server should recognize this client. /// The outbound message to apply authentication information to. public virtual void ApplyClientCredential(string clientIdentifier, AuthenticatedClientRequestBase request) { } /// /// Applies the client identifier and (when applicable) the client authentication to an outbound message. /// /// The identifier by which the authorization server should recognize this client. /// The outbound message to apply authentication information to. public virtual void ApplyClientCredential(string clientIdentifier, HttpRequestMessage request) { } /// /// Authenticates the client via HTTP Basic. /// private class NetworkCredentialApplicator : ClientCredentialApplicator { /// /// The client identifier and secret. /// private readonly NetworkCredential credential; /// /// The client secret. /// private readonly string clientSecret; /// /// Initializes a new instance of the class. /// /// The client secret. internal NetworkCredentialApplicator(string clientSecret) { Requires.NotNullOrEmpty(clientSecret, "clientSecret"); this.clientSecret = clientSecret; } /// /// Initializes a new instance of the class. /// /// The client credential. internal NetworkCredentialApplicator(NetworkCredential credential) { Requires.NotNull(credential, "credential"); this.credential = credential; } /// /// Applies the client identifier and (when applicable) the client authentication to an outbound message. /// /// The identifier by which the authorization server should recognize this client. /// The outbound message to apply authentication information to. 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; } /// /// Applies the client identifier and (when applicable) the client authentication to an outbound message. /// /// The identifier by which the authorization server should recognize this client. /// The outbound message to apply authentication information to. public override void ApplyClientCredential(string clientIdentifier, HttpRequestMessage request) { if (clientIdentifier != null) { if (this.credential != null) { ErrorUtilities.VerifyHost( string.Equals(this.credential.UserName, clientIdentifier, StringComparison.Ordinal), "Client identifiers \"{0}\" and \"{1}\" do not match.", this.credential.UserName, clientIdentifier); } // HttpWebRequest ignores the Credentials property until the remote server returns a 401 Unauthorized. // So we also set the HTTP Authorization request header directly. OAuthUtilities.ApplyHttpBasicAuth(request.Headers, clientIdentifier, this.clientSecret); } } } /// /// Authenticates the client via a client_secret parameter in the message. /// private class PostParameterApplicator : ClientCredentialApplicator { /// /// The client secret. /// private readonly string secret; /// /// Initializes a new instance of the class. /// /// The client secret. internal PostParameterApplicator(string clientSecret) { Requires.NotNullOrEmpty(clientSecret, "clientSecret"); this.secret = clientSecret; } /// /// Applies the client identifier and (when applicable) the client authentication to an outbound message. /// /// The identifier by which the authorization server should recognize this client. /// The outbound message to apply authentication information to. public override void ApplyClientCredential(string clientIdentifier, AuthenticatedClientRequestBase request) { if (clientIdentifier != null) { request.ClientSecret = this.secret; } } } } }