using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Web; namespace DotNetOpenAuth.Web.Clients { /// /// Represents the base class for OAuth 2.0 clients /// public abstract class OAuth2Client : IAuthenticationClient { private readonly string _providerName; private Uri _returnUrl; /// /// Initializes a new instance of the class with the specified provider name. /// /// Name of the provider. protected OAuth2Client(string providerName) { if (providerName == null) { throw new ArgumentNullException("providerName"); } _providerName = providerName; } /// /// Gets the name of the provider which provides authentication service. /// public string ProviderName { get { return _providerName; } } /// /// Attempts to authenticate users by forwarding them to an external website, and /// upon succcess or failure, redirect users back to the specified url. /// /// The return url after users have completed authenticating against external website. public virtual void RequestAuthentication(HttpContextBase context, Uri returnUrl) { if (context == null) { throw new ArgumentNullException("context"); } if (returnUrl == null) { throw new ArgumentNullException("returnUrl"); } _returnUrl = returnUrl; string redirectUrl = GetServiceLoginUrl(returnUrl).ToString(); context.Response.Redirect(redirectUrl, endResponse: true); } /// /// Check if authentication succeeded after user is redirected back from the service provider. /// /// /// An instance of containing authentication result. /// public virtual AuthenticationResult VerifyAuthentication(HttpContextBase context) { if (context == null) { throw new ArgumentNullException("context"); } string code = context.Request.QueryString["code"]; if (String.IsNullOrEmpty(code)) { return AuthenticationResult.Failed; } string accessToken = QueryAccessToken(_returnUrl, code); if (accessToken == null) { return AuthenticationResult.Failed; } IDictionary userData = 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)) { name = id; } return new AuthenticationResult( isSuccessful: true, provider: ProviderName, providerUserId: id, userName: name, extraData: userData); } /// /// 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. /// /// The return URL. /// [SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "Login", Justification = "Login is used more consistently in ASP.Net")] protected abstract Uri GetServiceLoginUrl(Uri returnUrl); /// /// Queries the access token from the specified authorization code. /// /// The return URL. /// The authorization code. /// protected abstract string QueryAccessToken(Uri returnUrl, string authorizationCode); /// /// Given the access token, gets the logged-in user's data. The returned dictionary must include /// two keys 'id', and 'username'. /// /// The access token of the current user. /// A dictionary contains key-value pairs of user data protected abstract IDictionary GetUserData(string accessToken); } }