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

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.

Related

within JSF, how to get the real request url

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!

Dynamic URLs for a Liferay Portlet

I am looking for a solution for developing a dynamic content Liferay Portlet with different URLs. I am not going create separate pages in Liferay.All the information are stored in separate database and all pages are generated by using a Liferay Portlet.My current Liferay version is 6.2 CE.
Sample URLs are ,
https://localhost/travel/hotel/Lanzarote/Costa Teguise/Hotel Beatriz Costa & Spa
https://localhost/travel/hotel/Lanzarote/Costa Teguise/Club Siroco Apartments
https://localhost/travel/hotel/Lanzarote/Costa Teguise/El Guarapo Apartments
How do I implement different URLs with out creating separate pages in Liferay? If I need to use Liferay API for generate dynamic URLs , what are the API components do I need to use?
You can get very similar urls with Liferay friendly url mapping:
https://localhost:8080/{page}/-/hotel/Lanzarote/Costa Teguise/Hotel Beatriz Costa
https://localhost:8080/{page}/-/hotel/Lanzarote/Costa Teguise/Club Siroco Apartments
https://localhost:8080/{page}/-/hotel/Lanzarote/Costa Teguise/El Guarapo Apartments
To make it work, you need to configure the mapping in liferay-portlet.xml:
<portlet>
<portlet-name>my-hotel-portlet</portlet-name>
<friendly-url-mapper-class>com.liferay.portal.kernel.portlet.DefaultFriendlyURLMapper</friendly-url-mapper-class>
<friendly-url-mapping>hotel</friendly-url-mapping>
<friendly-url-routes>friendly-url-routes.xml</friendly-url-routes>
...
</portlet>
The hotel part of the url that comes right after /-/ is defined by <friendly-url-mapping>hotel</friendly-url-mapping> value.
The configuration refers to the routes defined in friendly-url-routes.xml. Just one route definition is necessary:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE routes PUBLIC "-//Liferay//DTD Friendly URL Routes 6.2.0//EN" "http://www.liferay.com/dtd/liferay-friendly-url-routes_6_2_0.dtd">
<routes>
<route>
<pattern>/{region}/{town}/{hotel}</pattern>
</route>
</routes>
Sample Liferay MVCPortlet method reading the parameters:
#Override
public void doView(RenderRequest renderRequest, RenderResponse renderResponse) {
String region = ParamUtil.getString(renderRequest, "region");
String town = ParamUtil.getString(renderRequest, "town");
String hotel = ParamUtil.getString(renderRequest, "hotel");
...
}
Sample Spring controller method reading the parameters:
#RenderMapping
public String renderHotel(#RequestParam String region, #RequestParam String town, #RequestParam String hotel) {
...
return "hotel/view";
}
See FriendlyURLMapper for detailed coverage.
Another solution is writing a separate servlet filter hook plugin project.The idea is to transfer the current URL into Liferay specific URL.
As an example:
https://localhost/travel/hotel/Lanzarote/Costa Teguise/Hotel Beatriz Costa & Spa
Converted in to,
https://localhost/web/guest/travel/hotel?p_p_id=hotelsearch_WAR_hotelportlet&p_p_lifecycle=1&p_p_state=normal&p_p_mode=view&_hotelsearch_WAR_hotelportlet_param1=travel&_hotelsearch_WAR_hotelportlet_param2=hotel&_hotelsearch_WAR_hotelportlet_param3=Lanzarote&_hotelsearch_WAR_hotelportlet_param4=Costa%20Teguise&_hotelsearch_WAR_hotelportlet_param5=Hotel%20Beatriz%20Costa%20&%20Spa
First configure the mapping in sample hook project liferay-hook.xml :
<?xml version="1.0"?>
<!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 6.2.0//EN"
"http://www.liferay.com/dtd/liferay-hook_6_2_0.dtd">
<hook>
<servlet-filter>
<servlet-filter-name>CustomURLPatternFilter</servlet-filter-name>
<servlet-filter-impl>com.hotel.travel.portlet.customefilter.CustomURLPatternFilter</servlet-filter-impl>
<init-param>
<param-name>hello</param-name>
<param-value>world</param-value>
</init-param>
</servlet-filter>
<servlet-filter-mapping>
<servlet-filter-name>CustomURLPatternFilter</servlet-filter-name>
<url-pattern>/travel/hotel/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</servlet-filter-mapping>
Sample servlet filter class :
public class CustomURLPatternFilter implements Filter {
#Override
public void destroy() {
LOG.info("CustomURLPatternFilter.destroy()");
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
String requestURI = request.getRequestURI();
try {
String[] urlPaths = StringUtil.split(requestURI, StringPool.FORWARD_SLASH);
System.out.println(urlPaths[0]);
System.out.println(urlPaths[1]);
System.out.println(urlPaths[2]);
System.out.println(urlPaths[3]);
System.out.println(urlPaths[4]);
System.out.println(urlPaths[5]);
if (urlPaths.length == 6) {
String forwardPath = "/web/guest/travel/hotel?p_p_id=hotelsearch_WAR_hotelportlet&p_p_lifecycle=1&p_p_state=normal&p_p_mode=view"
+ "&_hotelsearch_WAR_hotelportlet_param1=" + urlPaths[1]
+ "&_hotelsearch_WAR_hotelportlet_param2=" + urlPaths[2]
+ "&_hotelsearch_WAR_hotelportlet_param3=" + urlPaths[3]
+ "&_hotelsearch_WAR_hotelportlet_param4=" + urlPaths[4]
+ "&_hotelsearch_WAR_hotelportlet_param5=" + urlPaths[5];
req.getRequestDispatcher(forwardPath).forward(req, res);
}
else {
chain.doFilter(req, res);
}
} catch (Exception e) {
chain.doFilter(req, res);
e.printStackTrace();
}
}
#Override
public void init(FilterConfig filterConfig) {
System.out.println("Called SampleFilter.init(" + filterConfig + ")");
}
private static final Log LOG =
LogFactoryUtil.getLog(CustomURLPatternFilter.class);
}
At the end in your original hotel portlet ,
HttpServletRequest httpReq = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(req));
System.out.println( httpReq.getParameter("_hotelsearch_WAR_hotelportlet_param1") );
System.out.println( httpReq.getParameter("_hotelsearch_WAR_hotelportlet_param2") );
System.out.println( httpReq.getParameter("_hotelsearch_WAR_hotelportlet_param3") );
System.out.println( httpReq.getParameter("_hotelsearch_WAR_hotelportlet_param4") );
System.out.println( httpReq.getParameter("_hotelsearch_WAR_hotelportlet_param5") );

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.

Homegrown authentication filter does not show the welcome page

So I've come accross quite a numbre of questions similar to mine, and I was starting to get it until I realised I don't, in short, here's the story :
In an authentification bean, success of authentification should result in accessing some web resources, failure should "filter" access and redirect to current login page.
Now, in that authentification bean, I added this line in case of success :
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(authentificationBean1.AUTH_STATE, "true") ;
AUTH_STATE is defined in the bean as :
public static final String AUTH_STATE = "";
In case of failure, I do the following :
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(authentificationBean1.AUTH_STATE, null) ;
Now in the filter (one that is applied to every file except of authentification page), my doFilter method looks like this :
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
if (((HttpServletRequest) request).getSession().getAttribute(authentificationBean1.AUTH_STATE) == null) {
((HttpServletResponse) response).sendRedirect("authentification.xhtml");
}
if(((HttpServletRequest) request).getSession().getAttribute(authentificationBean1.AUTH_STATE) != null) {
((HttpServletResponse) response).sendRedirect("accueil.xhtml");
}
}
My idea was that if authentification went well, the authentificationBean1.AUTH_STATE session attribut will be set to something not null, thus in the filter test I'll be able to redirect to a welcom page (accueil.xhtml) ; if that attribut is null, we'll stay in the authentification page.
Tasting the whole thing : the filter seems to work but too much, by that I mean even when authentification test must succeed it doesn't allow me to pass to the welcome page. It was actually working fine without the filter, it looks like I missed something about using filters with JSF or filters as it.
P.S : didn't apply chain.doFilter because I do not have another filter to call, but suspecting something there.
Thanks for your indications.
EDIT :
<filter>
<filter-name>RestrictionFilter</filter-name>
<filter-class>beans.RestrictionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RestrictionFilter</filter-name>
<url-pattern>/faces/accueil.xhtml</url-pattern>
</filter-mapping>
Your filter is running in an infinite loop, redirecting to itself everytime. It is never continuing the request to the servlet. It seems that you're misunderstood how HTTP works. With response.sendRedirect() you're basically firing a brand new HTTP request. This brand new HTTP request will invoke the filter again. So, when your filter matches the condition in order to redirect to accueil.xhtml, it will keep redirecting to that page in an infinite loop and never continue to the servlet in order to process the request.
Further you also misunderstood the meaning of chain.doFilter(). It does not explicitly advance to the next filter. It just continues the request as if there was no filter. Whether there's another filter next in the chain or not is completely irrelevant. If there's no filter, then it will just end up in the target servlet (which is the FacesServlet in your case, who's responsible for processing the JSF page).
Basically, the flow should be as follows:
If the user is not logged in, then:
If the currently requested page is not authentification.xhtml, then redirect to it.
Or if the currently requested page is already authentification.xhtml, then continue request.
Or if the user is logged in, then continue the request regardless of the requested page.
In other words, this should do it:
#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);
String loginURL = request.getContextPath() + "/authentification.xhtml";
boolean loggedIn = session != null && session.getAttribute(authentificationBean1.AUTH_STATE) != null;
boolean loginRequest = request.getRequestURI().startsWith(loginURL);
boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER);
if (loggedIn || loginRequest || resourceRequest)) {
chain.doFilter(request, response);
} else {
response.sendRedirect(loginURL);
}
}
Note that I also added a check on JSF resources (the CSS/JS/image files included via <h:outputStylesheet|outputScript|graphicImage>), otherwise they would also be blocked when the login page is presented. Also note that this filter can be mapped on /* and not on only a single page.

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.

Resources