summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AccessRequestBindingElement.cs
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2012-03-16 22:41:46 -0700
committerAndrew Arnott <andrewarnott@gmail.com>2012-03-16 22:41:46 -0700
commit1068d8217e19c6ac300a1077e13c2b1dae01bc4b (patch)
tree018d648707e90520f32f97462dbac78d12da2cb6 /src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AccessRequestBindingElement.cs
parent9f35726ca8389fb29aee849a8133e6672c4c55d6 (diff)
downloadDotNetOpenAuth-1068d8217e19c6ac300a1077e13c2b1dae01bc4b.zip
DotNetOpenAuth-1068d8217e19c6ac300a1077e13c2b1dae01bc4b.tar.gz
DotNetOpenAuth-1068d8217e19c6ac300a1077e13c2b1dae01bc4b.tar.bz2
Redistributed OAuth2 code into their more specific assemblies.
Diffstat (limited to 'src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AccessRequestBindingElement.cs')
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AccessRequestBindingElement.cs183
1 files changed, 183 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AccessRequestBindingElement.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AccessRequestBindingElement.cs
new file mode 100644
index 0000000..0533527
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AccessRequestBindingElement.cs
@@ -0,0 +1,183 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessRequestBindingElement.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Globalization;
+ using System.Linq;
+ using System.Security.Cryptography;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Bindings;
+ using DotNetOpenAuth.OAuth2.AuthServer.ChannelElements;
+ using DotNetOpenAuth.OAuth2.Messages;
+
+ /// <summary>
+ /// Decodes authorization codes, refresh tokens and access tokens on incoming messages.
+ /// </summary>
+ /// <remarks>
+ /// This binding element also ensures that the code/token coming in is issued to
+ /// the same client that is sending the code/token and that the authorization has
+ /// not been revoked and that an access token has not expired.
+ /// </remarks>
+ internal class AccessRequestBindingElement : AuthServerBindingElementBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessRequestBindingElement"/> class.
+ /// </summary>
+ internal AccessRequestBindingElement() {
+ }
+
+ /// <summary>
+ /// Gets the protection commonly offered (if any) by this binding element.
+ /// </summary>
+ /// <value></value>
+ /// <remarks>
+ /// This value is used to assist in sorting binding elements in the channel stack.
+ /// </remarks>
+ public override MessageProtections Protection {
+ get { return MessageProtections.None; }
+ }
+
+ /// <summary>
+ /// Prepares a message for sending based on the rules of this channel binding element.
+ /// </summary>
+ /// <param name="message">The message to prepare for sending.</param>
+ /// <returns>
+ /// The protections (if any) that this binding element applied to the message.
+ /// Null if this binding element did not even apply to this binding element.
+ /// </returns>
+ /// <remarks>
+ /// Implementations that provide message protection must honor the
+ /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
+ /// </remarks>
+ public override MessageProtections? ProcessOutgoingMessage(IProtocolMessage message) {
+ var responseWithOriginatingRequest = message as IDirectResponseProtocolMessage;
+ var accessRequest = responseWithOriginatingRequest.OriginatingRequest as IAccessTokenRequestInternal;
+
+ var authCodeCarrier = message as IAuthorizationCodeCarryingRequest;
+ if (authCodeCarrier != null) {
+ var codeFormatter = AuthorizationCode.CreateFormatter(this.AuthorizationServer);
+ var code = authCodeCarrier.AuthorizationDescription;
+ authCodeCarrier.Code = codeFormatter.Serialize(code);
+ return MessageProtections.None;
+ }
+
+ var accessTokenCarrier = message as IAccessTokenIssuingResponse;
+ if (accessTokenCarrier != null) {
+ var tokenFormatter = AccessToken.CreateFormatter(this.AuthorizationServer.AccessTokenSigningKey, accessRequest.AccessTokenCreationParameters.ResourceServerEncryptionKey);
+ var token = accessTokenCarrier.AuthorizationDescription;
+ accessTokenCarrier.AccessToken = tokenFormatter.Serialize(token);
+ accessTokenCarrier.Lifetime = accessRequest.AccessTokenCreationParameters.AccessTokenLifetime;
+
+ return MessageProtections.None;
+ }
+
+ var accessTokenResponse = message as AccessTokenSuccessResponse;
+ if (accessTokenResponse != null) {
+ var directResponseMessage = (IDirectResponseProtocolMessage)accessTokenResponse;
+ var accessTokenRequest = (AccessTokenRequestBase)directResponseMessage.OriginatingRequest;
+ ErrorUtilities.VerifyProtocol(accessTokenRequest.GrantType != GrantType.ClientCredentials || accessTokenResponse.RefreshToken == null, OAuthStrings.NoGrantNoRefreshToken);
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Performs any transformation on an incoming message that may be necessary and/or
+ /// validates an incoming message based on the rules of this channel binding element.
+ /// </summary>
+ /// <param name="message">The incoming message to process.</param>
+ /// <returns>
+ /// The protections (if any) that this binding element applied to the message.
+ /// Null if this binding element did not even apply to this binding element.
+ /// </returns>
+ /// <exception cref="ProtocolException">
+ /// Thrown when the binding element rules indicate that this message is invalid and should
+ /// NOT be processed.
+ /// </exception>
+ /// <remarks>
+ /// Implementations that provide message protection must honor the
+ /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
+ /// </remarks>
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "unauthorizedclient", Justification = "Protocol requirement")]
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "incorrectclientcredentials", Justification = "Protocol requirement")]
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "authorizationexpired", Justification = "Protocol requirement")]
+ [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "DotNetOpenAuth.Messaging.ErrorUtilities.VerifyProtocol(System.Boolean,System.String,System.Object[])", Justification = "Protocol requirement")]
+ public override MessageProtections? ProcessIncomingMessage(IProtocolMessage message) {
+ var tokenRequest = message as IAuthorizationCarryingRequest;
+ if (tokenRequest != null) {
+ try {
+ var authCodeCarrier = message as IAuthorizationCodeCarryingRequest;
+ var refreshTokenCarrier = message as IRefreshTokenCarryingRequest;
+ var resourceOwnerPasswordCarrier = message as AccessTokenResourceOwnerPasswordCredentialsRequest;
+ var clientCredentialOnly = message as AccessTokenClientCredentialsRequest;
+ if (authCodeCarrier != null) {
+ var authorizationCodeFormatter = AuthorizationCode.CreateFormatter(this.AuthorizationServer);
+ var authorizationCode = authorizationCodeFormatter.Deserialize(message, authCodeCarrier.Code, Protocol.code);
+ authCodeCarrier.AuthorizationDescription = authorizationCode;
+ } else if (refreshTokenCarrier != null) {
+ var refreshTokenFormatter = RefreshToken.CreateFormatter(this.AuthorizationServer.CryptoKeyStore);
+ var refreshToken = refreshTokenFormatter.Deserialize(message, refreshTokenCarrier.RefreshToken, Protocol.refresh_token);
+ refreshTokenCarrier.AuthorizationDescription = refreshToken;
+ } else if (resourceOwnerPasswordCarrier != null) {
+ try {
+ if (this.AuthorizationServer.IsResourceOwnerCredentialValid(resourceOwnerPasswordCarrier.UserName, resourceOwnerPasswordCarrier.Password)) {
+ resourceOwnerPasswordCarrier.CredentialsValidated = true;
+ } else {
+ Logger.OAuth.WarnFormat(
+ "Resource owner password credential for user \"{0}\" rejected by authorization server host.",
+ resourceOwnerPasswordCarrier.UserName);
+
+ // TODO: fix this to report the appropriate error code for a bad credential.
+ throw new ProtocolException();
+ }
+ } catch (NotSupportedException) {
+ // TODO: fix this to return the appropriate error code for not supporting resource owner password credentials
+ throw new ProtocolException();
+ } catch (NotImplementedException) {
+ // TODO: fix this to return the appropriate error code for not supporting resource owner password credentials
+ throw new ProtocolException();
+ }
+ } else if (clientCredentialOnly != null) {
+ // this method will throw later if the credentials are false.
+ clientCredentialOnly.CredentialsValidated = true;
+ } else {
+ throw ErrorUtilities.ThrowInternal("Unexpected message type: " + tokenRequest.GetType());
+ }
+ } catch (ExpiredMessageException ex) {
+ throw ErrorUtilities.Wrap(ex, Protocol.authorization_expired);
+ }
+
+ var accessRequest = tokenRequest as AccessTokenRequestBase;
+ if (accessRequest != null) {
+ // Make sure the client sending us this token is the client we issued the token to.
+ ErrorUtilities.VerifyProtocol(string.Equals(accessRequest.ClientIdentifier, tokenRequest.AuthorizationDescription.ClientIdentifier, StringComparison.Ordinal), Protocol.incorrect_client_credentials);
+
+ // Check that the client secret is correct.
+ var client = this.AuthorizationServer.GetClientOrThrow(accessRequest.ClientIdentifier);
+ string secret = client.Secret;
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(secret), Protocol.unauthorized_client); // an empty secret is not allowed for client authenticated calls.
+ ErrorUtilities.VerifyProtocol(MessagingUtilities.EqualsConstantTime(secret, accessRequest.ClientSecret), Protocol.incorrect_client_credentials);
+
+ var scopedAccessRequest = accessRequest as ScopedAccessTokenRequest;
+ if (scopedAccessRequest != null) {
+ // Make sure the scope the client is requesting does not exceed the scope in the grant.
+ ErrorUtilities.VerifyProtocol(scopedAccessRequest.Scope.IsSubsetOf(tokenRequest.AuthorizationDescription.Scope), OAuthStrings.AccessScopeExceedsGrantScope, scopedAccessRequest.Scope, tokenRequest.AuthorizationDescription.Scope);
+ }
+ }
+
+ // Make sure the authorization this token represents hasn't already been revoked.
+ ErrorUtilities.VerifyProtocol(this.AuthorizationServer.IsAuthorizationValid(tokenRequest.AuthorizationDescription), Protocol.authorization_expired);
+
+ return MessageProtections.None;
+ }
+
+ return null;
+ }
+ }
+}