Search This Blog

Sunday, July 31, 2011

JSF form authentication on servlet 3 container

In the post about security realms JDBC security realm with glassfish and jsf I showed how to configure GlassFish and simple web application for a successful authentication and authorization via web form.

Servlet 3.0 containers, such as Glassfish 3, support easy programmatic login that allow more control over the login process.

A simple example could be when user authenticates and one should decide where to redirect user depending on some preconditions or if you need to fetch some data from database for authenticated user before redirecting to secured pages.

This example just builds on top of the example from the JDBC security realm with glassfish jsf.

We will change login form (login.xhtml) so that no longer has to contain mandatory fields j_username, j_password and action attribute j_security_check previously required by container. Login form is now a regular JSF form with user defined input components and login command button  with action method attached.

<h:body>  
      <p>Login to access secure pages:</p>  
      <h:messages />  
      <h:form id="loginForm">  
           <h:panelGrid columns="2">  
                <h:outputLabel for="username" value="Username:" />  
                <h:inputText id="username" value="#{authBackingBean.username}" />  
                                 
                <h:outputLabel for="password" value="Password:" />  
                <h:inputSecret id="password" value="#{authBackingBean.password}" />  
                                 
                <h:commandButton id="loginButton" value="Login" action="#{authBackingBean.login}" />  
           </h:panelGrid>  
      </h:form>  
 </h:body>  

To AuthBackingBean we just add login action method that will handle authentication and authorization. Username and password bean properties will hold user entered values after form is submited.

@ManagedBean  
 @RequestScoped  
 public class AuthBackingBean {  
        
      private static Logger log = Logger.getLogger(AuthBackingBean.class.getName());  
        
      private String username;  
      private String password;  
        
      public String login() {  
           FacesContext context = FacesContext.getCurrentInstance();  
           HttpServletRequest request = (HttpServletRequest) context  
                                              .getExternalContext().getRequest();  
             
           try {  
                request.login(username, password);  
           } catch (ServletException e) {  
                context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN, "Login failed!", null));  
                return "login";  
           }  
             
           //you can fetch user from database for authenticated principal and do some action  
           Principal principal = request.getUserPrincipal();  
           log.info("Authenticated user: " + principal.getName());  
             
             
           if(request.isUserInRole("ADMIN")) {  
                return "/admins/admins?faces-redirect=true";  
           } else {  
                return "/users/users?faces-redirect=true";  
           }  
      }  
        
      public String logout() {  
           String result="/index?faces-redirect=true";  
             
           FacesContext context = FacesContext.getCurrentInstance();  
           HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();  
             
           try {  
                request.logout();  
           } catch (ServletException e) {  
                log.log(Level.SEVERE, "Failed to logout user!", e);  
                result = "/loginError?faces-redirect=true";  
           }  
             
           return result;  
      }  
   
      public String getUsername() {  
           return username;  
      }  
   
      public void setUsername(String username) {  
           this.username = username;  
      }  
   
      public String getPassword() {  
           return password;  
      }  
   
      public void setPassword(String password) {  
           this.password = password;  
      }  
 }  

On Servlet 3.0 container, HttpServletRequest has login method that  will validate the provided username and password in the password validation realm used by the web  container login mechanism configured for the ServletContext.