within JSF, how to get the real request url - jsf

everyone:
I'm using jsf to do my work.now i want to filter some request,so i need to get the real request url in my filter.
But i don't know how to get the real request url,for example,there is a "commandlink" with a action="#{backBean.test} in my test.xhtml page,now i want to filter the method test,how can i realise it?
i tried to get the request url with HttpServletRequest,but i just got the "test.xhtml" and faild to get the test method...
the following code is part of my filter:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse)response;
String reqUrl = req.getRequestURI();
String willFilterUrl = reqUrl.substring(reqUrl.lastIndexOf("/") + 1, reqUrl.length());
String contextPath = req.getContextPath();
if("order_confirm.xhtml".equals(willFilterUrl)) {
resp.sendRedirect(contextPath + "/pause_1.xhtml");
return;
}
chain.doFilter(req, resp);
}
Thanks a lot!

Related

JSF, session timeout handling [duplicate]

This question already has answers here:
Authorization redirect on session expiration does not work on submitting a JSF form, page stays the same
(2 answers)
Closed 4 years ago.
I have configured my session timeout in the server and have added a filter to handle session timeout. But when I am trying to redirect it back to the login page its not working. I searched the net but not getting anything solid. I am using jsf.. my code
public class SessionTimeoutFilter implements Filter {
private String timeoutPage = "login.seam";
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain filterChain) throws IOException,ServletException {
if ((request instanceof HttpServletRequest)
&& (response instanceof HttpServletResponse))
{
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
if (isSessionControlRequiredForThisResource(httpServletRequest)) {
if (isSessionInvalid(httpServletRequest))
{
String timeoutUrl = httpServletRequest.getContextPath()
+ "/" + getTimeoutPage();
System.out.println("Session is invalid! redirecting to timeoutpage : " + timeoutUrl);
httpServletResponse.sendRedirect(timeoutUrl);
return;
}
}
}
filterChain.doFilter(request, response);
}
Can anyone tell me what am i doing wrong... why is sendredirect not responding
Maybe this solution will be proper for your needs:
How to redirect to index page if session time out happened in jsf application
if you need perform some action on session timeout you can also create #Destory annotated method on session statefull bean.

Bypass login filter for 1 time when user chose continue as guest

I have a booking page with URL /booking/Create.jsf. I have a filter for URL pattern /booking/* so the user is asked to login on the page /login/signin.jsf before being taken to Create.jsf. But I have a button "Continue as guest" so that user that is not registered can create a booking on Create.jsf page without log-in. How can I make that happen. Any help will be appreciated. My filter looks like
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
UserLoginController loginController = (UserLoginController) req.getSession().getAttribute("userLoginController");
if(loginController != null && loginController.isLoggedIn()){
chain.doFilter(request, response);
}
else{
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.sendRedirect(req.getContextPath() + "/login/signin.jsf");
}
}
The page create.jsf is considered in the end as public page. So, in order to enable the filter for other pages concerning "booking", just create a new subfolder named for example "user" inside which you should put others pages of "booking", the new url pattern of the filter will be as a result: /booking/user/*. This way, the other stuff of booking remains safe and the page /booking/create.jsf will be easily available for the users and guests because it's not covered by the filter.

JSF page style missing when using login filter

I am using following filter to control access to all pages in JSF 2.0 using GlassFish as application server. The problem is that with this code although filter works fine and user are redirected to log.xhtml if they try to acess anyother page directly but the login.xhtml does not look good (no colored image displayed and while page shape changed) as it should be. However if i remove the sendRedirect statement and replace it with chain.doFilter statement, then the page displays in the same way as it should be looking nice and good however filtering does not work obviously. How can I fix this problem?
LoggingFilter.java
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
LoginBean auth = (LoginBean) req.getSession().getAttribute("loginBean");
if ((auth != null && auth.isLoggedIn()) || req.getRequestURI().endsWith("/login.xhtml")) {
// User is logged in, so just continue request.
HttpServletResponse httpResponse = (HttpServletResponse)response;
httpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
httpResponse.setHeader("Pragma", "no-cache"); // HTTP 1.0.
httpResponse.setDateHeader("Expires", 0); // Proxies.
chain.doFilter(request, response);
} else {
// User is not logged in, so redirect to index.
HttpServletResponse res = (HttpServletResponse) response;
res.sendRedirect(req.getContextPath() + "/faces/login.xhtml");
//FacesContext.getCurrentInstance().getExternalContext().dispatch("/login.xhtml");
//chain.doFilter(request, response);
}
}
This filter also redirects all requests on CSS/JS/image files to the login page. The browser end up getting a response containing some HTML code representing the login page instead of the concrete CSS/JS/image content it requested for and hence the browser fails applying the necessary look'n'feel.
Provided that you're 100% utilizing JSF resource management (<h:outputStylesheet>, etc) and thus they are all covered by /javax.faces.resource/* URIs, rewrite your filter as follows:
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
LoginBean auth = (session != null) ? session.getAttribute("loginBean") : null;
String loginURL = request.getContextPath() + "/faces/login.xhtml";
boolean loggedIn = auth != null && auth.isLoggedIn();
boolean loginRequest = request.getRequestURI().equals(loginURL);
boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + "/faces" + ResourceHandler.RESOURCE_IDENTIFIER);
if (loggedIn || loginRequest || resourceRequest)) {
if (!resourceRequest) {
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(request, response);
} else {
response.sendRedirect(loginURL);
}
}
Note that no-cache headers should not be set on resource requests, otherwise you defeat the benefit of the browser cache on CSS/JS/image files.

After logout, all restricted pages are still available in browser history, how to prevent that?

Here is my logout method:
public String logout() throws IOException, ServletException
{
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext ec = context.getExternalContext();
HttpSession session = (HttpSession) ec.getSession(false);
HttpServletResponse response = (HttpServletResponse) ec.getResponse();
final HttpServletRequest request = (HttpServletRequest)ec.getRequest();
session.invalidate();
Cookie[] cookies = request.getCookies();
Cookie opentoken = null;
for(Cookie c : cookies){
if (c.getName().equals("opentoken")){
if (session != null){
opentoken = c;
opentoken.setMaxAge(0);
opentoken.setValue("");
response.addCookie(opentoken);
response.sendRedirect(request.getContextPath());
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Cache-Control", "no-store");
response.setHeader("Cache-Control", "must-revalidate");
response.setHeader("Expires", "Mon, 8 Aug 2006 10:00:00 GMT");//past date
}
break;
}
}
context.getExternalContext().getSessionMap().remove("#{LogoutBean}");
return "login.xhtml?faces-redirect=false";
}
After calling this method, the navigation in browser history is still working. How can I solve this?
When you set response headers, it applies on the current response only, not on all previous responses (the restricted pages) or future responses (the redirect(!) and thereafter). You actually want to turn off the browser cache on all responses of the restricted requests. And indeed, as you guessed in your comment, you should be using a servlet filter for this.
Another problem is that when you call response.setHeader(), you're basically overridding any previously set header. You don't want to do that, the must-revalidate has totally no effect if no-cache and no-store are absent. You need to set the values commaseparated as a single header, or to use response.addHeader().
All with all, you should have a class like this in your webapp:
#WebFilter("/app/*")
public class NoCacheFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
chain.doFilter(req, res);
}
// ... (just implement init() and destroy() with empty bodies).
}
This example assumes that all restricted pages are available behind the /app/* URL pattern. If yours is different, e.g. /secured/*, /user/*, /admin/*, etc, then you need to alter the URL pattern in the #WebFilter accordingly.
Once done that, your logout() can then be simplified as follows:
public String logout() {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.invalidateSession();
if (ec.getRequestCookieMap().get("opentoken") != null) {
ec.addResponseCookie("opentoken", null, Collections.<String, Object>singletonMap("maxAge", 0));
}
return "login.xhtml?faces-redirect=true";
}

How to avoid ;jsessionid=XXX on the first call to a page? it works if first page is jsp

I have an application which uses the welcome-page index.jsp with an <iframe></iframe> the contents of the iframe is a jsf page. If I access index.jsp I see a cookie already on the first get in firebug:
Set-Cookie JSESSIONID=C615DA89B6EF73F801973EA3DCD3B226; Path=/
The page of the <iframe> inherits this jsessionid. BUT: when I directly access the page of the <iframe/> I get the jsessionId rewritten to all URLs without a cookie - on the first request. Afterwards the cookie is used. This is all fine - if:
The security system would allow me to perform url rewrites.
I run jboss 4.2.2
I want to achieve the same behaviour as I have with the index.jsp - e.g. always use cookies and always avoid http rewrite.
[EDIT]
thanks to balusc's answer I wrote this:
public class JsessionIdAvoiderFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
ServletException {
boolean allowFilterChain = redirectToAvoidJsessionId((HttpServletRequest) req, (HttpServletResponse)res);
//I'm doing this because if I execute the request completely, it will perform a pretty heavy lookup operation. No need to do it twice.
if(allowFilterChain)
chain.doFilter(req, res);
}
public static boolean redirectToAvoidJsessionId(HttpServletRequest req, HttpServletResponse res) {
HttpSession s = req.getSession();
if(s.isNew()) {
//after the redirect we don't want to redirect again.
if(!(req.isRequestedSessionIdFromCookie()&&req.isRequestedSessionIdFromURL()))
{
//yeah we have request parameters actually on that request.
String qs = req.getQueryString();
String requestURI = req.getRequestURI();
try {
res.sendRedirect(requestURI+"?"+qs);
return false;
} catch (IOException e) {
logger.error("Error sending redirect. " + e.getMessage());
}
}
}
return true;
}
}
Don't forget to add it to your web.xml
<filter>
<display-name>JsessionId Filter</display-name>
<filter-name>jsessionIdAvoiderFilter</filter-name>
<filter-class>my.namespace.JsessionIdAvoiderFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>jsessionIdAvoiderFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
Since Servlet 3.0 you could use <tracking-mode>COOKIE</tracking-mode> for this. But as JBoss 4.2.2 isn't Servlet 3.0 compilant, this isn't an option.
Easiest would be to create a servlet filter which sends a redirect to HttpServletRequest#getRequestURI() when HttpSession#isNew() returns true. Don't forget to check the HttpServletRequest#isRequestedSessionIdFromCookie() to prevent an infinite redirect loop when the client doesn't support cookies at all.
Based on Christopher Schultz recommendation I tried this and it works.
package com.rama.test.jsessionfilter
public class JsessionIdAvoiderFilter implements Filter {
protected static final Logger LOGGER = LogManager.getLogger(JsessionIdAvoiderFilter.class);
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
if (!(req instanceof HttpServletRequest)) {
chain.doFilter(req, res);
return;
}
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// Redirect requests with JSESSIONID in URL to clean old links
/* If you really want clean up some old links which have Jsession id bookmarked clean it. If its new app
this below check is not required. */
if (request.isRequestedSessionIdFromURL()) {
String url = request.getRequestURL().append(request.getQueryString() != null ? "?"
+ request.getQueryString() : "").toString();
response.setHeader("Location", url);
response.sendError(HttpServletResponse.SC_MOVED_PERMANENTLY);
LOGGER.info(" Found url with jsession id in it:"+ request.getRequestURL() +": url="+url);
return;
}
// Prevent rendering of JSESSIONID in URLs for all outgoing links
HttpServletResponseWrapper wrappedResponse = new HttpServletResponseWrapper(
response) {
#Override
public String encodeRedirectUrl(String url) {
return url;
}
#Override
public String encodeRedirectURL(String url) {
return url;
}
#Override
public String encodeUrl(String url) {
return url;
}
#Override
public String encodeURL(String url) {
return url;
}
};
chain.doFilter(req, wrappedResponse);
}
public void destroy() {
}
public void init(FilterConfig arg0) throws ServletException {
}
}
and the following entry in web.xml
<filter>
<display-name>JsessionId Filter</display-name>
<filter-name>jsessionIdAvoiderFilter</filter-name>
<filter-class>com.rama.test.jsessionfilter.JsessionIdAvoiderFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>jsessionIdAvoiderFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
Works great !!!.
This can be done with a simple Filter that wraps the request with an HttpServletRequest which overrides HttpServletRequest.encodeURL and HttpServletRequest.encodeRedirectURL. Simply return the String argument passed to it and you will disable URL re-writing. Note that this will only work for a single webapp unless you want to either configure it in conf/web.xml (not recommended) or configure it in all of your separate webapps.
This technique is superior to that posted later in your question because it does not require redirection which can slow-down your requests. IMO, it's also cleaner.

Resources