I am using JSF2.0 Mojarra 2.0.2.
I have a method that logs out a user and puts a logout message in the flash, forwards to the login page (which has a div that prints out the flash). However, when I use navigationHandlers handleNavigation method for some reason the flash is not being displayed. I have a similar method that forwards a user to the login page if he/she isn't logged in.
If I handle the navigation through an h:link and just call the logout method directly, the flash is displayed as normal, but if I use the handleNavigation() method, the flash is cleared for some reason.
The code in question is:
public void performLogout()
{
getFacesContext().getExternalContext().invalidateSession();
setCurrentUser(null);
getFlash().put("notice", "Successfully logged out.");
super.getFacesContext().getApplication().getNavigationHandler()
.handleNavigation(getFacesContext(), null, "login");
}
Is there some way I can keep the flash when navigating like this?
thanks.
Edit: I believe this issue is related to another issue involving the flash not being preserved during redirects when xhtml pages are in different directories: http://java.net/jira/browse/JAVASERVERFACES-1635
You're right.
The JSF 2 flash scope is currently extremly buggy, and based on the specification, will probably remain almost unusable: http://javaserverfaces.java.net/nonav/docs/2.0/javadocs/index.html
If you'd like a flash scope that works as follows, consider using CDI, and the flash scope from Seam Faces - http://docs.jboss.org/seam/3/faces/reference/snapshot/en-US/html_single/#flashscoped
"The flash scope should be active from
the moment an object is placed in the
scope, until the moment the response
has completed rendering."
--Lincoln
Related
I have a Wicket 8.6 application. Currently, when logging in to the application, mostly (does not always happen) the user has to login twice. After the first login (after entering the credentials and clicking the submit button) a white page appears saying "If you see this, it means that both javascript and meta-refresh are not support by your browser configuration. Please click this link to continue to the original destination." This is the BrowserInfoPage. After a few seconds the user is redirected to the login page again where he/she has to enter his/her credentials again and press the login button. This time, the user logs in successfully. My question is, how do I prevent that the user hast to enter his/her credentials twice.
From my research I know that it has something to do with the collection of extended browser info. In the init method of my WicketApplication class, I had the following code:
getRequestCycleSettings().setGatherExtendedBrowserInfo(true);
However, I already commented out this code several month ago. For some reason, the described effect occurs for every new deploy now. Maybe a newly added package in the application is the reason for it. I don't know. Is there a possibility to prevent this second login maybe by creating a customized bowser info page which forwards the login? Please point me in the right direction. Thanks.
After some research, I came up with a work around. It is probably not very efficient but it works for me so far. In my custom Session class which inherits from AuthenticatedWebSession, I added the following code.
#Override
protected WebPage newBrowserInfoPage() {
final Request request = RequestCycle.get().getRequest();
if(request.getUrl().toString().contains("LoginPage")) {
if(!isSignedIn()) {
signIn(username, password);
}
PageParametersEncoder encoder = new PageParametersEncoder();
PageParameters parameters = encoder.decodePageParameters(request.getUrl());
String url = parameters != null && parameters.get("originUrl") !=null && !parameters.get("originUrl").isNull() && !parameters.get("originUrl").isEmpty()?
parameters.get("originUrl").toString("pages/home"):"pages/home";
String finalUrl=url.startsWith("pages/")?url.substring("pages/".length()):url;
throw new RedirectToUrlException(finalUrl);
}
return super.newBrowserInfoPage();
}
Some explanation to the code. As mentioned in the question, I want to prevent the user from logging in multiple times. Thus, I check if the request comes from the LoginPage and perform my work around only in that case.
During my implementation, I realized, that the method newBrowserInfoPage is called in the process when I call session.signIn(username,password); on my LoginPage. In this signIn process the authenticate method of my custom Session is called but the signedIn flag in the AuthenticatedWebSession is not changed (keeps false on successfull authentication). Is this a bug? Thus, I have to login again to set the flag to true.
Finally, I read the URL of the LoginPage where I have stored the target URL and forward the user to the target URL.
I am aware this is probably not the best approach but it is the only solution I came up with. If someone has a better idea, I am happy to hear it.
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.
So my webpage has a Link remove Advertisment which should remove the ads from my website and remember to not show any ads in the rest of the session.
My approach at was first was a private static Variable in the controller, which could be set via methods.
private static boolean Ads = true;
public static void closeAds() {
Logger.debug("Ads removed");
Ads = false;
}
I did some research and found out that the session() method provided by the play framework probably would be more suitable.
Anyway my problem is, I don't know how to call those controller methods within my html page, since every HTTP request has to have an response and I don't want to reload my page, I only want to set the variable or session variable.
I figured Ajax could be the answer? I couldn`t come up with anything yet
Play keeps session information on client side within a signed cookie.
So you have 2 options (I would go with the 2nd):
1) Ajax call to update play's session data (because you will not want to modify this on client side with javascript since it is a signed cookie and break things)
2) Create another cookie for keeping the advertisements on/off flag and modify it by javascript on clientside, and then you can check the value of this cookie on server side to achieve ads on/off. This will prevent you from doing an extra ajax call.
I'm using Weblogic 10.3.5. I work on a large legacy enterprise application with Struts (1.x) mapped as the default servlet.
Background
A bit of legacy convolution to start: each enterprise customer has a "subscriber ID" which their users must provide at login in addition to their username and password. Subscriber IDs are numeric and always at least four digits, usually five. If you go to mysite.com/, you are presented with a three-field login page: subscriber ID, username, and password.
Our largest enterprise customers didn't like that, so many years ago we introduced skinned login pages: go to mysite.com/12345, where 12345 is your subscriber ID. We'll prepopulate and hide the subscriber ID field, and skin the login page with the enterprise customer's logo and color scheme.
Years later, we had 100+ servlet mappings, one for each subscriber. Every new customer required a software deployment to add the servlet mapping, so our implementations team was hamstrung by the dev team's deployment schedule, which in turn was limited by our large enterprise customers' need to budget time for user acceptance testing.
To address that, we changed the URL: mysite.com/login/12345, where /login/* is mapped to a single servlet that accepts any subscriber ID. We kept the old servlet mappings around so that existing customers didn't have to change the URL, but that left two annoyances:
A few hundred lines of cruft in web.xml
As a developer or QA, it's annoying to have to know whether this is an old subscriber or a new one before you know what URL to use to log in. Try to use the old method for a new subscriber? You get a 404 page.
Here's what I did
We had a pre-existing custom 404 page, correctly defined in web.xml and behaving exactly as expected. I updated it with the following code, right at the top:
<%
if (request.getRequestURI().matches("^/[\\d]{4,}$")) {
// probably someone trying to log in with the old-style URL
response.sendRedirect(String.format("/login%s", request.getRequestURI()));
return;
}
%>
This worked like a charm, until I noticed one oddity:
Here's what's wrong
The very first time I try to visit a URL that should result in a 404 but will be redirected because it matches the regex, it doesn't redirect. With my debugger, I've determined that the reason is that request.getRequestURI() returns "/errors/404error.jsp" rather than "/12345" like I would expect, resulting in the regex not matching and our normal 404 page being served to the user.
My first thought was that something was telling the browser to redirect to the 404 page, but Chrome Dev Tools "Network" tab indicates that is not the case.
After it fails that first time, my change works every subsequent time until the application server restarts.
If I hit /login/12345 first it loads fine. Any subsequent attempt to hit /12345 will work fine, so it seems like it might have something to do with the login servlet not being fully initialized until after the first request. Weblogic is closed source, so I'm not able to dig into what's happening.
Here's my question
I know it's a pretty weird thing I'm doing; I'm open to other approaches. But the question is this: what's causing the different request URI on the first attempt, and how do I fix it? I've scoured the HttpServletRequest object in the debugger and I don't see any indication of the real request URI.
I'm trying to expire all previous versions of a given page with Wicket 1.5.8. In wicket 1.4, it was done by getPage().getPageMap().clear(). Now in wicket 1.5, page map is gone, and I can't figure out how to dot that.
My use case is that I have a wizard (http://www.wicket-library.com/wicket-examples/wizard/) to create/edit an entity. When the wizard is submitted, the user is redirected to the entities list. At this point I don't want the user to be able to use the browser back button to go back to the wizard in the state it was, and thus want to expire previous versions of the page with the wizard (I am using getPageSettings().setRecreateMountedPagesAfterExpiry(true); so the mounted page will be recreated in a blank state if the page expires when the user goes back, which is what I want).
Looking around I found the possibility to use Session.get().clear(); which removes all pages from the Session (I don't know if the 1.4 version was removing all pages or just all versions of the page used to access the PageMap - which would be better for multi-tab support). However, using that works only partly, as the last page is not expired.
Supposing the wizard is mounted at /wizard, redirecting to /list at the end, the flow would be something like: /wizard?1, /wizard?2, /wizard?3, /list. Now when I use the back button, /wizard?3 is not expired, although /wizard?1 and /wizard?2 are as expected. The session clearing and sending to the list page are done in the onFinish method of the wizard, which reads like this:
#Override
public void onFinish() {
Session.get().clear();
Session.get().getFeedbackMessages().add(new FeedbackMessage(..));
setResponsePage(ListPage.class);
}
So, come to the question itself: would anyone know how to get the expected behaviour, i.e. expiring /wizard?3 as well?
Thanks
Note: ListPage is a bookmarkable page and I tried as well with setResponsePage(new ListPage());
Update with what I finally did base on Andrea's suggestion
It is to be noted that my application uses a custom session object extending wicket's Session; let's call it AppSession.
in AppSession, I added a boolean clearRequested attribute (defaults to false)
in AppSession, I added a static void method requestClear() which is just a shortcut to set clearRequested to true in the session
in the onFinish() of my wizard, just before calling setResponsePage, I call AppSession.requestClear()
lastly I just add a RequestCycleListener to my application.
getRequestCycleListeners.add(new AbstractRequestCycleListener() {
#Override
public void onBeginRequest(RequestCycle cycle) {
super.onBeginRequest(cycle);
AppSession session = AppSesssion.get();
if (session.isClearRequested()) {
session.clear();
session.setClearRequested(false);
}
}
});
Now anytime I need to clear session after an action in order to expire pages, I juste call AppSession.requestClear() and in the next request the session is cleared.
you could clear your session in ListPage. Since this page is bookmarkable you could pass it a page parameter indicating that ListPage must get rid of the pages in session.