Advertisement

Authentication in Seam

Seam Framework provides facilities to enable applications to be secured using user authentication and user authorization and other facilities. Author teaches more on Authentication in Seam.

Introduction
The topic of authentication is not new, as we have seen a number of login applications with various technologies-PHP, JSF, Rails, Grails etc. The Seam Framework provides facilities to enable applications to be secured using user authentication and user authorization and other facilities. Create a database and Create a project with seam gen with the following commands

1) seam setup
2) seam create-project.

For providing replies to the queries raised by the tool, you can refer to the earlier articles but remember to answer ear for the following question “Is this project deployed as an ear.. “ as we intend to use a stateless session bean for registration. Open the project in NetBeans and look at the files available. You can see only Authenticator.java in src folder and in view folder apart from home.xhtml and error.xhtml only login.xhtml. That is, even before you code or generate any model or action class, the authentication infrastructure is made available to you. The authenticate() action/method in Authenticator.java(component name authenticator) is even registered as the authenticate-method/login method in component.xml as follows:<security:identity authenticate-method = "#{authenticator.authenticate}". In other words projects created using the seam-gen tool already have the authentication routine configured. But the default configuration accepts any username and password. Out of the box, there’s no way for users to authenticate themselves. The generated code leaves a space for you to write your authentication routine. And we also need to code/generate

1) an action/method to register the user and
2) a view file for accepting values from the user and invoke the register action.

We also have to create a table in the database to store username and password and an entity class that maps to the table.  

Essentials of authenticate method  You can have a look at the code generated for the authenticate() method.1) the essentials of the authentication method are:

? It must take no arguments.
? It must return a boolean to indicate whether the credentials has been verified.
? It must be accessible via the EL

The authentication method can have any name, it can reside on any class, and that class doesn’t have to implement any special security interfaces. Seam plugs the authentication method into JAAS, but hides the complexity of JAAS in the SeamLogin-Module. Internally, JAAS invokes the authentication method if the method returns true. As noted above, this authentication routine is activated through Seam’s identity component, freeing you from having to interact with JASS that lies beneath. The built-in Identity component, named identity, maintains a reference to the authentication method as a method-binding expression.

What we should do

Create a table books with the following fields 1) id int auto-increment primary key 2) title varchar (20) not null 3) author varchar(20) not null. Generate model and action classes executing seam generate. The application is a Seam application to do CRUD operations on a database table generated without any code from us. We want to restrict the access to it only to registered users by filling up the skeleton authenticate () and providing the required files. The required steps are:

a) Create a table customer in the database we created earlier and User entity class for mapping the same We intend to use JPA EntityManager to query the database to authenticate the user and you can have a look at the code in the examples (especially registration folder) of the seam distribution to see how to do it. You can see, that the first requirement is a table and an entity class. Create a table customer with the following fields 1) id int auto-increment primary key 2) username varchar (20) not null 3) password varchar(20) not null. We should not create this table before executing “seam generate” and if you have already done it you have to edit resources/seam-gen.reveng.xml to exclude this table from reverse engineering. Otherwise, apart from necessary Entity class, Home and Query objects will be created for this table also. To manually code an entity class, in the NetBeans IDE in the project, under /src/main select /com/mydomain/myproject/model and create a new Java class User. The code may be filled up as follows:

User.java

 package com.mydomain.myproject.model;
import static org.jboss.seam.ScopeType.SESSION;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import javax.persistence.Transient;
import org.hibernate.validator.Length;
import org.hibernate.validator.NotNull;
import org.hibernate.validator.Pattern;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;

@Entity
@Name("user")
@Scope(SESSION)
@Table(name = "customer")  --------------------------1)
public class User implements Serializable {
private String username;
private String password;
public String verify;    -----------------------------------2)

            public User( String password, String username, String verify) {
this.password = password;
this.username = username;
this.verify = verify;

            }
public User() {
}

@NotNull
@Length(min = 5, max = 15)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}

            @Id
@Length(min = 4, max = 15)
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}

            @Override
public String toString() {
return "User(" + username + ")";
}

           
@Transient  ----------------------------------------------2)
public String getVerify() {
return verify;
}

           
public void setVerify(String verify) {
this.verify = verify;
}

}

1) You can see that this an entity class and we need a table customer in the database.
2) For the attributes in the class we need matching columns in the table except for verify, whose getter is annotated with @Transient. You know an attribute annotated with @Transient will be persisted to the database.

Execute seam new-action The next requirement is the view file for getting data from the user and an action for registering the user. By executing “seam new-action” we can create the above files. Go to Command Prompt and execute seam new-action. Answer the queries as follows:

Seam component name –register. The default answers are suggested for other queries as shown below:

Enter the local interface name   Register
Enter the bean class name   RegisterBean
Enter the action method name  register
Enter the page name  register

Accept the default answers. In a seam-gen created seam project the first page the user sees is the home page and it is composed from home.xhtml, template.xhtml and menu.xhtml. To add a link to register page from home page we have to modify menu.xhtml. In view/layout/menu.xhtml add to <rich:toolBarGroup location="right">the following line:
<s:link id="menuRegisterId" view="/register.xhtml" value="Register" rendered="#{not identity.loggedIn}" propagation="none"/>

If you click the link Register you will get the register page as in Figure 1

Figure 1

To the source code for register.xhtml which was generated, we can add after <h:form id=”registerForm”> the following:

register.xhtml

            <div class="dialog">
                <h:panelGrid columns="2" rowClasses="prop" columnClasses="name,value">
                    <h:outputLabel for="username">Username</h:outputLabel>
                    <h:inputText id="username"                                     value="#{user.username}"/>
                   
                    <h:outputLabel for="password">Password</h:outputLabel>
                    <h:inputSecret id="password"
                                value="#{user.password}"/>
                    <h:outputLabel for="verifypassword">Verify  Password</h:outputLabel>
                    <h:inputSecret id="verifypassword"
                                value="#{user.verify}"/>
                </h:panelGrid>
            </div>

            <div class=”actionButton>  //---------------1)
<h:commandButton id="register" value="register!"
action="#{register.register}"/> 
</div>  //----------1)
<h:messages/> //-------------------2)
</h:form>
</rich:panel>

</ui:define>
</ui:composition> 

1)  added portion is marked in bold letters. The code
                <h:commandButton id="register" value="register!"
                             action="#{register.register}"/> 
was enclosed within <div class=”actionButton>
          </div>

2) Added portion is marked in bold letters. <h:messages> tag was  added before <h:form> to display messages

Modification in RegsterBean.java To the code generated for the Java class  RegisterBean.java. Which contains the register() action we can add the following:

1)@PersistenceContext
private EntityManager entityManager;(add necessary imports
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;)

2)  @In
private User user;
(import com.mydomain.myproject.model.User;)

3) Replace the contents of register() with the following and make necessary imports:

 

    if(user.getPassword().equalsIgnoreCase(user.getVerify()))
{
List existing = entityManager.createQuery("select u.username from User u where u.username=#{user.username}")
.getResultList();

      if ( existing.size()==0 )
{
entityManager.persist(user);
log.info("Registered new user #{user.username}");
statusMessages.add("Successfully regstered,you can Login ");
}
else
{
statusMessages.add("User #{user.username} already exists");
}
}
statusMessages.add("Passwords do not match ");      

    }

The completed code may look as under:

 

RegisterBean.java

package com.mydomain.myproject.action;

import javax.ejb.Stateless;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.log.Log;
import org.jboss.seam.international.StatusMessages;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import com.mydomain.myproject.model.User;
import java.util.List;
@Stateless
@Name("register")
public class RegisterBean implements Register
{
@Logger private Log log;

    @In StatusMessages statusMessages;
@In User user;
@PersistenceContext
private EntityManager entityManager;

 

    public void register()
{
if(user.getPassword().equalsIgnoreCase(user.getVerify()))
{
List existing = entityManager.createQuery("select u.username from User u where u.username=#{user.username}")
.getResultList();

      if ( existing.size()==0 )
{
entityManager.persist(user);
log.info("Registered new user #{user.username}");
statusMessages.add("Successfully regstered,you can Login ");
}
else
{
statusMessages.add("User #{user.username} already exists");
}
}
statusMessages.add("Passwords do not match ");       

    }

}

1) If the two passwords match, for the username provided by the user, a list of user objects from the database is fetched. If its size is 0- that is if there is no user with that username- the user object is saved into the database and message “Successfully registered, you can Login” is sent to the page for the user to login. Otherwise error message is sent to the page for display.

The login page is composed from login.xhtml and the template.xhtml and the generated code for them require no modification. However have a look at the extract from login.xhtml

login.xhtml

<h:panelGrid columns="2" rowClasses="prop" columnClasses="name,value">
<h:outputLabel for="username">Username</h:outputLabel>
<h:inputText id="username"
value="#{credentials.username}"/> //……….1)
<h:outputLabel for="password">Password</h:outputLabel>
<h:inputSecret id="password"
value="#{credentials.password}"/>
<h:outputLabel for="rememberMe">Remember me</h:outputLabel>
<h:selectBooleanCheckbox id="rememberMe"
value="#{rememberMe.enabled}"/>
</h:panelGrid>
……………………
<div class="actionButtons">
<h:commandButton id="submit" value="Login" action="#{identity.login}"/>  //-------------------------------2)
</div>

  1. The input from the user is stored in the built-in credentials component
  2. The method login() in the built-in identity component is triggered.

We have to remember the above facts when we code our authenticate() action.
Fill up the authenticate() method   We mentioned earlier that the generated code for authenticate() leaves a space for filling up. How to fill up the authenticate method? You can replace it with the following:

 

log.info("authenticating {0}", credentials.getUsername());
try {
User result = (User)em.createQuery("from User where username=:username")
.setParameter("username", credentials.getUsername()).getSingleResult();
if(result.getPassword().equals ( credentials.getPassword()))

                        return true;

        } catch (NoResultException e) {}

            return false;
}

The filled up AuthenticatorBean.java may look as under:

package com.mydomain.myproject.action;
import javax.ejb.Stateless;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.log.Log;
import org.jboss.seam.security.Credentials;
import org.jboss.seam.security.Identity;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import com.mydomain.myproject.model.User;
import javax.persistence.NoResultException;

@Stateless
@Name("authenticator")
public class AuthenticatorBean implements Authenticator {
@Logger
private Log log;
@In
Identity identity;
@In
Credentials credentials;
@PersistenceContext                //-----------------------1)
EntityManager entityManager;
private final String query="from User where username=:username";
public boolean authenticate() {
log.debug("Authenticating username:"+ credentials.getUsername());
try {
User result = (User)entityManager.createQuery(query)  ----------2)
.setParameter("username", credentials.getUsername())                    .getSingleResult();
if(result.getPassword().equals ( credentials.getPassword()))

                        return true;

        } catch (NoResultException e) {}

return false;
}
}

     As already sad, the following entry in components.xml of the made by seam-gen makes the above authenticate method() the login method:


<security:identity authenticate-method="#{authenticator.authenticate}"/>

   1) Container managed Persistent Context is injected and EntityManager object is obtained.

2) createQuery() method in EntityManager is invoked passing on credentials.getUsername(username got from the user) as a parameter and the object got is cast to User. The password in the User object is compared to the password collected from the user(credentials.getPassword()). If they match Boolean value true is returned and user is welcomed as shown in Figure 2. Otherwise error message is sent to the user.

Figure 2

Check   You can try by clicking Log-out. Now you can place your mouse point on Browse data and click Books List. You can see the list of books available as in Figure 3 but if you click Create Books button you will be asked to login as in Figure 4.To define pages that require authentication, we can add a login-required attribute to the page element within the pages.xml file. You know you can have a single page.xml file for the entire application stating the navigation rules or separate files for each page and the application created with seam-gen follows the second option. In BookEdit.page.xml you can see the line login-required="true". If you look at Book.page.xml or BookList.page.xml there is no such line and hence no such restriction

Figure 4

Conclusion

If you want to know more about Security in Seam, you are requested to go through Chapter 10 of the book Seam 2.x Web Development by David Salter and see how both authentication(login) and authorization can be used in it. You know authorization is assigning roles to users and restricting access to certain modules only for certain roles. For example users with guest role may not have access to that portion of the software that users with admin role alone can see-. Seam uses JASS underneath for authentication and authorization.  It uses JBoss Drools for rule based security which secures your modules better than the above two. In-fact when you create a project with seam-gen the necessary jars- drools-core.jar, droolscompiler.jar, core.jar (Eclipse JDT), antlr-runtime.jar, janino.jar, and mvel14.jar-have been added to the project and necessary entries in the component.xml have been made.    You have to activate the set of security rules.

Some of the more advanced security features of Seam -covered in the above book- include:
1) Auditing security events
2) CAPTCHAs. A CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart) allows a challenge-response input to be      provided by the users to enable computer systems to validate that a "live" user is accessing the system rather than a computer.
3) The Seam identity manager API- it provides fine-grained security access permission on top of security roles. We create users and assign roles to them by methods provided by this API as shown below:IdentityManager.createUser(String username, String password);
IdentityManager.grantRole(String username, String rolename);
4) Open ID.It is an open standard authentication scheme that allows users to log onto many different web sites using the same identity on each of the web sites.

For more information on authentication in Seam you can contact the author from the following URL. sekaran.madhan@gmail.com








Added on January 26, 2012 Comment

Comments

#1

mahesh commented, on January 26, 2012 at 11:35 a.m.:

thanks. this software worked great for? me.

#2

Rekha Tiwari commented, on January 26, 2012 at 4:05 p.m.:

Provide some articles on Oracle database also. I will hope to see something from you soon. :)

Post a comment