jsf filter seems not to work
authentication, faces-config, jsf, servlet-filters
Solution
You've mapped `FacesServlet` on `/faces/*` instead of `*.xhtml`. So all JSF requests will have the `/faces` prefix in the URL. But you've mapped the `AuthFilter` on `/restricted/*` instead of `/faces/restricted/*`, so it will never kick in on `/faces/*` URLs.
You can solve this in 2 ways:
Map `FacesServlet` on `*.xhtml` instead of on `/faces/*`. This has the additional advantage that the enduser won't ever be able to see the raw JSF source code when the enduser purposefully removes the `/faces` path from the URL in browser address bar.
Map `AuthFilter` on `/faces/restricted/*` instead of on `/restricted/*`.
I personally recommend the first way. You end up with a shorter and nicer URL and you immediately also prevent the JSF source code leak.
Problem
I was trying to create a secure login page with jsf, and I used these code snippets as the solution, found in this question. My problem is, that I can access the /restricted/secret.xhtml without logging in, there is no redirect it's like the filter is not applied, because if I go directly to the /restricted/secret.xhtml the #{user.loggedIn} evaluates to false and I still can view the page. Here is my code: AuthFilter.java ``` public class AuthFilter implements Filter { private FilterConfig config; @Override public void destroy() { this.config = null; } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain ch) throws IOException, ServletException { HttpSession s = ((HttpServletRequest) req).getSession(); if (s.getAttribute(UserBean.CREDENTIAL)==null) { ((HttpServletResponse) resp).sendRedirect("/login.faces"); }else { ch.doFilter(req, resp); } } @Override public void init(FilterConfig config) throws ServletException { this.config = config; } } ``` UserBean.java ``` @ManagedBean(name="user") @SessionScoped public class UserBean implements Serializable { private String name; private String password; protected static final String CREDENTIAL = "ontherun"; private static final long serialVersionUID = 1L; public String getName() { return this.name; } public void setName(String newName) { this.name = newName; } public String getPassword() { return this.password; } public void setPassword(String newPassword) { this.password = newPassword; } public boolean isLoggedIn() { return FacesContext.getCurrentInstance().getExternalContext() .getSessionMap().get(CREDENTIAL) != null; } public String logout() { FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove(CREDENTIAL); return null; } public String login() { FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(CREDENTIAL, this.name); return "secret"; } } ``` Here is my login.xhtml ; the page works correctly, so there is no problem with the template file. ``` <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"> <head><title>IGNORED</title></head> <body> <ui:composition template="/templates/masterLayoutTemplate.xhtml"> <ui:define name="windowTitle"> #{msgs.window_title} </ui:define> <ui:define name="header"> <ui:include src="/sections/login/header.xhtml"></ui:include> </ui:define> <ui:define name="footer"> <ui:include src="/sections/login/footer.xhtml"></ui:include> </ui:define> <ui:define name="content"> <h:form> <h:panelGrid columns="2"> #{msgs.namePrompt} <h:inputText id="name" value="#{user.name}"/> #{msgs.passwordPrompt} <h:inputSecret id="password" value="#{user.password}"/> </h:panelGrid> <p> <h:commandButton value="#{msgs.loginButtonText}" action="#{user.login }"/> </p> <p> You are logged in : #{user.loggedIn} </p> <p> <h:commandButton value="logout" action="#{user.logout }"/> </p> </h:form> </ui:define> </ui:composition> </body> </html> ``` Here is the secret.xhtml which is supposed to be restricted: ``` <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"> <head><title>IGNORED</title></head> <body> <ui:composition template="/templates/masterLayoutTemplate.xhtml"> <ui:define name="windowTitle"> #{msgs.window_title} </ui:define> <ui:define name="content"> <h:head></h:head> <h:body> <p>You are #{user.loggedIn}</p> </h:body> </ui:define> </ui:composition> </body> </html> ``` And here are my config files: web.xml ``` <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name>OnTheRun</display-name> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>faces/index.xhtml</welcome-file> </welcome-file-list> <filter> <filter-name>AuthFilter</filter-name> <filter-class>on.run.AuthFilter</filter-class> </filter> <filter-mapping> <filter-name>AuthFilter</filter-name> <url-pattern>/restricted/*</url-pattern> </filter-mapping> <context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param> </web-app> ``` and faces-config.xml ``` <?xml version="1.0" encoding="UTF-8"?> <faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" version="2.0"> <application> <resource-bundle> <base-name>on.run.messages</base-name> <var>msgs</var> </resource-bundle> </application> <navigation-rule> <from-view-id>/index.xhtml</from-view-id> <navigation-case> <from-outcome>login</from-outcome> <to-view-id>/profile.xhtml</to-view-id> <redirect/> </navigation-case> </navigation-rule> <navigation-rule> <from-view-id>/login.xhtml</from-view-id> <navigation-case> <from-outcome>secret</from-outcome> <to-view-id>/restricted/secret.xhtml</to-view-id> <redirect/> </navigation-case> </navigation-rule> </faces-config> ``` My directory structure looks like this: dirStruct 2