JSF page style missing when using login filter - jsf

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.

Related

Jmeter + JSF can't pass login filter

I got a problem when use Jmeter to test a JSF application.
I'm a newbie in Jmeter, follow some post on net i did
And code filter
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
try {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpSession httpSession = httpRequest.getSession(false);
if (!httpRequest.getRequestURI().startsWith(httpRequest.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
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.
}
String strRequestURI = httpRequest.getRequestURI();
// httpRequest.getServletPath()
// httpRequest.getServerName()
if (strRequestURI.indexOf("/public/") >= 0)
chain.doFilter(request, response);
else if ( (strRequestURI.indexOf("/login.xhtml") >= 0)
|| strRequestURI.contains("javax.faces.resource")
|| (strRequestURI.indexOf("/admin-access-denied.xhtml") >= 0)) {
chain.doFilter(request, response);
} else if ((httpSession != null) && (httpSession.getAttribute(SessionBean.SESSION_KEY) != null)) {
if (strRequestURI.indexOf("/lazy-load.xhtml") >= 0) {
chain.doFilter(request, response);
} else {
chain.doFilter(request, response);
}
} else {
httpResponse.sendRedirect(httpRequest.getContextPath() + "/login.xhtml");
}
} catch (Exception e) {
e.printStackTrace();
}
I did all things that i read : add Coockie Manager, add Regular Expression Extrator, add parameter to Http request but after run test, my response data is blank ( only access to login.xhtml page )
But response is blank , only login page is showed .
Pls help me to solve this problem.
PS: I run debug mode and httpSession.getAttribute(SessionBean.SESSION_KEY) is always null , its set on login controller ( when login successed ).
HttpSession session = SessionBean.getSession();
session.setAttribute(SessionBean.SESSION_KEY, sessionData);
Thanks a lot,
Most likely your javax.faces.Viewstate value is not propertly correlated, you're sending ${viewstate} instead of the extracted value, most likely your Regular Expression fails somewhere
It's better to put PostProcessors as children of the specific Samplers, otherwise they are being triggered on each sampler causing execution overhead and in some cases JMeter Variables data loss
So your test should have the following structure:
lazy-load.xhtml
Extract Viewstate
login.xhtml
You may want to consider using CSS/JQuery Extractor or XPath Extractor instead of Regular Expressions Extractor as Regular Expressions are fragile, sensitive to markup change and complex ones can hardly be understood and maintained.
Example expressions:
XPath: //input[#id='javax.faces.ViewState]/#value
CSS:
- Expression: input[id=javax.faces.ViewState]
- Attribute: value

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!

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.

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 differentiate a new log in (new Session) and a session time out

Could someone let me know how to differentiate a new log in (new Session) and a session time out .
Only on login : user must be authenticated and redirected to a servlet to load user details (on other screnarios user must not be redirected to the servlet)
and on timeout user must be redirected to the timeout page.
To identify a new session (user not logged in):
-- Session attributes cannot be used since the session becomes null on timeout.
-- Setting cookies for session management didnt work.
The cookies are getting removed for the current session
Cookie cookie = new Cookie("activeSession", null);
cookie.setMaxAge(0);
cookie.setPath("/");
cookie.setValue("");
httpServletResponse.addCookie(cookie);
getCookieValue(httpServletRequest , "activeSession"); returns null
public static String getCookieValue(HttpServletRequest request, String name) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie != null && name.equals(cookie.getName())) {
return cookie.getValue();
}
}
}
return null;
}
After logout or Timeout (session is invalidated) when user logs in and a new session is created.
The cookies that were removed in the previous sessions reappears with the preset values.
getCookieValue(httpServletRequest , "activeSession") returns a value;
If I use the below approach it works for the 1 st login attempt.
After the first login session has timedout ,the filter redirects to timeout page.
The actual problem arises when user accesses the application in the same window after timeout.
public void doFilter(ServletRequest request, ServletResponse response,FilterChain filterChain) throws IOException,
{ if ((request instanceof HttpServletRequest)
&& (response instanceof HttpServletResponse)) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
//Check for a new login
if (httpServletRequest.getSession(false) == null && httpServletRequest.getRequestedSessionId()==null)
{
// Create a new session
httpServletRequest.getSession();
//Redirect to servlet on 1 st login to fetch details from DB
httpRequest.getRequestDispatcher("/loginServlet").forward(request,response);
}else{
//validate active or timedout sessions.
boolean isSessionValid = (httpServletRequest.getRequestedSessionId() != null) && !httpServletRequest.isRequestedSessionIdValid();
if(isSessionValid)
{
httpServletResponse.sendRedirect(getTimeoutPage());
}
}
}
filterChain.doFilter(request, response);
}
Therefore the details are not fetched from DB and the page is not loaded correctly.
Browser:IE 8
Server : Weblogic server
Your cookie approach is unnecessary and technically invalid. A max age of 0 makes it to expire immediately when the response is processed. But anyway, you don't need an additional cookie. The HttpSession is by itself already backed by a cookie and the Servlet API already offers methods to check the one and other. Just store the logged-in user as an attribute of the HttpSession (which can in turn be a session scoped JSF managed bean).
The following example should do, assuming that you've stored the logged-in user as a property of a session scoped JSF managed bean with the managed bean name "auth".
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
Authenticator auth = (Authenticator) req.getSession().getAttribute("auth");
if (req.getRequestedSessionId() != null && !req.isRequestedSessionIdValid()) {
res.sendRedirect(req.getContextPath() + "/timeout.xhtml");
} else if (auth == null || !auth.isLoggedIn()) {
res.sendRedirect(req.getContextPath() + "/login.xhtml");
} else {
chain.doFilter(request, response);
}
}

Resources