Restrict access to all asp.net pages - asp.net

I am mainlining one asp.net Project, this project is configured in IIS. The website is open for everyone, when i review the code in asp.net page, its checking window login "enterprise id" and allowing all users to view the all the aspx pages.
Now, my management team requested us to restrict those who are under junior level employees.(Junior engg, Developer, software engg).
I have written the query, passing enterprise id and validate grade, if its junior level , returning "0" values,else returning "1" values.
My questions is, I do not want go and edit each page and check this query and restrict each page.
can you please suggest , how can i implement simplest and best way to restric the users.
Thanks,
--------------------------------------- Update on 09/24/2015
Index.aspx
protected void Page_Load(object sender, EventArgs e)
{
string UserStatus = UtilFunctions.ValidateUser();
Response.Write(UserStatus);
if (UserStatus == "0")
{
Response.Write("<div><font color=red><h1>You are not authorized to view this page</h1></font></div>");
Response.End();
}
}
Utilifunctions.cs
public static String ValidateUser()
{
string CurrentUser = getLoggedOnUser();
using (System.Data.SqlClient.SqlConnection myConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["TestDB"].ConnectionString))
{
using (SqlCommand myCommand = myConnection.CreateCommand())
{
myConnection.Open();//Opens the Connection
myCommand.CommandText = "Select Permission From Temp_Validate Where EnterpriseId='" + CurrentUser + "'";
SqlDataReader IDReader = myCommand.ExecuteReader(); //Gets the ID
IDReader.Read();
string UserStatus = IDReader["Permission"].ToString();
IDReader.Close();
return UserStatus;
}
}
I implemented the above functionalite in my index.aspx page, if the userstatus equal to "0" , it will display the "You are not authrized to view this message" and it will end.
I have around 30 aspx page,its currently running in Production. I do not want go include the same code (index.aspx) in every page load to stop the user validation.
could you please suggest how can i implement without editing all pages.
Updated on 09/28 : Utilifunction.cs
public static String getLoggedOnUser()
{
String user = HttpContext.Current.User.Identity.Name.Substring(HttpContext.Current.User.Identity.Name.IndexOf("\\") + 1);
if (user == "") user = "anonymous";
string UserStatus = IsValidUser(user);
if (UserStatus == "0")
{
HttpContext.Current.Response.Redirect("PSF_Error.aspx", true);
}
return user;
}
public static String IsValidUser(string currentUser)
{
using (System.Data.SqlClient.SqlConnection myConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["Test"].ConnectionString))
{
using (SqlCommand myCommand = myConnection.CreateCommand())
{
//Gets email of the creator of current user
myConnection.Open();//Opens the Connection
myCommand.CommandText = "Select Permission From Temp_Validate Where EnterpriseId='" + currentUser + "'";
SqlDataReader IDReader = myCommand.ExecuteReader(); //Gets the ID
IDReader.Read();
string UserStatus = IDReader["Permission"].ToString();
IDReader.Close();
return UserStatus;
}
}
}
Index.aspx
Page_load
{
string CurrentUser = UtilFunctions.getLoggedOnUser();
}

You have a few options, here:
1) Set up role-based access with Owin or AspNet.Identity. This is probably your best option, but I couldn't find a good tutorial for you. Those packages are well-documented, however, and I'm sure you can figure them out with some effort.
2) Build a Roles table, and customize access yourself. The best example I found was here: http://www.codeproject.com/Articles/875547/Custom-Roles-Based-Access-Control-RBAC-in-ASP-NET
3) Redirect unauthorized users without the use of roles. So something like:
public ActionResult SecurePage(User u)
{
if(u.level == "junior"){
return RedirectToAction("CustomErrorPage");
} else {
return View();
}
}
I'm not sure that that option is terribly secure, but it should work.
Hope that helps!

after setting up roles you can use a web.config file in every directory specifying authorization and/or use the 'location' element in the web.config file.

First off, sorry about the confusing code. I've been using MVC, and you've clearly posted your code behind.
I don't think that you can achieve what you are trying to do, without adding your code to each page, or learning about roles. You could reduce some code duplication in a number of clever ways, but I can't think of anything that doesn't seem like a total hack.
If you want to, say, put all of your secure pages in the same directory, and restrict low-level access to that directory, you are going to have to filter by specific users or, if you can implement them, roles. As I understand it, the deny and allow nodes in your web.config file are setting server side (so IIS, probably) authorization rules, so the keywords and rules you can use are limited. Check this page out, for some basics:
http://weblogs.asp.net/gurusarkar/setting-authorization-rules-for-a-particular-page-or-folder-in-web-config
While it is likely POSSIBLE to build a rule based on values in your DB, doing so would probably be far more work than it would be worth.
Sorry that I can't offer a more satisfactory answer, but I would recommend: 1) Get to work, and add a check to the code behind for each page, or 2) (and I highly suggest this option) close this question, and post another, about implementing roles in .net, and assigning roles to users, in code. If, say, you can use your login page to assign every junior-level user the custom role of Junior, and place all of your secure pages in a directory named SecurePages you could add the following code to your web.config, and achieve exactly what you are trying to do:
<location path="SecurePages">
<system.web>
<authorization>
<deny roles="Junior">
<deny users="*">
</authorization></system.web></location>
Good luck!

Related

Inconsistent results when listing groups an external account belongs to

Our Google domain has groups (synced copies of our Active Directory email listservs/distribution groups) that have a lot of external accounts (currently kept as contacts in Active Directory).
As part of an intranet site I'm building I'm trying to be able to do mass search and replace of individual contact email address when for example a school district changes its domain name. One of the visual/verification steps I'm working on is to list the Google group membership of any selected external account, but I'm getting mixed results. For some accounts it seems to list the groups properly, and for others it doesn't seem to pull any. I have verified the external account's group membership in both Active Directory and in Google Admin group management, but when I query Google via code I don't get valid results every time... What am I missing? Code below.
-- in Global.asax
public static List<string> GOOGLE_GetListOfUsersGroups(string useremail)
{
List<string> groupList = new List<string>();
try
{
///stripped out credential/service stuff...
var groups = service.Groups.List();
groups.UserKey = useremail;
Groups gs = groups.Execute();
if (gs != null)
{
foreach (Google.Apis.Admin.Directory.directory_v1.Data.Group g in gs.GroupsValue)
groupList.Add(g.Email);
}
}
catch (Exception ex)
{
SendERROREmail("GLOBAL<HR>GOOGLE_GetListOfUsersGroups()<HR>useremail:" + useremail + "<HR>" + ex.ToString());
}
return groupList;
}
and the consuming function:
--- in Page.aspx
protected void ddlADExternalContacts_SelectedIndexChanged(object sender, EventArgs e)
{
lbContactsGoogleGroups.Items.Clear();
if (ddlADExternalContacts.SelectedIndex > 0)
{
//show what google has for same group
List<string> memberList = Global.GOOGLE_GetListOfUsersGroups(ddlADExternalContacts.SelectedValue);
if (memberList != null)
{
foreach (string s in memberList)
lbContactsGoogleGroups.Items.Add(new ListItem(s, s));
}
}
}
Also, does anyone have a good example how to handle this in Google's 'preferred' JSON format rather then the API route?
UPDATE: Ok, its not my code, its something with the group/Google. When I use the 'try it' functionality on the sdk admin site I get the same results for groups that work (in my code and their site) and no results from the same groups that should be showing results...
{
"kind": "admin#directory#groups",
"etag": "\"HKdfSgTnCxrWl3RtRnlZSCPY3NjdWJxz53nrhwSz7ob4/oMWMqbsluP5m2PCo8Y7WmWeHGP4\""
}
Not that that helps me any, as there's no error or anything, just the 'no groups' result as if it can't find the external account...
UPDATE2: Ok, based on what I'm seeing after some testing, I have a sneaky suspicion that Google is doing some validation of emails before checking for group membership and reporting anything. I.E. if the email being searched for is no longer valid (client's server doesn't responds that the account is reachable/enabled/exists...), it won't bother going any further... will try it out with a few more email addresses that I know should be invalid and update....later.
It looks like what you are experiencing might be a bug.
This has been reported on Google Issue Tracker here.
What you can do in this situation is to star the issue above and eventually add a comment saying that you are affected by it.

.Net Core 3.1 Razor Pages : autoredirect to culture

I try to accomplish a similar behaviour with MS Docs.
For example, if you visit https://learn.microsoft.com/, you will be redirected to your culture, in my case I'm being redirected automatically to https://learn.microsoft.com/en-gb/.
Same goes for inner pages if you access them without the culture in the URL.
For instance, by accessing:
https://learn.microsoft.com/aspnet/core/razor-pages/?view=aspnetcore-3.1&tabs=visual-studio
it will be automatically redirect you to:
https://learn.microsoft.com/en-gb/aspnet/core/razor-pages/?view=aspnetcore-3.1&tabs=visual-studio
I have a small demo app where I conduct my localisation experiment for .NET Core 3.1 and Razor Pages here.
I have set options.Conventions here, and I have created CustomCultureRouteRouteModelConvention class here, but I'm fairly novice with .NET Core and I'm kind of stuck on how to implement the above-described functionality.
Thank you all in advance!
You should use existing Rewriting Middleware to do redirects: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting?view=aspnetcore-3.1
In the simplest form, you can tell rewrite middleware to redirect if it does not see a locale pattern at the beginning of the URL path, maybe
new RewriteOptions() .AddRedirect("^([a-z]{2}-[a-z]{2})", "en-US/$1")
(regex not tested) or do full redirect class with more detailed rules when and to what locale you want to redirect. Example in that aspnet document references RedirectImageRequest which you can use to get an understanding of how custom redirect rules works. Adapting to your case as a proof of concept, I reused most of the logic in your existing RedirectUnsupportedCulture:
public class RedirectUnsupportedCultures : IRule
{
private readonly string _extension;
private readonly PathString _newPath;
private IList<CultureInfo> _cultureItems;
private string _cultureRouteKey;
public RedirectUnsupportedCultures(IOptions<RequestLocalizationOptions> options)
{
RouteDataRequestCultureProvider provider = options.Value.RequestCultureProviders
.OfType<RouteDataRequestCultureProvider>()
.First();
_cultureItems = options.Value.SupportedUICultures;
_cultureRouteKey = provider.RouteDataStringKey;
}
public void ApplyRule(RewriteContext rewriteContext)
{
// do not redirect static assets and do not redirect from a controller that is meant to set the locale
// similar to how you would not restrict a guest user from login form on public site.
if (rewriteContext.HttpContext.Request.Path.Value.EndsWith(".ico") ||
rewriteContext.HttpContext.Request.Path.Value.Contains("change-culture"))
{
return;
}
IRequestCultureFeature cultureFeature = rewriteContext.HttpContext.Features.Get<IRequestCultureFeature>();
string actualCulture = cultureFeature?.RequestCulture.Culture.Name;
string requestedCulture = rewriteContext.HttpContext.GetRouteValue(_cultureRouteKey)?.ToString();
// Here you can add more rules to redirect based on maybe cookie setting, or even language options saved in database user profile
if(string.IsNullOrEmpty(requestedCulture) || _cultureItems.All(x => x.Name != requestedCulture)
&& !string.Equals(requestedCulture, actualCulture, StringComparison.OrdinalIgnoreCase))
{
string localizedPath = $"/{actualCulture}{rewriteContext.HttpContext.Request.Path.Value}";
HttpResponse response = rewriteContext.HttpContext.Response;
response.StatusCode = StatusCodes.Status301MovedPermanently;
rewriteContext.Result = RuleResult.EndResponse;
// preserve query part parameters of the URL (?parameters) if there were any
response.Headers[HeaderNames.Location] =
localizedPath + rewriteContext.HttpContext.Request.QueryString;
}
}
and registered it in Startup.cs with
// Attempt to make auto-redirect to culture if it is not exist in the url
RewriteOptions rewriter = new RewriteOptions();
rewriter.Add(new RedirectUnsupportedCultures(app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>()));
app.UseRewriter(rewriter);
Improvement:
After using the above code I bumped on a bug that in case the culture is not supported by the application, the redirection will end up with infinite culture paths. For example, if I support the cultures en (default) and gr, if instead of either /en/foobar or /gr/foobar I would write /fr/foobar, I would end up getting /en/fr/foobar then /en/en/fr/foobar and etc.
I added private readonly LinkGenerator _linkGenerator; to the class, which I initialise it in the constructor. I removed that line string localizedPath = $"/{actualCulture}{rewriteContext.HttpContext.Request.Path.Value}"; and the code after that line looks like this:
rewriteContext.HttpContext.GetRouteData().Values[_cultureRouteKey] = actualCulture;
HttpResponse response = rewriteContext.HttpContext.Response;
response.StatusCode = StatusCodes.Status301MovedPermanently;
rewriteContext.Result = RuleResult.EndResponse;
// preserve query part parameters of the URL (?parameters) if there were any
response.Headers[HeaderNames.Location] =
_linkGenerator.GetPathByAction(
rewriteContext.HttpContext,
values: rewriteContext.HttpContext.GetRouteData().Values
)
+ rewriteContext.HttpContext.Request.QueryString;
As decribed in Microsoft docs localization middleware; each the localization request initializes a list of RequestCultureProvider and is enumerated by the below order :
QueryStringRequestCultureProvider : e.g. http://localhost:1234/Index?culture=en
CookieRequestCultureProvider : Looks for the culture cookie, and it will be null if you haven't set it manually.
AcceptLanguageHeaderRequestCultureProvider : This one depends on the browsers cultures adn this is what you need to look for.
To make sure how it works, delete the culture cookie and change the browser language preferences by moving the desired language to the top, you will see that the language is selected according to the browser preferences.

ASP.NET Facebook app session issue with safari

Currently I am working on a Facebook app and it's developed by using ASP.NET.
This app works fine with IE(7,8 and 9) FF and Chrome.
The first page is default.aspx and it will handle the authentication then redirect to home.aspx
Now the only issue it has is that Safari doesn't accept cross-domain cookies. I've changed the web.config file and add it in order to avoid the use of cookies.
After that, the URL comes to
http://www.testdomain.com/(S(gvsc2i45pqvzqm3lv2xoe4zm))/default.aspx
It just can't be redirect from default.aspx to home.aspx automatically...
Anyone got a clue?
Or, is there anyway that i can deal with Safari with ASP.Net session in Facebook app?
Tons of thanks
PS. The code from default.aspx page
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
if (!string.IsNullOrEmpty(Request.Params["signed_request"]))
{
string signed_request = Request.Params["signed_request"];
if (!string.IsNullOrEmpty(signed_request))
{
// split signed request into encoded signature and payload
string[] signedRequestParts = signed_request.Split('.');
string encodedSignature = signedRequestParts[0];
string payload = signedRequestParts[1];
// decode signature
string signature = decodeSignature(encodedSignature);
// calculate signature from payload
string expectedSignature = hash_hmac(payload, Facebook.FacebookApplication.Current.AppSecret);
if (signature == expectedSignature)
{
// signature was not modified
Dictionary<string, string> parameters = DecodePayload(payload);
if (parameters != null)
{
string UserId = parameters["user_id"];
Session.Add("UserId", _SystemUser.SystemUserId);
Session.Add("Username", _SystemUser.Username);
Response.Redirect("Home.aspx?user_id=" + UserId);
}
}
}
}
if (!String.IsNullOrEmpty(Request["error_reason"])) // user denied your request to login
{
logger.Debug("Error Reason: " + Request["error_reason"]);
//User denied access
}
if (String.IsNullOrEmpty(Request["code"])) // request to login
{
string url1 = String.Format("https://www.facebook.com/dialog/oauth?client_id={0}&redirect_uri={1}&scope={2}", Facebook.FacebookApplication.Current.AppId, callbackUrl, ext_perms);
Response.Redirect(url1);
}
}
}
When using cookieless sessions, ASP.Net will automatically redirect any requests without a session ID in the URL to the same page, but with a new SessionID in the URL. However, it redirects as a GET request, and thus does not forward on any POSTED parameters ... so after the redirect your "parameters" variable, from the decoded signed_request, will be missing because the page will no longer have the signed_request POSTed parameter.
There are two possible solutions to this (that I know of):
Intercept the initial redirect in Global.ascx, and instead do your own redirect with the new SessionID in the URL ... BUT, do this as a self-posting form in Javascript where the form also has a signed_request param with the value of the signed_request.
Turn cookie sessions back on, and in your first page redirect out of FB to a page. In this page set a Session variable (which will get ASP.Net to set a session cookie), and then redirect back into FB.
You may/will also need some code to handle any app_data, if this is on a tab page too.
Sorry I can't be more useful code wise. I've written my own handlers for my job, but my workplace now owns that code! I'm never sure how much is OK to share.
I used cookieless session, but as the initial page was getting refreshed, the Facebook "signed_request" POSTed to the landing page was lost.
As a workaround, I added an HTTPModule to override EndRequest() event. In the event if the page is "initial page" & contained "signed_request" POSTed, the value is added as querystring. In the page we would check the querystring value and set it into session, to be used in the application.
The EndRequest is as below:
void context_EndRequest(object sender, EventArgs e)
{
HttpContext cntxt = HttpContext.Current;
const string paramname = "signed_request";
const string initialPage= "/startapp.aspx";
if ((String.Compare(cntxt.Request.Url.AbsolutePath, initialPage, true) == 0) && (!String.IsNullOrEmpty(cntxt.Request[paramname])))
{
string strQuerySignedReq = paramname+"=" + cntxt.Request[paramname];
if (cntxt.Response.RedirectLocation.Contains(".aspx?"))
cntxt.Response.RedirectLocation = cntxt.Response.RedirectLocation + "&" + strQuerySignedReq;
else
cntxt.Response.RedirectLocation = cntxt.Response.RedirectLocation + "?" + strQuerySignedReq;
}
}
The initial page - "startapp.aspx", load event would be:
protected void Page_Load(object sender, EventArgs e)
{
signed_request = Request.QueryString["signed_request"];
}
The disadvantage of the code is that EndRequest() would execute for all requests. Also, only relative url should be used for links. I have had several annoying experiences on cookies and Facebook, due to various security levels on different browsers. Hence, I can live with the disadvantages. Hope this helps!
I know this is an old question, but I had exactly the same problem and found a solution.
The solution here works if you're using a SQL Server in your application.
Using cookieless to store your SessionId in the URL will avoid the cookie problem, but still missing the Session issue in Safari.
Well, you'll need to set a SQL SessionState, this will make your application communicate with your Database to store the Sessions. This will work for facebook canvas apps in Safari.
Setting this is simple:
Registering: run aspnet_regsql.exe (in C:/Windows/Microsoft.NET/Framework/'Framework version'/)
Check parameters in https://msdn.microsoft.com/en-us/library/ms229862.aspx (the main ones are -S –ssadd)
In the same path, there is a InstallSqlState.SQL script. Run it on your Database Server.
Now, set this tag in your Web.Config file:
<configuration>
<system.web>
<sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:42424" timeout="120" cookieless="true" />
</system.web>
</configuration>
And the magic is done!
There is something to remember. You can't do WebRequests to facebook from Server side to request for access tokens, because facebook redirects the calls to the "Valid OAuth redirect URIs", and completely ignores the SessionId parameters in the Request URI. You still can make WebRequests to APIs, but the authentication will need to be assyncronous, using Javascript.

How can I access session variables when the page is loaded using a SimpleWorkerRequest?

I'm reading an ASPX file as a string and using the returned HTML as the source for an email message. This is the code:
public string GetEmailHTML(int itemId)
{
string pageUrl = "HTMLEmail.aspx";
StringWriter stringWriter = new StringWriter();
HttpRuntime.ProcessRequest(new SimpleWorkerRequest(pageUrl, "ItemId=" + itemId.ToString(), stringWriter));
stringWriter.Flush();
stringWriter.Close();
return stringWriter.ToString();
}
HTMLEmail.aspx uses the ItemId query string variable to load data from a DB and populate the page with results. I need to secure the HTMLEmail.aspx page so a manipulated query string isn't going to allow just anybody to see the results.
I store the current user like this:
public User AuthenticatedUser
{
get { return Session["User"] as User; }
set { Session["User"] = value; }
}
Because the page request isn't made directly by the browser, but rather the SimpleWorkerRequest, there is no posted SessionId and therefore HTMLEmail.aspx cannot access any session variables. At least, I think that's the problem.
I've read the overview on session variables here: http://msdn.microsoft.com/en-us/library/ms178581.aspx
I'm wondering if I need to implement a custom session identifier. I can get the current SessionId inside the GetEmailHTML method and pass it as a query string param into HTMLEmail.aspx. If I have the SessionId inside HTMLEmail.aspx I could maybe use the custom session identifier to get access to the session variables.
That fix sounds messy. It also removes the encryption layer ASP automatically applies to the SessionId.
Anyone have a better idea?
As far as I can see, your best bet is to pass on all the values you need inside HTMLEmail.aspx to it via the query parameters, just like you do with ItemId.
Apart from that, you can probably get away with just sending in the UserId of the user to that page and make it hit the DB (or wherever you are storing your users) to the User object, instead of trying to read it off the Session variables.
Edit:
Why don't you use:
public string GetEmailHTML(int itemId)
{
string pageUrl = "HTMLEmail.aspx";
StringWriter stringWriter = new StringWriter();
Server.Execute(pageUrl, stringWriter);
stringWriter.Flush();
stringWriter.Close();
return stringWriter.ToString();
}
instead? As far as I can see Server.Execute inherits the same http request.

Facebook Connect and ASP.NET

I'm at step 8 of the authentication overview found here: http://wiki.developers.facebook.com/index.php/How_Connect_Authentication_Works
In particular, the user has logged into facebook via Facebook Connect and their web session has been created. How do I use the facebook developer toolkit v2.0 (from clarity) to retrieve information about the user. For example, I'd like to get the user's first name and last name.
Examples in the documentation are geared towards facebook applications, which this is not.
Update
Facebook recently released the Graph API. Unless you are maintaining an application that is using Facebook Connect, you should check out the latest API: http://developers.facebook.com/docs/
I had a lot of trouble figuring out how to make server side calls once a user logged in with Facebook Connect. The key is that the Facebook Connect javascript sets cookies on the client once there's a successful login. You use the values of these cookies to perform API calls on the server.
The confusing part was looking at the PHP sample they released. Their server side API automatically takes care of reading these cookie values and setting up an API object that's ready to make requests on behalf of the logged in user.
Here's an example using the Facebook Toolkit on the server after the user has logged in with Facebook Connect.
Server code:
API api = new API();
api.ApplicationKey = Utility.ApiKey();
api.SessionKey = Utility.SessionKey();
api.Secret = Utility.SecretKey();
api.uid = Utility.GetUserID();
facebook.Schema.user user = api.users.getInfo();
string fullName = user.first_name + " " + user.last_name;
foreach (facebook.Schema.user friend in api.friends.getUserObjects())
{
// do something with the friend
}
Utility.cs
public static class Utility
{
public static string ApiKey()
{
return ConfigurationManager.AppSettings["Facebook.API_Key"];
}
public static string SecretKey()
{
return ConfigurationManager.AppSettings["Facebook.Secret_Key"];
}
public static string SessionKey()
{
return GetFacebookCookie("session_key");
}
public static int GetUserID()
{
return int.Parse(GetFacebookCookie("user"));
}
private static string GetFacebookCookie(string name)
{
if (HttpContext.Current == null)
throw new ApplicationException("HttpContext cannot be null.");
string fullName = ApiKey() + "_" + name;
if (HttpContext.Current.Request.Cookies[fullName] == null)
throw new ApplicationException("Could not find facebook cookie named " + fullName);
return HttpContext.Current.Request.Cookies[fullName].Value;
}
}
I followed up on this concept and wrote a full fledged article that solves this problem in ASP.NET. Please see the following.
How to Retrieve User Data from Facebook Connect in ASP.NET - Devtacular
Thanks to Calebt for a good start on that helper class.
Enjoy.
Facebook Connect actually isn't too difficult, there's just a lack of documentation.
Put the necessary javascript from here: http://tinyurl.com/5527og
Validate the cookies match the signature provided by facebook to prevent hacking, see: http://tinyurl.com/57ry3s for an explanation on how to get started
Create an api object (Facebook.API.FacebookAPI)
On the api object, set the application key and secret Facebook provides you when you create your app.
Set api.SessionKey and api.UserId from the cookies created for you from facebook connect.
Once that is done, you can start making calls to facebook:
Facebook.Entity.User user = api.GetUserInfo(); //will get you started with the authenticated person
This is missing from the answers listed so far:
After login is successful, Facebook recommends that you validate the cookies are in fact legit and placed on the client machine by them.
Here is two methods that can be used together to solve this. You might want to add the IsValidFacebookSignature method to calebt's Utility class. Notice I have changed his GetFacebookCookie method slightly as well.
private bool IsValidFacebookSignature()
{
//keys must remain in alphabetical order
string[] keyArray = { "expires", "session_key", "ss", "user" };
string signature = "";
foreach (string key in keyArray)
signature += string.Format("{0}={1}", key, GetFacebookCookie(key));
signature += SecretKey; //your secret key issued by FB
MD5 md5 = MD5.Create();
byte[] hash = md5.ComputeHash(Encoding.UTF8.GetBytes(signature.Trim()));
StringBuilder sb = new StringBuilder();
foreach (byte hashByte in hash)
sb.Append(hashByte.ToString("x2", CultureInfo.InvariantCulture));
return (GetFacebookCookie("") == sb.ToString());
}
private string GetFacebookCookie(string cookieName)
{
//APIKey issued by FB
string fullCookie = string.IsNullOrEmpty(cookieName) ? ApiKey : ApiKey + "_" + cookieName;
return Request.Cookies[fullCookie].Value;
}
The SecretKey and ApiKey are values provided to you by Facebook. In this case these values need to be set, preferably coming from the .config file.
I followed up from Bill's great article, and made this little component. It takes care of identifying and validating the user from the Facebook Connect cookies.
Facebook Connect Authentication for ASP.NET
I hope that helps somebody!
Cheers,
Adam
You may also use SocialAuth.NET
It provides authentication, profiles and contacts with facebook, google, MSN and Yahoo with little development effort.
My two cents: a very simple project utilizing the "login with Facebook" feature - facebooklogin.codeplex.com
Not a library, but shows how it all works.

Resources