Status: Waiting for comprehensive answers with code examples concerning dao, service, controller, view.
With spring 3 + hibernate 4, in a service, dao, controller, view (mvc scenario), like http://www.cavalr.com/blog/Spring_3_and_Annotation_Based_Hibernate_4_Example ,
where is the good place to have authentications before doing something. e.g
Occasions:
Is user logged in? (first check by session , then by data base username password match)
session made? getting previous session on every transaction and authenticating if no session has made.
More authentications for every transaction e.g:
get some value or boolean from database, check if its true (e.g can this user add more users), then proceed.
Does user have permissions? and if authentication fails, how to respond to user?
Ways to respond:
a. Redirect to error page (dont like that though)
b. redirect to the same page with an error message (ok)
c. Do all with ajax, (most preferred) dont reload or redirect page, just authentication by
session and or
database
send error message on the same page by ajax.
proceed if authentication succeeds.
Where to put the logic? in dao, service, controller?
What options do I have?
Can some one give a sample code? I have googled but found irrelevent examples.
I know one solution is spring security, but what do you think? and is there a sample code for it that covers all my questions?
Example scenario:
my scenarios is like this. a user comes and a db query tels/lists the borads he has access to. when he enters a board. the boxes privileges are lists and only readable boxes are shown to him. then same with tasks. each of them has create/read/update/delete permision and that is known/fetched at the time when the user acts for one. e.g tries to create/read/update/delete a board/box/task.
now there are millions of boxes / tasks. loading permissions for each might be insane?
I do not understand how to and where to do the authentication and authorization. daos, services,controllers, and then sending the problems to views as error messages. One dao may call another, one service may call another dao(s) and / or service. all or most may give authorization failures. how to pass the failure strings to view placing them accordingly?
Thanks!
Related
I have set max concurrent sessions to one.
Now there are 2 situations I want to handle if there is an active session (Someone is already logged in for that User Id):
If the user accesses login page again on the same browser:
In this case, he will be directly logged in.
If the user logs in from different browser/client machine: In this case, need to show the error "A session is already active for this user. Are you sure you want to overwrite the session?". If the user selects 'yes', the error will be shown at the previous session (this I know error page can be configured), and if he selects no, it will not login, the previous session will persist.
How can these usecases be achieved using spring security? So far, I have been able to found the basic management of concurrent sessions, by setting max session count and error page.
Please help.
Thanks.
I think you have almost done it. To ask user before overwriting a session follow the below steps.
The expiredUrl property of ConcurrentSessionFilter should got to a page where the UI is provided to ask user (e.g. askUser.html).
The askUser.html form submits to another url (e.g. /api/confirmSessionRewrite) with POST parameter yes or no.
In controller ConfirmSessionRewrite either remove the user from session registry or forward it to login page.
sessionRegistry.removeSessionInformation(info.getSessionId());
You have to modify your config so that the ConcurrentSessionFilter would not run on /api/confirmSessionRewrite request. Otherwise it will be a loop.
My question is somewhat similar to the two questions below but they don't quite offer the solution for my particular situation, I think:
How to track login attempts using HttpSession in Java?
Should I use cookies or sessions to store login attempts and current login status?
Here's the skinny.
A user logs in, via a JSP webpage. The form submits to a login authentication servlet created by an external vendor. I cannot modify this servlet nor can I programmatically authenticate the server. It's not that I don't how to modify it but, for business reasons, I cannot touch it.
The user's credentials are maintained on a database that is specific to this same vendor. If the login attempt fails, it returns to the user back to the login page.
With all that said, I need to display a message to the user, if they have been locked out. The lock out mechanism is controlled by the vendor, so I don't have to worry about that. The user is locked out after x attempts. So, say the user is locked out by the system after 10 login attempts. It'd be relatively easy to display the message if I had control of the login authentication servlet. My idea is to create a servlet filter which maps to the login authentication servlet. However, because servlet filters fire before the mapped servlet/url is processed, I can only verify the user up to x-1 attempts.
On the xth attempt, the filter fires before the authentication servlet checks the user's credentials. Say the user's credentials are incorrect. The user would be kicked back to the login page. Now what am I to do? I can't assume the user is using one username. Maybe he has tried some combination of a few username/password credentials to login. Essentially, what I'm running into is the user would have to have x+1 failed login attempts to display a lockout message. I.e., a user is technically locked out after 10 attempts but the lockout message will only show up after 11 or more attempts.
I'm not quite sure what can I do to show a lockout message after x attempts with all these restrictions.
Just to be perfectly clear, in this proposed servlet filter, a vendor DB table, of which I did not create and have no control over, tracks the number of attempts per username. So, in order for me to validate that the user is locked out, I look at this table. I need the username entered at the login page, of course, to do so. I'm not aggregating login attempts in the code. A database table takes care of this.
My problem is I need to display a message on the login page after x attempts for a particular username. With the servlet filter, firing before the login authentication servlet, I can only display it after x+1 attempts for a particular username. Again, I can't assume the person sitting at the computer is using one username or the same person has been sitting there the whole time. There could be multiple login attempts from different usernames at the same computer.
If there really is no feasible way, other than add the lock out validation in the vendor's servlet, then I will try to push for that. Otherwise, I'm not sure what I can do.
Thank you for any help.
How does the redirect work if there is a login failure? If it sends a HTTP 401 then you can check that after you call chain.doFilter but before you return from your own doFilter. Store the number of failed logins in the HttpSession and boot them out when the number reaches 10;
I am making a module for a server software that is allowing support for facebook.
The problem is with the callback URL. If one client start the authorization proccess, then another client starts the proccess at the same time, or before the first user finish. How could I check what user finished first?
I need a way to check what client's callback I'm getting. One solution would be to lock other from register until the first one has finished, but I don't want to do that. Is there another way? I have thought about including ?client=clientid at the end of the callback, but I heard facebook only allows the exact url specified in the app on facebook.
UPDATE
It didn't work to add client="clientid" to the callback. Any other ideas?
After some more searchig I figured facebook will allow a parameter: state. (thanks to #jacob https://stackoverflow.com/a/6470835/1104307)
So I just did ?state=clientId.
For anyone using scribe the code is this:
service.getAuthorizationUrl(null) + "&state=" + clientId;
I think there is no problem on adding and GET parameter like client=clientID. Facebook will redirect you to the URL you have specified and using the REQUEST parameters you can check who completed the request. The problem exist if you have specified URL as http://yoursite.com and pass redirect to http://some-sub-domain.yoursite.com or entirely different location.
if you are using the server-side flow then the oauth 2 flow will be:
redirect user to facebook
facebook then rediects the user to your specified callback
your server uses something like curl to get the access token
your server does some more curl to get maybe more user data or update the user's data
my recommendation would be to set a session cookie in step 1 and simultaneously store this session id on your server. then the session cookie will automatically be sent to the callback url in step 2 and you can identify the session in the database this way.
this will work for all service providers (google, twitter, linkedin, etc) and is the preferred way of maintaining session continuity.
Scenario:
User logs into website.com using firefox. Login credentials are valid, user is directed to member's page.
User tries to log in to website.com using chrome. Login credentials are valid, because use is already logged in using firefox, system will throw error, asks user to close other session to login through chrome.
How can I detect that? Right now I am able to detect it if user only use one browser, but seems to break when user uses two different browsers to log in at different times.
EDIT* I want to say it's more than just using different browsers, the website should not allow multiple people to log in with the same login credentials.
I am assuming your application is j2EE/servlet based. If it is the case, two browsers are independent of each other, hence they have their own sessionId and can function independently, as long as your application does not interfere.
To prevent this scenario, one way to implement is, keep a hashmap of SessionID and UserID in your servlet. You populate this on every successful login, for example via a filter or a valve. When you are populating the hashmap, make a check, to see if any other sessionID is already using this userID. If it is used, check if the corresponding sessionID is still active. If it is not active, allow the login, and delete the stale sessionID. If it is active, terminate the other session and allow the login.
If you're using Spring Security - it may be specified by parameter in the configuration file.
If just plain java - during log-in put user's session id to some storage; when he tries to log-in again you should prohibit it.
But you need to avoid situation when the user will be in storage very long time after closing the browser (one possible solution is short session timeout + keep-alive requests)
In your application, keep a timeout of the user that's updated after each call to the app. You can define the user as 'locked' into a session (for example your firefox session) until either the timeout expires, or the user requests a logout. When you log in on another browse (for example, chrome) it checks to see if there's an active session and, if there is, denies the login attempt.
I'm going to make up a quick example. This isn't even close to production ready and is for illustrative purposes only.
class User {
long lastCheckin;
int userId;
String username;
}
Now, when someone does anything in the app, like viewing a page, you do this
user.lastCheckin = System.currentTimeMillis();
Now, when someone specifically requests a logout, you do this
user.lastCheckin = 0L;
Now, when someone tries to log in, you do this
if(user.lastCheckin + PREDEFINED_TIMEOUT > System.currentTimeMillis()) {
return new LoginResponse(false,"User is active in another session.");
}
You can store a map of logged-in users on an application scope variable like a ServletContext. For example, on your auth servlet, you can probably do something like:
Map<String,String> activeUsers = request.getSession().getServletContext().getAttribute("__ONLINE_AUTHENTICATED_USERS");
//if null, context hasn't been prepared yet, create and attach a new one?2
You have to be careful though. Being an application scope variable, you need to ensure some thread safety and this is something which the servletContext.setAttribute/getAttribute is providing(e.g. those operations are not thread safe). You may be able to handle this by using some sort of application lifecycle listener to 'initialize' the servletContext to have the user map. This way you won't need to worry about the set/getAttribute. You still need to think about the map operations themselves(e.g. use j.u.c.ConcurrentHashMap maybe?).
You also have to take care of cleaning up(e.g. removing from the map) when a user logs out or session times out.
You also have to consider that a user might lock himself out for a long time by this approach(e.g. close browser but do not logout properly, session needs to timeout before the mapping is cleared).
Edit:
You also need to think about scalability and this depends on your application. Are you expecting a million online users? Or only a couple of thousands?
We have a spring security application with a pretty standard setup. Currently we only allow 1 session per principal, rejecting additional logins by the same principal until the first session is logged out or expired (maximumSessions=1, excpeptionIfMaximumExceeded=true).
I'd like to change this so that when a principal logs in a second time with a currently active login on another session the first session is invalidated/replaced. This is easily accomplished using the provided spring security concurrent session control strategy but I am having trouble figuring out how to alert the user. When a user's session is replaced the session is invalidated by the logout handler. The next request will get a redirect to the login page with a error code on the query string. However, if the request which gets this redirect is an image or other non-programatic call I'm unable to handle this.
It seems like I need to put the user into an inbetween state, where they have a session but it is expired and they need to log back in if they didn't mean to replace their original session. However I don't see a good way to do this.
Is there an example of a setup like this somewhere?
Have you thought of working out a polling mechanism in javascript to alert the user when their session is about to be invalidated? This way they will know that their session isnt valid and possibly have a chance to refresh it in case they have partially filled out forms or text areas.
This can also work from the login side. You can add a step after login if they have another session active and have them verify they want to invalidate it.
It seems that an in between step isnt necessary because, generally,authentication should be boolean. Either they are authenticated or they arent. The inbetween zone might be tougher to handle all cases for.