Search This Blog

Monday, December 19, 2011

EJB asynchronous processing


In J2EE world JMS was often used for asynchronous execution of synchronous methods. There was no other way to invoke session beans in a background thread. EJB 3.1 introduced an easy way to solve background execution without using messaging.
 It is sufficient to declare methods as @Asynchronous and they will be invoked in background thread. The result value of an asynchronous invocation is available to the client by returning the Future object and even allows canceling of background tasks.
 The built-in support for asynchronous processing is easier and cleaner compared to the JMS way and it also allows bidirectional communication. Implementing request-response communication with JMS messaging is harder and you would need input queue and output queue. JMS on the other hand allows looser coupling.

So, say for example that you want to send email asynchronously (example assumes that glassfish application server is used).
Using JMS you can do it in combination with message driven beans (components designed to consume the asynchronous messages). As soon as a new message reaches the jms destination, an message driven bean instance is retrieved from the pool to handle the message.

To use JMS and message driven beans you have to first configure JMS connection factory and destination queue through glassfish administration console. For example:





 
Calling client (JSF bean or another EJB for example) then can inject these resources and use them to send message (queue asynchronous task).
//inject connection factory and destination  
      @Resource(name="connFactory", mappedName="mailConnFactory")  
      private QueueConnectionFactory qFactory;  
      @Resource(name="jmsQueue", mappedName="mailQueue")  
      private Queue queue;  

And asynchronous call is done by sending message that will be asynchronously processed by message driven bean.

QueueConnection qConn = (QueueConnection)qFactory.  
                   createConnection();  
           // Get session  
           Session session = qConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);  
           // Create the JMS message  
           ObjectMessage msg = session.createObjectMessage();  
           // set payload  
           MailData data = new MailData("reciever@mail.com","message text");  
           msg.setObject(data);  
           // Send JMS message  
           session.createProducer(queue).send(msg);  
           //release resources  
           session.close();  
           qConn.close();  


Once message is queued you need message driven bean that will process message. In this case this message driven bean will send actual email. Mail session resource in glassfish administration console(under resources/java mail sessions node) must be configured to send actual email.
@MessageDriven(mappedName="mailQueue")  
 public class MailSenderBean implements MessageListener {  
      @Resource(name = "mail" )  
      private Session mailSession;  
      @Override  
      public void onMessage(Message message) {  
            if (message instanceof ObjectMessage) {  
                 try{  
                      ObjectMessage msg = (ObjectMessage)message;  
                      MailData data = (MailData)msg.getObject();  
                      MimeMessage msg = new MimeMessage(mailSession);  
                      msg.setSubject("subject");  
                      msg.setRecipient(RecipientType.TO,  
                               new InternetAddress(data.getRecipient()));  
                      msg.setContent(data.getText(), "text/html");
                     Transport.send(msg);  
                 }catch(Exception e) {  
                      // handle exception  
                 }  
            }  
      }  
 }  

And to accomplish same thing with built in asynchronous support you just have to annotate session bean method with @Asynchronous annotation and container will execute method in background thread.

@Stateless  
 public class MailSenderBean implements MailSender {  
      @Resource(name = "mail" )  
      private Session mailSession;  
      @Asynchronous  
      @Override  
      public void sendEmail(MailData data){  
           try {  
                MimeMessage msg = new MimeMessage(mailSession);  
                msg.setSubject("subject");  
                msg.setRecipient(RecipientType.TO,  
                     new InternetAddress(data.getRecipient())); 
                msg.setContent(data.getText(), "text/html"); 
                Transport.send(msg);  
           } catch (Exception e) {  
                //handle error  
           }  
      }  
 }  

This method could also return Future object. Calling client could then check with future.isDone() if processing thread has finished with execution and fetch result of execution with future.get().

Wednesday, September 7, 2011

JSF composite component binding to custom UIComponent

In last post about  JSF form authentication on servlet 3 container I showed an example of how to make a simple user authentication on servlet 3 conainer using JSF.

This example creates jsf composite component that handles login.
When composite component is included in the page, actually whole subtree of components is included with parent top level component that is actual representation of composite component.  This is just a simple showcase, but when developing more complicated composite components, sometimes it is handy to implement behavior using java code instead of only using xhtml markup. So, this example will create some sort of backing class for the composite component.

First, here is an example of using page that uses login component:

<!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:f="http://java.sun.com/jsf/core"   
    xmlns:h="http://java.sun.com/jsf/html"   
    xmlns:ui="http://java.sun.com/jsf/facelets"  
    xmlns:g="http://java.sun.com/jsf/composite/components">  
   
 <h:body>  
      <p>Login to access secure pages:</p>  
      <h:form id="loginComponent">  
           <g:login login="#{authBackingBean.login}"   
                success="/admins/admins?faces-redirect=true"/>  
      </h:form>  
 </h:body>  
 </html>

And the actual login is performed by #{authBackingBean.login} method that is called by our composite component when user clicks login button. Only requirement for login method is that it must return boolean value and accept two String parameters (that will be username and password). Here is an example of backing bean:

@ManagedBean  
 @RequestScoped  
 public class AuthBackingBean {  
        
      private static Logger log = Logger.getLogger(AuthBackingBean.class.getName());  
             
      public boolean login(String username, String password) {  
           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 false;  
           }  
   
           Principal principal = request.getUserPrincipal();  
           log.info("Authenticated user: " + principal.getName());  
           return true;       
      }  
 } 


Composite component is then responsible for calling login method with parameters that are entered by user and submited as username and password.

Below is an example of composite login component. It consists of login.xhtml  facelet file and LoginComponent class that extends UINamingContainer component.

login.xhtml markup file should be placed in resource library folder. Resource library is folder named resources in the top-level web application root and is accessible to the classpath.
In my example, I have resources/components folder that contains login.xhtml facelet file.


The name of the resource library is what comes after http://java.sun.com/jsf/composite and is actually the name of subdirectory that resides in resources folder. In code snipet above, i have http://java.sun.com/jsf/composite/components namespace since my component is in components subdirectory.

<!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:h="http://java.sun.com/jsf/html"  
   xmlns:f="http://java.sun.com/jsf/core"   
   xmlns:composite="http://java.sun.com/jsf/composite">  
   
  <composite:interface componentType="loginComponent">  
       <composite:attribute name="login" required="true"   
                 method-signature="boolean f(java.lang.String, java.lang.String)"/>  
       <composite:attribute name="success" required="true"/>  
       <composite:attribute name="failure" required="false"/>  
  </composite:interface>  
   
       
   <composite:implementation>  
           <h:panelGrid columns="2">  
                <h:outputLabel for="#{cc.clientId}:username" value="Username:" />  
                <h:inputText id="username" binding="#{cc.username}" />  
                                 
                <h:outputLabel for="#{cc.clientId}:password" value="Password:" />  
                <h:inputSecret id="password" binding="#{cc.password}" />  
                                 
                <h:commandButton id="loginButton" value="Login"   
                     action="#{cc.action}" actionListener="#{cc.actionListener}" />  
           </h:panelGrid>  
   </composite:implementation>  
 </html>

I will not go into detail about interface and implementation sections, there is plenty of articles about composite components. 
Here is important to note that componentType on interface tag is interpreted as component type of a component already registered with JSF  and when JSF runtime encounters a composite component tag of that type it will create instance of that component that will serve as the composite component root (top level component).

Interface section declares method attribute login that has two String parameters and  will be called when user clicks login button and will perform actual login process. Login method is called by backing UIComponent class for showcase purpose to show how method expression can be called manually from java code .  If there were no custom backing UIComponent attached to this composite component, than method expresion could be attached directly to action attribute of login button.
In case of successful login, success attribute is used as outcome where user will be redirected.

Interesting thing is also #{cc.action} and #{cc.actionListener} action methods that point directly to methods on actual UIComponent that is top-level component. JSF assumes that top-level component for composite component is javax.faces.component.NamingContainer component.

The easiest way is to extend javax.faces.component.UINamingContainer. Here is an example of backing component for composite component:

@FacesComponent(value="loginComponent")  
 public class LoginComponent extends UINamingContainer {  
        
      private UIInput username;  
      private UIInput password;  
        
      private String action;  
        
      public LoginComponent() {  
           super();  
      }  
        
      public void actionListener(ActionEvent ae) {  
             
           FacesContext context = FacesContext.getCurrentInstance();  
           ELContext elContext = context.getELContext();  
   
           Object params[] = new Object[2];  
           params[0] = username.getValue();  
           params[1] = password.getValue();  
             
           MethodExpression me = (MethodExpression)this.getAttributes().get("login");  
           boolean loginSuccess = (Boolean)me.invoke(elContext, params);  
             
           if(loginSuccess) {  
                action = (String)getAttributes().get("success");  
           } else {  
                action = (String)getAttributes().get("failure");  
           }  
      }  
        
      public String action() {  
           return action;  
      }  
        
      public UIInput getUsername() {  
           return username;  
      }  
   
      public void setUsername(UIInput username) {  
           this.username = username;  
      }  
   
      public UIInput getPassword() {  
           return password;  
      }  
   
      public void setPassword(UIInput password) {  
           this.password = password;  
      }            
 }  

@FacesComponent annotation registers this UIComponent with JSF runtime. Notice that annotation value loginComponent matches the value of componentType in login.xhtml facelet file. When user clicks login button, ActionListener method is called. Login method expression is obtained from attributes map and submited username and password values are obtained from binded UIInput components. This values are then used as parameters to invoke login method.
Depending on method invocation result, action  variable is then set with success or failure attribute value and is used as outcome for login button so that user is redirected to appropriate view.

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.

Thursday, June 9, 2011

JSF2 Flash scope example

JSF 2 introduced new scope called Flash scope that  provides a way to pass temporary objects between user views generated by the faces lifecycle.

By using flash scope you don't have to use session to store objects so that you could access them across requests. In this example I'll show you how to transfer data between three views - inputForm.xhtml, confirm.xhtml and done.xhtml by using flash scope. It is a good practice to use as little as possible session scope to minimize memory consumption. 

So, I have simple RequestScoped bean that will hold user entered values when user submits form and will perform navigation. After user submits form on inputForm.xhtml he is redirected to confirm.xhtml view where he can preview data and confirm submitted data. If user clicks edit he is returned back to inputForm.xhtml page allowing him to change input. If user clicks confirm he is redirected to done.xhtml view where final info is shown after successfull processing.

Navigation between pages is done by using POST REDIRECT GET pattern (Michael Jouravlev, 2004., theserverside.com) that states:
  1. Never show pages as response of POST request
  2. Always load page with GET request
  3. Navigate between POST to GET using redirect
If i don't use redirect after submitting form on inputForm.xhtml page, user  will see confirm.xhtml page content but browser url will point to inputForm.xhtml and that can be confusing. So, to avoid that, I use ?faces-redirect=true that causes POSTback to faces server. Server then responds with 302 REDIRECT HTTP response (with Location http header including confirm.xhtml) and then browser issues GET request to load confirm.xhtml page.
    So, here is an example of my RequestScoped bean:

    @ManagedBean  
     @RequestScoped  
     public class ModelBean {  
            
          private String firstName;  
          private String lastName;  
            
          public ModelBean() {  
               super();  
          }  
            
          /**  
           * set submitted values to flash scope and   
           * redirect to confirm view  
           * @return  
           */  
          public String goToConfirmView() {  
               Flash flash = FacesContext.getCurrentInstance().  
                    getExternalContext().getFlash();  
               flash.put("firstName", firstName);  
               flash.put("lastName", lastName);  
                 
               return "confirm?faces-redirect=true";  
          }  
            
          /**  
           * redirect to confirm view   
           * @return  
           */  
          public String goToInputFormView() {  
               return "inputForm?faces-redirect=true";  
          }  
       
          /**  
           * Called on confirm.xhtml page  
           * here could be some database   
           * processing  
           * @return  
           */  
          public String insertValue() {  
               Flash flash = FacesContext.getCurrentInstance().  
                                        getExternalContext().getFlash();  
               //preserve messages across redirect  
               flash.setKeepMessages(true);  
                 
               pullValuesFromFlash(null);  
       
               //do something with firstName, lastName  
               System.out.println("First name: " + firstName);  
               System.out.println("Last name: " + lastName);  
                 
               FacesContext.getCurrentInstance().addMessage(null,   
                         new FacesMessage("Value inserted"));  
               return "done?faces-redirect=true";  
          }  
            
          /**  
           * System event called before view rendering   
           * used to pull values from flash and set to  
           * bean properties  
           * @param e  
           */  
          public void pullValuesFromFlash(ComponentSystemEvent e) {  
               Flash flash = FacesContext.getCurrentInstance().  
                                   getExternalContext().getFlash();  
               firstName = (String)flash.get("firstName");  
               lastName = (String)flash.get("lastName");  
          }  
            
                 
          public String getFirstName() {  
               return firstName;  
          }  
       
          public void setFirstName(String firstName) {  
               this.firstName = firstName;  
          }  
       
          public String getLastName() {  
               return lastName;  
          }  
       
          public void setLastName(String lastName) {  
               this.lastName = lastName;  
          }  
     }  

    inputForm.xhtml:

    <h:head>  
          <title>Input form</title>  
     </h:head>  
     <h:body>  
          <f:metadata>  
               <f:event type="preRenderView" listener="#{modelBean.pullValuesFromFlash}"/>  
          </f:metadata>  
          <h:form>  
               <h:messages />  
               <h:panelGrid columns="2">  
                    <h:outputText value="First name:" />  
                    <h:inputText value="#{modelBean.firstName}" required="true"/>  
                      
                    <h:outputText value="Last name:" />  
                    <h:inputText value="#{modelBean.lastName}" required="true" />  
               </h:panelGrid>  
               <h:commandButton value="Next"   
                    action="#{modelBean.goToConfirmView}" />  
          </h:form>  
     </h:body>  
    

    After submitting form by clicking on the Next button, values are put to flash scope in goToConfirmView action method and browser is redirected to confirm page. Notice that I am using confirm?faces-redirect=true. Since values put to flash scope survive redirects those values are available on confirm.xhtml page.
    inputForm.xhtml view uses system event preRenderViewEvent (called during render response phase) to load values from flash and set them to ModelBean properties. This is used when user clicks edit button on confirm.xhtml view and is redirected back to inputForm.xhtml with prepopulated values.

    confirm.xhtml:

    <h:head>  
          <title>Confirm page</title>  
     </h:head>  
     <h:body>       
          <h:form>  
               <h:panelGrid columns="2">  
                    <h:outputText value="First name:" />  
                    <h:outputText value="#{flash.keep.firstName}" />  
                      
                    <h:outputText value="Last name:" />  
                    <h:outputText value="#{flash.keep.lastName}" />  
               </h:panelGrid>       
               <h:commandButton value="Edit"   
                    action="#{modelBean.goToInputFormView}" />  
               <h:commandButton value="Confirm"   
                    action="#{modelBean.insertValue}" />  
          </h:form>  
     </h:body>  
    

    Confirm page simply displays entered values. Values are fetched from flash scope object.Notice that I am using #{flash.keep.firstName} instead of #{flash.firstName}. That is because values put to flash survive only one redirect and then are cleared out.Since I put values on inputForm.xhtml page and redirect to confirm.xhtml page I must tell the flash to keep (by keep keyword) values in flash scope for the next request as I want to fetch them also on the done.xhtml view or inputForm.xhtml view. If user clicks Edit button he is redirected to inputForm.xhtml view with already populated values for edit.

    done.xhtml;

    <h:head>  
          <title>Done page</title>  
     </h:head>  
     <h:body>  
          <f:metadata>  
               <f:event type="preRenderView" listener="#{modelBean.pullValuesFromFlash}"/>  
          </f:metadata>  
          <h:messages />  
          <h:panelGrid columns="2">  
                    <h:outputText value="First name:" />  
                    <h:outputText value="#{modelBean.firstName}" />  
                      
                    <h:outputText value="Last name:" />  
                    <h:outputText value="#{modelBean.lastName}" />  
          </h:panelGrid>       
          <h:link outcome="inputForm" value="Back to inputForm"/>  
     </h:body>  
    

    done.xhtml view uses same method to obtain flash values as inputForm.xhtml view by using system preRenderViewEvent to load values from flash and set them to bean properties.

    Source code can be downloaded from the following link:
    FlashExample.war

    Friday, March 11, 2011

    Custom HTTP headers with XmlRpcClient

    Recently I encountered the problem with apache xml-rpc client when I needed to set some custom request headers with each request. Since I didn't find any examples on google how to do it here is an example.


    For this to work you need to implement XmlRpcTransport and override initHttpHeaders method.


    XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
            config.setServerURL(new URL("http", "localhost", 9000, ""));
                   
            config.setEnabledForExtensions(true);
            config.setContentLengthOptional(false);
            
            client = new XmlRpcClient();
            client.setConfig(config);
            //implement transport factory
            XmlRpcTransportFactory xmlRpcTransportFactory = new XmlRpcCommonsTransportFactory(client) {
    
                @Override
                public XmlRpcTransport getTransport() {
    
                    return new XmlRpcCommonsTransport(this) {
    
                        @Override
                        protected void initHttpHeaders(XmlRpcRequest pRequest) throws XmlRpcClientException {
                            super.initHttpHeaders(pRequest);
                            //add custom header
                            super.method.addRequestHeader("My-Header", "some header");
                        }
                    };
                }
            };
            client.setTransportFactory(xmlRpcTransportFactory);
            
            
            factory = new ClientFactory(client);
            
            //actual method call
            IMyInterface myHandler = (IMyInterface)factory.newInstance(IMyInterface.class);
            myHandler.testHeaderMethod("test");
    
    For every remote method call, header named My-header will be set to http request.

    Sunday, March 6, 2011

    Tomcat load balancing

    I will demonstrate tomcat load balancing by connecting apache web server and tomcat application servers through ajp connector.

    In this example I use mod_proxy and mod_proxy_ajp which is built into Apache web server from versions 2.2 and up. AJP stands for Apache Jserv Protocol wich is binary packet-oriented protocol and apache web server communicates with tomcat over TCP connections, maintains persistent connections and reuses a connection for multiple request/response cycles. 

    By having apache web server in front of multiple tomcat application servers you can achive to handle more concurent requests and also have some sort of failover in case one of the nodes breaks down.
    Good thing is also that you can serve your static content like images, javascript and css files from apache web server(apache web server is somewhat faster in serving static content than tomcat), and let the tomcat application server to handle the real applcation processing.

    For example purposes I'll install two tomcat application servers and apache web server on the same physical machine but in the real world that would probably be separate machines.

    1. First, I install two separate instances of tomcat application servers(download and unzip). You will need to change the ports in server.xml config file to avoid port conflicts.
    Tomcat A
    <Server port="8005" shutdown="SHUTDOWN"> 
    <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcatA">
    
    Tomcat B
    <Server port="8006" shutdown="SHUTDOWN"> 
    <Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
    <Connector port="8010" protocol="AJP/1.3" redirectPort="8443" />
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcatB">
    
    Last line has attribute jvmRoute and is concerned to session stickyness explained further bellow.
    For test purposes deploy some dummy application under /balance context.
    Try to start both instances to see if everything is ok.

    2. Install apache web server. I am using Ubuntu:
    sudo apt-get install apache2

    3. Edit virtual host configuration file.
    On Ubuntu, I edit /etc/apache2/sites-enabled/000-default.

    <Proxy balancer://tomcatservers>
        BalancerMember ajp://localhost:8009 route=tomcatA loadfactor=1
            BalancerMember ajp://localhost:8010 route=tomcatB loadfactor=2
        </Proxy>
    
        <Location /balancetest>
        Allow From All
            ProxyPass balancer://tomcatservers/balance stickysession=JSESSIONID nofailover=off
        </Location>
    
    We defined load balancer for two nodes (tomcatA and tomcatB) and proxy pass for load balancer. In proxy pass we defined that all request going to /balancetest are proxied to tomcat application server to /balance context. Entering url http://localhost/balancetest will display jsp page or whatever either from tomcatA or tomcatB depending on load balancer.

    The load balancer supports session stickyness wich means that all request for some session identifier are proxied to same tomcat web application instance in cluster that first served the client. To track this information tomcat adds jvmRoute information that uniquely identifies tomcat application server in the cluster.

    So, jsessionid cookie would look something like this:
    jsessionid=4C87288CB0CDB71D0DCA412E178A1480.tomcatB

    Apache web server will compare route  value defined in balancer with cookie value to proxy request to tomcat instance that maintains corresponding session.
    It is important that jvmRoute attribute in server.xml config file and route attribute in virtual host config file are identical for some tomcat instance.

    Load factor attribute allows to distribute load between nodes. If load factors are equal, load is equally distributed. In our case tomcatB will recieve two times more requests than tomcatA.

    4. And for this to work following modules must be enabled on apache server.
    • proxy
    • proxy_balancer
    • proxy_ajp
    On Ubuntu, you can do this from console by typing a2enmod command.
    a2enmod proxy
    a2enmod proxy_balancer
    a2enmod proxy_ajp


    Restart apache and tomcat servers and you'll have load balancing set up with minimal configuration.

    Sunday, February 6, 2011

    JDBC security realm with glassfish and jsf


    Security realm is very important aspect of almost every application.

    In this post I'll show an example of glassfish JDBC realm authentication through simple jsf web application. Example includes glassfish and web app configuration. At the end of this post is also source code for download.

    When dealing with web application security you have two choices: implement your own application security or use container based security solution. I prefer second choice because you now that it has been implemented by security professionals and it requires very little coding. For the most part, securing an application is achieved by setting up users and security groups in a security realm in application server.
    But if the constraints of container-managed security don't fit your application requirements then you can implement your own application-managed security from scratch or on top of existing container-managed facilities.

    Web application security is actually broken to authentication (process of verifying user identity) and authorization (process of determining whether a user has access to a particular resource or task, and it comes into play once a user is authenticated.

    In this post I will demonstrate how to set up web application form based login using glassfish application server(version 3.0.1) and java server faces (Mojarra 2.0.4).

    Let's assume you have web application and two type of users: regular users (who can access /users/ part of the site) and admin users (who in addition to being able to access users resources, have access to /admin/ part of the site). Users that are not authenticated can access only public part of the site.

    We want our application to use JDBC realm to read information about user and user groups.

    Security realms are, in essence, collections of users and related security groups. User can belong to one or more security group and groups that user belongs to define what actions the system will allow the user to perform. For application container, realm is interpreted as string to identify a data store for resolving username and password information.

    1. To begin, we will first create database with following structure:
    ERA model of user and user groups


    Our database has three tables. Users table holding user information, a groups table holding group information and join table between users and groups as there is a many-to-many relationship. I created also a view v_user_role that joins data from users and groups tables. I'll explain this later.

    CREATE TABLE `groups` (
    
      `group_id` int(10) NOT NULL,
    
      `group_name` varchar(20) NOT NULL,
    
      `group_desc` varchar(200) DEFAULT NULL,
    
      PRIMARY KEY (`group_id`)
    
    );
    
    CREATE TABLE `users` (
    
      `user_id` int(10) NOT NULL AUTO_INCREMENT,
    
      `username` varchar(10) NOT NULL,
    
      `first_name` varchar(20) DEFAULT NULL,
    
      `middle_name` varchar(20) DEFAULT NULL,
    
      `last_name` varchar(20) DEFAULT NULL,
    
      `password` char(32) NOT NULL,
    
      PRIMARY KEY (`user_id`)
    
    );
    
    CREATE TABLE `user_groups` (
    
      `user_id` int(10) NOT NULL,
    
      `group_id` int(10) NOT NULL,
    
      PRIMARY KEY (`user_id`,`group_id`),
    
      KEY `fk_users_has_groups_groups1` (`group_id`),
    
      KEY `fk_users_has_groups_users` (`user_id`),
    
      CONSTRAINT `fk_groups` FOREIGN KEY (`group_id`) REFERENCES `groups` (`group_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
    
      CONSTRAINT `fk_users` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
    
    ); 
    
    CREATE VIEW `v_user_role` AS
    
    SELECT  u.username, u.password, g.group_name
    
     FROM `user_groups` ug
    
     INNER JOIN `users` u ON u.user_id = ug.user_id
    
     INNER JOIN `groups` g ON g.group_id =  ug.group_id; 
    
    INSERT  INTO `groups`(`group_id`,`group_name`,`group_desc`) VALUES 
      (1,'USER','Regular users'),
      (2,'ADMIN','Administration users');
      
    INSERT  INTO `users`(`user_id`,`username`,`first_name`,`middle_name`,`last_name`,`password`) VALUES 
      (1,'john','John',NULL,'Doe','6e0b7076126a29d5dfcbd54835387b7b'), /*john123*/
      (2,'admin',NULL,NULL,NULL,'21232f297a57a5a743894a0e4a801fc3'); /*admin*/
      
    INSERT  INTO `user_groups`(`user_id`,`group_id`) VALUES (1,1),(2,1),(2,2);
    
    


    2. Now that we have database that will hold user credentials, we are ready to create connection to our database through glassfish administration console.

    Go to glassfish administration console and go to Resources-Connection Pools and choose New.
    Enter name and choose resource type and click next.


    Create JDBC connection pool

    On second step just leave defaults for now and click finish.

    Create JDBC connection pool step2


     
    After that select your connection pool, go to Additional properties and add properties as on picture bellow.

    Configure connection properties


    When done, you can ping database to see if connection is set up properly.

    If connection succeeded click on JDBC resources and click on new. JNDI name of this resource will be provided to jdbc security realm to obtain database connection. Enter some JNDI name and choose your connection pool.

     
    Create resource


    3. Once we have the database that will hold user credentials and JDBC connection to our database, we can setup JDBC realm. Go to Configuration-Security-Realms-New. 

    Create JDBC security realm

     
    Enter name for this jdbc realm (this name will be used in web.xml) and select JDBCRealm in select box. Enter properties as on picture above.
    The value of JNDI property must be the JNDI name of the data source corresponding to the database that contains the realm's user and group data.

    Interesting part here is that for user table and group table I used v_user_role as the value for the property. v_user_role is a database view that contains both user and group information. The reason i didn't use the users table directly is because glassfish assumes that both the user table and the group table contain a column containing the user name and that would result in duplicate data.

    You can enter properties as I did and all other properties are optional and can be left blank.

    4. Once we have defined JDBC realm we need to configure our application. All authentication logic is taken care of by the application server, so we only need to make modifications in order to secure the application in its deployment descriptors, web.xml and sun-web.xml.

    Add following snippet to web.xml file.
    <login-config>
        <auth-method>FORM</auth-method>
        <realm-name>jdbc-realm</realm-name>
        <form-login-config>
          <form-login-page>/faces/login.xhtml</form-login-page>
          <form-error-page>/faces/loginError.xhtml</form-error-page>
        </form-login-config>
        </login-config>
    

    login-config element defines authorization method for the application (in this case form will be displayed to end user to authenticate) and security realm that is used for authorization. We define login and login error pages. If user tries to go to restricted url without authenticating first, he will be redirected to login page first. If authentication fails, he will be redirected to loginError page.

    <security-constraint>
        <web-resource-collection>
          <web-resource-name>Admin user</web-resource-name>
          <url-pattern>/faces/admin/*</url-pattern>
          <http-method>GET</http-method>
              <http-method>POST</http-method>
        </web-resource-collection>
        <auth-constraint>
          <role-name>ADMIN</role-name>
        </auth-constraint>
      </security-constraint>
      
      <security-constraint>
        <web-resource-collection>
          <web-resource-name>Admin user</web-resource-name>
          <url-pattern>/faces/users/*</url-pattern>
          <http-method>GET</http-method>
              <http-method>POST</http-method>
        </web-resource-collection>
        <auth-constraint>
          <role-name>ADMIN</role-name>
          <role-name>USER</role-name>
        </auth-constraint>
      </security-constraint>
    
    


    security-constraint element defines who can access pages mathcing a certain URL pattern. Roles allowed to access the pages are defined in the element.

    We want only admin users to have access to /admin/* resources. Regular users and admin users both are allowed to access /users/* resources.

    Before we can successfully authenticate our users, we need to link the user roles defined in web.xml with the groups defined in the realm. We do this linking in sun-web.xml deployment descriptor.

    <security-role-mapping>
        <role-name>ADMIN</role-name>
        <group-name>ADMIN</group-name>
      </security-role-mapping>
      <security-role-mapping>
        <role-name>USER</role-name>
        <group-name>USER</group-name>
      </security-role-mapping>
    
    

    sun-web.xml deployment descriptor can have one or more elements. One of these elements for each role defined in web.xml.

    5. So, if user enters url something like http://host/showcase/faces/users/users.xhtml he will be redirected to login page. Code for login page is bellow.

    <h:body>
      <p>Login to access secure pages:</p>
      <form method="post" action="j_security_check">
        <h:panelGrid columns="2">
          <h:outputLabel for="j_username" value="Username" />
          <input type="text" name="j_username" />
    
          <h:outputLabel for="j_password" value="Password" />
          <input type="password" name="j_password" />
    
          <h:outputText value="" />
          <h:panelGrid columns="2">
            <input type="submit" name="submit" value="Login" />
            <h:button outcome="index" value="Cancel" />
          </h:panelGrid>
        </h:panelGrid>
      </form>
    </h:body>
    
    
    The important thing to note is that j_security_check, j_username and j_password attributes are required by container-managed authentication and shouldn't be renamed.
    After user authenticates, he will be redirected to requested url, in our case to /users/users.xhtml. Users page has just one simple link for logout.
    <h:body>
      <p>Welcome to user pages</p>
      <h:form>
        <h:commandButton action="#{authBackingBean.logout}" value="Logout" />
      </h:form>
    </h:body>
    

    And bean that executes logout is:

    @ManagedBean
    @RequestScoped
    public class AuthBackingBean {
      
      private static Logger log = Logger.getLogger(AuthBackingBean.class.getName());
      
      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;
      }
    }
    

    As you can see, Servlet 3.0, wich is new in Java EE 6, has method called logout() that will make the container unaware of the authentication credentials.

    So, what we have done is that when regular user tries to access /users/somePage.xhtml he will be redirected to login page and will have to authenticate. After he submits his credentials he will be allowed to access requested resources. If he tries to access /admin/ resources he will get access denied. Admin user on the other hand, when authenticated, he will be allowed to acces /admin/ and /users/ resources.

    Source code can be downloaded from the following link:
    LoginApp.war

    Migrating to glassfish 3.1.1 version

    I see a lot of people have problems running this example on GlassFish version 3.1.1. Only thing that needs to be configured is  Digest Algorithm in realm configuration page.
    By default glassfish 3.0.1 version assumed MD5 digest algorithm if nothing was set for this property - as in my example. Glassfish 3.1.1 version by default assumes SHA-256 so we need to set MD5 digest algorithm (since passwords in my sql script are in MD5 format).
    Go to Configurations - server-config - security -realm and edit realm by setting Digest Algorithm to MD5 (or any other algorithm depending what you use).

    And that's it. I tried and it works ok.