diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2011-07-31 23:14:49 -0600 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2011-07-31 23:14:49 -0600 |
commit | 7d874b645d575ed4cf7f879e7919c277cd7bfae7 (patch) | |
tree | 5b95aa5f3b7345a894ab184b85a60349766ebe02 /src/DotNetOpenAuth.OAuth/OAuth/ChannelElements | |
parent | cb2960f2af1c4148d8581c3543594355cccabe6f (diff) | |
download | DotNetOpenAuth-7d874b645d575ed4cf7f879e7919c277cd7bfae7.zip DotNetOpenAuth-7d874b645d575ed4cf7f879e7919c277cd7bfae7.tar.gz DotNetOpenAuth-7d874b645d575ed4cf7f879e7919c277cd7bfae7.tar.bz2 |
Moved more OAuth code from the common library to the individual Consumer or SP ones.
Diffstat (limited to 'src/DotNetOpenAuth.OAuth/OAuth/ChannelElements')
11 files changed, 11 insertions, 1156 deletions
diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IConsumerDescription.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IConsumerDescription.cs deleted file mode 100644 index db505d5..0000000 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IConsumerDescription.cs +++ /dev/null @@ -1,59 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="IConsumerDescription.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuth.ChannelElements { - using System; - using System.Security.Cryptography.X509Certificates; - - /// <summary> - /// A description of a consumer from a Service Provider's point of view. - /// </summary> - public interface IConsumerDescription { - /// <summary> - /// Gets the Consumer key. - /// </summary> - string Key { get; } - - /// <summary> - /// Gets the consumer secret. - /// </summary> - string Secret { get; } - - /// <summary> - /// Gets the certificate that can be used to verify the signature of an incoming - /// message from a Consumer. - /// </summary> - /// <returns>The public key from the Consumer's X.509 Certificate, if one can be found; otherwise <c>null</c>.</returns> - /// <remarks> - /// This property must be implemented only if the RSA-SHA1 algorithm is supported by the Service Provider. - /// </remarks> - X509Certificate2 Certificate { get; } - - /// <summary> - /// Gets the callback URI that this consumer has pre-registered with the service provider, if any. - /// </summary> - /// <value>A URI that user authorization responses should be directed to; or <c>null</c> if no preregistered callback was arranged.</value> - Uri Callback { get; } - - /// <summary> - /// Gets the verification code format that is most appropriate for this consumer - /// when a callback URI is not available. - /// </summary> - /// <value>A set of characters that can be easily keyed in by the user given the Consumer's - /// application type and form factor.</value> - /// <remarks> - /// The value <see cref="OAuth.VerificationCodeFormat.IncludedInCallback"/> should NEVER be returned - /// since this property is only used in no callback scenarios anyway. - /// </remarks> - VerificationCodeFormat VerificationCodeFormat { get; } - - /// <summary> - /// Gets the length of the verification code to issue for this Consumer. - /// </summary> - /// <value>A positive number, generally at least 4.</value> - int VerificationCodeLength { get; } - } -} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderAccessToken.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderAccessToken.cs deleted file mode 100644 index 35ba52d..0000000 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderAccessToken.cs +++ /dev/null @@ -1,48 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="IServiceProviderAccessToken.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuth.ChannelElements { - using System; - using System.Collections.Generic; - using System.Diagnostics.CodeAnalysis; - using System.Linq; - using System.Text; - - /// <summary> - /// A description of an access token and its metadata as required by a Service Provider. - /// </summary> - public interface IServiceProviderAccessToken { - /// <summary> - /// Gets the token itself. - /// </summary> - string Token { get; } - - /// <summary> - /// Gets the expiration date (local time) for the access token. - /// </summary> - /// <value>The expiration date, or <c>null</c> if there is no expiration date.</value> - DateTime? ExpirationDate { get; } - - /// <summary> - /// Gets the username of the principal that will be impersonated by this access token. - /// </summary> - /// <value> - /// The name of the user who authorized the OAuth request token originally. - /// </value> - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Username", Justification = "Breaking change.")] - string Username { get; } - - /// <summary> - /// Gets the roles that the OAuth principal should belong to. - /// </summary> - /// <value> - /// The roles that the user belongs to, or a subset of these according to the rights - /// granted when the user authorized the request token. - /// </value> - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "By design.")] - string[] Roles { get; } - } -} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderRequestToken.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderRequestToken.cs deleted file mode 100644 index 6dfa416..0000000 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderRequestToken.cs +++ /dev/null @@ -1,52 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="IServiceProviderRequestToken.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuth.ChannelElements { - using System; - using DotNetOpenAuth.OAuth.Messages; - - /// <summary> - /// A description of a request token and its metadata as required by a Service Provider - /// </summary> - public interface IServiceProviderRequestToken { - /// <summary> - /// Gets the token itself. - /// </summary> - string Token { get; } - - /// <summary> - /// Gets the consumer key that requested this token. - /// </summary> - string ConsumerKey { get; } - - /// <summary> - /// Gets the (local) date that this request token was first created on. - /// </summary> - DateTime CreatedOn { get; } - - /// <summary> - /// Gets or sets the callback associated specifically with this token, if any. - /// </summary> - /// <value>The callback URI; or <c>null</c> if no callback was specifically assigned to this token.</value> - Uri Callback { get; set; } - - /// <summary> - /// Gets or sets the verifier that the consumer must include in the <see cref="AuthorizedTokenRequest"/> - /// message to exchange this request token for an access token. - /// </summary> - /// <value>The verifier code, or <c>null</c> if none has been assigned (yet).</value> - string VerificationCode { get; set; } - - /// <summary> - /// Gets or sets the version of the Consumer that requested this token. - /// </summary> - /// <remarks> - /// This property is used to determine whether a <see cref="VerificationCode"/> must be - /// generated when the user authorizes the Consumer or not. - /// </remarks> - Version ConsumerVersion { get; set; } - } -} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs deleted file mode 100644 index 7df67ce..0000000 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/IServiceProviderTokenManager.cs +++ /dev/null @@ -1,251 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="IServiceProviderTokenManager.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuth.ChannelElements { - using System; - using System.Collections.Generic; - using System.Diagnostics.Contracts; - using System.Linq; - using System.Text; - - /// <summary> - /// A token manager for use by a web site in its role as a - /// service provider. - /// </summary> - [ContractClass(typeof(IServiceProviderTokenManagerContract))] - public interface IServiceProviderTokenManager : ITokenManager { - /// <summary> - /// Gets the Consumer description for a given a Consumer Key. - /// </summary> - /// <param name="consumerKey">The Consumer Key.</param> - /// <returns>A description of the consumer. Never null.</returns> - /// <exception cref="KeyNotFoundException">Thrown if the consumer key cannot be found.</exception> - IConsumerDescription GetConsumer(string consumerKey); - - /// <summary> - /// Checks whether a given request token has already been authorized - /// by some user for use by the Consumer that requested it. - /// </summary> - /// <param name="requestToken">The Consumer's request token.</param> - /// <returns> - /// True if the request token has already been fully authorized by the user - /// who owns the relevant protected resources. False if the token has not yet - /// been authorized, has expired or does not exist. - /// </returns> - bool IsRequestTokenAuthorized(string requestToken); - - /// <summary> - /// Gets details on the named request token. - /// </summary> - /// <param name="token">The request token.</param> - /// <returns>A description of the token. Never null.</returns> - /// <exception cref="KeyNotFoundException">Thrown if the token cannot be found.</exception> - /// <remarks> - /// It is acceptable for implementations to find the token, see that it has expired, - /// delete it from the database and then throw <see cref="KeyNotFoundException"/>, - /// or alternatively it can return the expired token anyway and the OAuth channel will - /// log and throw the appropriate error. - /// </remarks> - IServiceProviderRequestToken GetRequestToken(string token); - - /// <summary> - /// Gets details on the named access token. - /// </summary> - /// <param name="token">The access token.</param> - /// <returns>A description of the token. Never null.</returns> - /// <exception cref="KeyNotFoundException">Thrown if the token cannot be found.</exception> - /// <remarks> - /// It is acceptable for implementations to find the token, see that it has expired, - /// delete it from the database and then throw <see cref="KeyNotFoundException"/>, - /// or alternatively it can return the expired token anyway and the OAuth channel will - /// log and throw the appropriate error. - /// </remarks> - IServiceProviderAccessToken GetAccessToken(string token); - - /// <summary> - /// Persists any changes made to the token. - /// </summary> - /// <param name="token">The token whose properties have been changed.</param> - /// <remarks> - /// This library will invoke this method after making a set - /// of changes to the token as part of a web request to give the host - /// the opportunity to persist those changes to a database. - /// Depending on the object persistence framework the host site uses, - /// this method MAY not need to do anything (if changes made to the token - /// will automatically be saved without any extra handling). - /// </remarks> - void UpdateToken(IServiceProviderRequestToken token); - } - - /// <summary> - /// Code contract class for the <see cref="IServiceProviderTokenManager"/> interface. - /// </summary> - [ContractClassFor(typeof(IServiceProviderTokenManager))] - internal abstract class IServiceProviderTokenManagerContract : IServiceProviderTokenManager { - /// <summary> - /// Prevents a default instance of the <see cref="IServiceProviderTokenManagerContract"/> class from being created. - /// </summary> - private IServiceProviderTokenManagerContract() { - } - - #region IServiceProviderTokenManager Members - - /// <summary> - /// Gets the Consumer description for a given a Consumer Key. - /// </summary> - /// <param name="consumerKey">The Consumer Key.</param> - /// <returns> - /// A description of the consumer. Never null. - /// </returns> - /// <exception cref="KeyNotFoundException">Thrown if the consumer key cannot be found.</exception> - IConsumerDescription IServiceProviderTokenManager.GetConsumer(string consumerKey) { - Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(consumerKey)); - Contract.Ensures(Contract.Result<IConsumerDescription>() != null); - throw new NotImplementedException(); - } - - /// <summary> - /// Checks whether a given request token has already been authorized - /// by some user for use by the Consumer that requested it. - /// </summary> - /// <param name="requestToken">The Consumer's request token.</param> - /// <returns> - /// True if the request token has already been fully authorized by the user - /// who owns the relevant protected resources. False if the token has not yet - /// been authorized, has expired or does not exist. - /// </returns> - bool IServiceProviderTokenManager.IsRequestTokenAuthorized(string requestToken) { - Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(requestToken)); - throw new NotImplementedException(); - } - - /// <summary> - /// Gets details on the named request token. - /// </summary> - /// <param name="token">The request token.</param> - /// <returns>A description of the token. Never null.</returns> - /// <exception cref="KeyNotFoundException">Thrown if the token cannot be found.</exception> - /// <remarks> - /// It is acceptable for implementations to find the token, see that it has expired, - /// delete it from the database and then throw <see cref="KeyNotFoundException"/>, - /// or alternatively it can return the expired token anyway and the OAuth channel will - /// log and throw the appropriate error. - /// </remarks> - IServiceProviderRequestToken IServiceProviderTokenManager.GetRequestToken(string token) { - Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(token)); - Contract.Ensures(Contract.Result<IServiceProviderRequestToken>() != null); - throw new NotImplementedException(); - } - - /// <summary> - /// Gets details on the named access token. - /// </summary> - /// <param name="token">The access token.</param> - /// <returns>A description of the token. Never null.</returns> - /// <exception cref="KeyNotFoundException">Thrown if the token cannot be found.</exception> - /// <remarks> - /// It is acceptable for implementations to find the token, see that it has expired, - /// delete it from the database and then throw <see cref="KeyNotFoundException"/>, - /// or alternatively it can return the expired token anyway and the OAuth channel will - /// log and throw the appropriate error. - /// </remarks> - IServiceProviderAccessToken IServiceProviderTokenManager.GetAccessToken(string token) { - Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(token)); - Contract.Ensures(Contract.Result<IServiceProviderAccessToken>() != null); - throw new NotImplementedException(); - } - - /// <summary> - /// Persists any changes made to the token. - /// </summary> - /// <param name="token">The token whose properties have been changed.</param> - /// <remarks> - /// This library will invoke this method after making a set - /// of changes to the token as part of a web request to give the host - /// the opportunity to persist those changes to a database. - /// Depending on the object persistence framework the host site uses, - /// this method MAY not need to do anything (if changes made to the token - /// will automatically be saved without any extra handling). - /// </remarks> - void IServiceProviderTokenManager.UpdateToken(IServiceProviderRequestToken token) { - Contract.Requires<ArgumentNullException>(token != null); - throw new NotImplementedException(); - } - - #endregion - - #region ITokenManager Members - - /// <summary> - /// Gets the Token Secret given a request or access token. - /// </summary> - /// <param name="token">The request or access token.</param> - /// <returns> - /// The secret associated with the given token. - /// </returns> - /// <exception cref="ArgumentException">Thrown if the secret cannot be found for the given token.</exception> - string ITokenManager.GetTokenSecret(string token) { - throw new NotImplementedException(); - } - - /// <summary> - /// Stores a newly generated unauthorized request token, secret, and optional - /// application-specific parameters for later recall. - /// </summary> - /// <param name="request">The request message that resulted in the generation of a new unauthorized request token.</param> - /// <param name="response">The response message that includes the unauthorized request token.</param> - /// <exception cref="ArgumentException">Thrown if the consumer key is not registered, or a required parameter was not found in the parameters collection.</exception> - /// <remarks> - /// Request tokens stored by this method SHOULD NOT associate any user account with this token. - /// It usually opens up security holes in your application to do so. Instead, you associate a user - /// account with access tokens (not request tokens) in the <see cref="ITokenManager.ExpireRequestTokenAndStoreNewAccessToken"/> - /// method. - /// </remarks> - void ITokenManager.StoreNewRequestToken(DotNetOpenAuth.OAuth.Messages.UnauthorizedTokenRequest request, DotNetOpenAuth.OAuth.Messages.ITokenSecretContainingMessage response) { - throw new NotImplementedException(); - } - - /// <summary> - /// Deletes a request token and its associated secret and stores a new access token and secret. - /// </summary> - /// <param name="consumerKey">The Consumer that is exchanging its request token for an access token.</param> - /// <param name="requestToken">The Consumer's request token that should be deleted/expired.</param> - /// <param name="accessToken">The new access token that is being issued to the Consumer.</param> - /// <param name="accessTokenSecret">The secret associated with the newly issued access token.</param> - /// <remarks> - /// <para> - /// Any scope of granted privileges associated with the request token from the - /// original call to <see cref="ITokenManager.StoreNewRequestToken"/> should be carried over - /// to the new Access Token. - /// </para> - /// <para> - /// To associate a user account with the new access token, - /// <see cref="System.Web.HttpContext.User">HttpContext.Current.User</see> may be - /// useful in an ASP.NET web application within the implementation of this method. - /// Alternatively you may store the access token here without associating with a user account, - /// and wait until <see cref="WebConsumer.ProcessUserAuthorization()"/> or - /// <see cref="DesktopConsumer.ProcessUserAuthorization(string, string)"/> return the access - /// token to associate the access token with a user account at that point. - /// </para> - /// </remarks> - void ITokenManager.ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) { - throw new NotImplementedException(); - } - - /// <summary> - /// Classifies a token as a request token or an access token. - /// </summary> - /// <param name="token">The token to classify.</param> - /// <returns> - /// Request or Access token, or invalid if the token is not recognized. - /// </returns> - TokenType ITokenManager.GetTokenType(string token) { - throw new NotImplementedException(); - } - - #endregion - } -} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthChannel.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthChannel.cs index 76b5149..b6ad28d 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthChannel.cs +++ b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthChannel.cs @@ -25,49 +25,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// <summary> /// An OAuth-specific implementation of the <see cref="Channel"/> class. /// </summary> - internal class OAuthChannel : Channel { - /// <summary> - /// Initializes a new instance of the <see cref="OAuthChannel"/> class. - /// </summary> - /// <param name="signingBindingElement">The binding element to use for signing.</param> - /// <param name="store">The web application store to use for nonces.</param> - /// <param name="tokenManager">The token manager instance to use.</param> - /// <param name="securitySettings">The security settings.</param> - [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Diagnostics.Contracts.__ContractsRuntime.Requires<System.ArgumentNullException>(System.Boolean,System.String,System.String)", Justification = "Code contracts"), SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "securitySettings", Justification = "Code contracts")] - internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, IConsumerTokenManager tokenManager, ConsumerSecuritySettings securitySettings) - : this( - signingBindingElement, - store, - tokenManager, - securitySettings, - new OAuthConsumerMessageFactory()) { - Contract.Requires<ArgumentNullException>(tokenManager != null); - Contract.Requires<ArgumentNullException>(securitySettings != null); - Contract.Requires<ArgumentNullException>(signingBindingElement != null); - Contract.Requires<ArgumentException>(signingBindingElement.SignatureCallback == null, OAuthStrings.SigningElementAlreadyAssociatedWithChannel); - } - - /// <summary> - /// Initializes a new instance of the <see cref="OAuthChannel"/> class. - /// </summary> - /// <param name="signingBindingElement">The binding element to use for signing.</param> - /// <param name="store">The web application store to use for nonces.</param> - /// <param name="tokenManager">The token manager instance to use.</param> - /// <param name="securitySettings">The security settings.</param> - [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Diagnostics.Contracts.__ContractsRuntime.Requires<System.ArgumentNullException>(System.Boolean,System.String,System.String)", Justification = "Code contracts"), SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "securitySettings", Justification = "Code contracts")] - internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, IServiceProviderTokenManager tokenManager, ServiceProviderSecuritySettings securitySettings) - : this( - signingBindingElement, - store, - tokenManager, - securitySettings, - new OAuthServiceProviderMessageFactory(tokenManager)) { - Contract.Requires<ArgumentNullException>(tokenManager != null); - Contract.Requires<ArgumentNullException>(securitySettings != null); - Contract.Requires<ArgumentNullException>(signingBindingElement != null); - Contract.Requires<ArgumentException>(signingBindingElement.SignatureCallback == null, OAuthStrings.SigningElementAlreadyAssociatedWithChannel); - } - + internal abstract class OAuthChannel : Channel { /// <summary> /// Initializes a new instance of the <see cref="OAuthChannel"/> class. /// </summary> @@ -79,12 +37,13 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// Except for mock testing, this should always be one of /// <see cref="OAuthConsumerMessageFactory"/> or <see cref="OAuthServiceProviderMessageFactory"/>.</param> [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Diagnostics.Contracts.__ContractsRuntime.Requires<System.ArgumentNullException>(System.Boolean,System.String,System.String)", Justification = "Code contracts"), SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "securitySettings", Justification = "Code contracts")] - internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, SecuritySettings securitySettings, IMessageFactory messageTypeProvider) - : base(messageTypeProvider, InitializeBindingElements(signingBindingElement, store, tokenManager, securitySettings)) { + protected OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, SecuritySettings securitySettings, IMessageFactory messageTypeProvider, IChannelBindingElement[] bindingElements) + : base(messageTypeProvider, bindingElements) { Contract.Requires<ArgumentNullException>(tokenManager != null); Contract.Requires<ArgumentNullException>(securitySettings != null); Contract.Requires<ArgumentNullException>(signingBindingElement != null); Contract.Requires<ArgumentException>(signingBindingElement.SignatureCallback == null, OAuthStrings.SigningElementAlreadyAssociatedWithChannel); + Contract.Requires<ArgumentNullException>(bindingElements != null, "bindingElements"); this.TokenManager = tokenManager; signingBindingElement.SignatureCallback = this.SignatureCallback; @@ -263,7 +222,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// <returns> /// An array of binding elements used to initialize the channel. /// </returns> - private static IChannelBindingElement[] InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, SecuritySettings securitySettings) { + protected static List<IChannelBindingElement> InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, SecuritySettings securitySettings) { Contract.Requires(securitySettings != null); var bindingElements = new List<IChannelBindingElement> { @@ -273,13 +232,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { new StandardReplayProtectionBindingElement(store), }; - var spTokenManager = tokenManager as IServiceProviderTokenManager; - var serviceProviderSecuritySettings = securitySettings as ServiceProviderSecuritySettings; - if (spTokenManager != null && serviceProviderSecuritySettings != null) { - bindingElements.Insert(0, new TokenHandlingBindingElement(spTokenManager, serviceProviderSecuritySettings)); - } - - return bindingElements.ToArray(); + return bindingElements; } /// <summary> @@ -392,19 +345,6 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { } } - /// <summary> - /// Gets the consumer secret for a given consumer key. - /// </summary> - /// <param name="consumerKey">The consumer key.</param> - /// <returns>The consumer secret.</returns> - private string GetConsumerSecret(string consumerKey) { - var consumerTokenManager = this.TokenManager as IConsumerTokenManager; - if (consumerTokenManager != null) { - ErrorUtilities.VerifyInternal(consumerKey == consumerTokenManager.ConsumerKey, "The token manager consumer key and the consumer key set earlier do not match!"); - return consumerTokenManager.ConsumerSecret; - } else { - return ((IServiceProviderTokenManager)this.TokenManager).GetConsumer(consumerKey).Secret; - } - } + protected abstract string GetConsumerSecret(string consumerKey); } } diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs deleted file mode 100644 index 327b923..0000000 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs +++ /dev/null @@ -1,109 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="OAuthConsumerMessageFactory.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuth.ChannelElements { - using System; - using System.Collections.Generic; - using System.Diagnostics.Contracts; - using DotNetOpenAuth.Messaging; - using DotNetOpenAuth.OAuth.Messages; - - /// <summary> - /// An OAuth-protocol specific implementation of the <see cref="IMessageFactory"/> - /// interface. - /// </summary> - public class OAuthConsumerMessageFactory : IMessageFactory { - /// <summary> - /// Initializes a new instance of the <see cref="OAuthConsumerMessageFactory"/> class. - /// </summary> - protected internal OAuthConsumerMessageFactory() { - } - - #region IMessageFactory Members - - /// <summary> - /// Analyzes an incoming request message payload to discover what kind of - /// message is embedded in it and returns the type, or null if no match is found. - /// </summary> - /// <param name="recipient">The intended or actual recipient of the request message.</param> - /// <param name="fields">The name/value pairs that make up the message payload.</param> - /// <returns> - /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can - /// deserialize to. Null if the request isn't recognized as a valid protocol message. - /// </returns> - /// <remarks> - /// The request messages are: - /// UserAuthorizationResponse - /// </remarks> - public virtual IDirectedProtocolMessage GetNewRequestMessage(MessageReceivingEndpoint recipient, IDictionary<string, string> fields) { - MessageBase message = null; - - if (fields.ContainsKey("oauth_token")) { - Protocol protocol = fields.ContainsKey("oauth_verifier") ? Protocol.V10a : Protocol.V10; - message = new UserAuthorizationResponse(recipient.Location, protocol.Version); - } - - if (message != null) { - message.SetAsIncoming(); - } - - return message; - } - - /// <summary> - /// Analyzes an incoming request message payload to discover what kind of - /// message is embedded in it and returns the type, or null if no match is found. - /// </summary> - /// <param name="request"> - /// The message that was sent as a request that resulted in the response. - /// Null on a Consumer site that is receiving an indirect message from the Service Provider. - /// </param> - /// <param name="fields">The name/value pairs that make up the message payload.</param> - /// <returns> - /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can - /// deserialize to. Null if the request isn't recognized as a valid protocol message. - /// </returns> - /// <remarks> - /// The response messages are: - /// UnauthorizedTokenResponse - /// AuthorizedTokenResponse - /// </remarks> - public virtual IDirectResponseProtocolMessage GetNewResponseMessage(IDirectedProtocolMessage request, IDictionary<string, string> fields) { - MessageBase message = null; - - // All response messages have the oauth_token field. - if (!fields.ContainsKey("oauth_token")) { - return null; - } - - // All direct message responses should have the oauth_token_secret field. - if (!fields.ContainsKey("oauth_token_secret")) { - Logger.OAuth.Error("An OAuth message was expected to contain an oauth_token_secret but didn't."); - return null; - } - - var unauthorizedTokenRequest = request as UnauthorizedTokenRequest; - var authorizedTokenRequest = request as AuthorizedTokenRequest; - if (unauthorizedTokenRequest != null) { - Protocol protocol = fields.ContainsKey("oauth_callback_confirmed") ? Protocol.V10a : Protocol.V10; - message = new UnauthorizedTokenResponse(unauthorizedTokenRequest, protocol.Version); - } else if (authorizedTokenRequest != null) { - message = new AuthorizedTokenResponse(authorizedTokenRequest); - } else { - Logger.OAuth.ErrorFormat("Unexpected response message given the request type {0}", request.GetType().Name); - throw new ProtocolException(OAuthStrings.InvalidIncomingMessage); - } - - if (message != null) { - message.SetAsIncoming(); - } - - return message; - } - - #endregion - } -} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthIdentity.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthIdentity.cs deleted file mode 100644 index 65bde20..0000000 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthIdentity.cs +++ /dev/null @@ -1,64 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="OAuthIdentity.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuth.ChannelElements { - using System; - using System.Diagnostics.CodeAnalysis; - using System.Diagnostics.Contracts; - using System.Runtime.InteropServices; - using System.Security.Principal; - using DotNetOpenAuth.Messaging; - - /// <summary> - /// Represents an OAuth consumer that is impersonating a known user on the system. - /// </summary> - [SuppressMessage("Microsoft.Interoperability", "CA1409:ComVisibleTypesShouldBeCreatable", Justification = "Not cocreatable.")] - [Serializable] - [ComVisible(true)] - public class OAuthIdentity : IIdentity { - /// <summary> - /// Initializes a new instance of the <see cref="OAuthIdentity"/> class. - /// </summary> - /// <param name="username">The username.</param> - internal OAuthIdentity(string username) { - Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(username)); - this.Name = username; - } - - #region IIdentity Members - - /// <summary> - /// Gets the type of authentication used. - /// </summary> - /// <value>The constant "OAuth"</value> - /// <returns> - /// The type of authentication used to identify the user. - /// </returns> - public string AuthenticationType { - get { return "OAuth"; } - } - - /// <summary> - /// Gets a value indicating whether the user has been authenticated. - /// </summary> - /// <value>The value <c>true</c></value> - /// <returns>true if the user was authenticated; otherwise, false. - /// </returns> - public bool IsAuthenticated { - get { return true; } - } - - /// <summary> - /// Gets the name of the user who authorized the OAuth token the consumer is using for authorization. - /// </summary> - /// <returns> - /// The name of the user on whose behalf the code is running. - /// </returns> - public string Name { get; private set; } - - #endregion - } -} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthPrincipal.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthPrincipal.cs deleted file mode 100644 index 82ecb0a..0000000 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthPrincipal.cs +++ /dev/null @@ -1,91 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="OAuthPrincipal.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuth.ChannelElements { - using System; - using System.Collections.Generic; - using System.Diagnostics.CodeAnalysis; - using System.Diagnostics.Contracts; - using System.Linq; - using System.Runtime.InteropServices; - using System.Security.Principal; - - /// <summary> - /// Represents an OAuth consumer that is impersonating a known user on the system. - /// </summary> - [SuppressMessage("Microsoft.Interoperability", "CA1409:ComVisibleTypesShouldBeCreatable", Justification = "Not cocreatable.")] - [Serializable] - [ComVisible(true)] - public class OAuthPrincipal : IPrincipal { - /// <summary> - /// The roles this user belongs to. - /// </summary> - private ICollection<string> roles; - - /// <summary> - /// Initializes a new instance of the <see cref="OAuthPrincipal"/> class. - /// </summary> - /// <param name="userName">The username.</param> - /// <param name="roles">The roles this user belongs to.</param> - public OAuthPrincipal(string userName, string[] roles) - : this(new OAuthIdentity(userName), roles) { - } - - /// <summary> - /// Initializes a new instance of the <see cref="OAuthPrincipal"/> class. - /// </summary> - /// <param name="token">The access token.</param> - internal OAuthPrincipal(IServiceProviderAccessToken token) - : this(token.Username, token.Roles) { - Contract.Requires<ArgumentNullException>(token != null); - - this.AccessToken = token.Token; - } - - /// <summary> - /// Initializes a new instance of the <see cref="OAuthPrincipal"/> class. - /// </summary> - /// <param name="identity">The identity.</param> - /// <param name="roles">The roles this user belongs to.</param> - internal OAuthPrincipal(OAuthIdentity identity, string[] roles) { - this.Identity = identity; - this.roles = roles; - } - - /// <summary> - /// Gets the access token used to create this principal. - /// </summary> - /// <value>A non-empty string.</value> - public string AccessToken { get; private set; } - - #region IPrincipal Members - - /// <summary> - /// Gets the identity of the current principal. - /// </summary> - /// <value></value> - /// <returns> - /// The <see cref="T:System.Security.Principal.IIdentity"/> object associated with the current principal. - /// </returns> - public IIdentity Identity { get; private set; } - - /// <summary> - /// Determines whether the current principal belongs to the specified role. - /// </summary> - /// <param name="role">The name of the role for which to check membership.</param> - /// <returns> - /// true if the current principal is a member of the specified role; otherwise, false. - /// </returns> - /// <remarks> - /// The role membership check uses <see cref="StringComparer.OrdinalIgnoreCase"/>. - /// </remarks> - public bool IsInRole(string role) { - return this.roles.Contains(role, StringComparer.OrdinalIgnoreCase); - } - - #endregion - } -} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs deleted file mode 100644 index 5b3c918..0000000 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthServiceProviderMessageFactory.cs +++ /dev/null @@ -1,126 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="OAuthServiceProviderMessageFactory.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuth.ChannelElements { - using System; - using System.Collections.Generic; - using System.Diagnostics.Contracts; - using DotNetOpenAuth.Messaging; - using DotNetOpenAuth.OAuth.Messages; - - /// <summary> - /// An OAuth-protocol specific implementation of the <see cref="IMessageFactory"/> - /// interface. - /// </summary> - public class OAuthServiceProviderMessageFactory : IMessageFactory { - /// <summary> - /// The token manager to use for discerning between request and access tokens. - /// </summary> - private IServiceProviderTokenManager tokenManager; - - /// <summary> - /// Initializes a new instance of the <see cref="OAuthServiceProviderMessageFactory"/> class. - /// </summary> - /// <param name="tokenManager">The token manager instance to use.</param> - public OAuthServiceProviderMessageFactory(IServiceProviderTokenManager tokenManager) { - Contract.Requires<ArgumentNullException>(tokenManager != null); - - this.tokenManager = tokenManager; - } - - #region IMessageFactory Members - - /// <summary> - /// Analyzes an incoming request message payload to discover what kind of - /// message is embedded in it and returns the type, or null if no match is found. - /// </summary> - /// <param name="recipient">The intended or actual recipient of the request message.</param> - /// <param name="fields">The name/value pairs that make up the message payload.</param> - /// <returns> - /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can - /// deserialize to. Null if the request isn't recognized as a valid protocol message. - /// </returns> - /// <remarks> - /// The request messages are: - /// UnauthorizedTokenRequest - /// AuthorizedTokenRequest - /// UserAuthorizationRequest - /// AccessProtectedResourceRequest - /// </remarks> - public virtual IDirectedProtocolMessage GetNewRequestMessage(MessageReceivingEndpoint recipient, IDictionary<string, string> fields) { - MessageBase message = null; - Protocol protocol = Protocol.V10; // default to assuming the less-secure 1.0 instead of 1.0a until we prove otherwise. - string token; - fields.TryGetValue("oauth_token", out token); - - try { - if (fields.ContainsKey("oauth_consumer_key") && !fields.ContainsKey("oauth_token")) { - protocol = fields.ContainsKey("oauth_callback") ? Protocol.V10a : Protocol.V10; - message = new UnauthorizedTokenRequest(recipient, protocol.Version); - } else if (fields.ContainsKey("oauth_consumer_key") && fields.ContainsKey("oauth_token")) { - // Discern between RequestAccessToken and AccessProtectedResources, - // which have all the same parameters, by figuring out what type of token - // is in the token parameter. - bool tokenTypeIsAccessToken = this.tokenManager.GetTokenType(token) == TokenType.AccessToken; - - if (tokenTypeIsAccessToken) { - message = (MessageBase)new AccessProtectedResourceRequest(recipient, protocol.Version); - } else { - // Discern between 1.0 and 1.0a requests by checking on the consumer version we stored - // when the consumer first requested an unauthorized token. - protocol = Protocol.Lookup(this.tokenManager.GetRequestToken(token).ConsumerVersion); - message = new AuthorizedTokenRequest(recipient, protocol.Version); - } - } else { - // fail over to the message with no required fields at all. - if (token != null) { - protocol = Protocol.Lookup(this.tokenManager.GetRequestToken(token).ConsumerVersion); - } - - // If a callback parameter is included, that suggests either the consumer - // is following OAuth 1.0 instead of 1.0a, or that a hijacker is trying - // to attack. Either way, if the consumer started out as a 1.0a, keep it - // that way, and we'll just ignore the oauth_callback included in this message - // by virtue of the UserAuthorizationRequest message not including it in its - // 1.0a payload. - message = new UserAuthorizationRequest(recipient, protocol.Version); - } - - if (message != null) { - message.SetAsIncoming(); - } - - return message; - } catch (KeyNotFoundException ex) { - throw ErrorUtilities.Wrap(ex, OAuthStrings.TokenNotFound); - } - } - - /// <summary> - /// Analyzes an incoming request message payload to discover what kind of - /// message is embedded in it and returns the type, or null if no match is found. - /// </summary> - /// <param name="request"> - /// The message that was sent as a request that resulted in the response. - /// Null on a Consumer site that is receiving an indirect message from the Service Provider. - /// </param> - /// <param name="fields">The name/value pairs that make up the message payload.</param> - /// <returns> - /// The <see cref="IProtocolMessage"/>-derived concrete class that this message can - /// deserialize to. Null if the request isn't recognized as a valid protocol message. - /// </returns> - /// <remarks> - /// The response messages are: - /// None. - /// </remarks> - public virtual IDirectResponseProtocolMessage GetNewResponseMessage(IDirectedProtocolMessage request, IDictionary<string, string> fields) { - Logger.OAuth.Error("Service Providers are not expected to ever receive responses."); - return null; - } - - #endregion - } -} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/RsaSha1SigningBindingElement.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/RsaSha1SigningBindingElement.cs index f7b8370..83be094 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/RsaSha1SigningBindingElement.cs +++ b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/RsaSha1SigningBindingElement.cs @@ -15,101 +15,17 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// <summary> /// A binding element that signs outgoing messages and verifies the signature on incoming messages. /// </summary> - public class RsaSha1SigningBindingElement : SigningBindingElementBase { + public abstract class RsaSha1SigningBindingElement : SigningBindingElementBase { /// <summary> /// The name of the hash algorithm to use. /// </summary> - private const string HashAlgorithmName = "RSA-SHA1"; + protected const string HashAlgorithmName = "RSA-SHA1"; /// <summary> - /// The token manager for the service provider. + /// Initializes a new instance of the <see cref="RsaSha1SigningBindingElement"/> class. /// </summary> - private IServiceProviderTokenManager tokenManager; - - /// <summary> - /// Initializes a new instance of the <see cref="RsaSha1SigningBindingElement"/> class - /// for use by Consumers. - /// </summary> - /// <param name="signingCertificate">The certificate used to sign outgoing messages.</param> - public RsaSha1SigningBindingElement(X509Certificate2 signingCertificate) + protected RsaSha1SigningBindingElement() : base(HashAlgorithmName) { - Contract.Requires<ArgumentNullException>(signingCertificate != null); - - this.SigningCertificate = signingCertificate; - } - - /// <summary> - /// Initializes a new instance of the <see cref="RsaSha1SigningBindingElement"/> class - /// for use by Service Providers. - /// </summary> - /// <param name="tokenManager">The token manager.</param> - public RsaSha1SigningBindingElement(IServiceProviderTokenManager tokenManager) - : base(HashAlgorithmName) { - Contract.Requires<ArgumentNullException>(tokenManager != null); - - this.tokenManager = tokenManager; - } - - /// <summary> - /// Gets or sets the certificate used to sign outgoing messages. Used only by Consumers. - /// </summary> - public X509Certificate2 SigningCertificate { get; set; } - - /// <summary> - /// Calculates a signature for a given message. - /// </summary> - /// <param name="message">The message to sign.</param> - /// <returns>The signature for the message.</returns> - /// <remarks> - /// This method signs the message per OAuth 1.0 section 9.3. - /// </remarks> - protected override string GetSignature(ITamperResistantOAuthMessage message) { - ErrorUtilities.VerifyOperation(this.SigningCertificate != null, OAuthStrings.X509CertificateNotProvidedForSigning); - - string signatureBaseString = ConstructSignatureBaseString(message, this.Channel.MessageDescriptions.GetAccessor(message)); - byte[] data = Encoding.ASCII.GetBytes(signatureBaseString); - var provider = (RSACryptoServiceProvider)this.SigningCertificate.PrivateKey; - byte[] binarySignature = provider.SignData(data, "SHA1"); - string base64Signature = Convert.ToBase64String(binarySignature); - return base64Signature; - } - - /// <summary> - /// Determines whether the signature on some message is valid. - /// </summary> - /// <param name="message">The message to check the signature on.</param> - /// <returns> - /// <c>true</c> if the signature on the message is valid; otherwise, <c>false</c>. - /// </returns> - protected override bool IsSignatureValid(ITamperResistantOAuthMessage message) { - ErrorUtilities.VerifyInternal(this.tokenManager != null, "No token manager available for fetching Consumer public certificates."); - - string signatureBaseString = ConstructSignatureBaseString(message, this.Channel.MessageDescriptions.GetAccessor(message)); - byte[] data = Encoding.ASCII.GetBytes(signatureBaseString); - - byte[] carriedSignature = Convert.FromBase64String(message.Signature); - - X509Certificate2 cert = this.tokenManager.GetConsumer(message.ConsumerKey).Certificate; - if (cert == null) { - Logger.Signatures.WarnFormat("Incoming message from consumer '{0}' could not be matched with an appropriate X.509 certificate for signature verification.", message.ConsumerKey); - return false; - } - - var provider = (RSACryptoServiceProvider)cert.PublicKey.Key; - bool valid = provider.VerifyData(data, "SHA1", carriedSignature); - return valid; - } - - /// <summary> - /// Clones this instance. - /// </summary> - /// <returns>A new instance of the binding element.</returns> - protected override ITamperProtectionChannelBindingElement Clone() { - if (this.tokenManager != null) { - return new RsaSha1SigningBindingElement(this.tokenManager); - } else { - return new RsaSha1SigningBindingElement(this.SigningCertificate); - } } } } diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/TokenHandlingBindingElement.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/TokenHandlingBindingElement.cs deleted file mode 100644 index f53aa1b..0000000 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/TokenHandlingBindingElement.cs +++ /dev/null @@ -1,201 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="TokenHandlingBindingElement.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuth.ChannelElements { - using System; - using System.Collections.Generic; - using System.Diagnostics.CodeAnalysis; - using System.Diagnostics.Contracts; - using System.Linq; - using System.Text; - using DotNetOpenAuth.Configuration; - using DotNetOpenAuth.Messaging; - using DotNetOpenAuth.OAuth.Messages; - - /// <summary> - /// A binding element for Service Providers to manage the - /// callbacks and verification codes on applicable messages. - /// </summary> - internal class TokenHandlingBindingElement : IChannelBindingElement { - /// <summary> - /// The token manager offered by the service provider. - /// </summary> - private IServiceProviderTokenManager tokenManager; - - /// <summary> - /// The security settings for this service provider. - /// </summary> - private ServiceProviderSecuritySettings securitySettings; - - /// <summary> - /// Initializes a new instance of the <see cref="TokenHandlingBindingElement"/> class. - /// </summary> - /// <param name="tokenManager">The token manager.</param> - /// <param name="securitySettings">The security settings.</param> - [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Diagnostics.Contracts.__ContractsRuntime.Requires<System.ArgumentNullException>(System.Boolean,System.String,System.String)", Justification = "Code contract"), SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "securitySettings", Justification = "Code contracts")] - internal TokenHandlingBindingElement(IServiceProviderTokenManager tokenManager, ServiceProviderSecuritySettings securitySettings) { - Contract.Requires<ArgumentNullException>(tokenManager != null); - Contract.Requires<ArgumentNullException>(securitySettings != null); - - this.tokenManager = tokenManager; - this.securitySettings = securitySettings; - } - - #region IChannelBindingElement Members - - /// <summary> - /// Gets or sets the channel that this binding element belongs to. - /// </summary> - /// <remarks> - /// This property is set by the channel when it is first constructed. - /// </remarks> - public Channel Channel { get; set; } - - /// <summary> - /// Gets the protection commonly offered (if any) by this binding element. - /// </summary> - /// <remarks> - /// This value is used to assist in sorting binding elements in the channel stack. - /// </remarks> - public 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 MessageProtections? ProcessOutgoingMessage(IProtocolMessage message) { - var userAuthResponse = message as UserAuthorizationResponse; - if (userAuthResponse != null && userAuthResponse.Version >= Protocol.V10a.Version) { - var requestToken = this.tokenManager.GetRequestToken(userAuthResponse.RequestToken); - requestToken.VerificationCode = userAuthResponse.VerificationCode; - this.tokenManager.UpdateToken(requestToken); - return MessageProtections.None; - } - - // Hook to store the token and secret on its way down to the Consumer. - var grantRequestTokenResponse = message as UnauthorizedTokenResponse; - if (grantRequestTokenResponse != null) { - this.tokenManager.StoreNewRequestToken(grantRequestTokenResponse.RequestMessage, grantRequestTokenResponse); - - // The host may have already set these properties, but just to make sure... - var requestToken = this.tokenManager.GetRequestToken(grantRequestTokenResponse.RequestToken); - requestToken.ConsumerVersion = grantRequestTokenResponse.Version; - if (grantRequestTokenResponse.RequestMessage.Callback != null) { - requestToken.Callback = grantRequestTokenResponse.RequestMessage.Callback; - } - this.tokenManager.UpdateToken(requestToken); - - return MessageProtections.None; - } - - 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> - public MessageProtections? ProcessIncomingMessage(IProtocolMessage message) { - var authorizedTokenRequest = message as AuthorizedTokenRequest; - if (authorizedTokenRequest != null) { - if (authorizedTokenRequest.Version >= Protocol.V10a.Version) { - string expectedVerifier = this.tokenManager.GetRequestToken(authorizedTokenRequest.RequestToken).VerificationCode; - ErrorUtilities.VerifyProtocol(string.Equals(authorizedTokenRequest.VerificationCode, expectedVerifier, StringComparison.Ordinal), OAuthStrings.IncorrectVerifier); - return MessageProtections.None; - } - - this.VerifyThrowTokenTimeToLive(authorizedTokenRequest); - } - - var userAuthorizationRequest = message as UserAuthorizationRequest; - if (userAuthorizationRequest != null) { - this.VerifyThrowTokenTimeToLive(userAuthorizationRequest); - } - - var accessResourceRequest = message as AccessProtectedResourceRequest; - if (accessResourceRequest != null) { - this.VerifyThrowTokenNotExpired(accessResourceRequest); - } - - return null; - } - - #endregion - - /// <summary> - /// Ensures that access tokens have not yet expired. - /// </summary> - /// <param name="message">The incoming message carrying the access token.</param> - private void VerifyThrowTokenNotExpired(AccessProtectedResourceRequest message) { - Contract.Requires<ArgumentNullException>(message != null); - - try { - IServiceProviderAccessToken token = this.tokenManager.GetAccessToken(message.AccessToken); - if (token.ExpirationDate.HasValue && DateTime.Now >= token.ExpirationDate.Value.ToLocalTimeSafe()) { - Logger.OAuth.ErrorFormat( - "OAuth access token {0} rejected because it expired at {1}, and it is now {2}.", - token.Token, - token.ExpirationDate.Value, - DateTime.Now); - ErrorUtilities.ThrowProtocol(OAuthStrings.TokenNotFound); - } - } catch (KeyNotFoundException ex) { - throw ErrorUtilities.Wrap(ex, OAuthStrings.TokenNotFound); - } - } - - /// <summary> - /// Ensures that short-lived request tokens included in incoming messages have not expired. - /// </summary> - /// <param name="message">The incoming message.</param> - /// <exception cref="ProtocolException">Thrown when the token in the message has expired.</exception> - private void VerifyThrowTokenTimeToLive(ITokenContainingMessage message) { - ErrorUtilities.VerifyInternal(!(message is AccessProtectedResourceRequest), "We shouldn't be verifying TTL on access tokens."); - if (message == null || string.IsNullOrEmpty(message.Token)) { - return; - } - - try { - IServiceProviderRequestToken token = this.tokenManager.GetRequestToken(message.Token); - TimeSpan ttl = this.securitySettings.MaximumRequestTokenTimeToLive; - if (DateTime.Now >= token.CreatedOn.ToLocalTimeSafe() + ttl) { - Logger.OAuth.ErrorFormat( - "OAuth request token {0} rejected because it was originally issued at {1}, expired at {2}, and it is now {3}.", - token.Token, - token.CreatedOn, - token.CreatedOn + ttl, - DateTime.Now); - ErrorUtilities.ThrowProtocol(OAuthStrings.TokenNotFound); - } - } catch (KeyNotFoundException ex) { - throw ErrorUtilities.Wrap(ex, OAuthStrings.TokenNotFound); - } - } - } -} |