Following are the two approaches to validate the current action
Save user details on login in the user session. For every action after login, check whether user has roles and permissions every time. DB needs to be queried since an administrator can change the privilege of the user any time. Query the roles and permissions of the current user and verify the operation every time.
Save user details on login in the user session. For every action after login, check just the roles/permission associated with the session. DB doesn't needs to be queried. However if Administrator or any user changes the permission of the current user from different country invalidate the current user session which should be stored somewhere.
Which of the above would be the best approach on the above ? How to achieve it
Many applications hit the DB for every action.
Some application invalidate the session...
Any reference or code snippet for the above two would be helpful
Not sure whether any other approach is available other than the two
You could employ a hybrid approach: cache roles+permissions in user session for N minutes, then invalidate cache and reload them from the database. Thus, user permissions would be incorrect for no longer than N minutes.
Another approach is to store last update date+time per role in memory and in user session. When an administrator updates role permissions, you set 'update date+time' for this role to 'now'. Also, for each user action, you first check whether 'load date+time' for their role stored in their session is older than that global update date+time stored in memory. If it is older, then you need to reload role and its permissions from database.
This will only work well if
You only have one application instance (no distribution), or you can share that data a lot faster than access the database (some kind of a distributed cache?)
Permissions are changed by administrator via the same application
Your security model is not too complex
Imagine that you have an object roleUpdateTimes that contains a map from a role to its last update date+time (or null if the role was not updated since last restart).
When a role is updates by an administrator, the following is done:
roleUpdateTimes.updated(roleName);
where updated() method just puts the current date to the map:
public void updated(String roleName) {
map.put(roleName, new Date());
}
map may be a ConcurrentHashMap here, so that we have a correct behavior knowing that the map will be accessed by different threads.
For the user, you could have the following in a Filter:
Date roleDate = getRoleDateFromSession(session);
String roleName = getRoleNameFromSession(session);
if (roleUpdateTimes.roleIsStale(roleName, roleDate)) {
... reload role permissions from database and save them to session
saveRoleDateToSession(session, new Date());
}
And
public void roleIsStale(String roleName, Date snapshotDate) {
Date updateDate = map.get(roleName)) {
if (updateDate == null) {
// role was not changed by admin, it's not stale
return false;
}
return updateDate.after(snapshotDate);
}
Also you might need to load map on startup: just put new Date() for every known role.
Related
I use the Firebase realtime database in my Android app where disk persistence is enabled.
When the user opens the app for the first time I read auth status, if that is null I show the login screen and after the login, I will get the username stored against this user id in the realtime database.
If the username is null then I will show username setup screen where he will choose the unique username for him. The problem arises when the connection goes off during the username setup phase. username is not yet written to the database but when he opens the app next time username will not be null as Real-time database gives me value stored in the cache. So I proceed to the home screen but what if someone else chooses the same username during this phase?
I maintain two-way mapping between uid and username as suggested in this answer
I can't use transaction because at a time transcation can be run only on one path but in my case, I have to automatically update two paths.
I also have security rules setup up for maintaining unique username but what to do with the users who are already crossed the username setup screen.
What if someone else chooses the same username during this phase?
Everytime you want to perform a write operation for a user name, you need to make sure it's unique. To check if a user name exists in a Firebase realtime database, a query like this is required:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
Query query = rootRef.child("users").orderByChild("userName").equalTo(userName);
query.addValueEventListener(/* ... */);
So if the user tries to set/change the user name while offline, the above query is added to a queue. Once the user regains the connection, every change that is made while offline, will be updated on Firebase servers. With other words, the above query will be commited on the server. So if a user chooses a user name that already exists in the database while offline, when is back online, he'll receive a message that user name already exists.
I can't use transaction because at a time transcation can be run only on one path but in my case, I have to automatically update two paths.
I cannot use transaction because it can be run only on one path, you cannot use transactions at all. Transactions are not supported for offline use. This is because a transaction absolutely requires round trip communications with server in order to ensure that the code inside the transaction completes successfully. So, transactions can only execute when you are online.
I have a Vaadin application that starts with a user login, but the problem is with Vaadin is the session handling as I can open two sessions from 2 different browsers with the same login which should not be possible to do. But I did not find any documentation regarding that besides this topic but it's not working properly as the data are not saved in the hashmap correctly.Anyone got the same problem?
Vaadin 7 works by default so that it creates everytime a new UI instance when a new browser tab is opened (or the tab is refreshed). You should store information about current user to VaadinSession or standard HttpSession and check in UI.init() if the session contains user information.
To store information into VaadinSession one can say:
VaadinSession.getCurrent().setAttribute("currentUser", currentUser)
HttpSession can be accessed as follows in Vaadin:
VaadinSession.getCurrent().getSession()
Please note that VaadinSessions are stored into HttpSession and HttpSession can contain multiple VaadinSessions if multiple Vaadin servlets are deployed from the same war file, and the user uses those at the same time.
How to prevent concurrent logins?
I keep track of logins using a self-generated login-token. A random string between 32 and 128 bytes in length that gets stored in a cookie and a backend database, typically under a user's account.
If User (A) shares her login credentials with User (B) a new login-token is generated for the new login and stored in a cookie and updated in the backed database.
If User (A) (who might for example already be logged in) attempts to perform an action while User (B) has just logged-in, User (A)'s session will be destroyed and she'll be redirected to the login screen after a backend test confirmed her login-token isn't a match.
Think of Sessions and Logins as two different things. Sessions can be generated all day long, but login STATE should be stored in a central store.
You can save all logged users to static Set. Static variables are globally shared. On start app, check whether the collection is already login.
I am trying to implement the functionality with which , when a user is loggedIn at one place and when he try to login to some where else , He should automatically be LoggedOut from the previous place .
Like in GMAIL..
If some one can give me the concept , As i think I need to save the user LoggedIn Status in Db,As sessions doesnt looks to be heplful. But then I dont understand how we update user status in DB ,if there is no activity for lets say 5 minutes (how will i capture the inactivity and updating in db).
If some one can please guide, I am struggling on this for hours now .
Thanks
When user login add the user session with id to a hashmap. When the same user logins again check for entry in the HashMap and if available invalidate the session and create new session for the user.
If you are using Spring Security, it provides this functionality out of the box.
Otherwise:
Create a java.util.Map (A ConcurrentMap is prefered, so manipulating it concurrently won't corrupt it), and stores it in application scope (ServletContext).
Now, you shall store each user and a reference to its session upon login in the map, and if a user logins again, just fetch previous session object and invalidate it.
Now implement an instance of javax.servlet.http.HttpSessionListener, and in void sessionDestroyed(javax.servlet.http.HttpSessionEvent httpSessionEvent); method, remove the specified session from the Map. (This listener is invoked on session invalidation, whether it is done automatically by container or if you do it programmatically). just register this listener in web.xml and everything is done.
p.s. I know that it will be some-how harder, if you are deploying your application on a cluster of web-containers, but when you have just one server, that's ok.
p.s. I don't recommend storing session information in DB.
I am trying to create a webapplication using Spring. The webapplication is a beta/demo site, which is invitation only. So, I need to generate a link to the webapplication url, appending a unique id, which would be valid for 24 hours. User can use that link for 24 hours and make use of the (I kind of also have plans of restricting the user by ip)
To achieve such token generation and expiry, should I just rely on the container with session time out to do it? or does it make sense to create spring backed service layer with token creation and expiry services?
EDIT
Now that I have a bounty on this to draw more attention, I thought I will rephrase the question so that it makes more sense - what would be a good strategy to force users out of a web application after a certain period of time?
Relying on session timeout would not be sufficient solution .
I am not acquaint with Spring . I would put my generic solution as below for any web application having requirement as yours :
Invitation is assumed to include a link to the Web Application .
The link is assumed to include the unique id .
The Beta/Demo user table is assumed to have a beta-expiry ( datetime ) column to hold the expiry date and time .
When your web application is accessed using the link in the invitation , update the beta-expiry column for that unique_id considering 24 hrs from then .
When a Beta/Demo user attempts to sign in , check the beta-expiry column for that particular user and allow access if the expiry is not reached . Display appropriate message in case of expiry .
Whenever a signed in Beta/Demo user performs subsequent accesses to your web application , check the beta-expiry column for that particular user and allow access if the expiry is not reached . Display appropriate message in case of expiry .
If seems useful , display a countdown timer showing the left over time somewhere in the header area .
In case of extension of Beta usage for all or a portion of users , you could update the beta_expiry column appropriately .
Additionally you could also have an invitation-expiry column to hold invitation expiry considering a particular duration for eg. a 48 hrs from when the invitation was sent .
We use a little bit similar solution to sign out ( signed in ) users from our SaaS application after a particular duration of no access .
I think that you should rely more in the back-end rather than a session on a cookie, imagine the case that you set the cookie for 24 hours expiration but the client deletes the cookies from the browser, (depending on your logic) your link will generate a new session or the request will be blocked.
IMHO you can store a session cookie on the client but you need to have a second source of comparison in the server, maybe a database, no-sql document, a collection in cache, something that you can compare and check the latest access to the client.
just to put all together imagine the following use case:
the user get the invitation link and click on it
the system check if the first time they log into the system, and save that date as a "start date" and another one as "last access"
the system sets an authentication cookie with 24 hours expiration
the system track every post back/ ajax call to the server and update "last access" date
if user deletes the cookie the system check the "last access" and make a comparison with the current server date
if valid the system creates a new auth cookie with the remaining hours
if not valid the system sends a message to the user.
for the user the cookie will expire according to the time left (calculation between start date and last access)
I hope this helps.
regards
One strategy is to keep track of expiry date-time of all the users by storing the relevant data in DB and using a cache library (to reduce DB hits while checking for the expiry date). Here is a small example:
Create a DB table with columns to map user id to expiry date: id, unique_user_id, expiry_date_time. You need to create the unique user id in your code and save it in DB before sending the URL to the user with this id. You can keep null as the initial value for expiry_date_time. Create a class to represent this mapping in Java:
class UserIdWithExpiryDate{
private String userId;
private Date expiryDateTime;
...
}
Define a Service with a cacheable method that will return an instance of this for a given userId :
public interface CacheableService {
#Cacheable("expiryDates")
public UserIdWithExpiryDate getUserIdWithExpiryDate(String id);
public void updateUserIdWithExpiryDate(String userId);
}
import org.joda.time.DateTime;
#Service
public class CacheableServiceImpl implements CacheableService {
#Autowired
private YourDao dao;
#Override
public UserIdWithExpiryDate getUserIdWithExpiryDate(String id) {
return dao.getUserIdWithExpiryDate(id);
}
public void updateUserIdWithExpiryDate(String userId){
Date expiryDate = new Date(new DateTime().plusHours(24).getMillis());
dao.update(userId, expiryDate);
}
}
The result of getUserIdWithExpiryDate method is stored into the cache so on subsequent invocations (with the same argument), the value in the cache is returned without having to actually execute the method.
Next step is to check the user's expiry date while accessing the site. This can be done using OncePerRequestFilter:
#Component("timeoutFilter")
public class TimeoutFilter extends OncePerRequestFilter {
#Autowired
CacheableService cacheableService;
// Here you need to decide whether to proceed with the request or not
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
filterChain.doFilter(request, response);
}
}
Steps that can be taken inside the doFilterInternal method to check the validity of the user:
Get the user Id from request
Execute: cacheableService.getUserIdWithExpiryDate(userId)
If step 2 returns null, there is no user present with this id. You should not proceed with the request.
If step 2 returns an instance of UserIdWithExpiryDate, check the value of "expiryDateTime"
If the value of "expiryDateTime" is null,it means user is accessing the site for the first time.Update "userExpiryDate":cacheableService.updateUserIdWithExpiryDate(userId) and proceed with the request.
If "expiryDateTime" is not null, compare this with current date_time. If expiryDateTime.isAfter(currentDateTime), proceed with the request.
For caching, you can use Spring Cache Abstraction with EHCACHE.
Tokens
For this marketing purposes we generate tokens upfront, store them in a database alongside all information like restrictions to certain user account, ip ranges (for certain mobile carriers), the date and time ranges of use and so on.
In case of one time codes we just mark it as being used in the database.
To generate those codes we use Random Numbers or encode some information and use (SHA-1 or better). Then we use bigInteger.toString(36) or a different scheme and group the first 16 letters to let it look like a license key.
If we express information with it like useraccount/name or carrier (mobile) or whatever we can even validate the token without a database.
Forcing User Out
Just check for the validity of the token the first time the user starts a session or logs in. Throughout the session you just check if the token has expired (store a value in the session if you have one, append it (encrypted) in the url or whatever or check against a database.
So on every request you just check if the user has permission to access your site otherwise you block the user with an error / info page.
You can also add a java script to each page. The script can determine whether the users permission to use your site has expired by:
Encrypt the relative time that the token is valid in a hidden div and calculate the absolute time using the users local time. Then compare the absolute expire time with the user time every now and than (lets say every 3 seconds) and you can yourself all those polling and pushing (comet, ajax, websockets) behaviour.
Once the java script program notice the token has become expired remove the content sections and replace it (or mark a hidden div as visible) with the info / error page content. This way every time the user revisits pages still stored in the browser history are destroyed also. (if this is a necessity for you).
Summary
Use random tokens and a database or encrypt information (like the day the token can be used) and SHA-1.
Check the tokens validity every time the user requests a page (store the timeframe in a session / url to save roundtrips to the database)
Provide a java script that destroys local pages in the history on revisit.
Here I can think of two use cases that I have seen.
1.) This kind of management is used in applications like online tests or email verifications, where user is provided a link with some token. This link and the token is valid for some fixed period of time and can be used only once. (Ex. online tests or password reset-emails)
2.) Another use case is to provide link with a token which are also valid for a fixed period of time, but in this case the link and the token can be used any number of time within the time period allowed (Ex. Online registration forms for test or some university enrollments).
So, definitely managing this using a session only will not be a good choice as the browsers can be cleared.
So you need to maintain the pair of the link and the token at the server (May be in a DB) with some other information like last accessed time, creation date and time, Valid upto .
To be more flexible validity time for link and the token can be set differently (eg. link can be used for a set of users, but the tokens are unique to a user).
So you can use this info on every user visit to check whether the link or token is still valid and what are their last accessed time. If it turn out to be expired then you can show the relevant error message.
What about "deleting the user's account" (depends on how you are building your logging system) after 24 hours.
Coupling this with checking user's account every time (s)he loads the page, will force him/her out at the first refreshing after the 24 hours threshold passses.
You can store the id with expiration time and when a request comes in with that id check if
it's still valid
and if you are trying to accomplish something like id is valid say 5 hrs after first request then store time when the first request is made and for each subsequent request check if it's still valid
i have one java web application in jsp and servlet and db as oracle 10g EE. In login if one user has been logged in then how can i prevent same user from logging again unless sign out?
Note: I am not telling that if a logged in user will click on login page then immediately he would be forwarded to his home page.
I am asking is how can i prevent that logged in user to login again if he is already logged in. Suppose user A is already logged in into the db(sign out not done), then user B tries to login in to db with the user id and password of user A, then simply user B will be prevented from login. How do i implement that?
You need to manage a map of logged in users, Map<String, String> userToSessionIdMap when user logs in you check if there is any session exist for this user name if yes deny else allow login,
Now on logout you need to remove the entry from map, also you need to implement HttpSessionBindingListener so when session expires it removes the entry again
Also See
prevent multiple login using the same user name and password
Preventing multiple login
Let the database do it's own job!
(This solution assumes that you can get help from DBAs; or you have SYSDBA access to the database.)
First create a profile that allows only 1 session per user:
CREATE PROFILE single_session_profile
LIMIT SESSIONS_PER_USER 1;
Then create the user with the right profile or alter an existing user to use the profile:
CREATE USER user_a
IDENTIFIED BY user_id
DEFAULT TABLESPACE users
TEMPORARY TABLESPACE temp
QUOTA UNLIMITED ON users
PROFILE single_session_profile;
or
ALTER USER user_a
PROFILE single_session_profile;
Finally, the database needs to be observe these limits:
ALTER SYSTEM SET RESOURCE_LIMIT = TRUE SCOPE = MEMORY;
(SCOPE = MEMORY enables limit enforcement for the currently running database instance; if you want to make it persistent, i.e. enabled after a database restart, you need to use SCOPE = BOTH where BOTH means both MEMORY and SPFILE, i.e. DB initialization file. If the database does not use the new SPFILE format, but the old PFILE (init.ora), then you need to add the RESOURCE_LIMIT setting to the init.ora and restart the database.)
That's it. If a user_a tries to log in twice, it will get:
ORA-02391: exceeded simultaneous SESSIONS_PER_USER limit