Using Spring 4.2.9
Web-Flow: My web-flow has three pages page-1, page-2 and error-Page
Scenario: User clicks on a link in the email, my back-end code consumes the link and user lands on a page-1(the link in the address bar now is different than what the user clicked on), the user does the required stuff on page-1 and clicks continue button and lands on page-2.
What I need when the user is on page-2:
User presses browser back button they should go to error-Page.
The user had copied the link when they were on page-1 and open a new tab and paste the page-1 link, they should land on error-page.
It's a quite common problem. A simple google search gave some possible solutions. Did you tried them? If yes, then update the question with more specifics on the issue. If not, here are a couple of links:
How to Detect Browser Back Button event - Cross Browser
Solution to browser back button click event handling
You can achieve this by configuring a Spring MVC filter (or interceptor). There you can check if the request is GET and it contains the url that you want to block. If true, you can redirect that request to the error or access denied page.
To prevent the user from resetting values when going back with the browser back button you can put a variable in the conversationScope, variables in this scope are not reverted to their previous state when you use the back button. You can this way set a variable when they reach part 2 and check for it when you load part 1, but for this to work part 1 and part 2 need to be in the same flow.
To prevent the users from using a link again, if they are authenticated users you can save a flag in the database that say they have finished the flow and simply look at the database when loading part 1 and throw an exception if the user shouldn't have access. If they are unauthenticated users (like when doing surveys), give each users a token in the url (the token should be random enough that it cannot be brute forced easily) and store it in your database, when part 1 load check that the token is in the database and when your flow is done remove the token from the database.
If you can't do any of this, you can use cookies, just send a cookie to the user when they arrive on part 2, their browser will automatically send it on any new request so if you see it on part 1 you can throw an exception. But users will be able to delete their cookies to circumvent the protection.
Changing page-2 to end-state solved the problem. The solution was mentioned in "The Definitive Guide to Spring Web Flow".
Thank you all for your help.
Related
Background:
I've successfully added Google authentication to my website. There's a Login button that works (and stores the user from the db into the session) as well as a Logout button that logs out the user from my application, but obviously not from Google also. There's a menu item that reflects that authentication by only displaying the appropriate Login or Logout menu item, plus access to a Profile page if they're authenticated. In my SecurityConfig.filterChain() method, I have
.antMatchers("/secure/**").authenticated()
to ensure users can't get into the secure part of the site (ex: secure/xyz) without being authenticated.
Problem:
However, when a user returns to my website (with a new session) and is still logged into Google, my application thinks the user is authenticated and allows access to the secure URLs, via the browser address bar (ex: secure/xyz), without having to log in again.
I want to know if a user is authenticated when they return to the site, at the very least for UI purposes (displaying Login or Logout). Storing the User in the session is insufficient. I assume I need a SessionListener or a HttpSessionIdListener for this, but I'm not sure what code to put in the sessionCreated() or sessionIdChanged() method to get the identity of the authenticated user. What code do I need?
Well, the actual solution show that I'm still learning. When the user returns back to the site, they are not already authenticated. I thought they were only because I had things in SecurityConfig.filterChain() in the wrong order. Once I put
.antMatchers("/secure/**").authenticated()
at the beginning, everything started working as expected.
We are developing Java-Gwt web application and we have a login page to access the application. Recently we had facing
one scenario which is described below.
1) The user opens the application in one browser window (say Chrome) and login page will show to the user.
2) The user again opens the same application in another browser window (say Chrome) and there also login page will show to the user.
here, the user enters the login credentials and access the application from the first browser window, then again user enters the
different login credentials in the second browser window and access the application. Here We have opened application with two different
credentials in 2 browser windows even though the browser instance is same.
If we do like above we are going into inconsistency state as per our implementation.
What is the best way of doing in the above case?
I have observed in 'Gmail' application with the above explained case, It is reloading the second window if the user logs in first window.
If We consider 'Gmail' is good example how to detect second browser window from first window in GWT or JavaScript?
Any suggestions would be great.
Okay, I misunderstood your question. So you have cookie/HTTP sessions implemented properly, and the following occurs:
A user loads the login page in two browser windows (or tabs) of the same browser application. A single HTTP session (unauthenticated) and corresponding browser cookie are created (on the first load).
User logs in as user A in the first window, which updates the session and cookie to reflect that user A is logged in.
User then logs in as user B in the second window, which updates the session and cookie to reflect that user A is logged in.
If your app has user-specific content, user A's data will still be displayed in the first browser window, but refreshing the page or browsing around will show that it's really user B logged in.
None of this behavior is indicative of a problem, but you'd like to be able to detect when this has happened (or at least steps 1-3). To do this, I would recommend storing something about the user in the session/cookie after authentication, such as an ID (you may already be doing this). When setting this value in the HTTP session/cookie, first check to see if there's already a non-null value in it. If so, then you have successfully detected the scenario above.
So after authentication, something like this, where request is the HttpServletRequest:
Integer userId = (Integer) request.getSession().getAttribute("userId");
if (userId != null && userId != newlyAuthenticatedUserId) {
System.out.println("Second login from same browser!");
}
request.getSession().setAttribute("userId", userId);
Phase 1: I succesfully confirm the user password in a web form using HttpClient and HttpPost.
In this case, the code I receive from the server is 200OK.
Phase 2: Now, let's say the user will attempt to confirm his password again. But he can't do that,
because the initial URL won't exist anymore, so he will be redirected to the login page.
Here's a bit of a difficulty: in this case, server responds again with 200OK, not a redirect code.
How can I differentiate between the first phase and the second?
I tried
serverResponse.getStatusLine().getStatusCode();
and
serverResponse.getLastHeader("Location").getValue();
without luck, as there's no real redirect happening from the server point of view.
I thought about getting the response content and parsing it as html, but I believe that's not a good solution.
I also thought about storing in a boolean SharedPreference the confirmation action, but then there's the case when the user has multiple devices.
Another possible solution is to hide the confirm password fragment, once the user confirms his password.
What do you think it would be a good way to differentiate between phases or to prevent phase 2?
I appreciate any idea.
Thank you.
Summary
In our web application when the user clicks "faster" than the page loads, apparently the browser shows the first request to the user (according to some error messages we get). I would have expected that to be the second request.
More background information
We have a Struts1 web application. In the user session we put the current context of the user interaction.
request.getSession().setAttribute("context", <something>);
For instance, the app shows a list of master records, and the context holds information about the user. When the user clicks on a master record, we save the the information about that record in the user session object. In the JSPs we often would assign the context object to a local variable. This needs casting to the specific type (e.g. MasterRecordDTO or UserDTO):
<% MasterRecordDTO dto = (MasterRecordDTO) request.getSession().getAttribute("context"); %>
The user can then drill down into details views of that master record. We have a breadcrumbs showing sth like list > master > detail. These are links so the user can navigate using breadcrumbs.
Now when in that situation the user clicks first on "master" and quickly enough on "list" he gets an ClassCastException saying
"UserDTO cannot be cast to MasterRecordDTO"
in the MasterRecord-JSP, which means that when the MasterRecord-JSP assigns the dto variable in the first request, the second request has already set the context session attribute to a UserDTO object.
Question
I would have expected that the browser would "abandon" the first request and shows the result of the second request to the user (the list of master records in this example). Can anybody explain this to me?
Update
The breadcrumb links are in another HTML Frame. We have this issue with Internet Explorer 7. I tried it with Firefox 11 but apparently it doesn't even submit the second click.
I guess it's a general concurrent programming situation.
The browser send 2 request simultaneously to server, the server use 2 threads to handle 2 request.
request/thread 1 set session attribute context to MasterRecordDTO
request/thread 2 then changed it to UserDTO (Here's the source of the problem)
request/thread 1 continue running, it will cause ClassCastException occured.
request/thread 2 continue running, it will generate a successful response to client. (but the browser does not show it)
The behaviour of browser is not controled by your application, it just show the result of response 1 (sometimes may be response 2, it's also a concurrent situation, because most current browsers are multi-threading designed).
Try to use request scope to store such context information to get an expected result.
I have a web app in which I have set the maximum inactivity time to 10 min. This is just for testing purposes. Basically, if the session has timeout and I click on a link, the following window browser checks if the session is valid. This is also working fine. If this happens, I get a message saying "session has expired, please login again". But the orginal window stays open and if I click on the same link, then this time is letting me see the page, even though I have not logged in again. Why is this?
I am using the session.invalidate() if the session is expired, to make sure all attributes are removed, but this is not working somehow.
I using the following part of the code at the beginning of the page:
if(request.isRequestedSessionIdValid() == false)
{
response.sendRedirect("expired.jsp");
session.invalidate();
return;
}
This is working the first time this page is loaded, but if I click on the link again to load it once more, this condition is not met, despite the session being timeout.
Could you please give any advice?
Update: My webapp works the following way:
User gets to the index.jsp page and uses an ID and password to access the system, then there is a BRMspace.jsp page where there is a folder structure for the user to access depending on the documents they are after. By clicking on each folder, a table with a database populated is displayed for the user to download the documents they want.
The issue I am having is that after 10 min of inactivity, if the user clicks on one folder on the initial screen, the database is not displayed, instead I get a message saying that session has expired and I am redirected to the login page, which is ideal. However, if I click on the same folder again, this time I get the usual table with the data and all documents. It seems that after one click, the inactivity time is not longer valid.... so I am not sure how to do... I am using session.invalidate() to delete all data about the session, but obvioulsy is not working.
I need the user to be redirected to login page again after the inactivity time no matter where the user clicks on.
This is an update:
Hi there, I have to re-take this question, which has been very helpful to resolve 90% of my original issue, but I still have one left.... on my web application, when user logins, they have a list of options to click on, each click takes them to a new tab which are different .jsp files... if session has expired, these tabs show the expired.jsp file, which is perfect... however, the original tab, the one that is shown after the user logins, stays live, I mean, it does not show that the session has expired... what can I do in this case?...
A web session doesn't have anything to do with any login or access credentials. It simply means that the container has data saved for you that can be retrieved if you pass in the correct session token (either by cookie or request parameter). If you have been inactive on the site for a period of time (in your case 10 minutes), that data is discarded and if you check for a sessions validity, you will discover whether the data is still around or has been discarded. If the session has expired, the container will automatically create a new session for you to handle future requests. And if another request is sent to the server before the timeout expires, that requested session will not be invalid.
If you are trying to prevent people from access a page when they have not logged in, you actually need to put some value into the session that says they have authenticated, and check that value. Just checking whether their requested session is valid is not sufficient.