Uniquely identify machine in web application using asp.net c# - c#

I have one login page, user can use any machine while login into that page for the first time. once the user logged in for the first time, i need to restrict that user to not login into another machine. So user need to use only one machine that's used for the first time login.
I tried to get the client side mac address, but i can't able to get client side mac address in my website. Is there any other way to identity a machine uniquely?

For asp.net it's not possible to get the mac address of the client. You need to have some kind of windows application for that, that runs on the user's system.
A permanent cookie with a with a GUID might also be a solution.
Another solution might be to look up the servervariables when they make a request you will have Request.ServerVariables["REMOTE_ADDR"]; which would probably be the internal IP if the app is internal/intranet. There is also REMOTE_HOST. Sometimes these are filtered off by proxies/firewalls/nat but hopefully not in your situation.
Hope it helps!

if its intranet webapp, then you can enforce windows authentication - and keep a list of logged in users, in the database, with a timestamp of when the logged in user will automatically logout after the timestamp period.
Alternatively, use a cookie in forms authentication to do just that. But in any case, you will need the list of logged in users, and automatically log the user off, if he is on another machine.
More so, you can get the client's IP address and go from there, but its not reliable as it could be of an ISP. Its tricky, but cookies seems to be the simplest way of doing this.
However, a good solution would be to do it like IRC does, to keep track of logged in users. It sends a PING to the client, and expects the client to return a PONG, at different intervals of time. If the PONG is not received by the client, the IRC server automatically disconnects the user. Try this with something like SignalR. The downside of this is, if the user closes the browser and a PING request comes in, it will bounce back and the client will be disconnected as he/she will not be able to send a PONG request back.

I believe you want a user logged in on the website only in one session at any given time. Problem is that you can't know for sure when the user leaves, if he doesn't logout using the logout button.To fix this you have to have a timeout. I used a text file on the server in an application and it works.
Login button:
protected void btLogin_Click(object sender, EventArgs e)
{
if (check(txtPass.Text) && check(txtUser.Text))
{
var user = new UserManager().login(txtUser.Text, txtPass.Text);
if (user != null)
{
// this is the test you're looking for, the rest is only context
if (!FileManager.alreadyLoggedIn(user.email))
{
FormsAuthentication.SetAuthCookie(user.email, false);
}
else
{
//throw error that it is already connected in some other place
}
}
else
{
//throw error that login details are not OK
}
}
}
In a class two static methods:
//you have to call this function at every request a user makes
internal static void saveUserSessionID(string email)//email or any unique string to user
{
var dir = HostingEnvironment.MapPath("~/temp/UserSession/");// a folder you choose
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
string path = dir + email + ".txt";
File.WriteAllText(path, HttpContext.Current.Session.SessionID);
}
// if a request has not been made in tha last 4 minutes, the user left, closed the browser
// the test checks this only on a real server, localhost is not tested to be easy for the developer
internal static bool alreadyLoggedIn(string email)
{
var file = HostingEnvironment.MapPath("~/temp/UserSession/" + email + ".txt");
return File.Exists(file) && File.GetLastWriteTime(file).AddMinutes(4) > DateTime.Now && !HttpContext.Current.Request.IsLocal;
}
Obviously this is from another application, you can only take the idea and implement it in your own application. You can't just copy paste it.

Related

Accurate Session Tracking in ASP.NET MVC

Whenever a user hits a page on my website, I run the following code to track user hits, page views, where they are going, etc...
public static void AddPath(string pathType, string renderType, int pageid = 0, int testid = 0)
{
UserTracking ut = (UserTracking)HttpContext.Current.Session["Paths"];
if (ut == null)
{
ut = new UserTracking();
ut.IPAddress = HttpContext.Current.Request.UserHostAddress;
ut.VisitDate = DateTime.Now;
ut.Device = (string)HttpContext.Current.Session["Browser"];
if (HttpContext.Current.Request.UrlReferrer != null)
{
ut.Referrer = HttpContext.Current.Request.UrlReferrer.PathAndQuery.ToString();
ut.ReferrerHost = HttpContext.Current.Request.UrlReferrer.Host.ToString();
ut.AbsoluteUri = HttpContext.Current.Request.UrlReferrer.AbsoluteUri.ToString();
}
}
//Do some stuff including adding paths
HttpContext.Current.Session["Paths"] = ut;
}
In my Global.asax.cs file when the session ends, I store that session information. The current session timeout is set to 20 minutes.
protected void Session_End(object sender, EventArgs e)
{
UserTracking ut = (UserTracking)Session["Paths"];
if (ut != null)
TrackingHelper.StorePathData(ut);
}
The problem is that I'm not getting accurate storage of the information. For instance, I'm getting thousands of session stores that look like this within a couple minutes.
Session #1
Time: 2014-10-21 01:30:31.990
Paths: /blog
IP Address: 54.201.99.134
Session #2
Time: 2014-10-21 01:30:31.357
Paths: /blog-page-2
IP Address: 54.201.99.134
What it should be doing, is storing only one session for these instances:
What the session should look like
Time: 2014-10-21 01:30:31.357
Paths: /blog,/blog-page-2
IP Address: 54.201.99.134
Clearly, this seems like a search engine crawl, but the problem is, I'm not sure if this is the case.
1) Why is this happening?
2) How can I get an accurate # of sessions to match Google analytics as closely as possible?
3) How can I exclude bots? Or how to detect that it was a bot that fired it?
Edit: Many people are asking "Why"
For those of you that are asking "Why" we are doing this as opposed to just using analytics, to make a very long story short, we are building user profiles to mine data out of their profile. We're looking at what they are viewing, how long they are viewing it, their click paths, we also have A/B tests running for certain pages and we're detecting which pages are firing throughout the user viewing cycle and we're tracking some other information that is custom and we're not able to put this into a google analytics API and pull this information out. Once they've navigated the site, we're thing using this information to build user profiles for every session on the site. We essentially need to then detect which of these sessions is actually real and give the site owners the ability to view the data along with our data mining application to analyze the data and provide feedback to the site owners on certain criteria to help them better their website from these profiles. If you have a better way of doing this, we're all ears.
1) the asp.net session is tracked with the help of the asp.net session Cookie.
But it is disabled for anonymous users (not logged on users)
You can activate sessionId creation for anonymous user's in the web.config
<configuration>
<system.web>
<anonymousIdentification enabled="true"/>
</system.web>
</configuration>
A much better place to hook up your tackin is to add an global mvc ActionFilterAttribute.
The generated SessionId is stored in the httprequest, accessed by
filterContext.RequestContext.HttpContext.Request.AnonymousID
2) You should create a feed of tracking paths to analys it asyncronly or not even in the same process. Maybe you want to store the tracking on disk "like a Server log" to reanalyse it later.
Geo Location and db lookup's needs some processing time and most likly you cant get the accurate geo location from the ip address.
A much better source is to get it from the user profiles / user address later on. (after the order submit)
Sometimes the asp.net session cookie don't work, because the user has some notracking plugin activated. Google Analytics would fail here too. You can increase the tracking accuracy with a custom
ajax Client callback.
To make the Ajax callback happen globally for all pages, you can use the help of the ActionFilterAttribute to inject some Script-Content to the end of the html content stream Response.
To map an IPv4 address to a session can help, but it should only be a hint.
Noadays a lot of ISP supporting IPv6. They are mapping there clients
most of the time to a small IPv4 pool. So one user can switch its ipv4 very fast
and there is a high possibility that visitors of the same page are using the same ISP and so share a IPv4.
3) Most robots identify themselves by a custom user agent in the request headers.
There are good and bad ones. See http://www.affiliatebeginnersguide.com/articles/block_bots.html
But with the Ajax callback u can verify the browser presents, at least the present of a costly
html-dom with JavaScript Environment.
X) To simplfy the start and concentrate on the Analysis. Implement a simple ActionFilterAttribute
and Register it globaly in RegisterGlobalFilters
filters.Add(new OurTrackingActionFilterAttribute(ourTrackingService));
In the filter override OnActionExecuting
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
OnTrackingAction(filterContext);
}
public virtual void OnTrackingAction(ActionExecutingContext filterContext)
{
var context = filterContext.RequestContext.HttpContext;
var track = new OurWebTrack(context);
trackingService.Track(track);
}
To don't delay the Server Response with some tracking processing,
take a look into the Reactive package http://msdn.microsoft.com/en-us/data/gg577609.aspx
It's a good way to split the capture from the processing.
Create a "Subject" in the TrackingService and simple push our tracking objects into it.
You can write observers to transmit, save or process the tracking objects.
As default the observers will only get one object at a time and so you dont need to syncronise/lock your status variables/Directory/memeory-cache and maybe u want to load the data and reprocess it with a new version of your application later on (maybe in debuging).

Recognize user already logged in C# WPF

I have created the registration and login form. Both work perfectly. But how do i recognize the user logged in as the PHP does by using SESSIONS and COOKIES. I can use static class to get data between different pages, but how can i retrieve the logged user data if he closes the application.
Is there any way for achieving this?
Thanks!
I'm assuming that you want something like instant messenger applications like Skype, or cloud storage applications like DropBox, OneDrive or Mega do. They ask you to enter user name and password once, and then start automatically without asking for user's credentials again.
They achieve this by storing user name and password in encrypted format in the file they normally keep in application folder under specific user account. See the following link for details: How can I get the current user directory?
This is standard practice, as another user will not be automatically logged into your app, if they not entered their own credentials.
Make sure you encrypt the user name and password or the whole file before saving it to disk, otherwise it may become an easy target for password stealing malware.
You should use user settings to do this, as this mechanism hides all the necessary work for creating files in the right locations, etc. from the developer. It works fine and it is made for stuff like this.
You design them in Visual Studio in the project properties on the "Settings" tab. Make sure to select the settings type correctly, as application settings are read-only.
Assume you have to settings UserName and UserPassword. Then, in your code, you could do this:
if (String.IsNullOrWhitespace(Properties.Settings.Default.UserName))
{
// USER NEEDS TO LOG IN
string userName;
string password;
if (Login(out userName, out password))
{
try
{
Properties.Settings.Default.UserName = Encrypt(userName);
Properties.Settings.Default.Password = Encrypt(password);
Properties.Settings.Default.Save();
}
catch (Exception exp)
{
...
}
}
}
else
{
// USER IS ALREADY LOGGED IN
}
private bool Login(out string userName, out string password) would be a method that shows a login user interface and returns true on success or false on failure.
private string Encrypt(string input) would be a method to encrypt a string.

Concerning the sliding expiration of ASP.NET's forms authentication and session

We have a ASP.NET 4.5 WebForms application using the native forms authentication and session functionality. Both have a timeout of 20 minutes with sliding expiration.
Imagine the following scenario. A user has worked in our application for a while and then proceeds to do some other things, leaving our application idle for 20 minutes. The user then returns to our application to write a report. However, when the user tries to save, he/she is treated with the login screen, and the report is lost.
Obviously, this is unwanted. Instead of this scenario, we want the browser to be redirected to the login page the moment either authentication or session has expired. To realize this, we have build a Web Api service that can be called to check whether this is the case.
public class SessionIsActiveController : ApiController
{
/// <summary>
/// Gets a value defining whether the session that belongs with the current HTTP request is still active or not.
/// </summary>
/// <returns>True if the session, that belongs with the current HTTP request, is still active; false, otherwise./returns>
public bool GetSessionIsActive()
{
CookieHeaderValue cookies = Request.Headers.GetCookies().FirstOrDefault();
if (cookies != null && cookies["authTicket"] != null && !string.IsNullOrEmpty(cookies["authTicket"].Value) && cookies["sessionId"] != null && !string.IsNullOrEmpty(cookies["sessionId"].Value))
{
var authenticationTicket = FormsAuthentication.Decrypt(cookies["authTicket"].Value);
if (authenticationTicket.Expired) return false;
using (var asdc = new ASPStateDataContext()) // LINQ2SQL connection to the database where our session objects are stored
{
var expirationDate = SessionManager.FetchSessionExpirationDate(cookies["sessionId"].Value + ApplicationIdInHex, asdc);
if (expirationDate == null || DateTime.Now.ToUniversalTime() > expirationDate.Value) return false;
}
return true;
}
return false;
}
}
This Web Api service is called every 10 seconds by the client to check if either authentication or session has expired. If so, the script redirects the browser to the login page. This works like a charm.
However, calling this service triggers the sliding expiration of both authentication and session. Thus, essentially, creating never ending authentication and session. I have set a breakpoint at the start of the service to check if it is one of our own functions that triggers this. But this is not the case, it seems to occur somewhere deeper in ASP.NET, before the execution of the service.
Is there a way to disable the triggering of ASP.NET's authentication and session sliding expirations for a specific request?
If not, what is best practice to tackle a scenario like this?
This seems to be impossible. Once sliding expiration is enabled, it is always triggered. If there is a way to access the session without extending it, we have not been able to find it.
So how to tackle this scenario? We came up with the following alternative solution to the one originally proposed in the question. This one is actually more efficient because it doesn't use a web service to phone home every x seconds.
So we want to have a way to know when either ASP.NET's forms authentication or session has expired, so we can pro-actively logout the user. A simple javascript timer on every page (as proposed by Khalid Abuhakmeh) would not suffice because the user could be working with the application in multiple browser windows/tabs at the same time.
The first decision we made to make this problem simpler is to make the expiration time of the session a few minutes longer than the expiration time of the forms authentication. This way, the session will never expire before the forms authentication. If there is a lingering old session the next time the user tries to log in, we abandon it to force a fresh new one.
All right, so now we only have to take the forms authentication expiration into account.
Next, we decided to disable the forms authentication's automatic sliding expiration (as set in the web.config) and create our own version of it.
public static void RenewAuthenticationTicket(HttpContext currentContext)
{
var authenticationTicketCookie = currentContext.Request.Cookies["AuthTicketNameHere"];
var oldAuthTicket = FormsAuthentication.Decrypt(authenticationTicketCookie.Value);
var newAuthTicket = oldAuthTicket;
newAuthTicket = FormsAuthentication.RenewTicketIfOld(oldAuthTicket); //This triggers the regular sliding expiration functionality.
if (newAuthTicket != oldAuthTicket)
{
//Add the renewed authentication ticket cookie to the response.
authenticationTicketCookie.Value = FormsAuthentication.Encrypt(newAuthTicket);
authenticationTicketCookie.Domain = FormsAuthentication.CookieDomain;
authenticationTicketCookie.Path = FormsAuthentication.FormsCookiePath;
authenticationTicketCookie.HttpOnly = true;
authenticationTicketCookie.Secure = FormsAuthentication.RequireSSL;
currentContext.Response.Cookies.Add(authenticationTicketCookie);
//Here we have the opportunity to do some extra stuff.
SetAuthenticationExpirationTicket(currentContext);
}
}
We call this method from the OnPreRenderComplete event in our application's BasePage class, from which every other page inherits. It does exactly the same thing as the normal sliding expiration functionality, but we get the opportunity to do some extra stuff; like call our SetAuthenticationExpirationTicket method.
public static void SetAuthenticationExpirationTicket(HttpContext currentContext)
{
//Take the current time, in UTC, and add the forms authentication timeout (plus one second for some elbow room ;-)
var expirationDateTimeInUtc = DateTime.UtcNow.AddMinutes(FormsAuthentication.Timeout.TotalMinutes).AddSeconds(1);
var authenticationExpirationTicketCookie = new HttpCookie("AuthenticationExpirationTicket");
//The value of the cookie will be the expiration date formatted as milliseconds since 01.01.1970.
authenticationExpirationTicketCookie.Value = expirationDateTimeInUtc.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds.ToString("F0");
authenticationExpirationTicketCookie.HttpOnly = false; //This is important, otherwise we cannot retrieve this cookie in javascript.
authenticationExpirationTicketCookie.Secure = FormsAuthentication.RequireSSL;
currentContext.Response.Cookies.Add(authenticationExpirationTicketCookie);
}
Now we have an extra cookie at our disposal that always represents the correct forms authentication expiration time, even if the user works in different browser windows/tabs. After all, cookies have a browser wide scope. Now the only thing left is a javascript function to verify the cookie's value.
function CheckAuthenticationExpiration() {
var c = $.cookie("AuthenticationExpirationTicket");
if (c != null && c != "" && !isNaN(c)) {
var now = new Date();
var ms = parseInt(c, 10);
var expiration = new Date().setTime(ms);
if (now > expiration) location.reload(true);
}
}
(Note that we use jQuery Cookie Plugin to retrieve the cookie.)
Put this function in an interval, and users will be logged out the moment his or her forms authentication has expired. VoilĂ  :-) An extra perk of this implementation is that you now have control over when the forms authentication's expiration gets extended. If you want a bunch of web services that don't extend the expiration, just don't call the RenewAuthenticationTicket method for them.
Please drop a comment if you have anything to add!
Your website functionality should work without JavaScript or you just replace one problem with another. I have tackled this problem also and here is how it was solved:
When you authenticate yourself then session cookie is created with default lifetime on 20 min. When this expires user will be logged out.
When user selects "remember me" in the sign in form then additional persistence cookie [AuthCookie] is created in client side and in the database. This cookie has a lifetime of 1 month. Whenever page is loaded, session and persistence cookie data is recreated with a new lifetime (normally you want to decrypt/crypt the ticket).
Imagine the following scenario. A user has worked in our application
for a while and then proceeds to do some other things, leaving our
application idle for 20 minutes. The user then returns to our
application to write a report. When the user tries to save, his session is restored before the request.
One way to do this is to extend global.aspx to handle prerequest. Something in the lines of:
void application_PreRequestHandlerExecute(object sender, EventArgs e){
...
if (HttpContext.Current.Handler is IRequiresSessionState) {
if (!context.User.Identity.IsAuthenticated)
AuthService.DefaultProvider.AuthenticateUserFromExternalSource();
AuthenticateUserFromExternalSource should check if cookie data matches with the database one, because anything stored in client side can be changed. If you have paid services with access rights then you need to check if user still has those rights and then you can recreate the session.
This can all be solved client side, without the need to go back to the server.
In JavaScript do this.
var timeout = setTimeout(function () {
window.location = "/login";
}, twentyMinutesInMilliseconds + 1);
The timeout will be set to 20 minutes on every page refresh. This ensures that the user needs to get all their work done before the timeout happens. A lot of sites use this method, and it saves you from doing unnecessary server requests.

Validate User via remote active directory

I have a strange scenario that I hope you guys can help with, I need to validate the current logged in user with active directory, this isn't a problem if they are on the network but in some instances they will be on another network (visiting clients) and in order for them to use the software they need to validate against AD.
At present I am using the following code am I correct in saying this will work locally and remotely? If not how can I get it to validate credentials?
DomainServer = new ActiveDirectory(Microsoft.Exchange.WebServices.Data.ExchangeVersion.Exchange2010, "LDAP://DOMAIN.NAME", "https://exchange.domain.name/ews/exchange.asmx");
DomainServer.connect();
if (!DomainServer.isConnected())
{
domain_errors = "Unable to connect to Active Directory.";
}
class ActiveDirectory
{
private ExchangeService _ExchangeServer;
private DirectoryEntry _searchRoot;
private DirectorySearcher _search;
private SearchResult _searchresult;
private ExchangeVersion _ExchangeVer;
private string _ActiveDirectoryAddress;
private string _ActiveDirectoryURL;
public ActiveDirectory(ExchangeVersion Ver, string ActiveDirectoryAddress, string ActiveDirectoryURL)
{
_ActiveDirectoryURL = ActiveDirectoryURL;
_ActiveDirectoryAddress = ActiveDirectoryAddress;
_ExchangeVer = Ver;
}
public void connect()
{
_ExchangeServer = new ExchangeService(_ExchangeVer);
_ExchangeServer.UseDefaultCredentials = true;
_ExchangeServer.Url = new Uri(_ActiveDirectoryURL);
_ExchangeServer.Timeout = 60;
}
public bool isConnected()
{
if (_searchRoot.Properties.Count > 0){
return true;
} else {
return false;
}
}
}
Windows caches usernames and passwords on local machines so that a domain user can login even if the machine, such as a laptop, is not connected to the domain. Since Windows is essentially handling the authentication for you, all you really need to do is authorize who can use the software. I can think of a few possibilities.
First, in the database, you could maintain a user table with the SIDs and usernames of those users with access to the software. When a user executes the program, check that the SID of the currently logged in user is in that table. This way, you can restrict what users can actually execute the software without connecting to Active Directory. This would also allow you to revoke access at the database level.
Secondly, does the database server have access to the Active Directory? If so, create a group in AD for users with access to this system, then grant that group access in the database. Set the database connection to use Windows authentication. Therefore, if the person is in that group, they have access to the database. Otherwise, they do not. Then, you can control access just by adding or removing them from that group and security will be controlled at the database level.
Third (and I'm not a fan of this one), if you have a web server, run a web service (using HTTPS of course) that accepts a username and password and then use that web service to connect through your firewall and authenticate against AD. Then, just return a result to your application. This presents some security concerns with passing credentials to a web service and opening connections through the firewall.

Not able to access user information through Facebook api in c# on the same computer?

What's happening is say user A Logs in and provides the rights for the app to access his/her Data we extract his data then..
But what the problem is when another person Logs into his/her account using the same computer and grants permission we are getting the Data of User A and not B..
if(Request.Params["code"] != null)
{
Facebook.FacebookAPI api = new Facebook.FacebookAPI(GetAccessToken());
string me = api.Get("/me");
string meFriends = api.Get("/me/friends/");
}
I am accessing the user info by the above code ..
What should we do about it?
It's a known problem with the SDK saving the data into the session. I'm not 100% sure for C# but I guess it's the same as PHP. The SDK (in PHP ) checks if user's Signed Request is available in session:
public function getSignedRequest() {
if (!$this->signedRequest) {
if (isset($_REQUEST['signed_request'])) {
$this->signedRequest = $this->parseSignedRequest(
...
What I do is everytime I check the validity of the current user's access token. But someone mentioned that's not effective (although I tend to disagree:) ).
In short SDK doesn't check for validity and takes the data from session as first source. That's why 2nd user has the 1st user data.

Categories

Resources