using Auction.Web.Domain;
using Auction.Web.Domain.Commands;
using Auction.Web.Domain.Entities;
using Auction.Web.Domain.Queries;
using Facebook;
using Microsoft.Web.WebPages.OAuth;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Web;
using System.Web.Routing;
namespace Auction.Web.Areas.Facebook
{
public static class FacebookAuth
{
public const string facebookCustomAuth = "FacebookCustomAuth";
public const string FacebookAccessToken = "http://www.facebook.com/claims/AccessToken";
public static bool InFacebookArea(HttpRequest request)
{
return (request.Url.Segments.Length >= 2 && request.Url.Segments[1].TrimEnd('/').Equals("facebook", StringComparison.InvariantCultureIgnoreCase));
}
public static bool InFacebookArea(HttpRequestBase request)
{
return (request.Url.Segments.Length >= 2 && request.Url.Segments[1].TrimEnd('/').Equals("facebook", StringComparison.InvariantCultureIgnoreCase));
}
public static RouteValueDictionary CombineRouteValues(HttpContextBase context, RouteValueDictionary routeValues)
{
if (context.User != null && context.User.Identity != null && context.User.Identity.AuthenticationType == facebookCustomAuth)
{
var principal = context.User as ClaimsPrincipal;
routeValues["username"] = principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name).Value;
routeValues["token"] = principal.Claims.FirstOrDefault(c => c.Type == FacebookAccessToken).Value;
routeValues["area"] = "Facebook";
}
return routeValues;
}
public static RouteValueDictionary CombineRouteValues(HttpContextBase context, object routeValues)
{
var routeValueResult = new RouteValueDictionary(routeValues);
return CombineRouteValues(context, routeValueResult);
}
public static Uri GetLoginUrl(Uri requestUri, string[] scope = null, string state = null, bool isMobile = false)
{
string redirectUri = "https://apps.facebook.com/" + ConfigurationManager.AppSettings["FacebookNamespace"];
var parameters = new Dictionary<string, object>();
parameters["client_id"] = ConfigurationManager.AppSettings["FacebookAppId"];
// TODO: combine requestUri
parameters["redirect_uri"] = redirectUri.ToString();
if (scope != null && scope.Length > 0)
parameters["scope"] = scope;
if (!string.IsNullOrWhiteSpace(state))
parameters["state"] = state;
if (isMobile)
parameters["mobile"] = true;
var client = new FacebookClient();
return client.GetLoginUrl(parameters);
}
public static void AuthenticateRequest(HttpApplication context)
{
// int userId;
string userName;
string authToken;
HttpRequest request = context.Request;
// Facebook canvas apps lives inside an iframe, therefore when third party cookies are blocked, sessions do not work!
// Facebook posts user data in its first iframe request to the app.
// We get the fb auth_token and our userid, save those in the HttpContext and pass them in each and every link or form action that happen inside /Facebook
if (InFacebookArea(request))
{
if (request["token"] != null && request["username"] != null)
{
// Save them into the http context
authToken = request["token"].ToString();
userName = request["username"].ToString();
if (context.Context.User == null)
{
// user is not authenticated yet -> set user to facebook principal
//var userIdentity = new FacebookIdentity(userId, authToken, "Facebook user");
//var principal = new FacebookPrincipal(userIdentity);
var userIdentity = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, userName),
new Claim(FacebookAccessToken, authToken),
new Claim(ClaimTypes.Role, "Facebook")
}, facebookCustomAuth);
var principal = new ClaimsPrincipal(new[] { userIdentity });
context.Context.User = principal;
Thread.CurrentPrincipal = principal;
}
}
else if (request["signed_request"] != null)
{
var client = new FacebookClient();
var signedRequest = client.ParseSignedRequest(ConfigurationManager.AppSettings["FacebookAppSecret"], request["signed_request"]);
if (signedRequest == null)
throw new ArgumentNullException("signedRequest");
var dict = signedRequest as IDictionary<string, object>;
if (dict != null)
{
if (dict.ContainsKey("oauth_token"))
{
authToken = (string)dict["oauth_token"];
client.AccessToken = authToken;
dynamic result = client.Get("me", new { fields = new[] { "email" } });
string fbUserId = result.id;
using (var ctx = new DomainContext())
{
var user = ctx.Query(new GetUserByClaims("facebook", result.id));
if (user != null)
{
// returning user -> get id from database
userName = user.UserName;
}
else
{
// check if we have this email in our database already (from normal site)
user = ctx.Query(new GetUserByName(result.email));
if (user != null)
{
userName = user.UserName;
}
else
{
// new user -> save to database with email as the unique name
userName = result.email;
// will throw if username exists
ctx.ExecuteCommand(new CreateUser(new UserProfile { UserName = userName }));
}
OAuthWebSecurity.CreateOrUpdateAccount("facebook", fbUserId, userName); // links OAuth to UserProfile based on the username, not on UserId
OAuthWebSecurity.Login("facebook", fbUserId, createPersistentCookie: false);
}
}
if (context.Context.User == null)
{
// Now set the HttpContext.User.Identity
var userIdentity = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, userName),
new Claim(FacebookAccessToken, authToken),
new Claim(ClaimTypes.Role, "Facebook")
}, facebookCustomAuth);
var principal = new ClaimsPrincipal(new[] { userIdentity });
context.Context.User = principal;
Thread.CurrentPrincipal = principal;
}
}
}
else
{
throw new ArgumentException("Cannot read signed_request!");
}
}
}
}
}
}