summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2012-04-18 19:55:50 -0700
committerAndrew Arnott <andrewarnott@gmail.com>2012-04-18 19:55:50 -0700
commit2ddd19d9f037bebbbdc80d7de35ce4d899710859 (patch)
treebaf8ad19d4799b1a1284b9fc668afd53e3b008a4 /src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements
parentbd0de8217763d02759815b91588cd578becf496b (diff)
downloadDotNetOpenAuth-2ddd19d9f037bebbbdc80d7de35ce4d899710859.zip
DotNetOpenAuth-2ddd19d9f037bebbbdc80d7de35ce4d899710859.tar.gz
DotNetOpenAuth-2ddd19d9f037bebbbdc80d7de35ce4d899710859.tar.bz2
We have HTTP Basic client authentication working now in OAuth 2.
Diffstat (limited to 'src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements')
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AggregatingClientCredentialReader.cs62
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialHttpBasicReader.cs37
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialMessagePartReader.cs29
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialReader.cs50
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/MessageValidationBindingElement.cs15
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/OAuth2AuthorizationServerChannel.cs10
6 files changed, 196 insertions, 7 deletions
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AggregatingClientCredentialReader.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AggregatingClientCredentialReader.cs
new file mode 100644
index 0000000..4248c6f
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AggregatingClientCredentialReader.cs
@@ -0,0 +1,62 @@
+//-----------------------------------------------------------------------
+// <copyright file="AggregatingClientCredentialReader.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Globalization;
+ using System.Linq;
+ using System.Text;
+ using System.Web;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.Messages;
+
+ /// <summary>
+ /// Applies OAuth 2 spec policy for supporting multiple methods of client authentication.
+ /// </summary>
+ internal class AggregatingClientCredentialReader : ClientAuthenticationModuleBase {
+ /// <summary>
+ /// The set of authenticators to apply to an incoming request.
+ /// </summary>
+ private readonly IEnumerable<IClientAuthenticationModule> authenticators;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AggregatingClientCredentialReader"/> class.
+ /// </summary>
+ /// <param name="authenticators">The set of authentication modules to apply.</param>
+ internal AggregatingClientCredentialReader(IEnumerable<IClientAuthenticationModule> authenticators) {
+ Requires.NotNull(authenticators, "readers");
+ this.authenticators = authenticators;
+ }
+
+ public override ClientAuthenticationResult TryAuthenticateClient(AuthenticatedClientRequestBase requestMessage, out string clientIdentifier) {
+ Requires.NotNull(requestMessage, "requestMessage");
+
+ IClientAuthenticationModule authenticator = null;
+ ClientAuthenticationResult result = ClientAuthenticationResult.NoAuthenticationRecognized;
+ clientIdentifier = null;
+
+ foreach (var candidateAuthenticator in this.authenticators) {
+ string candidateClientIdentifier;
+ var resultCandidate = candidateAuthenticator.TryAuthenticateClient(requestMessage, out candidateClientIdentifier);
+
+ ErrorUtilities.VerifyProtocol(
+ result == ClientAuthenticationResult.NoAuthenticationRecognized || resultCandidate == ClientAuthenticationResult.NoAuthenticationRecognized,
+ "Message rejected because multiple forms of client authentication ({0} and {1}) were detected, which is forbidden by the OAuth 2 Protocol Framework specification.",
+ authenticator,
+ candidateAuthenticator);
+
+ if (resultCandidate != ClientAuthenticationResult.NoAuthenticationRecognized) {
+ authenticator = candidateAuthenticator;
+ result = resultCandidate;
+ clientIdentifier = candidateClientIdentifier;
+ }
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialHttpBasicReader.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialHttpBasicReader.cs
new file mode 100644
index 0000000..da3f8ff
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialHttpBasicReader.cs
@@ -0,0 +1,37 @@
+//-----------------------------------------------------------------------
+// <copyright file="ClientCredentialHttpBasicReader.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;
+ using System.Web;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.Messages;
+
+ public class ClientCredentialHttpBasicReader : ClientAuthenticationModuleBase {
+ private readonly IAuthorizationServerHost authorizationServerHost;
+
+ public ClientCredentialHttpBasicReader(IAuthorizationServerHost authorizationServerHost) {
+ Requires.NotNull(authorizationServerHost, "authorizationServerHost");
+ this.authorizationServerHost = authorizationServerHost;
+ }
+
+ public override ClientAuthenticationResult TryAuthenticateClient(AuthenticatedClientRequestBase requestMessage, out string clientIdentifier) {
+ Requires.NotNull(requestMessage, "requestMessage");
+
+ var credential = OAuthUtilities.ParseHttpBasicAuth(requestMessage.Headers);
+ if (credential != null) {
+ clientIdentifier = credential.UserName;
+ return TryAuthenticateClient(this.authorizationServerHost, credential.UserName, credential.Password);
+ }
+
+ clientIdentifier = null;
+ return ClientAuthenticationResult.NoAuthenticationRecognized;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialMessagePartReader.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialMessagePartReader.cs
new file mode 100644
index 0000000..07ededf
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialMessagePartReader.cs
@@ -0,0 +1,29 @@
+//-----------------------------------------------------------------------
+// <copyright file="ClientCredentialMessagePartReader.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;
+ using System.Web;
+ using DotNetOpenAuth.OAuth2.Messages;
+
+ public class ClientCredentialMessagePartReader : ClientAuthenticationModuleBase {
+ private readonly IAuthorizationServerHost authorizationServerHost;
+
+ public ClientCredentialMessagePartReader(IAuthorizationServerHost authorizationServerHost) {
+ Requires.NotNull(authorizationServerHost, "authorizationServerHost");
+ this.authorizationServerHost = authorizationServerHost;
+ }
+
+ public override ClientAuthenticationResult TryAuthenticateClient(AuthenticatedClientRequestBase requestMessage, out string clientIdentifier) {
+ Requires.NotNull(requestMessage, "requestMessage");
+ clientIdentifier = requestMessage.ClientIdentifier;
+ return TryAuthenticateClient(this.authorizationServerHost, requestMessage.ClientIdentifier, requestMessage.ClientSecret);
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialReader.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialReader.cs
new file mode 100644
index 0000000..085600a
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialReader.cs
@@ -0,0 +1,50 @@
+//-----------------------------------------------------------------------
+// <copyright file="ClientCredentialReader.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;
+ using System.Threading;
+ using System.Web;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.Messages;
+
+ public abstract class ClientAuthenticationModuleBase : IClientAuthenticationModule {
+ protected ClientAuthenticationModuleBase() {
+ }
+
+ public abstract ClientAuthenticationResult TryAuthenticateClient(AuthenticatedClientRequestBase requestMessage, out string clientIdentifier);
+
+ public ClientAuthenticationResult TryAuthenticateClient(IDirectedProtocolMessage requestMessage, out string clientIdentifier) {
+ return this.TryAuthenticateClient((AuthenticatedClientRequestBase)requestMessage, out clientIdentifier);
+ }
+
+ protected static ClientAuthenticationResult TryAuthenticateClient(IAuthorizationServerHost authorizationServerHost, string clientIdentifier, string clientSecret) {
+ Requires.NotNull(authorizationServerHost, "authorizationServerHost");
+
+ if (!string.IsNullOrEmpty(clientIdentifier)) {
+ var client = authorizationServerHost.GetClient(clientIdentifier);
+ if (client != null) {
+ if (!string.IsNullOrEmpty(clientSecret)) {
+ if (client.IsValidClientSecret(clientSecret)) {
+ return ClientAuthenticationResult.ClientAuthenticated;
+ } else { // invalid client secret
+ return ClientAuthenticationResult.ClientAuthenticationRejected;
+ }
+ } else { // no client secret provided
+ return ClientAuthenticationResult.ClientIdNotAuthenticated;
+ }
+ } else { // The client identifier is not recognized.
+ return ClientAuthenticationResult.ClientAuthenticationRejected;
+ }
+ } else { // no client id provided.
+ return ClientAuthenticationResult.NoAuthenticationRecognized;
+ }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/MessageValidationBindingElement.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/MessageValidationBindingElement.cs
index 7361fb9..fa21bdd 100644
--- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/MessageValidationBindingElement.cs
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/MessageValidationBindingElement.cs
@@ -23,6 +23,13 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
/// not been revoked and that an access token has not expired.
/// </remarks>
internal class MessageValidationBindingElement : AuthServerBindingElementBase {
+ private readonly IClientAuthenticationModule clientAuthenticationModule;
+
+ internal MessageValidationBindingElement(IClientAuthenticationModule clientAuthenticationModule) {
+ Requires.NotNull(clientAuthenticationModule, "clientAuthenticationModule");
+ this.clientAuthenticationModule = clientAuthenticationModule;
+ }
+
/// <summary>
/// Gets the protection commonly offered (if any) by this binding element.
/// </summary>
@@ -80,9 +87,11 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
var clientCredentialOnly = message as AccessTokenClientCredentialsRequest;
var authenticatedClientRequest = message as AuthenticatedClientRequestBase;
if (authenticatedClientRequest != null) {
- var client = this.AuthorizationServer.GetClientOrThrow(authenticatedClientRequest.ClientIdentifier);
- AuthServerUtilities.TokenEndpointVerify(client.HasNonEmptySecret, Protocol.AccessTokenRequestErrorCodes.UnauthorizedClient); // an empty secret is not allowed for client authenticated calls.
- AuthServerUtilities.TokenEndpointVerify(client.IsValidClientSecret(authenticatedClientRequest.ClientSecret), Protocol.AccessTokenRequestErrorCodes.InvalidClient, AuthServerStrings.ClientSecretMismatch);
+ string clientIdentifier;
+ var result = this.clientAuthenticationModule.TryAuthenticateClient(authenticatedClientRequest, out clientIdentifier);
+ AuthServerUtilities.TokenEndpointVerify(result != ClientAuthenticationResult.ClientIdNotAuthenticated, Protocol.AccessTokenRequestErrorCodes.UnauthorizedClient); // an empty secret is not allowed for client authenticated calls.
+ AuthServerUtilities.TokenEndpointVerify(result == ClientAuthenticationResult.ClientAuthenticated, Protocol.AccessTokenRequestErrorCodes.InvalidClient, AuthServerStrings.ClientSecretMismatch);
+ authenticatedClientRequest.ClientIdentifier = clientIdentifier;
if (clientCredentialOnly != null) {
clientCredentialOnly.CredentialsValidated = true;
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/OAuth2AuthorizationServerChannel.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/OAuth2AuthorizationServerChannel.cs
index bd154bc..2521e5f 100644
--- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/OAuth2AuthorizationServerChannel.cs
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/OAuth2AuthorizationServerChannel.cs
@@ -35,8 +35,8 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
/// Initializes a new instance of the <see cref="OAuth2AuthorizationServerChannel"/> class.
/// </summary>
/// <param name="authorizationServer">The authorization server.</param>
- protected internal OAuth2AuthorizationServerChannel(IAuthorizationServerHost authorizationServer)
- : base(MessageTypes, InitializeBindingElements(authorizationServer)) {
+ protected internal OAuth2AuthorizationServerChannel(IAuthorizationServerHost authorizationServer, IClientAuthenticationModule clientAuthenticationModule)
+ : base(MessageTypes, InitializeBindingElements(authorizationServer, clientAuthenticationModule)) {
Requires.NotNull(authorizationServer, "authorizationServer");
this.AuthorizationServer = authorizationServer;
}
@@ -109,12 +109,14 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
/// <returns>
/// An array of binding elements used to initialize the channel.
/// </returns>
- private static IChannelBindingElement[] InitializeBindingElements(IAuthorizationServerHost authorizationServer) {
+ private static IChannelBindingElement[] InitializeBindingElements(IAuthorizationServerHost authorizationServer, IClientAuthenticationModule clientAuthenticationModule) {
Requires.NotNull(authorizationServer, "authorizationServer");
+ Requires.NotNull(clientAuthenticationModule, "clientAuthenticationModule");
+
var bindingElements = new List<IChannelBindingElement>();
// The order they are provided is used for outgoing messgaes, and reversed for incoming messages.
- bindingElements.Add(new MessageValidationBindingElement());
+ bindingElements.Add(new MessageValidationBindingElement(clientAuthenticationModule));
bindingElements.Add(new TokenCodeSerializationBindingElement());
return bindingElements.ToArray();