Skip to content

Instantly share code, notes, and snippets.

@promontis
Created September 8, 2014 19:41
Show Gist options
  • Save promontis/cf2fd7063f800c8d0e43 to your computer and use it in GitHub Desktop.
Save promontis/cf2fd7063f800c8d0e43 to your computer and use it in GitHub Desktop.
public class FacebookConnectAssertionGrantValidator : IAssertionGrantValidator
{
private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string";
private const string GraphApiEndpoint = "https://graph.facebook.com/me";
private readonly static ILog Logger = LogProvider.GetCurrentClassLogger();
private readonly IExternalClaimsFilter _externalClaimsFilter;
public FacebookConnectOptions Options { get; set; }
public FacebookConnectAssertionGrantValidator(FacebookConnectOptions options)
{
Options = options;
_externalClaimsFilter = new DefaultExternalClaimsFilter();
}
public async Task<ClaimsPrincipal> ValidateAsync(ValidatedTokenRequest request, IUserService userService)
{
if (request.GrantType == "facebook_connect")
{
var accessToken = request.Assertion;
using (var httpClient = new HttpClient())
{
string graphAddress = GraphApiEndpoint + "?access_token=" + Uri.EscapeDataString(accessToken);
HttpResponseMessage graphResponse = await httpClient.GetAsync(graphAddress);
graphResponse.EnsureSuccessStatusCode();
var text = await graphResponse.Content.ReadAsStringAsync();
JObject user = JObject.Parse(text);
var context = new FacebookAuthenticatedContext(null, user, accessToken, "");
context.Identity = new ClaimsIdentity(
Options.AuthenticationType,
ClaimsIdentity.DefaultNameClaimType,
ClaimsIdentity.DefaultRoleClaimType);
if (!string.IsNullOrEmpty(context.Id))
{
context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, context.Id, XmlSchemaString,
Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.UserName))
{
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.UserName,
XmlSchemaString, Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.Email))
{
context.Identity.AddClaim(new Claim(ClaimTypes.Email, context.Email, XmlSchemaString,
Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.Name))
{
context.Identity.AddClaim(new Claim("urn:facebook:name", context.Name, XmlSchemaString,
Options.AuthenticationType));
// Many Facebook accounts do not set the UserName field. Fall back to the Name field instead.
if (string.IsNullOrEmpty(context.UserName))
{
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.Name,
XmlSchemaString, Options.AuthenticationType));
}
}
if (!string.IsNullOrEmpty(context.Link))
{
context.Identity.AddClaim(new Claim("urn:facebook:link", context.Link, XmlSchemaString,
Options.AuthenticationType));
}
await Options.Provider.Authenticated(context);
var externalIdentity = MapToExternalIdentity(context.Identity.Claims);
if (externalIdentity == null)
{
Logger.Error("no subject or unique identifier claims from external identity provider");
}
Logger.InfoFormat("external user provider: {0}, provider ID: {1}", externalIdentity.Provider,
externalIdentity.ProviderId);
var authResult = await userService.AuthenticateExternalAsync(context.Id, externalIdentity);
return IdentityServerPrincipal.Create(authResult.Subject, authResult.Name, "external", authResult.Provider);
}
}
return null;
}
private ExternalIdentity MapToExternalIdentity(IEnumerable<Claim> claims)
{
var externalId = ExternalIdentity.FromClaims(claims);
if (externalId != null && _externalClaimsFilter != null)
{
externalId.Claims = _externalClaimsFilter.Filter(externalId.Provider, externalId.Claims);
}
return externalId;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment