diff options
24 files changed, 1255 insertions, 615 deletions
diff --git a/src/DotNetOpenAuth.AspNet/AuthenticationResult.cs b/src/DotNetOpenAuth.AspNet/AuthenticationResult.cs index 24ef18d..84d9abe 100644 --- a/src/DotNetOpenAuth.AspNet/AuthenticationResult.cs +++ b/src/DotNetOpenAuth.AspNet/AuthenticationResult.cs @@ -11,40 +11,84 @@ namespace DotNetOpenAuth.AspNet { using DotNetOpenAuth.Messaging; /// <summary> - /// Represents the result of OAuth & OpenId authentication + /// Represents the result of OAuth or OpenID authentication. /// </summary> public class AuthenticationResult { + #region Constants and Fields + /// <summary> /// Returns an instance which indicates failed authentication. /// </summary> - [SuppressMessage( - "Microsoft.Security", - "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "This type is immutable.")] public static readonly AuthenticationResult Failed = new AuthenticationResult(isSuccessful: false); + #endregion + + #region Constructors and Destructors + /// <summary> - /// Gets a value indicating whether the authentication step is successful. + /// Initializes a new instance of the <see cref="AuthenticationResult"/> class. /// </summary> - /// <value> - /// <c>true</c> if authentication is successful; otherwise, <c>false</c>. - /// </value> - public bool IsSuccessful { get; private set; } + /// <param name="isSuccessful"> + /// if set to <c>true</c> [is successful]. + /// </param> + public AuthenticationResult(bool isSuccessful) + : this(isSuccessful, provider: null, providerUserId: null, userName: null, extraData: null) {} /// <summary> - /// Gets the provider's name. + /// Initializes a new instance of the <see cref="AuthenticationResult"/> class. /// </summary> - public string Provider { get; private set; } + /// <param name="exception"> + /// The exception. + /// </param> + public AuthenticationResult(Exception exception) + : this(isSuccessful: false) { + if (exception == null) { + throw new ArgumentNullException("exception"); + } + + this.Error = exception; + } /// <summary> - /// Gets the unique user id that is returned from the provider. + /// Initializes a new instance of the <see cref="AuthenticationResult"/> class. /// </summary> - public string ProviderUserId { get; private set; } + /// <param name="isSuccessful"> + /// if set to <c>true</c> [is successful]. + /// </param> + /// <param name="provider"> + /// The provider. + /// </param> + /// <param name="providerUserId"> + /// The provider user id. + /// </param> + /// <param name="userName"> + /// Name of the user. + /// </param> + /// <param name="extraData"> + /// The extra data. + /// </param> + public AuthenticationResult( + bool isSuccessful, string provider, string providerUserId, string userName, IDictionary<string, string> extraData) { + this.IsSuccessful = isSuccessful; + this.Provider = provider; + this.ProviderUserId = providerUserId; + this.UserName = userName; + if (extraData != null) { + // wrap extraData in a read-only dictionary + this.ExtraData = new ReadOnlyDictionary<string, string>(extraData); + } + } + + #endregion + + #region Public Properties /// <summary> - /// Gets the user name that is returned from the provider. + /// Gets the error that may have occured during the authentication process /// </summary> - public string UserName { get; private set; } + public Exception Error { get; private set; } /// <summary> /// Gets the optional extra data that may be returned from the provider @@ -52,57 +96,25 @@ namespace DotNetOpenAuth.AspNet { public IDictionary<string, string> ExtraData { get; private set; } /// <summary> - /// Gets the error that may have occured during the authentication process + /// Gets a value indicating whether the authentication step is successful. /// </summary> - public Exception Error { get; private set; } + /// <value> <c>true</c> if authentication is successful; otherwise, <c>false</c> . </value> + public bool IsSuccessful { get; private set; } /// <summary> - /// Initializes a new instance of the <see cref="AuthenticationResult"/> class. + /// Gets the provider's name. /// </summary> - /// <param name="isSuccessful">if set to <c>true</c> [is successful].</param> - public AuthenticationResult(bool isSuccessful) : - this(isSuccessful, - provider: null, - providerUserId: null, - userName: null, - extraData: null) { - } + public string Provider { get; private set; } /// <summary> - /// Initializes a new instance of the <see cref="AuthenticationResult"/> class. + /// Gets the unique user id that is returned from the provider. /// </summary> - /// <param name="exception">The exception.</param> - public AuthenticationResult(Exception exception) - : this(isSuccessful: false) { - if (exception == null) { - throw new ArgumentNullException("exception"); - } - - Error = exception; - } + public string ProviderUserId { get; private set; } /// <summary> - /// Initializes a new instance of the <see cref="AuthenticationResult"/> class. + /// Gets the user name that is returned from the provider. /// </summary> - /// <param name="isSuccessful">if set to <c>true</c> [is successful].</param> - /// <param name="provider">The provider.</param> - /// <param name="providerUserId">The provider user id.</param> - /// <param name="userName">Name of the user.</param> - /// <param name="extraData">The extra data.</param> - public AuthenticationResult( - bool isSuccessful, - string provider, - string providerUserId, - string userName, - IDictionary<string, string> extraData) { - IsSuccessful = isSuccessful; - Provider = provider; - ProviderUserId = providerUserId; - UserName = userName; - if (extraData != null) { - // wrap extraData in a read-only dictionary - ExtraData = new ReadOnlyDictionary<string, string>(extraData); - } - } + public string UserName { get; private set; } + #endregion } -}
\ No newline at end of file +} diff --git a/src/DotNetOpenAuth.AspNet/Clients/DictionaryExtensions.cs b/src/DotNetOpenAuth.AspNet/Clients/DictionaryExtensions.cs index e0f2b08..0dfa5d6 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/DictionaryExtensions.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/DictionaryExtensions.cs @@ -9,37 +9,54 @@ namespace DotNetOpenAuth.AspNet.Clients { using System.Collections.Generic; using System.Xml.Linq; + /// <summary> + /// The dictionary extensions. + /// </summary> internal static class DictionaryExtensions { + #region Public Methods and Operators + + /// <summary> + /// Adds the value from an XDocument with the specified element name if it's not empty. + /// </summary> + /// <param name="dictionary"> + /// The dictionary. + /// </param> + /// <param name="document"> + /// The document. + /// </param> + /// <param name="elementName"> + /// Name of the element. + /// </param> + public static void AddDataIfNotEmpty( + this Dictionary<string, string> dictionary, XDocument document, string elementName) { + var element = document.Root.Element(elementName); + if (element != null) { + dictionary.AddItemIfNotEmpty(elementName, element.Value); + } + } + /// <summary> /// Adds a key/value pair to the specified dictionary if the value is not null or empty. /// </summary> - /// <param name="dictionary">The dictionary.</param> - /// <param name="key">The key.</param> - /// <param name="value">The value.</param> + /// <param name="dictionary"> + /// The dictionary. + /// </param> + /// <param name="key"> + /// The key. + /// </param> + /// <param name="value"> + /// The value. + /// </param> public static void AddItemIfNotEmpty(this IDictionary<string, string> dictionary, string key, string value) { if (key == null) { throw new ArgumentNullException("key"); } - if (!String.IsNullOrEmpty(value)) { + if (!string.IsNullOrEmpty(value)) { dictionary[key] = value; } } - /// <summary> - /// Adds the value from an XDocument with the specified element name if it's not empty. - /// </summary> - /// <param name="dictionary">The dictionary.</param> - /// <param name="document">The document.</param> - /// <param name="elementName">Name of the element.</param> - public static void AddDataIfNotEmpty( - this Dictionary<string, string> dictionary, - XDocument document, - string elementName) { - var element = document.Root.Element(elementName); - if (element != null) { - dictionary.AddItemIfNotEmpty(elementName, element.Value); - } - } + #endregion } } diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs index 4dc3dcc..8edbeed 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs @@ -13,9 +13,34 @@ namespace DotNetOpenAuth.AspNet.Clients { using DotNetOpenAuth.OAuth.ChannelElements; using DotNetOpenAuth.OAuth.Messages; + /// <summary> + /// The dot net open auth web consumer. + /// </summary> public class DotNetOpenAuthWebConsumer : IOAuthWebWorker { + #region Constants and Fields + + /// <summary> + /// The _web consumer. + /// </summary> private readonly WebConsumer _webConsumer; + #endregion + + #region Constructors and Destructors + + /// <summary> + /// Initializes a new instance of the <see cref="DotNetOpenAuthWebConsumer"/> class. + /// </summary> + /// <param name="serviceDescription"> + /// The service description. + /// </param> + /// <param name="tokenManager"> + /// The token manager. + /// </param> + /// <exception cref="ArgumentNullException"> + /// </exception> + /// <exception cref="ArgumentNullException"> + /// </exception> public DotNetOpenAuthWebConsumer(ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager) { if (serviceDescription == null) { throw new ArgumentNullException("consumer"); @@ -25,21 +50,50 @@ namespace DotNetOpenAuth.AspNet.Clients { throw new ArgumentNullException("tokenManager"); } - _webConsumer = new WebConsumer(serviceDescription, tokenManager); + this._webConsumer = new WebConsumer(serviceDescription, tokenManager); } - public void RequestAuthentication(Uri callback) { - var redirectParameters = new Dictionary<string, string>() { { "force_login", "false" } }; - UserAuthorizationRequest request = _webConsumer.PrepareRequestUserAuthorization(callback, null, redirectParameters); - _webConsumer.Channel.PrepareResponse(request).Send(); + #endregion + + #region Public Methods and Operators + + /// <summary> + /// The prepare authorized request. + /// </summary> + /// <param name="profileEndpoint"> + /// The profile endpoint. + /// </param> + /// <param name="accessToken"> + /// The access token. + /// </param> + /// <returns> + /// </returns> + public HttpWebRequest PrepareAuthorizedRequest(MessageReceivingEndpoint profileEndpoint, string accessToken) { + return this._webConsumer.PrepareAuthorizedRequest(profileEndpoint, accessToken); } + /// <summary> + /// The process user authorization. + /// </summary> + /// <returns> + /// </returns> public AuthorizedTokenResponse ProcessUserAuthorization() { - return _webConsumer.ProcessUserAuthorization(); + return this._webConsumer.ProcessUserAuthorization(); } - public HttpWebRequest PrepareAuthorizedRequest(MessageReceivingEndpoint profileEndpoint, string accessToken) { - return _webConsumer.PrepareAuthorizedRequest(profileEndpoint, accessToken); + /// <summary> + /// The request authentication. + /// </summary> + /// <param name="callback"> + /// The callback. + /// </param> + public void RequestAuthentication(Uri callback) { + var redirectParameters = new Dictionary<string, string> { { "force_login", "false" } }; + UserAuthorizationRequest request = this._webConsumer.PrepareRequestUserAuthorization( + callback, null, redirectParameters); + this._webConsumer.Channel.PrepareResponse(request).Send(); } + + #endregion } -}
\ No newline at end of file +} diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/IOAuthWebWorker.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/IOAuthWebWorker.cs index 82c55fb..413b624 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/IOAuthWebWorker.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/IOAuthWebWorker.cs @@ -10,9 +10,39 @@ namespace DotNetOpenAuth.AspNet.Clients { using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OAuth.Messages; + /// <summary> + /// The io auth web worker. + /// </summary> public interface IOAuthWebWorker { - void RequestAuthentication(Uri callback); - AuthorizedTokenResponse ProcessUserAuthorization(); + #region Public Methods and Operators + + /// <summary> + /// The prepare authorized request. + /// </summary> + /// <param name="profileEndpoint"> + /// The profile endpoint. + /// </param> + /// <param name="accessToken"> + /// The access token. + /// </param> + /// <returns> + /// </returns> HttpWebRequest PrepareAuthorizedRequest(MessageReceivingEndpoint profileEndpoint, string accessToken); + + /// <summary> + /// The process user authorization. + /// </summary> + /// <returns> + /// </returns> + AuthorizedTokenResponse ProcessUserAuthorization(); + + /// <summary> + /// The request authentication. + /// </summary> + /// <param name="callback"> + /// The callback. + /// </param> + void RequestAuthentication(Uri callback); + #endregion } -}
\ No newline at end of file +} diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/InMemoryOAuthTokenManager.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/InMemoryOAuthTokenManager.cs index a10e777..e8509af 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/InMemoryOAuthTokenManager.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/InMemoryOAuthTokenManager.cs @@ -14,13 +14,26 @@ namespace DotNetOpenAuth.AspNet.Clients { /// An implementation of IOAuthTokenManager which stores keys in memory. /// </summary> public sealed class InMemoryOAuthTokenManager : IConsumerTokenManager { + #region Constants and Fields + + /// <summary> + /// The _tokens and secrets. + /// </summary> private readonly Dictionary<string, string> _tokensAndSecrets = new Dictionary<string, string>(); + #endregion + + #region Constructors and Destructors + /// <summary> /// Initializes a new instance of the <see cref="InMemoryOAuthTokenManager"/> class. /// </summary> - /// <param name="consumerKey">The consumer key.</param> - /// <param name="consumerSecret">The consumer secret.</param> + /// <param name="consumerKey"> + /// The consumer key. + /// </param> + /// <param name="consumerSecret"> + /// The consumer secret. + /// </param> public InMemoryOAuthTokenManager(string consumerKey, string consumerSecret) { if (consumerKey == null) { throw new ArgumentNullException("consumerKey"); @@ -30,94 +43,119 @@ namespace DotNetOpenAuth.AspNet.Clients { throw new ArgumentNullException("consumerSecret"); } - ConsumerKey = consumerKey; - ConsumerSecret = consumerSecret; + this.ConsumerKey = consumerKey; + this.ConsumerSecret = consumerSecret; } + #endregion + + #region Public Properties + /// <summary> /// Gets the consumer key. /// </summary> - public string ConsumerKey { - get; - private set; - } + public string ConsumerKey { get; private set; } /// <summary> /// Gets the consumer secret. /// </summary> - public string ConsumerSecret { - get; - private set; - } + public string ConsumerSecret { get; private set; } - #region ITokenManager Members + #endregion - /// <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> - public string GetTokenSecret(string token) { - return _tokensAndSecrets[token]; - } - - /// <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="ExpireRequestTokenAndStoreNewAccessToken"/> - /// method. - /// </remarks> - public void StoreNewRequestToken(UnauthorizedTokenRequest request, ITokenSecretContainingMessage response) { - _tokensAndSecrets[response.Token] = response.TokenSecret; - } + #region Public Methods and Operators /// <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> + /// <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> + /// <para> /// Any scope of granted privileges associated with the request token from the - /// original call to <see cref="StoreNewRequestToken"/> should be carried over - /// to the new Access Token. + /// original call to + /// <see cref="StoreNewRequestToken"/> + /// should be carried over + /// to the new Access Token. /// </para> - /// <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. + /// <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> - public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) { - _tokensAndSecrets.Remove(requestToken); - _tokensAndSecrets[accessToken] = accessTokenSecret; + public void ExpireRequestTokenAndStoreNewAccessToken( + string consumerKey, string requestToken, string accessToken, string accessTokenSecret) { + this._tokensAndSecrets.Remove(requestToken); + this._tokensAndSecrets[accessToken] = accessTokenSecret; + } + + /// <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> + public string GetTokenSecret(string token) { + return this._tokensAndSecrets[token]; } /// <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> + /// <param name="token"> + /// The token to classify. + /// </param> + /// <returns> + /// Request or Access token, or invalid if the token is not recognized. + /// </returns> public TokenType GetTokenType(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="ExpireRequestTokenAndStoreNewAccessToken"/> method. + /// </remarks> + public void StoreNewRequestToken(UnauthorizedTokenRequest request, ITokenSecretContainingMessage response) { + this._tokensAndSecrets[response.Token] = response.TokenSecret; + } + #endregion } -}
\ No newline at end of file +} diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs index 8f49c80..68cf135 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.AspNet.Clients { using System; using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net; using System.Xml.Linq; @@ -19,48 +20,69 @@ namespace DotNetOpenAuth.AspNet.Clients { /// Represents LinkedIn authentication client. /// </summary> public sealed class LinkedInClient : OAuthClient { + #region Constants and Fields + /// <summary> /// Describes the OAuth service provider endpoints for LinkedIn. /// </summary> public static readonly ServiceProviderDescription LinkedInServiceDescription = new ServiceProviderDescription { - RequestTokenEndpoint = new MessageReceivingEndpoint("https://api.linkedin.com/uas/oauth/requestToken", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), - UserAuthorizationEndpoint = new MessageReceivingEndpoint("https://www.linkedin.com/uas/oauth/authenticate", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), - AccessTokenEndpoint = new MessageReceivingEndpoint("https://api.linkedin.com/uas/oauth/accessToken", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), - TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() }, + RequestTokenEndpoint = + new MessageReceivingEndpoint( + "https://api.linkedin.com/uas/oauth/requestToken", + HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), + UserAuthorizationEndpoint = + new MessageReceivingEndpoint( + "https://www.linkedin.com/uas/oauth/authenticate", + HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), + AccessTokenEndpoint = + new MessageReceivingEndpoint( + "https://api.linkedin.com/uas/oauth/accessToken", + HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), + TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() }, }; + #endregion + + #region Constructors and Destructors + /// <summary> /// Initializes a new instance of the <see cref="LinkedInClient"/> class. /// </summary> - /// <param name="consumerKey">The LinkedIn app's consumer key.</param> - /// <param name="consumerSecret">The LinkedIn app's consumer secret.</param> - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Microsoft.Reliability", - "CA2000:Dispose objects before losing scope", + /// <param name="consumerKey"> + /// The LinkedIn app's consumer key. + /// </param> + /// <param name="consumerSecret"> + /// The LinkedIn app's consumer secret. + /// </param> + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "We can't dispose the object because we still need it through the app lifetime.")] - public LinkedInClient(string consumerKey, string consumerSecret) : - base("linkedIn", LinkedInServiceDescription, consumerKey, consumerSecret) { - } + public LinkedInClient(string consumerKey, string consumerSecret) + : base("linkedIn", LinkedInServiceDescription, consumerKey, consumerSecret) {} + + #endregion + + #region Methods /// <summary> /// Check if authentication succeeded after user is redirected back from the service provider. /// </summary> - /// <param name="response">The response token returned from service provider</param> + /// <param name="response"> + /// The response token returned from service provider + /// </param> /// <returns> - /// Authentication result. + /// Authentication result. /// </returns> - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Microsoft.Design", - "CA1031:DoNotCatchGeneralExceptionTypes", + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We don't care if the request fails.")] protected override AuthenticationResult VerifyAuthenticationCore(AuthorizedTokenResponse response) { // See here for Field Selectors API http://developer.linkedin.com/docs/DOC-1014 - const string profileRequestUrl = "http://api.linkedin.com/v1/people/~:(id,first-name,last-name,headline,industry,summary)"; + const string profileRequestUrl = + "http://api.linkedin.com/v1/people/~:(id,first-name,last-name,headline,industry,summary)"; string accessToken = response.AccessToken; var profileEndpoint = new MessageReceivingEndpoint(profileRequestUrl, HttpDeliveryMethods.GetRequest); - HttpWebRequest request = WebWorker.PrepareAuthorizedRequest(profileEndpoint, accessToken); + HttpWebRequest request = this.WebWorker.PrepareAuthorizedRequest(profileEndpoint, accessToken); try { using (WebResponse profileResponse = request.GetResponse()) { @@ -79,16 +101,14 @@ namespace DotNetOpenAuth.AspNet.Clients { extraData.AddDataIfNotEmpty(document, "industry"); return new AuthenticationResult( - isSuccessful: true, - provider: ProviderName, - providerUserId: userId, - userName: userName, - extraData: extraData); + isSuccessful: true, provider: this.ProviderName, providerUserId: userId, userName: userName, extraData: extraData); } } } catch (Exception exception) { return new AuthenticationResult(exception); } } + + #endregion } -}
\ No newline at end of file +} diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/OAuthClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/OAuthClient.cs index 5908225..56e046e 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/OAuthClient.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/OAuthClient.cs @@ -16,25 +16,56 @@ namespace DotNetOpenAuth.AspNet.Clients { /// Represents base class for OAuth 1.0 clients /// </summary> public abstract class OAuthClient : IAuthenticationClient { + #region Constructors and Destructors + /// <summary> /// Initializes a new instance of the <see cref="OAuthClient"/> class. /// </summary> - /// <param name="providerName">Name of the provider.</param> - /// <param name="serviceDescription">The service description.</param> - /// <param name="consumerKey">The consumer key.</param> - /// <param name="consumerSecret">The consumer secret.</param> - protected OAuthClient(string providerName, ServiceProviderDescription serviceDescription, string consumerKey, string consumerSecret) : - this(providerName, serviceDescription, new InMemoryOAuthTokenManager(consumerKey, consumerSecret)) { - } + /// <param name="providerName"> + /// Name of the provider. + /// </param> + /// <param name="serviceDescription"> + /// The service description. + /// </param> + /// <param name="consumerKey"> + /// The consumer key. + /// </param> + /// <param name="consumerSecret"> + /// The consumer secret. + /// </param> + protected OAuthClient( + string providerName, ServiceProviderDescription serviceDescription, string consumerKey, string consumerSecret) + : this(providerName, serviceDescription, new InMemoryOAuthTokenManager(consumerKey, consumerSecret)) {} /// <summary> /// Initializes a new instance of the <see cref="OAuthClient"/> class. /// </summary> - /// <param name="providerName">Name of the provider.</param> - protected OAuthClient(string providerName, ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager) : - this(providerName, new DotNetOpenAuthWebConsumer(serviceDescription, tokenManager)) { - } + /// <param name="providerName"> + /// Name of the provider. + /// </param> + /// <param name="serviceDescription"> + /// The service Description. + /// </param> + /// <param name="tokenManager"> + /// The token Manager. + /// </param> + protected OAuthClient( + string providerName, ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager) + : this(providerName, new DotNetOpenAuthWebConsumer(serviceDescription, tokenManager)) {} + /// <summary> + /// Initializes a new instance of the <see cref="OAuthClient"/> class. + /// </summary> + /// <param name="providerName"> + /// The provider name. + /// </param> + /// <param name="webWorker"> + /// The web worker. + /// </param> + /// <exception cref="ArgumentNullException"> + /// </exception> + /// <exception cref="ArgumentNullException"> + /// </exception> protected OAuthClient(string providerName, IOAuthWebWorker webWorker) { if (providerName == null) { throw new ArgumentNullException("providerName"); @@ -44,32 +75,41 @@ namespace DotNetOpenAuth.AspNet.Clients { throw new ArgumentNullException("webWorker"); } - ProviderName = providerName; - WebWorker = webWorker; + this.ProviderName = providerName; + this.WebWorker = webWorker; } + #endregion + + #region Public Properties + /// <summary> /// Gets the name of the provider which provides authentication service. /// </summary> - public string ProviderName { - get; - private set; - } + public string ProviderName { get; private set; } + + #endregion + + #region Properties /// <summary> - /// Gets the <see cref="OAuthWebConsumer"/> instance which handles constructing requests - /// to the OAuth providers. + /// Gets the <see cref="OAuthWebConsumer" /> instance which handles constructing requests to the OAuth providers. /// </summary> - protected IOAuthWebWorker WebWorker { - get; - private set; - } + protected IOAuthWebWorker WebWorker { get; private set; } + + #endregion + + #region Public Methods and Operators /// <summary> - /// Attempts to authenticate users by forwarding them to an external website, and - /// upon succcess or failure, redirect users back to the specified url. + /// Attempts to authenticate users by forwarding them to an external website, and upon succcess or failure, redirect users back to the specified url. /// </summary> - /// <param name="returnUrl">The return url after users have completed authenticating against external website.</param> + /// <param name="context"> + /// The context. + /// </param> + /// <param name="returnUrl"> + /// The return url after users have completed authenticating against external website. + /// </param> public virtual void RequestAuthentication(HttpContextBase context, Uri returnUrl) { if (returnUrl == null) { throw new ArgumentNullException("returnUrl"); @@ -80,36 +120,47 @@ namespace DotNetOpenAuth.AspNet.Clients { } Uri callback = returnUrl.StripQueryArgumentsWithPrefix("oauth_"); - WebWorker.RequestAuthentication(callback); + this.WebWorker.RequestAuthentication(callback); } /// <summary> /// Check if authentication succeeded after user is redirected back from the service provider. /// </summary> + /// <param name="context"> + /// The context. + /// </param> /// <returns> - /// An instance of <see cref="AuthenticationResult"/> containing authentication result. + /// An instance of <see cref="AuthenticationResult"/> containing authentication result. /// </returns> public virtual AuthenticationResult VerifyAuthentication(HttpContextBase context) { - AuthorizedTokenResponse response = WebWorker.ProcessUserAuthorization(); + AuthorizedTokenResponse response = this.WebWorker.ProcessUserAuthorization(); if (response == null) { return AuthenticationResult.Failed; } // add the access token to the user data dictionary just in case page developers want to use it - AuthenticationResult result = VerifyAuthenticationCore(response); - if (result.IsSuccessful && result.ExtraData != null) - { + AuthenticationResult result = this.VerifyAuthenticationCore(response); + if (result.IsSuccessful && result.ExtraData != null) { result.ExtraData["accesstoken"] = response.AccessToken; } return result; } + #endregion + + #region Methods + /// <summary> /// Check if authentication succeeded after user is redirected back from the service provider. /// </summary> - /// <param name="response">The response token returned from service provider</param> - /// <returns>Authentication result</returns> + /// <param name="response"> + /// The response token returned from service provider + /// </param> + /// <returns> + /// Authentication result + /// </returns> protected abstract AuthenticationResult VerifyAuthenticationCore(AuthorizedTokenResponse response); + #endregion } -}
\ No newline at end of file +} diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/TwitterClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/TwitterClient.cs index b147040..ad1a556 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/TwitterClient.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/TwitterClient.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.AspNet.Clients { using System; using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net; using System.Xml.Linq; @@ -19,48 +20,69 @@ namespace DotNetOpenAuth.AspNet.Clients { /// Represents a Twitter client /// </summary> public class TwitterClient : OAuthClient { + #region Constants and Fields + /// <summary> /// The description of Twitter's OAuth protocol URIs for use with their "Sign in with Twitter" feature. /// </summary> public static readonly ServiceProviderDescription TwitterServiceDescription = new ServiceProviderDescription { - RequestTokenEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/request_token", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), - UserAuthorizationEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/authenticate", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), - AccessTokenEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/access_token", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), - TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() }, + RequestTokenEndpoint = + new MessageReceivingEndpoint( + "http://twitter.com/oauth/request_token", + HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), + UserAuthorizationEndpoint = + new MessageReceivingEndpoint( + "http://twitter.com/oauth/authenticate", + HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), + AccessTokenEndpoint = + new MessageReceivingEndpoint( + "http://twitter.com/oauth/access_token", + HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), + TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() }, }; + #endregion + + #region Constructors and Destructors + /// <summary> /// Initializes a new instance of the <see cref="TwitterClient"/> class with the specified consumer key and consumer secret. /// </summary> - /// <param name="consumerKey">The consumer key.</param> - /// <param name="consumerSecret">The consumer secret.</param> - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Microsoft.Reliability", - "CA2000:Dispose objects before losing scope", + /// <param name="consumerKey"> + /// The consumer key. + /// </param> + /// <param name="consumerSecret"> + /// The consumer secret. + /// </param> + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "We can't dispose the object because we still need it through the app lifetime.")] - public TwitterClient(string consumerKey, string consumerSecret) : - base("twitter", TwitterServiceDescription, consumerKey, consumerSecret) { - } + public TwitterClient(string consumerKey, string consumerSecret) + : base("twitter", TwitterServiceDescription, consumerKey, consumerSecret) {} + + #endregion + + #region Methods /// <summary> /// Check if authentication succeeded after user is redirected back from the service provider. /// </summary> - /// <param name="response">The response token returned from service provider</param> + /// <param name="response"> + /// The response token returned from service provider + /// </param> /// <returns> - /// Authentication result + /// Authentication result /// </returns> - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Microsoft.Design", - "CA1031:DoNotCatchGeneralExceptionTypes", + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We don't care if the request for additional data fails.")] protected override AuthenticationResult VerifyAuthenticationCore(AuthorizedTokenResponse response) { string accessToken = response.AccessToken; string userId = response.ExtraData["user_id"]; string userName = response.ExtraData["screen_name"]; - string profileRequestUrl = "http://api.twitter.com/1/users/show.xml?user_id=" + MessagingUtilities.EscapeUriDataStringRfc3986(userId); + string profileRequestUrl = "http://api.twitter.com/1/users/show.xml?user_id=" + + MessagingUtilities.EscapeUriDataStringRfc3986(userId); var profileEndpoint = new MessageReceivingEndpoint(profileRequestUrl, HttpDeliveryMethods.GetRequest); - HttpWebRequest request = WebWorker.PrepareAuthorizedRequest(profileEndpoint, accessToken); + HttpWebRequest request = this.WebWorker.PrepareAuthorizedRequest(profileEndpoint, accessToken); var extraData = new Dictionary<string, string>(); try { @@ -80,11 +102,9 @@ namespace DotNetOpenAuth.AspNet.Clients { } return new AuthenticationResult( - isSuccessful: true, - provider: ProviderName, - providerUserId: userId, - userName: userName, - extraData: extraData); + isSuccessful: true, provider: this.ProviderName, providerUserId: userId, userName: userName, extraData: extraData); } + + #endregion } -}
\ No newline at end of file +} diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/FacebookClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/FacebookClient.cs index b98989a..5745bad 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/FacebookClient.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/FacebookClient.cs @@ -13,65 +13,98 @@ namespace DotNetOpenAuth.AspNet.Clients { using DotNetOpenAuth.AspNet.Resources; using DotNetOpenAuth.Messaging; + /// <summary> + /// The facebook client. + /// </summary> public sealed class FacebookClient : OAuth2Client { + #region Constants and Fields + + /// <summary> + /// The authorization endpoint. + /// </summary> private const string AuthorizationEndpoint = "https://www.facebook.com/dialog/oauth"; + + /// <summary> + /// The token endpoint. + /// </summary> private const string TokenEndpoint = "https://graph.facebook.com/oauth/access_token"; + /// <summary> + /// The _app id. + /// </summary> private readonly string _appId; + + /// <summary> + /// The _app secret. + /// </summary> private readonly string _appSecret; + #endregion + + #region Constructors and Destructors + + /// <summary> + /// Initializes a new instance of the <see cref="FacebookClient"/> class. + /// </summary> + /// <param name="appId"> + /// The app id. + /// </param> + /// <param name="appSecret"> + /// The app secret. + /// </param> + /// <exception cref="ArgumentException"> + /// </exception> + /// <exception cref="ArgumentException"> + /// </exception> public FacebookClient(string appId, string appSecret) : base("facebook") { - if (String.IsNullOrEmpty(appId)) { + if (string.IsNullOrEmpty(appId)) { throw new ArgumentException( - String.Format(CultureInfo.CurrentCulture, WebResources.Argument_Cannot_Be_Null_Or_Empty, "appId"), - "appId"); + string.Format(CultureInfo.CurrentCulture, WebResources.Argument_Cannot_Be_Null_Or_Empty, "appId"), "appId"); } - if (String.IsNullOrEmpty("appSecret")) { + if (string.IsNullOrEmpty("appSecret")) { throw new ArgumentException( - String.Format(CultureInfo.CurrentCulture, WebResources.Argument_Cannot_Be_Null_Or_Empty, "appSecret"), - "appSecret"); + string.Format(CultureInfo.CurrentCulture, WebResources.Argument_Cannot_Be_Null_Or_Empty, "appSecret"), "appSecret"); } - _appId = appId; - _appSecret = appSecret; + this._appId = appId; + this._appSecret = appSecret; } + #endregion + + #region Methods + + /// <summary> + /// The get service login url. + /// </summary> + /// <param name="returnUrl"> + /// The return url. + /// </param> + /// <returns> + /// </returns> protected override Uri GetServiceLoginUrl(Uri returnUrl) { // Note: Facebook doesn't like us to url-encode the redirect_uri value var builder = new UriBuilder(AuthorizationEndpoint); - builder.AppendQueryArgs(new Dictionary<string, string> { - { "client_id", _appId }, - { "redirect_uri", returnUrl.AbsoluteUri }, - }); + builder.AppendQueryArgs( + new Dictionary<string, string> { { "client_id", this._appId }, { "redirect_uri", returnUrl.AbsoluteUri }, }); return builder.Uri; } - protected override string QueryAccessToken(Uri returnUrl, string authorizationCode) { - // Note: Facebook doesn't like us to url-encode the redirect_uri value - var builder = new UriBuilder(TokenEndpoint); - builder.AppendQueryArgs(new Dictionary<string, string> { - { "client_id", _appId }, - { "redirect_uri", returnUrl.AbsoluteUri }, - { "client_secret", _appSecret }, - { "code", authorizationCode }, - }); - - using (WebClient client = new WebClient()) { - string data = client.DownloadString(builder.Uri); - if (String.IsNullOrEmpty(data)) { - return null; - } - - var parsedQueryString = HttpUtility.ParseQueryString(data); - return parsedQueryString["access_token"]; - } - } - + /// <summary> + /// The get user data. + /// </summary> + /// <param name="accessToken"> + /// The access token. + /// </param> + /// <returns> + /// </returns> protected override IDictionary<string, string> GetUserData(string accessToken) { FacebookGraphData graphData; - var request = WebRequest.Create("https://graph.facebook.com/me?access_token=" + MessagingUtilities.EscapeUriDataStringRfc3986(accessToken)); + var request = + WebRequest.Create( + "https://graph.facebook.com/me?access_token=" + MessagingUtilities.EscapeUriDataStringRfc3986(accessToken)); using (var response = request.GetResponse()) { using (var responseStream = response.GetResponseStream()) { graphData = JsonHelper.Deserialize<FacebookGraphData>(responseStream); @@ -88,5 +121,41 @@ namespace DotNetOpenAuth.AspNet.Clients { userData.AddItemIfNotEmpty("birthday", graphData.Birthday); return userData; } + + /// <summary> + /// The query access token. + /// </summary> + /// <param name="returnUrl"> + /// The return url. + /// </param> + /// <param name="authorizationCode"> + /// The authorization code. + /// </param> + /// <returns> + /// The query access token. + /// </returns> + protected override string QueryAccessToken(Uri returnUrl, string authorizationCode) { + // Note: Facebook doesn't like us to url-encode the redirect_uri value + var builder = new UriBuilder(TokenEndpoint); + builder.AppendQueryArgs( + new Dictionary<string, string> { + { "client_id", this._appId }, + { "redirect_uri", returnUrl.AbsoluteUri }, + { "client_secret", this._appSecret }, + { "code", authorizationCode }, + }); + + using (WebClient client = new WebClient()) { + string data = client.DownloadString(builder.Uri); + if (string.IsNullOrEmpty(data)) { + return null; + } + + var parsedQueryString = HttpUtility.ParseQueryString(data); + return parsedQueryString["access_token"]; + } + } + + #endregion } } diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/FacebookGraphData.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/FacebookGraphData.cs index 80c42b7..53c2797 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/FacebookGraphData.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/FacebookGraphData.cs @@ -6,71 +6,61 @@ namespace DotNetOpenAuth.AspNet.Clients { using System; - using System.Runtime.Serialization; using System.ComponentModel; + using System.Runtime.Serialization; /// <summary> /// Contains data of a Facebook user. /// </summary> /// <remarks> - /// Technically, this class doesn't need to be public, but because we want to make it serializable - /// in medium trust, it has to be public. + /// Technically, this class doesn't need to be public, but because we want to make it serializable in medium trust, it has to be public. /// </remarks> [DataContract] [EditorBrowsable(EditorBrowsableState.Never)] public class FacebookGraphData { + #region Public Properties + /// <summary> - /// Gets or sets the id. + /// Gets or sets the birthday. /// </summary> - /// <value> - /// The id. - /// </value> - [DataMember(Name = "id")] - public string Id { get; set; } + /// <value> The birthday. </value> + [DataMember(Name = "birthday")] + public string Birthday { get; set; } /// <summary> /// Gets or sets the email. /// </summary> - /// <value> - /// The email. - /// </value> + /// <value> The email. </value> [DataMember(Name = "email")] public string Email { get; set; } /// <summary> - /// Gets or sets the name. + /// Gets or sets the gender. /// </summary> - /// <value> - /// The name. - /// </value> - [DataMember(Name = "name")] - public string Name { get; set; } + /// <value> The gender. </value> + [DataMember(Name = "gender")] + public string Gender { get; set; } /// <summary> - /// Gets or sets the link. + /// Gets or sets the id. /// </summary> - /// <value> - /// The link. - /// </value> - [DataMember(Name = "link")] - public Uri Link { get; set; } + /// <value> The id. </value> + [DataMember(Name = "id")] + public string Id { get; set; } /// <summary> - /// Gets or sets the gender. + /// Gets or sets the link. /// </summary> - /// <value> - /// The gender. - /// </value> - [DataMember(Name = "gender")] - public string Gender { get; set; } + /// <value> The link. </value> + [DataMember(Name = "link")] + public Uri Link { get; set; } /// <summary> - /// Gets or sets the birthday. + /// Gets or sets the name. /// </summary> - /// <value> - /// The birthday. - /// </value> - [DataMember(Name = "birthday")] - public string Birthday { get; set; } + /// <value> The name. </value> + [DataMember(Name = "name")] + public string Name { get; set; } + #endregion } } diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/JsonHelper.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/JsonHelper.cs index 7a2da18..ddb8879 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/JsonHelper.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/JsonHelper.cs @@ -9,7 +9,24 @@ namespace DotNetOpenAuth.AspNet.Clients { using System.IO; using System.Runtime.Serialization.Json; + /// <summary> + /// The json helper. + /// </summary> internal static class JsonHelper { + #region Public Methods and Operators + + /// <summary> + /// The deserialize. + /// </summary> + /// <param name="stream"> + /// The stream. + /// </param> + /// <typeparam name="T"> + /// </typeparam> + /// <returns> + /// </returns> + /// <exception cref="ArgumentNullException"> + /// </exception> public static T Deserialize<T>(Stream stream) where T : class { if (stream == null) { throw new ArgumentNullException("stream"); @@ -18,5 +35,7 @@ namespace DotNetOpenAuth.AspNet.Clients { var serializer = new DataContractJsonSerializer(typeof(T)); return (T)serializer.ReadObject(stream); } + + #endregion } } diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/OAuth2AccessTokenData.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/OAuth2AccessTokenData.cs index d17b452..5da24dd 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/OAuth2AccessTokenData.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/OAuth2AccessTokenData.cs @@ -12,40 +12,35 @@ namespace DotNetOpenAuth.AspNet.Clients { /// </summary> [DataContract] public class OAuth2AccessTokenData { + #region Public Properties + /// <summary> /// Gets or sets the access token. /// </summary> - /// <value> - /// The access token. - /// </value> + /// <value> The access token. </value> [DataMember(Name = "access_token")] public string AccessToken { get; set; } /// <summary> /// Gets or sets the refresh token. /// </summary> - /// <value> - /// The refresh token. - /// </value> + /// <value> The refresh token. </value> [DataMember(Name = "refresh_token")] public string RefreshToken { get; set; } /// <summary> /// Gets or sets the scope. /// </summary> - /// <value> - /// The scope. - /// </value> + /// <value> The scope. </value> [DataMember(Name = "scope")] public string Scope { get; set; } /// <summary> /// Gets or sets the type of the token. /// </summary> - /// <value> - /// The type of the token. - /// </value> + /// <value> The type of the token. </value> [DataMember(Name = "token_type")] public string TokenType { get; set; } + #endregion } } diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/OAuth2Client.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/OAuth2Client.cs index 7570b4d..9003bc0 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/OAuth2Client.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/OAuth2Client.cs @@ -14,33 +14,62 @@ namespace DotNetOpenAuth.AspNet.Clients { /// Represents the base class for OAuth 2.0 clients /// </summary> public abstract class OAuth2Client : IAuthenticationClient { + #region Constants and Fields + + /// <summary> + /// The _provider name. + /// </summary> private readonly string _providerName; + + /// <summary> + /// The _return url. + /// </summary> private Uri _returnUrl; + #endregion + + #region Constructors and Destructors + /// <summary> /// Initializes a new instance of the <see cref="OAuth2Client"/> class with the specified provider name. /// </summary> - /// <param name="providerName">Name of the provider.</param> + /// <param name="providerName"> + /// Name of the provider. + /// </param> protected OAuth2Client(string providerName) { if (providerName == null) { throw new ArgumentNullException("providerName"); } - _providerName = providerName; + this._providerName = providerName; } + #endregion + + #region Public Properties + /// <summary> /// Gets the name of the provider which provides authentication service. /// </summary> public string ProviderName { - get { return _providerName; } + get { + return this._providerName; + } } + #endregion + + #region Public Methods and Operators + /// <summary> - /// Attempts to authenticate users by forwarding them to an external website, and - /// upon succcess or failure, redirect users back to the specified url. + /// Attempts to authenticate users by forwarding them to an external website, and upon succcess or failure, redirect users back to the specified url. /// </summary> - /// <param name="returnUrl">The return url after users have completed authenticating against external website.</param> + /// <param name="context"> + /// The context. + /// </param> + /// <param name="returnUrl"> + /// The return url after users have completed authenticating against external website. + /// </param> public virtual void RequestAuthentication(HttpContextBase context, Uri returnUrl) { if (context == null) { throw new ArgumentNullException("context"); @@ -50,17 +79,20 @@ namespace DotNetOpenAuth.AspNet.Clients { throw new ArgumentNullException("returnUrl"); } - _returnUrl = returnUrl; + this._returnUrl = returnUrl; - string redirectUrl = GetServiceLoginUrl(returnUrl).AbsoluteUri; + string redirectUrl = this.GetServiceLoginUrl(returnUrl).AbsoluteUri; context.Response.Redirect(redirectUrl, endResponse: true); } /// <summary> /// Check if authentication succeeded after user is redirected back from the service provider. /// </summary> + /// <param name="context"> + /// The context. + /// </param> /// <returns> - /// An instance of <see cref="AuthenticationResult"/> containing authentication result. + /// An instance of <see cref="AuthenticationResult"/> containing authentication result. /// </returns> public virtual AuthenticationResult VerifyAuthentication(HttpContextBase context) { if (context == null) { @@ -68,21 +100,23 @@ namespace DotNetOpenAuth.AspNet.Clients { } string code = context.Request.QueryString["code"]; - if (String.IsNullOrEmpty(code)) { + if (string.IsNullOrEmpty(code)) { return AuthenticationResult.Failed; } - string accessToken = QueryAccessToken(_returnUrl, code); + string accessToken = this.QueryAccessToken(this._returnUrl, code); if (accessToken == null) { return AuthenticationResult.Failed; } - IDictionary<string, string> userData = GetUserData(accessToken); + IDictionary<string, string> userData = this.GetUserData(accessToken); if (userData == null) { return AuthenticationResult.Failed; } + string id = userData["id"]; string name; + // Some oAuth providers do not return value for the 'username' attribute. // In that case, try the 'name' attribute. If it's still unavailable, fall back to 'id' if (!userData.TryGetValue("username", out name) && !userData.TryGetValue("name", out name)) { @@ -93,36 +127,50 @@ namespace DotNetOpenAuth.AspNet.Clients { userData["accesstoken"] = accessToken; return new AuthenticationResult( - isSuccessful: true, - provider: ProviderName, - providerUserId: id, - userName: name, - extraData: userData); + isSuccessful: true, provider: this.ProviderName, providerUserId: id, userName: name, extraData: userData); } + #endregion + + #region Methods + /// <summary> - /// Gets the full url pointing to the login page for this client. The url should include the - /// specified return url so that when the login completes, user is redirected back to that url. + /// Gets the full url pointing to the login page for this client. The url should include the specified return url so that when the login completes, user is redirected back to that url. /// </summary> - /// <param name="returnUrl">The return URL.</param> - /// <returns>An absolute URL.</returns> - [SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "Login", Justification = "Login is used more consistently in ASP.Net")] + /// <param name="returnUrl"> + /// The return URL. + /// </param> + /// <returns> + /// An absolute URL. + /// </returns> + [SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "Login", + Justification = "Login is used more consistently in ASP.Net")] protected abstract Uri GetServiceLoginUrl(Uri returnUrl); /// <summary> - /// Queries the access token from the specified authorization code. + /// Given the access token, gets the logged-in user's data. The returned dictionary must include two keys 'id', and 'username'. /// </summary> - /// <param name="returnUrl">The return URL.</param> - /// <param name="authorizationCode">The authorization code.</param> - /// <returns>The access token</returns> - protected abstract string QueryAccessToken(Uri returnUrl, string authorizationCode); + /// <param name="accessToken"> + /// The access token of the current user. + /// </param> + /// <returns> + /// A dictionary contains key-value pairs of user data + /// </returns> + protected abstract IDictionary<string, string> GetUserData(string accessToken); /// <summary> - /// Given the access token, gets the logged-in user's data. The returned dictionary must include - /// two keys 'id', and 'username'. + /// Queries the access token from the specified authorization code. /// </summary> - /// <param name="accessToken">The access token of the current user.</param> - /// <returns>A dictionary contains key-value pairs of user data</returns> - protected abstract IDictionary<string, string> GetUserData(string accessToken); + /// <param name="returnUrl"> + /// The return URL. + /// </param> + /// <param name="authorizationCode"> + /// The authorization code. + /// </param> + /// <returns> + /// The access token + /// </returns> + protected abstract string QueryAccessToken(Uri returnUrl, string authorizationCode); + #endregion } -}
\ No newline at end of file +} diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/WindowsLiveClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/WindowsLiveClient.cs index 548d6bd..dced87f 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/WindowsLiveClient.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/WindowsLiveClient.cs @@ -9,60 +9,140 @@ namespace DotNetOpenAuth.AspNet.Clients { using System.Collections.Generic; using System.IO; using System.Net; - using System.Text; using DotNetOpenAuth.Messaging; + /// <summary> + /// The windows live client. + /// </summary> public sealed class WindowsLiveClient : OAuth2Client { - private const string TokenEndpoint = "https://oauth.live.com/token"; + #region Constants and Fields + + /// <summary> + /// The authorization endpoint. + /// </summary> private const string AuthorizationEndpoint = "https://oauth.live.com/authorize"; + + /// <summary> + /// The token endpoint. + /// </summary> + private const string TokenEndpoint = "https://oauth.live.com/token"; + + /// <summary> + /// The _app id. + /// </summary> private readonly string _appId; + + /// <summary> + /// The _app secret. + /// </summary> private readonly string _appSecret; + #endregion + + #region Constructors and Destructors + + /// <summary> + /// Initializes a new instance of the <see cref="WindowsLiveClient"/> class. + /// </summary> + /// <param name="appId"> + /// The app id. + /// </param> + /// <param name="appSecret"> + /// The app secret. + /// </param> + /// <exception cref="ArgumentNullException"> + /// </exception> + /// <exception cref="ArgumentNullException"> + /// </exception> public WindowsLiveClient(string appId, string appSecret) : base("windowslive") { - if (String.IsNullOrEmpty(appId)) { + if (string.IsNullOrEmpty(appId)) { throw new ArgumentNullException("appId"); } - if (String.IsNullOrEmpty("appSecret")) { + if (string.IsNullOrEmpty("appSecret")) { throw new ArgumentNullException("appSecret"); } - _appId = appId; - _appSecret = appSecret; + this._appId = appId; + this._appSecret = appSecret; } + #endregion + + #region Methods + /// <summary> - /// Gets the full url pointing to the login page for this client. The url should include the - /// specified return url so that when the login completes, user is redirected back to that url. + /// Gets the full url pointing to the login page for this client. The url should include the specified return url so that when the login completes, user is redirected back to that url. /// </summary> - /// <param name="returnUrl">The return URL.</param> + /// <param name="returnUrl"> + /// The return URL. + /// </param> protected override Uri GetServiceLoginUrl(Uri returnUrl) { var builder = new UriBuilder(AuthorizationEndpoint); - builder.AppendQueryArgs(new Dictionary<string, string> { - { "client_id", _appId }, - { "scope", "wl.basic" }, - { "response_type", "code" }, - { "redirect_uri", returnUrl.AbsoluteUri }, + builder.AppendQueryArgs( + new Dictionary<string, string> { + { "client_id", this._appId }, + { "scope", "wl.basic" }, + { "response_type", "code" }, + { "redirect_uri", returnUrl.AbsoluteUri }, }); return builder.Uri; } /// <summary> + /// Given the access token, gets the logged-in user's data. The returned dictionary must include two keys 'id', and 'username'. + /// </summary> + /// <param name="accessToken"> + /// The access token of the current user. + /// </param> + /// <returns> + /// A dictionary contains key-value pairs of user data + /// </returns> + protected override IDictionary<string, string> GetUserData(string accessToken) { + WindowsLiveUserData graph; + var request = + WebRequest.Create( + "https://apis.live.net/v5.0/me?access_token=" + MessagingUtilities.EscapeUriDataStringRfc3986(accessToken)); + using (var response = request.GetResponse()) { + using (var responseStream = response.GetResponseStream()) { + graph = JsonHelper.Deserialize<WindowsLiveUserData>(responseStream); + } + } + + var userData = new Dictionary<string, string>(); + userData.AddItemIfNotEmpty("id", graph.Id); + userData.AddItemIfNotEmpty("username", graph.Name); + userData.AddItemIfNotEmpty("name", graph.Name); + userData.AddItemIfNotEmpty("link", graph.Link == null ? null : graph.Link.AbsoluteUri); + userData.AddItemIfNotEmpty("gender", graph.Gender); + userData.AddItemIfNotEmpty("firstname", graph.FirstName); + userData.AddItemIfNotEmpty("lastname", graph.LastName); + return userData; + } + + /// <summary> /// Queries the access token from the specified authorization code. /// </summary> - /// <param name="returnUrl">The return URL.</param> - /// <param name="authorizationCode">The authorization code.</param> + /// <param name="returnUrl"> + /// The return URL. + /// </param> + /// <param name="authorizationCode"> + /// The authorization code. + /// </param> + /// <returns> + /// The query access token. + /// </returns> protected override string QueryAccessToken(Uri returnUrl, string authorizationCode) { var entity = MessagingUtilities.CreateQueryString( new Dictionary<string, string> { - { "client_id", _appId }, - { "redirect_uri", returnUrl.AbsoluteUri }, - { "client_secret", _appSecret }, - { "code", authorizationCode }, - { "grant_type", "authorization_code" }, + { "client_id", this._appId }, + { "redirect_uri", returnUrl.AbsoluteUri }, + { "client_secret", this._appSecret }, + { "code", authorizationCode }, + { "grant_type", "authorization_code" }, }); WebRequest tokenRequest = WebRequest.Create(TokenEndpoint); @@ -89,32 +169,6 @@ namespace DotNetOpenAuth.AspNet.Clients { return null; } - /// <summary> - /// Given the access token, gets the logged-in user's data. The returned dictionary must include - /// two keys 'id', and 'username'. - /// </summary> - /// <param name="accessToken">The access token of the current user.</param> - /// <returns> - /// A dictionary contains key-value pairs of user data - /// </returns> - protected override IDictionary<string, string> GetUserData(string accessToken) { - WindowsLiveUserData graph; - var request = WebRequest.Create("https://apis.live.net/v5.0/me?access_token=" + MessagingUtilities.EscapeUriDataStringRfc3986(accessToken)); - using (var response = request.GetResponse()) { - using (var responseStream = response.GetResponseStream()) { - graph = JsonHelper.Deserialize<WindowsLiveUserData>(responseStream); - } - } - - var userData = new Dictionary<string, string>(); - userData.AddItemIfNotEmpty("id", graph.Id); - userData.AddItemIfNotEmpty("username", graph.Name); - userData.AddItemIfNotEmpty("name", graph.Name); - userData.AddItemIfNotEmpty("link", graph.Link == null ? null : graph.Link.AbsoluteUri); - userData.AddItemIfNotEmpty("gender", graph.Gender); - userData.AddItemIfNotEmpty("firstname", graph.FirstName); - userData.AddItemIfNotEmpty("lastname", graph.LastName); - return userData; - } + #endregion } } diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/WindowsLiveUserData.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/WindowsLiveUserData.cs index 5c16269..52192c3 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/WindowsLiveUserData.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/WindowsLiveUserData.cs @@ -6,71 +6,61 @@ namespace DotNetOpenAuth.AspNet.Clients { using System; - using System.Runtime.Serialization; using System.ComponentModel; + using System.Runtime.Serialization; /// <summary> /// Contains data of a Windows Live user. /// </summary> /// <remarks> - /// Technically, this class doesn't need to be public, but because we want to make it serializable - /// in medium trust, it has to be public. + /// Technically, this class doesn't need to be public, but because we want to make it serializable in medium trust, it has to be public. /// </remarks> [DataContract] [EditorBrowsable(EditorBrowsableState.Never)] public class WindowsLiveUserData { - /// <summary> - /// Gets or sets the id. - /// </summary> - /// <value> - /// The id. - /// </value> - [DataMember(Name = "id")] - public string Id { get; set; } + #region Public Properties /// <summary> - /// Gets or sets the name. - /// </summary> - /// <value> - /// The name. - /// </value> - [DataMember(Name = "name")] - public string Name { get; set; } - - /// <summary> - /// Gets or sets the link. + /// Gets or sets the first name. /// </summary> - /// <value> - /// The link. - /// </value> - [DataMember(Name = "link")] - public Uri Link { get; set; } + /// <value> The first name. </value> + [DataMember(Name = "first_name")] + public string FirstName { get; set; } /// <summary> /// Gets or sets the gender. /// </summary> - /// <value> - /// The gender. - /// </value> + /// <value> The gender. </value> [DataMember(Name = "gender")] public string Gender { get; set; } /// <summary> - /// Gets or sets the first name. + /// Gets or sets the id. /// </summary> - /// <value> - /// The first name. - /// </value> - [DataMember(Name = "first_name")] - public string FirstName { get; set; } + /// <value> The id. </value> + [DataMember(Name = "id")] + public string Id { get; set; } /// <summary> /// Gets or sets the last name. /// </summary> - /// <value> - /// The last name. - /// </value> + /// <value> The last name. </value> [DataMember(Name = "last_name")] public string LastName { get; set; } + + /// <summary> + /// Gets or sets the link. + /// </summary> + /// <value> The link. </value> + [DataMember(Name = "link")] + public Uri Link { get; set; } + + /// <summary> + /// Gets or sets the name. + /// </summary> + /// <value> The name. </value> + [DataMember(Name = "name")] + public string Name { get; set; } + #endregion } } diff --git a/src/DotNetOpenAuth.AspNet/Clients/OpenID/GoogleOpenIdClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OpenID/GoogleOpenIdClient.cs index 2f71781..9650e3d 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OpenID/GoogleOpenIdClient.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OpenID/GoogleOpenIdClient.cs @@ -13,36 +13,33 @@ namespace DotNetOpenAuth.AspNet.Clients { /// Represents Google OpenID client. /// </summary> public sealed class GoogleOpenIdClient : OpenIdClient { - public GoogleOpenIdClient() : - base("google", "https://www.google.com/accounts/o8/id") { - } + #region Constructors and Destructors /// <summary> - /// Called just before the authentication request is sent to service provider. + /// Initializes a new instance of the <see cref="GoogleOpenIdClient"/> class. /// </summary> - /// <param name="request">The request.</param> - protected override void OnBeforeSendingAuthenticationRequest(IAuthenticationRequest request) { - // Attribute Exchange extensions - var fetchRequest = new FetchRequest(); - fetchRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.Email, isRequired: true)); - fetchRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.HomeAddress.Country, isRequired: false)); - fetchRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.First, isRequired: false)); - fetchRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.Last, isRequired: false)); + public GoogleOpenIdClient() + : base("google", "https://www.google.com/accounts/o8/id") {} - request.AddExtension(fetchRequest); - } + #endregion + + #region Methods /// <summary> /// Gets the extra data obtained from the response message when authentication is successful. /// </summary> - /// <param name="response">The response message.</param> - /// <returns></returns> + /// <param name="response"> + /// The response message. + /// </param> + /// <returns> + /// </returns> protected override Dictionary<string, string> GetExtraData(IAuthenticationResponse response) { FetchResponse fetchResponse = response.GetExtension<FetchResponse>(); if (fetchResponse != null) { var extraData = new Dictionary<string, string>(); extraData.AddItemIfNotEmpty("email", fetchResponse.GetAttributeValue(WellKnownAttributes.Contact.Email)); - extraData.AddItemIfNotEmpty("country", fetchResponse.GetAttributeValue(WellKnownAttributes.Contact.HomeAddress.Country)); + extraData.AddItemIfNotEmpty( + "country", fetchResponse.GetAttributeValue(WellKnownAttributes.Contact.HomeAddress.Country)); extraData.AddItemIfNotEmpty("firstName", fetchResponse.GetAttributeValue(WellKnownAttributes.Name.First)); extraData.AddItemIfNotEmpty("lastName", fetchResponse.GetAttributeValue(WellKnownAttributes.Name.Last)); @@ -51,5 +48,24 @@ namespace DotNetOpenAuth.AspNet.Clients { return null; } + + /// <summary> + /// Called just before the authentication request is sent to service provider. + /// </summary> + /// <param name="request"> + /// The request. + /// </param> + protected override void OnBeforeSendingAuthenticationRequest(IAuthenticationRequest request) { + // Attribute Exchange extensions + var fetchRequest = new FetchRequest(); + fetchRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.Email, isRequired: true)); + fetchRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.HomeAddress.Country, isRequired: false)); + fetchRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.First, isRequired: false)); + fetchRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.Last, isRequired: false)); + + request.AddExtension(fetchRequest); + } + + #endregion } -}
\ No newline at end of file +} diff --git a/src/DotNetOpenAuth.AspNet/Clients/OpenID/OpenIDClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OpenID/OpenIDClient.cs index ee1ddc1..4f31529 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OpenID/OpenIDClient.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OpenID/OpenIDClient.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.AspNet.Clients { using System; using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Web; using DotNetOpenAuth.AspNet.Resources; @@ -17,54 +18,83 @@ namespace DotNetOpenAuth.AspNet.Clients { /// Base classes for OpenID clients. /// </summary> public class OpenIdClient : IAuthenticationClient { + #region Constants and Fields + + /// <summary> + /// The _openid relaying party. + /// </summary> + private static readonly OpenIdRelyingParty _openidRelayingParty = + new OpenIdRelyingParty(new StandardRelyingPartyApplicationStore()); + + /// <summary> + /// The _provider identifier. + /// </summary> private readonly Identifier _providerIdentifier; + + /// <summary> + /// The _provider name. + /// </summary> private readonly string _providerName; - private static OpenIdRelyingParty _openidRelayingParty = - new OpenIdRelyingParty(new StandardRelyingPartyApplicationStore()); + #endregion + + #region Constructors and Destructors /// <summary> /// Initializes a new instance of the <see cref="OpenIdClient"/> class. /// </summary> - /// <param name="providerName">Name of the provider.</param> - /// <param name="providerIdentifier">The provider identifier, which is the usually the login url of the specified provider.</param> + /// <param name="providerName"> + /// Name of the provider. + /// </param> + /// <param name="providerIdentifier"> + /// The provider identifier, which is the usually the login url of the specified provider. + /// </param> public OpenIdClient(string providerName, string providerIdentifier) { - if (String.IsNullOrEmpty(providerIdentifier)) { + if (string.IsNullOrEmpty(providerIdentifier)) { throw new ArgumentException( - String.Format(CultureInfo.CurrentCulture, WebResources.Argument_Cannot_Be_Null_Or_Empty, "providerIdentifier"), + string.Format(CultureInfo.CurrentCulture, WebResources.Argument_Cannot_Be_Null_Or_Empty, "providerIdentifier"), "providerIdentifier"); } - if (String.IsNullOrEmpty(providerName)) { + if (string.IsNullOrEmpty(providerName)) { throw new ArgumentException( - String.Format(CultureInfo.CurrentCulture, WebResources.Argument_Cannot_Be_Null_Or_Empty, "providerName"), + string.Format(CultureInfo.CurrentCulture, WebResources.Argument_Cannot_Be_Null_Or_Empty, "providerName"), "providerName"); } - _providerName = providerName; - if (!Identifier.TryParse(providerIdentifier, out _providerIdentifier) || _providerIdentifier == null) { + this._providerName = providerName; + if (!Identifier.TryParse(providerIdentifier, out this._providerIdentifier) || this._providerIdentifier == null) { throw new ArgumentException(WebResources.OpenIDInvalidIdentifier, "providerIdentifier"); } } + #endregion + + #region Public Properties + /// <summary> /// Gets the name of the provider which provides authentication service. /// </summary> public string ProviderName { get { - return _providerName; + return this._providerName; } } + #endregion + + #region Public Methods and Operators + /// <summary> - /// Attempts to authenticate users by forwarding them to an external website, and - /// upon succcess or failure, redirect users back to the specified url. + /// Attempts to authenticate users by forwarding them to an external website, and upon succcess or failure, redirect users back to the specified url. /// </summary> - /// <param name="context">The context of the current request.</param> - /// <param name="returnUrl">The return url after users have completed authenticating against external website.</param> - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Microsoft.Usage", - "CA2234:PassSystemUriObjectsInsteadOfStrings", + /// <param name="context"> + /// The context of the current request. + /// </param> + /// <param name="returnUrl"> + /// The return url after users have completed authenticating against external website. + /// </param> + [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "We don't have a Uri object handy.")] public virtual void RequestAuthentication(HttpContextBase context, Uri returnUrl) { if (returnUrl == null) { @@ -72,27 +102,22 @@ namespace DotNetOpenAuth.AspNet.Clients { } var realm = new Realm(returnUrl.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped)); - IAuthenticationRequest request = _openidRelayingParty.CreateRequest(_providerIdentifier, realm, returnUrl); + IAuthenticationRequest request = _openidRelayingParty.CreateRequest(this._providerIdentifier, realm, returnUrl); // give subclasses a chance to modify request message, e.g. add extension attributes, etc. - OnBeforeSendingAuthenticationRequest(request); + this.OnBeforeSendingAuthenticationRequest(request); request.RedirectToProvider(); } /// <summary> - /// Called just before the authentication request is sent to service provider. - /// </summary> - /// <param name="request">The request.</param> - protected virtual void OnBeforeSendingAuthenticationRequest(IAuthenticationRequest request) { - } - - /// <summary> /// Check if authentication succeeded after user is redirected back from the service provider. /// </summary> - /// <param name="context">The context of the current request.</param> + /// <param name="context"> + /// The context of the current request. + /// </param> /// <returns> - /// An instance of <see cref="AuthenticationResult"/> containing authentication result. + /// An instance of <see cref="AuthenticationResult"/> containing authentication result. /// </returns> public virtual AuthenticationResult VerifyAuthentication(HttpContextBase context) { IAuthenticationResponse response = _openidRelayingParty.GetResponse(); @@ -104,30 +129,42 @@ namespace DotNetOpenAuth.AspNet.Clients { string id = response.ClaimedIdentifier; string username; - Dictionary<string, string> extraData = GetExtraData(response) ?? new Dictionary<string, string>(); + Dictionary<string, string> extraData = this.GetExtraData(response) ?? new Dictionary<string, string>(); + // try to look up username from the 'username' or 'email' property. If not found, fall back to 'friendly id' if (!extraData.TryGetValue("username", out username) && !extraData.TryGetValue("email", out username)) { username = response.FriendlyIdentifierForDisplay; } - return new AuthenticationResult( - true, - ProviderName, - id, - username, - extraData); + return new AuthenticationResult(true, this.ProviderName, id, username, extraData); } return AuthenticationResult.Failed; } + #endregion + + #region Methods + /// <summary> /// Gets the extra data obtained from the response message when authentication is successful. /// </summary> - /// <param name="response">The response message.</param> - /// <returns></returns> + /// <param name="response"> + /// The response message. + /// </param> + /// <returns> + /// </returns> protected virtual Dictionary<string, string> GetExtraData(IAuthenticationResponse response) { return null; } + + /// <summary> + /// Called just before the authentication request is sent to service provider. + /// </summary> + /// <param name="request"> + /// The request. + /// </param> + protected virtual void OnBeforeSendingAuthenticationRequest(IAuthenticationRequest request) {} + #endregion } -}
\ No newline at end of file +} diff --git a/src/DotNetOpenAuth.AspNet/Clients/OpenID/YahooOpenIdClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OpenID/YahooOpenIdClient.cs index d3a063f..67cb8c4 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OpenID/YahooOpenIdClient.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OpenID/YahooOpenIdClient.cs @@ -9,29 +9,30 @@ namespace DotNetOpenAuth.AspNet.Clients { using DotNetOpenAuth.OpenId.Extensions.AttributeExchange; using DotNetOpenAuth.OpenId.RelyingParty; + /// <summary> + /// The yahoo open id client. + /// </summary> public sealed class YahooOpenIdClient : OpenIdClient { - public YahooOpenIdClient() : - base("yahoo", "http://me.yahoo.com") { - } + #region Constructors and Destructors /// <summary> - /// Called just before the authentication request is sent to service provider. + /// Initializes a new instance of the <see cref="YahooOpenIdClient"/> class. /// </summary> - /// <param name="request">The request.</param> - protected override void OnBeforeSendingAuthenticationRequest(IAuthenticationRequest request) { - // Attribute Exchange extensions - var fetchRequest = new FetchRequest(); - fetchRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.Email, isRequired: true)); - fetchRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.FullName, isRequired: false)); + public YahooOpenIdClient() + : base("yahoo", "http://me.yahoo.com") {} - request.AddExtension(fetchRequest); - } + #endregion + + #region Methods /// <summary> /// Gets the extra data obtained from the response message when authentication is successful. /// </summary> - /// <param name="response">The response message.</param> - /// <returns></returns> + /// <param name="response"> + /// The response message. + /// </param> + /// <returns> + /// </returns> protected override Dictionary<string, string> GetExtraData(IAuthenticationResponse response) { FetchResponse fetchResponse = response.GetExtension<FetchResponse>(); if (fetchResponse != null) { @@ -44,5 +45,22 @@ namespace DotNetOpenAuth.AspNet.Clients { return null; } + + /// <summary> + /// Called just before the authentication request is sent to service provider. + /// </summary> + /// <param name="request"> + /// The request. + /// </param> + protected override void OnBeforeSendingAuthenticationRequest(IAuthenticationRequest request) { + // Attribute Exchange extensions + var fetchRequest = new FetchRequest(); + fetchRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.Email, isRequired: true)); + fetchRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.FullName, isRequired: false)); + + request.AddExtension(fetchRequest); + } + + #endregion } } diff --git a/src/DotNetOpenAuth.AspNet/IAuthenticationClient.cs b/src/DotNetOpenAuth.AspNet/IAuthenticationClient.cs index 4a9c8fb..58232c6 100644 --- a/src/DotNetOpenAuth.AspNet/IAuthenticationClient.cs +++ b/src/DotNetOpenAuth.AspNet/IAuthenticationClient.cs @@ -12,26 +12,38 @@ namespace DotNetOpenAuth.AspNet { /// Represents a client which can authenticate users via an external website/provider. /// </summary> public interface IAuthenticationClient { + #region Public Properties + /// <summary> /// Gets the name of the provider which provides authentication service. /// </summary> string ProviderName { get; } + #endregion + + #region Public Methods and Operators + /// <summary> - /// Attempts to authenticate users by forwarding them to an external website, and - /// upon succcess or failure, redirect users back to the specified url. + /// Attempts to authenticate users by forwarding them to an external website, and upon succcess or failure, redirect users back to the specified url. /// </summary> - /// <param name="context">The context of the current request.</param> - /// <param name="returnUrl">The return url after users have completed authenticating against external website.</param> + /// <param name="context"> + /// The context of the current request. + /// </param> + /// <param name="returnUrl"> + /// The return url after users have completed authenticating against external website. + /// </param> void RequestAuthentication(HttpContextBase context, Uri returnUrl); /// <summary> /// Check if authentication succeeded after user is redirected back from the service provider. /// </summary> - /// <param name="context">The context of the current request.</param> + /// <param name="context"> + /// The context of the current request. + /// </param> /// <returns> - /// An instance of <see cref="AuthenticationResult"/> containing authentication result. + /// An instance of <see cref="AuthenticationResult"/> containing authentication result. /// </returns> AuthenticationResult VerifyAuthentication(HttpContextBase context); + #endregion } } diff --git a/src/DotNetOpenAuth.AspNet/IOpenAuthDataProvider.cs b/src/DotNetOpenAuth.AspNet/IOpenAuthDataProvider.cs index 194b02d..9b3f8c2 100644 --- a/src/DotNetOpenAuth.AspNet/IOpenAuthDataProvider.cs +++ b/src/DotNetOpenAuth.AspNet/IOpenAuthDataProvider.cs @@ -5,7 +5,25 @@ //----------------------------------------------------------------------- namespace DotNetOpenAuth.AspNet { + /// <summary> + /// The i open auth data provider. + /// </summary> public interface IOpenAuthDataProvider { + #region Public Methods and Operators + + /// <summary> + /// The get user name from open auth. + /// </summary> + /// <param name="openAuthProvider"> + /// The open auth provider. + /// </param> + /// <param name="openAuthId"> + /// The open auth id. + /// </param> + /// <returns> + /// The get user name from open auth. + /// </returns> string GetUserNameFromOpenAuth(string openAuthProvider, string openAuthId); + #endregion } -}
\ No newline at end of file +} diff --git a/src/DotNetOpenAuth.AspNet/OpenAuthAuthenticationTicketHelper.cs b/src/DotNetOpenAuth.AspNet/OpenAuthAuthenticationTicketHelper.cs index 1c8d210..496e420 100644 --- a/src/DotNetOpenAuth.AspNet/OpenAuthAuthenticationTicketHelper.cs +++ b/src/DotNetOpenAuth.AspNet/OpenAuthAuthenticationTicketHelper.cs @@ -15,17 +15,26 @@ namespace DotNetOpenAuth.AspNet { /// Helper methods for setting and retrieving a custom forms authentication ticket for delegation protocols. /// </summary> internal static class OpenAuthAuthenticationTicketHelper { + #region Constants and Fields + + /// <summary> + /// The open auth cookie token. + /// </summary> private const string OpenAuthCookieToken = "OpenAuth"; - public static void SetAuthenticationTicket(HttpContextBase context, string userName, bool createPersistentCookie) { - if (!context.Request.IsSecureConnection && FormsAuthentication.RequireSSL) { - throw new HttpException(WebResources.ConnectionNotSecure); - } + #endregion - HttpCookie cookie = GetAuthCookie(userName, createPersistentCookie); - context.Response.Cookies.Add(cookie); - } + #region Public Methods and Operators + /// <summary> + /// The is valid authentication ticket. + /// </summary> + /// <param name="context"> + /// The context. + /// </param> + /// <returns> + /// The is valid authentication ticket. + /// </returns> public static bool IsValidAuthenticationTicket(HttpContextBase context) { HttpCookie cookie = context.Request.Cookies[FormsAuthentication.FormsCookieName]; if (cookie == null) { @@ -33,7 +42,7 @@ namespace DotNetOpenAuth.AspNet { } string encryptedCookieData = cookie.Value; - if (String.IsNullOrEmpty(encryptedCookieData)) { + if (string.IsNullOrEmpty(encryptedCookieData)) { return false; } @@ -45,28 +54,68 @@ namespace DotNetOpenAuth.AspNet { } } + /// <summary> + /// The set authentication ticket. + /// </summary> + /// <param name="context"> + /// The context. + /// </param> + /// <param name="userName"> + /// The user name. + /// </param> + /// <param name="createPersistentCookie"> + /// The create persistent cookie. + /// </param> + /// <exception cref="HttpException"> + /// </exception> + public static void SetAuthenticationTicket(HttpContextBase context, string userName, bool createPersistentCookie) { + if (!context.Request.IsSecureConnection && FormsAuthentication.RequireSSL) { + throw new HttpException(WebResources.ConnectionNotSecure); + } + + HttpCookie cookie = GetAuthCookie(userName, createPersistentCookie); + context.Response.Cookies.Add(cookie); + } + + #endregion + + #region Methods + + /// <summary> + /// The get auth cookie. + /// </summary> + /// <param name="userName"> + /// The user name. + /// </param> + /// <param name="createPersistentCookie"> + /// The create persistent cookie. + /// </param> + /// <returns> + /// </returns> + /// <exception cref="HttpException"> + /// </exception> private static HttpCookie GetAuthCookie(string userName, bool createPersistentCookie) { - Debug.Assert(!String.IsNullOrEmpty(userName)); + Debug.Assert(!string.IsNullOrEmpty(userName)); var ticket = new FormsAuthenticationTicket( - /* version */ 2, - userName, - DateTime.Now, - DateTime.Now.Add(FormsAuthentication.Timeout), - createPersistentCookie, - OpenAuthCookieToken, - FormsAuthentication.FormsCookiePath); + /* version */ + 2, + userName, + DateTime.Now, + DateTime.Now.Add(FormsAuthentication.Timeout), + createPersistentCookie, + OpenAuthCookieToken, + FormsAuthentication.FormsCookiePath); string encryptedTicket = FormsAuthentication.Encrypt(ticket); if (encryptedTicket == null || encryptedTicket.Length < 1) { throw new HttpException(WebResources.FailedToEncryptTicket); } - var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket) { - HttpOnly = true, - Path = FormsAuthentication.FormsCookiePath, - Secure = FormsAuthentication.RequireSSL - }; + var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket) + { + HttpOnly = true, Path = FormsAuthentication.FormsCookiePath, Secure = FormsAuthentication.RequireSSL + }; if (FormsAuthentication.CookieDomain != null) { cookie.Domain = FormsAuthentication.CookieDomain; @@ -78,5 +127,7 @@ namespace DotNetOpenAuth.AspNet { return cookie; } + + #endregion } -}
\ No newline at end of file +} diff --git a/src/DotNetOpenAuth.AspNet/OpenAuthSecurityManager.cs b/src/DotNetOpenAuth.AspNet/OpenAuthSecurityManager.cs index fefa3f5..6851c6d 100644 --- a/src/DotNetOpenAuth.AspNet/OpenAuthSecurityManager.cs +++ b/src/DotNetOpenAuth.AspNet/OpenAuthSecurityManager.cs @@ -7,7 +7,6 @@ namespace DotNetOpenAuth.AspNet { using System; using System.Diagnostics.CodeAnalysis; - using System.Diagnostics.Contracts; using System.Web; using DotNetOpenAuth.Messaging; @@ -15,104 +14,161 @@ namespace DotNetOpenAuth.AspNet { /// Manage authenticating with an external OAuth or OpenID provider /// </summary> public class OpenAuthSecurityManager { + #region Constants and Fields + + /// <summary> + /// The provider query string name. + /// </summary> private const string ProviderQueryStringName = "__provider__"; - private readonly HttpContextBase _requestContext; - private readonly IOpenAuthDataProvider _dataProvider; + /// <summary> + /// The _authentication provider. + /// </summary> private readonly IAuthenticationClient _authenticationProvider; /// <summary> + /// The _data provider. + /// </summary> + private readonly IOpenAuthDataProvider _dataProvider; + + /// <summary> + /// The _request context. + /// </summary> + private readonly HttpContextBase _requestContext; + + #endregion + + #region Constructors and Destructors + + /// <summary> /// Initializes a new instance of the <see cref="OpenAuthSecurityManager"/> class. /// </summary> - /// <param name="requestContext">The request context.</param> - public OpenAuthSecurityManager(HttpContextBase requestContext) : - this(requestContext, provider: null, dataProvider: null) { - } + /// <param name="requestContext"> + /// The request context. + /// </param> + public OpenAuthSecurityManager(HttpContextBase requestContext) + : this(requestContext, provider: null, dataProvider: null) {} /// <summary> /// Initializes a new instance of the <see cref="OpenAuthSecurityManager"/> class. /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="provider">The provider.</param> - /// <param name="dataProvider">The data provider.</param> - public OpenAuthSecurityManager(HttpContextBase requestContext, IAuthenticationClient provider, IOpenAuthDataProvider dataProvider) { + /// <param name="requestContext"> + /// The request context. + /// </param> + /// <param name="provider"> + /// The provider. + /// </param> + /// <param name="dataProvider"> + /// The data provider. + /// </param> + public OpenAuthSecurityManager( + HttpContextBase requestContext, IAuthenticationClient provider, IOpenAuthDataProvider dataProvider) { if (requestContext == null) { throw new ArgumentNullException("requestContext"); } - _requestContext = requestContext; - _dataProvider = dataProvider; - _authenticationProvider = provider; + this._requestContext = requestContext; + this._dataProvider = dataProvider; + this._authenticationProvider = provider; } + #endregion + + #region Public Properties + /// <summary> - /// Requests the specified provider to start the authentication by directing users to an external website + /// Gets a value indicating whether IsAuthenticatedWithOpenAuth. /// </summary> - /// <param name="returnUrl">The return url after user is authenticated.</param> - public void RequestAuthentication(string returnUrl) { - // convert returnUrl to an absolute path - Uri uri; - if (!String.IsNullOrEmpty(returnUrl)) { - uri = UriHelper.ConvertToAbsoluteUri(returnUrl, _requestContext); - } else { - uri = HttpRequestInfo.GetPublicFacingUrl(_requestContext.Request, _requestContext.Request.ServerVariables); + public bool IsAuthenticatedWithOpenAuth { + get { + return this._requestContext.Request.IsAuthenticated + && OpenAuthAuthenticationTicketHelper.IsValidAuthenticationTicket(this._requestContext); } - // attach the provider parameter so that we know which provider initiated - // the login when user is redirected back to this page - uri = uri.AttachQueryStringParameter(ProviderQueryStringName, _authenticationProvider.ProviderName); - _authenticationProvider.RequestAuthentication(_requestContext, uri); } - public static string GetProviderName(HttpContextBase context) { - return context.Request.QueryString[ProviderQueryStringName]; - } + #endregion + + #region Public Methods and Operators /// <summary> - /// Checks if user is successfully authenticated when user is redirected back to this user. + /// The get provider name. /// </summary> - /// <returns></returns> - public AuthenticationResult VerifyAuthentication() { - AuthenticationResult result = _authenticationProvider.VerifyAuthentication(_requestContext); - if (!result.IsSuccessful) { - // if the result is a Failed result, creates a new Failed response which has providerName info. - result = new AuthenticationResult(isSuccessful: false, - provider: _authenticationProvider.ProviderName, - providerUserId: null, - userName: null, - extraData: null); - } - - return result; + /// <param name="context"> + /// The context. + /// </param> + /// <returns> + /// The get provider name. + /// </returns> + public static string GetProviderName(HttpContextBase context) { + return context.Request.QueryString[ProviderQueryStringName]; } /// <summary> - /// Checks if the specified provider user id represents a valid account. - /// If it does, log user in. + /// Checks if the specified provider user id represents a valid account. If it does, log user in. /// </summary> - /// <param name="providerUserId">The provider user id.</param> - /// <param name="createPersistentCookie">if set to <c>true</c> create persistent cookie.</param> + /// <param name="providerUserId"> + /// The provider user id. + /// </param> + /// <param name="createPersistentCookie"> + /// if set to <c>true</c> create persistent cookie. + /// </param> /// <returns> - /// <c>true</c> if the login is successful. + /// <c>true</c> if the login is successful. /// </returns> - [SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "Login", Justification = "Login is used more consistently in ASP.Net")] + [SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "Login", + Justification = "Login is used more consistently in ASP.Net")] public bool Login(string providerUserId, bool createPersistentCookie) { - string userName = _dataProvider.GetUserNameFromOpenAuth(_authenticationProvider.ProviderName, providerUserId); - if (String.IsNullOrEmpty(userName)) { + string userName = this._dataProvider.GetUserNameFromOpenAuth( + this._authenticationProvider.ProviderName, providerUserId); + if (string.IsNullOrEmpty(userName)) { return false; } - OpenAuthAuthenticationTicketHelper.SetAuthenticationTicket(_requestContext, userName, createPersistentCookie); + OpenAuthAuthenticationTicketHelper.SetAuthenticationTicket(this._requestContext, userName, createPersistentCookie); return true; } /// <summary> - /// Gets a value indicating whether the current user is authenticated by an OAuth & OpenID provider. + /// Requests the specified provider to start the authentication by directing users to an external website /// </summary> - public bool IsAuthenticatedWithOpenAuth { - get { - return _requestContext.Request.IsAuthenticated && - OpenAuthAuthenticationTicketHelper.IsValidAuthenticationTicket(_requestContext); + /// <param name="returnUrl"> + /// The return url after user is authenticated. + /// </param> + public void RequestAuthentication(string returnUrl) { + // convert returnUrl to an absolute path + Uri uri; + if (!string.IsNullOrEmpty(returnUrl)) { + uri = UriHelper.ConvertToAbsoluteUri(returnUrl, this._requestContext); + } else { + uri = HttpRequestInfo.GetPublicFacingUrl(this._requestContext.Request, this._requestContext.Request.ServerVariables); } + + // attach the provider parameter so that we know which provider initiated + // the login when user is redirected back to this page + uri = uri.AttachQueryStringParameter(ProviderQueryStringName, this._authenticationProvider.ProviderName); + this._authenticationProvider.RequestAuthentication(this._requestContext, uri); } + + /// <summary> + /// Checks if user is successfully authenticated when user is redirected back to this user. + /// </summary> + /// <returns> + /// </returns> + public AuthenticationResult VerifyAuthentication() { + AuthenticationResult result = this._authenticationProvider.VerifyAuthentication(this._requestContext); + if (!result.IsSuccessful) { + // if the result is a Failed result, creates a new Failed response which has providerName info. + result = new AuthenticationResult( + isSuccessful: false, + provider: this._authenticationProvider.ProviderName, + providerUserId: null, + userName: null, + extraData: null); + } + + return result; + } + + #endregion } -}
\ No newline at end of file +} diff --git a/src/DotNetOpenAuth.AspNet/Properties/AssemblyInfo.cs b/src/DotNetOpenAuth.AspNet/Properties/AssemblyInfo.cs index 30776c7..dac3fa4 100644 --- a/src/DotNetOpenAuth.AspNet/Properties/AssemblyInfo.cs +++ b/src/DotNetOpenAuth.AspNet/Properties/AssemblyInfo.cs @@ -1,4 +1,12 @@ -using System.Reflection; +//----------------------------------------------------------------------- +// <copyright file="AssemblyInfo.cs" company=""> +// +// </copyright> +//----------------------------------------------------------------------- + + + +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -23,7 +31,11 @@ using System.Runtime.InteropServices; [assembly: Guid("c89b7e57-2735-4407-bcb9-dfe9bb9493a2")] #if StrongNameSigned -[assembly: InternalsVisibleTo("DotNetOpenAuth.AspNet.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998")] + +[assembly: + InternalsVisibleTo( + "DotNetOpenAuth.AspNet.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998" + )] #else [assembly: InternalsVisibleTo("DotNetOpenAuth.AspNet.Test")] -#endif
\ No newline at end of file +#endif diff --git a/src/DotNetOpenAuth.AspNet/UriHelper.cs b/src/DotNetOpenAuth.AspNet/UriHelper.cs index 300c662..53a5c7f 100644 --- a/src/DotNetOpenAuth.AspNet/UriHelper.cs +++ b/src/DotNetOpenAuth.AspNet/UriHelper.cs @@ -10,23 +10,26 @@ namespace DotNetOpenAuth.AspNet { using System.Web; using DotNetOpenAuth.Messaging; + /// <summary> + /// The uri helper. + /// </summary> internal static class UriHelper { + #region Public Methods and Operators + /// <summary> - /// Attaches the query string '__provider' to an existing url. If the url already - /// contains the __provider query string, it overrides it with the specified provider name. + /// The attach query string parameter. /// </summary> - /// <param name="url">The original url.</param> - /// <param name="providerName">Name of the provider.</param> - /// <returns>The new url with the provider name query string attached</returns> - /// <example> - /// If the url is: http://contoso.com, and providerName='facebook', the returned value is: http://contoso.com?__provider=facebook - /// If the url is: http://contoso.com?a=1, and providerName='twitter', the returned value is: http://contoso.com?a=1&__provider=twitter - /// If the url is: http://contoso.com?a=1&__provider=twitter, and providerName='linkedin', the returned value is: http://contoso.com?a=1&__provider=linkedin - /// </example> - /// <remarks> - /// The reason we have to do this is so that when the external service provider forwards user - /// back to our site, we know which provider it comes back from. - /// </remarks> + /// <param name="url"> + /// The url. + /// </param> + /// <param name="parameterName"> + /// The parameter name. + /// </param> + /// <param name="parameterValue"> + /// The parameter value. + /// </param> + /// <returns> + /// </returns> public static Uri AttachQueryStringParameter(this Uri url, string parameterName, string parameterValue) { UriBuilder builder = new UriBuilder(url); string query = builder.Query; @@ -44,8 +47,10 @@ namespace DotNetOpenAuth.AspNet { if (newQuery.Length > 0) { newQuery += "&"; } + newQuery = newQuery + parameterPrefix + encodedParameterValue; } + builder.Query = newQuery; return builder.Uri; @@ -54,8 +59,14 @@ namespace DotNetOpenAuth.AspNet { /// <summary> /// Converts an app-relative url, e.g. ~/Content/Return.cshtml, to a full-blown url, e.g. http://mysite.com/Content/Return.cshtml /// </summary> - /// <param name="returnUrl">The return URL.</param> - /// <returns></returns> + /// <param name="returnUrl"> + /// The return URL. + /// </param> + /// <param name="context"> + /// The context. + /// </param> + /// <returns> + /// </returns> public static Uri ConvertToAbsoluteUri(string returnUrl, HttpContextBase context) { if (Uri.IsWellFormedUriString(returnUrl, UriKind.Absolute)) { return new Uri(returnUrl, UriKind.Absolute); @@ -68,5 +79,7 @@ namespace DotNetOpenAuth.AspNet { Uri publicUrl = HttpRequestInfo.GetPublicFacingUrl(context.Request, context.Request.ServerVariables); return new Uri(publicUrl, returnUrl); } + + #endregion } -}
\ No newline at end of file +} |