How do we do authentications in web applications? - session

Sorry, I wrote a lot to explain my situation, If you don't have time or not in mood to read all these just jump to the questions. Even answering one of them helps my situation, thanks :D
I'm trying to write a web application in node.js, but since I'm too new to web, I don't know how to write the web login system. I don't want to use basic or digest http authentications, I want it like normal login systems with http forms and different pages shows different content for different types of users. I searched a bit, I know the basics, but they're not enough.
This is what I got:
We check the user and pass from the
POST data in the database
If correct we give the client a new session, and save it in a database.
The client saves the session as a cookie and sends it in each page request.
The server checks the session and gives the content intended for the user.
Here's the part I don't know:
How do we generate a session?
How do we send it to the client?
How is it saved in cookies?
When is it supposed to expire?
What happens if it is expired? What
should we do?
Is there anything else that I should
know?
If you can please, give me some examples in node.
Thank you in advance :D

A session is simply a unique key (session ID) associated with an object/array, this way you can connect data to a user of your site.
You send the session ID to the client as a cookie, once sent, the client sends its session ID to your server with every HTTP request.
You send the HTTP Set-Cookie header (Set-Cookie: sessionid=abcdefg38974).
You can make it expire when you want it to, when the browser closes or after for example a year (this would keep you logged in for a year, after which you'll have to login again).
When a cookie expires it is simply thrown away, on the serverside it will just look like the user doesn't have a session ID set yet so he has to log in again.
You should know of things like session hijacking (stealing someone else's session ID). Have a look at it.
Little example, it might increate the visit number twice each time you request because your browser also requests /favicon.ico. Keep in mind that this example is not very safe as session hijacking is possible, this also keeps all sessions in memory and forgets them when the server is restarted. It would be wise to save sessions to a database.
var http = require('http');
var sessions = {};
http.createServer(function (req, res) {
var ssid;
var session;
if (req.headers.cookie) {
// Cookie already set, read it
var parts = req.headers.cookie.split('=');
ssid = parts[1];
// Is the session id known to us?
if (typeof(sessions[ssid]) != "undefined") {
session = sessions[ssid];
console.log('Loaded session with id ' + ssid);
}
}
if (typeof(session) == "undefined") {
// No cookie set, make one
ssid = Math.random();
session = {
'visitNumber': 0
}
console.log('Created session with id ' + ssid);
}
session.visitNumber++;
// Respond to the browser
res.writeHead(200, {
'Content-Type': 'text/plain',
'Set-Cookie': 'ssid=' + ssid
});
res.end('Visit number: ' + session.visitNumber + '\n');
// Save the changes we have made to the session data
sessions[ssid] = session;
}).listen(8080);

Related

Only one User using entire web application at a time - Spring boot

In spring boot application only one user should be using the certain page at a time (let's call it home.jsp). Another users should be redirected to different page(let's call it another_home.jsp) if they appear when accessing that same url. User doesn't login and just uses the application as it is. Any policy can be used for home.jsp could be first-come-first-serve or any other.
If more than one users are using application at a time only one user should be using home.html and all rest of the others should be using another_home.jsp.
As no login is needed in the application I believe I need anonymous sessions. Also, session needs to be expired after some time of inactivity. I've searched spring security but couldn't find anything.
I think that you don't even need spring security. Simple http session will work too. As far as I can see you just want to allocate the stream to one user and for that you need first user's session id which you can compare against whenever the requests come again. So store session id and expire after some timeout with some Time object or Date object.
In properties
server.servlet.session.timeout = 600 // 10 minutes
Something like this
private String currSessionId = null;
private Date lastDate = new Date();
private Integer TIMEOUT = 600000; // 10 minutes
public String loadHomePage(Model model) {
if(currSessionId!=null && new Date().getTime()- lastDate.getTime()>TIMEOUT){
currSessionId = null;
}
if(currSessionId==null){
currSessionId = session.getId();
lastDate = new Date();
return "home";
}else{
if(session.getId().equals(currSessionId)){
return "home";
}else{
return "another_home";
}
}
}
This is as simple as it gets when you don't have logged in users to manage and also don't need to remember previous state where user left off. Let me know if it helps.
You need to create a serverside state that is either empty or stores the identifier of the visitor that is currently claiming /home.jsp.
This could be a field on a singleton Bean, or an entity in the database.
It has to expire automatically, or it will prevent new visitors forever to make a claim.
As long as the state is empty, the first visitors identifier will be stored in this state.
And from that moment on, you will redirect all other visitors to another_home.jsp
So the Controllers Code would be something like this
if(visitorHoldsTheClaim()) {
return "home.jsp"
} else if (noClaimActive()) {
createClaimForVisitor();
return "home.jsp"
} else {
return "redirect:/another_home.jsp"
}
Depending on your implementation, these methods will do different things.
I'd usually recommend against serverside session state (more about this in Roy Fieldings Dissertation),
but for your use case, you need a way to identify a visitor over many requests.
A session would certainly be a very simple way to achieve this.
You can at least minimize session usage by only creating one session at a time - the one for the visitor that holds the claim.
In this case you'd never have more than one open session, and the visitor that owns the session is the visitor that holds the claim.
So in this case, the implementation would be be something like this:
if(currentUserHasASession()) { // checks if the current user has a session, but !!!does not create a new session if it does not exist!!! careful, HttpServletRequest.getSession(true) would create it!
return "home.jsp"
} else if (serverHasNoSessions()) { // https://stackoverflow.com/questions/49539076/how-can-i-get-a-list-of-all-sessions-in-spring
createSessionForUser(); // HttpServletRequest.getSession(true)
return "home.jsp"
} else {
return "redirect:/another_home.jsp"
}
Keep in mind that this only works if you do not create Sessions in another place.
So you have to configure Spring Boot/Spring Security to not create Sessions. How to make spring boot never issue session cookie?
Also keep concurrency in mind. For example, if you had only one server instance, you could put this code into a synchronized method to avoid two visitors creating a claim at the same time.
So... first of all, this sounds like a bad idea. I would be curious why you would need such an unusual behavior. There might be more sensible approaches for it.
Like Gregor said, the redirect code part is rather straightforward:
if(pageLock.getUser() == null) {
pageLock.setUser(user);
}
if(user.equals(pageLock.getUser())) {
return "home.jsp"
} else {
return "redirect:/another_home.jsp"
}
What is actually more tricky is the part when "expiring" the lock. It's likely the user will simply close the browser and not click on "logout" (or whatever), leaving the lock forever. On the other extreme, the user might be gone for a lunch break but its browser still has the page open for hours.
So that's the first thing you wanna add: some keep-alive mechanism on the page, regularly prolonging the lock, and some expiration checker, releasing the lock if nothing was received for a while.
...but like I said in the beginning, the whole thing sounds fishy.

Dynamically set session cookie max age

I'm using Jetty's session management and want to implement a simple login with a 'Remember me' option.
So if the user doesn't want to be remembered, I want the JSESSIONID cookie to live until the browser session is closed. If the user opts-in to be remembered, the cookie will expire within 30 days.
I'm using SessionCookieConfig to configure the cookie details on startup and I can't change that per request.
So is there a way to dynamically change the max age per login request?
The only way I can see is to get the cookie from the request and then change the max age:
//in LoginServlet
doPost(HttpServletRequest request, HttpServletResponse response) {
//... Get remember me option from request
request.getCookies();
//... Find cookie in array by name JSESSIONID
if (rememberMe) {
sessionCookie.setMaxAge(60 * 60 * 24 * 30);
} else {
sessionCookie.setMaxAge(-1);
}
}
However I want to refrain as much as possible from dealing with the session and leave it to the container.
Is there another option?
The jsessionid cookie is handled by the container and so I wouldn't recommend that you try and repurpose it. Instead, there's a wealth of info on stackoverflow on how to implement a "remember me" function: try here.

Meteor Session Replacement?

In the latest Meteor release (version 0.5.8), Session has been removed from the server-side code.
Previously I've used Session to store client-specific variables for the server; what is the replacement for this functionality?
Example case: User One opens a browser, User Two opens a browser. One calls a method on the server setting some token, the other calls a method on the server doing the same. I then need to access this when the client requests something. How do I differentiate between the two?
You'll want to save your tokens to a collection in the database.
You could use a Session on the server if you wanted to simply by copying the session package into your application's packages directory and changing its package.js to also load on the server. But a Session is an in-memory data structure, and so won't work if you have multiple server instances; and you wouldn't be able to restart the server without losing your user's tokens.
If you store your tokens in the database they'll persist across server restarts, and will work with a future version of Meteor which is able to scale an application by adding more server instances when needed.
If you need to expire your tokens (so that your collection doesn't grow without bound), you could add a "lastUsed" Date field to your token collection, and periodically remove tokens that haven't been used for longer than your chosen expiration period.
You can use each one's session id which is unique to the tab too. Not too sure how to get the current session id but it should be there somewhere (you can see it in Meteor.default_server.sessions, so there is still a way:
Client js
Meteor.call("test", Meteor.default_connection._lastSessionId, function(err,result) {
console.log(result);
});
Server side Js
Session = {
set : function(key, value, sessionid) {
console.log(Meteor.default_server.sessions[sessionid]);
if(!Meteor.default_server.sessions[sessionid].session_hash) Meteor.default_server.sessions[sessionid].session_hash = {};
Meteor.default_server.sessions[sessionid].session_hash.key = value;
},
get : function(key, sessionid) {
if(Meteor.default_server.sessions[sessionid].session_hash)
return Meteor.default_server.sessions[sessionid].session_hash.key;
},
equals: function(key, value, sessionid) {
return (this.get(key, sessionid) == value)
},
listAllSessionids: function() {
return _.pluck(Meteor.default_server.sessions, "id");
}
};
Meteor.methods({
test:function(sessionid) {
if(!Session.get("initial_load", sessionid)) Session.set("initial_load", new Date().getTime(), sessionid);
return Session.get("initial_load", sessionid);
}
});
I hook into Meteor.default_connection._sessions to store the values so that theres some type of garbage collection involved when the session isn't valid anymore (i.e the user has closed his tabs) to prevent memory being wasted. In livedata_server.js these old sessions get destroyed after 1 minute of no activity on the DDP wire (like the heartbeat).
Because the server can see everyone's session you can use the sessionid to access another user's session data. and listAllSessionids to give out an array of all the sessionids currently active.
Automatically set session like this.userId in a Method without using a param in a call
It looks like there is functionality for this this but its not fully hooked up. The session id would be stored in this.sessionData but its likely still unfinished. Its there to be called in method but theres nowhere that its being set yet (in livedata_connection.js & livedata_server.js)

ExpressJS backend hanging with too much requests

I have an express app running with Sequelize.js as an ORM. My express app receives requests from my main Rails app, and because of the cross-domain policy, these requests are performed with getJSON.
On the client, the request is fired when the user hits a key.
Everything goes fine and express logs the queries being performed (and json being served) each time the user hits the key. Even trying to hit quickly it performs ok. But, whenever I leave the key pressed (or maybe several clients hitting the key very quickly), as it starts firing lots of requests, at some moment the server just hangs, all the requests from that point on are left pending (I see that in the Network tab of Chrome Dev Tools), and they slowly start to timeout. I have to reboot the server to make it respond again.
The server code for my request is:
models.Comment.findAllPublic(req.params.pId, req.params.sId, function(comments){
var json = comments.map(function(comment){
var com = {};
['user_id','user_avatar', 'user_slug', 'user_name', 'created_at', 'text', 'private', 'is_speaker_note'].forEach(function(key){
com[key]=comment[key];
});
return com;
});
res.json({comments: json});
});
And the findAllPublic method from the Comment model (this is a Sequelize model) is:
findAllPublicAndMyNotes: function(current_user, presentationId, slideId, cb){
db.query("SELECT * FROM `comments` WHERE commentable_type='Slide' AND commentable_id=(SELECT id from `slides` where `order_in_presentation`="+slideId+" AND `presentation_id`="+presentationId+") AND (`private` IS FALSE OR (`private` IS TRUE AND `user_id`="+current_user+" AND `is_speaker_note` IS FALSE))",self.Comment).on('success', cb).on('failure',function(err){console.log(err);});
}
How to avoid the server from getting stuck? Am I leaving some blocking code in the request that may slowly hang the server as new requests are made?
At first I thought it could be a problem because of the "forEach" when composing the json object from the Sequelize model, but I also tried leaving the callback for the mysql query empty, just responding empty json and it also got frozen.
Maybe it is a problem of the mysql connector? When the server gets stuck I can normally run the mysql console and perform queries on my database and it also responds, so I don't know if that's the problem.
I know I could just control the key event to prevent it from firing too many requests when the key gets pressed for a long time, but the problem seems to appear also when several clients hit the key repeatedly and concurrently.
Any thoughts? Thanks in advance for the help :D
Two things:
It seems like you have some path where res.render is not being called. It could be that the database you're connecting to is dropping the connection to your Express server after the absurd number of requests and the callback is never fired (and there's no database.on('close', function() { // Handle disconnect from DB, perhaps auto-restarting }) code to catch it.
Your client-side code should detect when an AJAX request on keypress is still pending while a new one is being started, and cancel the old one. I'm guessing getJSON is a jQuery method? Assuming it's jQuery's, then you need something like the following
.
var currKeyRequest = null;
function callOnKeyUp() {
var searchText = $('#myInputBox').value;
if(currKeyRequest) {
currKeyRequest.reject();
currKeyRequest = null;
}
currKeyRequest = $.getJSON('path/to/server', function(json) {
currKeyRequest = null;
// Use JSON code
});
}
This way, you reduce the load on the client, the latency of the autocomplete functionality (but why not use the jQuery UI autocomplete if that's what you're after?), and you can save the server from some of the load as well if the keypresses are faster than handshaking with the server (possible with a good touch-typist a few hours flight away).

ASP.NET MVC3 Forms Authentication user logon session renew

I have an AJAX method to call on server to return ".ASPXAUTH" cookie expiration time.
It works properly when the auth cookie presents.
Besides I want to renew user logon session with another AJAX call. I have a blank method "RenewSession" which is just for to make a call to the server. Is there any way to do this using Forms Authentication?
The problem is in that when I make a request to server to my "RenewSession" method to renew the session Response.Cookies array is always containing 0 items. But actually when the ".ASPXAUTH" cookie expiration time gets to 0 it renews.
So can anyone explain is it a browsers' or ASP.NET/MVCs' behaviour?
Maybe I need sliding expiration to be set to "true"?
Or maybe in my renew method I should re-login the user and put a new cookie in the response?
Thank you!
FormsAuthentication expiration is really a matter of two parts:
the expiration of the authentication ticket
the expiration of the cookie containing the ticket
If you want to leave sliding expiration off, and renew the ticket manually, you need to renew the ticket and return a new authentication cookie to the browser.
The Response.Cookies array is empty unless you (or other code) add something to it. It's only meant for adding cookies that are new or whose contents/expiration/whatever have changed. An empty Response.Cookies only means that nothing has changed - the browser will keep the cookies it already has (until they expire) and still send them on the next request.
The standard way of modifying cookie contents or expiration is to take a cookie the browser sent (from Request.Cookies), modify it, and then add it to Response.Cookies.
Here's a bit of sample code for manually renewing the authentication cookie (disclamer: Test thoroughly and think):
// You could also get the ticket from
// Request.Cookies using FormsAuthentication.Decode
FormsIdentity identity = HttpContext.Current.User.Identity as FormsIdentity;
if (identity == null) return; // User isn't authenticated
// Renew the ticket - you could also create a new ticket manually
// (see * below for an example), if you want to get rid of ASP.NET's
// rather confusing renew-if-old policy:
FormsAuthenticationTicket ticket =
FormsAuthentication.RenewTicketIfOld(identity.Ticket);
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(
FormsAuthentication.FormsCookieName,
encryptedTicket
);
// Better keep this (see * below):
cookie.Secure = FormsAuthentication.RequireSSL;
cookie.HttpOnly = true;
// Isn't a security issue if this is set too long - the ticket contained
// within will still expire after the set time, and the server will timeout
// the auth session on the next request.
// But let's just keep cookie and ticket in sync:
cookie.Expire = ticket.Expiration;
// Add cookie to response to send the changes to the browser:
HttpContext.Current.Response.Cookies.Add(cookie);
Note that FormsAuthentication.RenewTicketIfOld() won't always renew the ticket. It will only renew if less than half of the expiration time is left. I.e., if your timeout in web.config is set to 20 minutes and RenewTicketIfOld is called 7 minutes after the ticket was created, the ticket won't be renewed, and there'll still be 13 minutes left. If it's called after e.g. 12 minutes, it will be renewed to 20 minutes.
The reason for this is because RenewTicketIfOld is used by slidingExpiration on every request and so would send back a new cookie on every request (to reset the expiration to [timeout] minutes). Only sending a new ticket cookie back when at least half the time has elapsed gets rid of a lot of cookie overhead - at the expense of being confusing to developers and end users.
*) On cookie.Secure, see Hanselman: Weird Timeouts - this simply makes sure that if RequireSSL is set in web.config, the cookie will honor that, which avoids many a debugging nightmare if you ever move the site to SSL.

Resources