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);
}
}