Friday, 6 June 2014

Form based authentication through Spring Security.

Form based authentication is another one of the most common requirement for web applications. In this post we will look how we can implement form based security through Spring.
security-config.xml:




 

 


  
            
        
        
   
   
   
   
   
   
   
   
   
    
  
  
   
  
  
  
  
 
 
 
 
 
  
   
  
   
 
 



Wednesday, 4 June 2014

How to implement Reference table Items (Look up items) in Java through AspectJ

In almost every application we require dynamic constants which can be loaded dynamically or on start up. Drop downs are one of the good example. System parameters from your table is another example. Let's take a specific scenario,
Say suppose we have got three security roles:
1) USER_ROLE,
2) USER_ADMIN,
3) USER_API

The requirement is we have to refer them in the form of constants in our code as well as some times we may have to compose drop down let's say on account settings page we have to show that drop down, a drop down for roles. For a drop down we may require key (code) and label for each constant.

Challenge:


We have to implement these reference values in the database so we can change these reference values with out changing code (or without a deployment of code). Also we still would be able to refer them in code but the key and value would be coming from database.

Implementation:


Initially, I wanted to implement it as Enum but I could not. If someone can, I would happy to see implementation.

In this implementation I have introduced annotation (@ReferenceList) to map the reference type to database.

package com.zohaib.research.referenceTypes;
import com.zohaib.research.annotations.ReferenceList;

@ReferenceList("UserRoleNames")
public class UserRoleNames extends CommonReferenceTypeImplementation{
 
 protected UserRoleNames(String constantName) {
  super(constantName);
  
 }

 public static UserRoleNames
  USER_ROLE  = new UserRoleNames("USER_ROLE"),
  ADMIN_ROLE = new UserRoleNames("ADMIN_ROLE"),
  API_ROLE   = new UserRoleNames("API_ROLE");  
 
}

My reference types will have some common operations so we have got CommonReferenceTypeImplementation as follows:

package com.zohaib.research.referenceTypes;

public class CommonReferenceTypeImplementation implements ReferenceType{

  private String code;
 private String label;
 private String name;
 private boolean initialized;
 
 protected CommonReferenceTypeImplementation(String constantName) {
  this.name = constantName;
 }
 
 @Override
 public void init(String code, String label){
  this.code  = code;
  this.label = label;
  this.initialized = true;
 }
 
 
 @Override
 public String getCode() {
  return this.code;
 }

  @Override
 public String getLabel() {
  return this.label;
 }
 
 @Override
 public String name(){
  return this.name;
 }
 
 @Override
 public boolean hasBeenInitialized(){
  return this.initialized;
 }
}

An interface:


package com.zohaib.research.referenceTypes;


public interface ReferenceType {
 
 public abstract String getCode();
 public abstract String getLabel();
 public void init(String code, String label);
 public boolean hasBeenInitialized();
 public String name();
 
}
Annotation:
package com.zohaib.research.annotations;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface ReferenceList {

 public String value();
}

Usage:

And I want to use that some thing like as follows:
@Controller
public class UserService {

       @Autowired
 private transient UserRepository userRepository;

 @Autowired
 private transient RefItemRepository refItemRepository;

 @Autowired
 private transient UserRoleRepository userRoleRepository;

 protected transient Log logger = LogFactory.getLog(getClass());

@RequestMapping(value = "/userService/saveUser", method = RequestMethod.POST)
 public @ResponseBody JSendResponse saveUser(@ModelAttribute User user) {
  User savedUser = null;
  try {

   user.setUserName(user.getEmail());
   user.setEnabled(Boolean.TRUE);
   savedUser = userRepository.save(user);

   // String role = UserRoleNames.USER_ROLE.getCode();
   // TODO: Remove following fetch from above line in future.
   /*
    * RefItem userRoleRefItem =
    * refItemRepository.findByName(UserRoleNames.ROLE_USER.toString());
    * String role = userRoleRefItem.getCode();
    */
   String role = UserRoleNames.USER_ROLE.getCode();
   UserRole userRole = new UserRole();
   userRole.setRoleName(role);
   userRole.setUserId(savedUser.getId());
   userRoleRepository.save(userRole);

  } catch (Exception ex) {
   logger.error("An Exception occurred in saving user!", ex);
   return JSendResponse.applicationError(ex.getMessage());
  }
  return JSendResponse.success("userId", savedUser.getId());
 }
}
Magic: The actual magic is a Aspect:
package com.zohaib.research.aspects;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.hibernate.service.spi.InjectService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Component;

import com.zohaib.research.annotations.ReferenceList;
import com.zohaib.research.referenceTypes.ReferenceType;
import com.zohaib.research.relational.entities.RefItem;
import com.zohaib.research.repositories.jpa.RefItemRepository;
import com.zohaib.research.spring.SpringBeanUtils;

@Aspect
public class ReferenceTypeAspect {

 protected transient Log logger = LogFactory.getLog(getClass());
 
 
 @Before("execution(* com.zohaib.research.referenceTypes.CommonReferenceTypeImplementation.get*(..))")
 public void initializeReferenceType(JoinPoint joinPoint) throws Exception{
  if(logger.isDebugEnabled()){
   logger.debug("calling initializeReferenceType aspect....");
  }
  
  if(joinPoint.getThis() != null && joinPoint.getThis() instanceof ReferenceType){
   
   ReferenceType thisObject     = (ReferenceType) joinPoint.getThis();
   //Never ever call same method which you are already cross cutting. Otherwise infinite loop.
   //if(thisObject.getCode() == null && thisObject.getLabel() == null){
   //Lazy initialize reference item instance.
   if(! thisObject.hasBeenInitialized()){
    Class thisObjectClass = joinPoint.getThis().getClass();
    
    ReferenceList refListAnnotationOnClass = thisObjectClass.getAnnotation(ReferenceList.class);
    String referenceListName = refListAnnotationOnClass.value();
    String referenceItemName = thisObject.name();
    
    RefItemRepository refItemRepository = SpringBeanUtils.getBean(RefItemRepository.class);
    RefItem refItem = refItemRepository.findByNameAndRefListName(referenceItemName, referenceListName);
    thisObject.init(refItem.getCode(), refItem.getLabel());
   
   }
   
  }
  
 }
 
}
We need aop.xml which would be in META-INF folder (src/main/resources/META-INF/aop.xml)

 
  
 

Model: Following is my model in JPA POJO:
package com.zohaib.research.relational.entities;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name="RefList")
public class RefList extends AbstractEntity{

 
 private static final long serialVersionUID = 7396124355136909774L;

 @Column(name = "name",nullable=false)
 private String name;
 
 @Column(name = "description",nullable=false)
 private String description;

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getDescription() {
  return description;
 }

 public void setDescription(String description) {
  this.description = description;
 }
 
}
package com.zohaib.research.relational.entities;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name="RefItem")
public class RefItem extends AbstractEntity{
 
 @Column(name = "name",nullable=false)
 private String name;
 
 @Column(name = "code",nullable=false)
 private String code;
 
 @Column(name = "label",nullable=false)
 private String label;
 
 @Column(name = "refListId",nullable=false)
 private Long refListId;
 
 @ManyToOne(fetch=FetchType.LAZY)
 @JoinColumn(name = "refListId",insertable=false,updatable=false)
 private RefList refList;
 
 @Column(name = "description")
 private String description;
 
 @Column(name = "archiveDate")
 @Temporal(TemporalType.TIMESTAMP)
 private Date archiveDate;
 
 

 public RefList getRefList() {
  return refList;
 }

 public void setRefList(RefList refList) {
  this.refList = refList;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getCode() {
  return code;
 }

 public void setCode(String code) {
  this.code = code;
 }

 public String getLabel() {
  return label;
 }

 public void setLabel(String label) {
  this.label = label;
 }

 public Long getRefListId() {
  return refListId;
 }

 public void setRefListId(Long refListId) {
  this.refListId = refListId;
 }

 public String getDescription() {
  return description;
 }

 public void setDescription(String description) {
  this.description = description;
 }

 public Date getArchiveDate() {
  return archiveDate;
 }

 public void setArchiveDate(Date archiveDate) {
  this.archiveDate = archiveDate;
 }
  
}
package com.zohaib.research.relational.entities;

import java.io.Serializable;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

import org.apache.commons.lang.builder.ToStringBuilder;

@MappedSuperclass
public class AbstractEntity implements Serializable{

 private static final long serialVersionUID = -992911032580505536L;
 
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private Long id;

 /**
  * Returns the identifier of the entity.
  * 
  * @return the id
  */
 public Long getId() {
  return id;
 }

 /*
  * (non-Javadoc)
  * 
  * @see java.lang.Object#equals(java.lang.Object)
  */
 @Override
 public boolean equals(Object obj) {

  if (this == obj) {
   return true;
  }

  if (this.id == null || obj == null
    || !(this.getClass().equals(obj.getClass()))) {
   return false;
  }

  AbstractEntity that = (AbstractEntity) obj;

  return this.id.equals(that.getId());
 }

 /*
  * (non-Javadoc)
  * 
  * @see java.lang.Object#hashCode()
  */
 @Override
 public int hashCode() {
  return id == null ? 0 : id.hashCode();
 }
 

 @Override
 public String toString()
 {
     return ToStringBuilder.reflectionToString(this);
 }
}
The hardest part: Following is POM.xml with right maven plugin configuration. I am trying to use aspect with out spring dependency.


 4.0.0
 com.zohaib.research
 researchPrj
 war
 1.0-SNAPSHOT
 Maven Webapp
 http://maven.apache.org

 

  
   Maven central
   http://central.maven.org/maven2
  

  
   maven2
   http://repo2.maven.org/maven2
  

  
   maven.springframework
   http://maven.springframework.org/release
  


  
   spring-milestones
   http://repo.spring.io/milestone
   
    true
   
  


 


 
  
  true
  4.0.3.RELEASE
  1.5.2.RELEASE
  3.2.3.RELEASE
  4.3.5.Final
  2.3.2
  5.1.30

 

 


  
   javax.servlet
   jstl
   1.2
  

  
   javax.servlet
   javax.servlet-api
   3.0.1
   provided
  


  
   org.springframework
   spring-webmvc
   ${org.springframework-version}
  


  
   org.springframework.data
   spring-data-jpa
   ${org.springData-version}
  

  
   org.springframework
   spring-tx
   ${org.springframework-version}
  

  
   org.aspectj
   aspectjrt
   1.6.5
  

  
   org.aspectj
   aspectjweaver
   1.8.0.RELEASE
  


  
  
   org.springframework.security
   spring-security-web
   ${spring.security.version}
  

  
   org.springframework.security
   spring-security-config
   ${spring.security.version}
  

  
  
   org.springframework.security
   spring-security-taglibs
   ${spring.security.version}
  


  
   org.hibernate
   hibernate-core
   ${hibernate.version}
  
  
   org.hibernate
   hibernate-entitymanager
   ${hibernate.version}
  


  
   mysql
   mysql-connector-java
   ${mysql.connector.version}
  

  
   opensymphony
   sitemesh
   2.4.2
  

  
   cglib
   cglib-nodep
   2.2
  

  
   commons-collections
   commons-collections
   3.1
  

  
   commons-dbcp
   commons-dbcp
   1.3
  


  
   commons-beanutils
   commons-beanutils
   1.8.3
  

  
   org.apache.httpcomponents
   httpclient
   4.1.1
  

  
   commons-fileupload
   commons-fileupload
   1.2.2
  

  
   commons-io
   commons-io
   1.4
  

  
   commons-lang
   commons-lang
   2.5
  

  
   commons-pool
   commons-pool
   1.5.4
  

  
   org.codehaus.jackson
   jackson-mapper-asl
   1.9.3
  


  
   junit
   junit
   3.8.1
   test
  

 

 
  ROOT
  
   
    org.apache.maven.plugins
    maven-compiler-plugin
    2.3.2
    
     1.6
     1.6
    
   
   
    org.apache.maven.plugins
    maven-war-plugin
    2.1.1
    
     false
    
   

   
    org.codehaus.mojo
    aspectj-maven-plugin
    1.5
    
    
     1.6
     1.6
     1.6
    
    
     
      
       compile
       test-compile
      
     
    
   

   
    org.apache.maven.plugins
    maven-site-plugin
    3.0
    
     
      
      
       org.codehaus.mojo
       cobertura-maven-plugin
       2.5.1
      
     
    
   
  
 



What Else: You may want to write implementations of repository but I am using Spring Data JPA repositories so I have got only interfaces, implementation will be generated by spring data:

package com.zohaib.research.repositories.jpa;

import java.io.Serializable;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;

@NoRepositoryBean
public interface JpaBasedRepository extends JpaRepository {
 

}

package com.zohaib.research.repositories.jpa;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import com.zohaib.research.relational.entities.RefItem;

public interface RefItemRepository extends JpaBasedRepository{

 @Query("SELECT r FROM RefItem r WHERE r.name = :constantName")
 public RefItem findByName(@Param("constantName") String constantName);
 
 @Query("SELECT r FROM RefItem r inner join r.refList l WHERE r.name = :constantName and l.name = :refListName ")
 public RefItem findByNameAndRefListName(
   @Param("constantName") String constantName, 
   @Param("refListName") String refListName
 );
 
}

package com.zohaib.research.repositories.jpa;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import com.zohaib.research.relational.entities.RefList;

public interface RefListRepository extends JpaBasedRepository{
 
 @Query("SELECT l FROM RefList l WHERE l.name = :refListName")
 public RefList findByName(@Param("refListName") String refListName);
}


Tuesday, 12 June 2012

Integration of Maven and ANT

The idea behind this post is to build through maven so we don't have dirty lib folders in our repository or don't have to worry about class paths either. 

Also some time you want to deploy locally as you are deploying in real production environment. 

Following is a sample build script:

pom.xml:



 4.0.0
 com.zohaib.research
 researchPrj
 war
 1.0-SNAPSHOT
 Maven Webapp
 http://maven.apache.org

 

  
   Maven central
   http://central.maven.org/maven2
  

  
   maven2
   http://repo2.maven.org/maven2
  

  
   maven.springframework
   http://maven.springframework.org/release
  


  
   spring-milestones
   http://repo.spring.io/milestone
   
    true
   
  


 


 
  
  true
  4.0.3.RELEASE
  1.5.2.RELEASE
  3.2.3.RELEASE
  4.3.5.Final
  2.3.2
  5.1.30

 

 


  
   javax.servlet
   jstl
   1.2
  

  
   javax.servlet
   javax.servlet-api
   3.0.1
   provided
  


  
   org.springframework
   spring-webmvc
   ${org.springframework-version}
  


  
   org.springframework.data
   spring-data-jpa
   ${org.springData-version}
  

  
   org.springframework
   spring-tx
   ${org.springframework-version}
  

  
   org.aspectj
   aspectjrt
   1.6.5
  

  
   org.aspectj
   aspectjweaver
   1.8.0.RELEASE
  


  
  
   org.springframework.security
   spring-security-web
   ${spring.security.version}
  

  
   org.springframework.security
   spring-security-config
   ${spring.security.version}
  

  
  
   org.springframework.security
   spring-security-taglibs
   ${spring.security.version}
  


  
   org.hibernate
   hibernate-core
   ${hibernate.version}
  
  
   org.hibernate
   hibernate-entitymanager
   ${hibernate.version}
  


  
   mysql
   mysql-connector-java
   ${mysql.connector.version}
  

  
   opensymphony
   sitemesh
   2.4.2
  

  
   cglib
   cglib-nodep
   2.2
  

  
   commons-collections
   commons-collections
   3.1
  

  
   commons-dbcp
   commons-dbcp
   1.3
  


  
   commons-beanutils
   commons-beanutils
   1.8.3
  

  
   org.apache.httpcomponents
   httpclient
   4.1.1
  

  
   commons-fileupload
   commons-fileupload
   1.2.2
  

  
   commons-io
   commons-io
   1.4
  

  
   commons-lang
   commons-lang
   2.5
  

  
   commons-pool
   commons-pool
   1.5.4
  

  
   org.codehaus.jackson
   jackson-mapper-asl
   1.9.3
  


  
   junit
   junit
   3.8.1
   test
  

 

 
  ROOT
  
   
    org.apache.maven.plugins
    maven-compiler-plugin
    2.3.2
    
     1.6
     1.6
    
   
   
    org.apache.maven.plugins
    maven-war-plugin
    2.1.1
    
     false
    
   

   
    org.codehaus.mojo
    aspectj-maven-plugin
    1.5
    
    
     1.6
     1.6
     1.6
    
    
     
      
       compile
       test-compile
      
     
    
   

   
    org.apache.maven.plugins
    maven-site-plugin
    3.0
    
     
      
      
       org.codehaus.mojo
       cobertura-maven-plugin
       2.5.1
      
     
    
   
  
 



build.properties:


deployment.dir=C:/SOFTWARE_INSTALL/TESTING_TOMCAT/apache-tomcat-7.0.53/webapps
tomcat.home=C:/SOFTWARE_INSTALL/TESTING_TOMCAT/apache-tomcat-7.0.53
build.dir=../target
war.file.name=ROOT.war
maven.home=C:/MAVEN/apache-maven-3.0.4
catalina.fileName=catalina.bat
maven.fileName=mvn.bat

build.xml:



 
  ANT SCRIPT
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


 
 

 


 
  
   
  
 

 
  
   
  
 

 
  
   
  
 

 
  
   
  
 



 

 
  
  
 

 

  
  

  
  

   
   

  
  
   
  

 

 
  
  

  

  
   
  
  
  

  
   
   
   
  

  
   
  

  
   
   
   
  


 

 


 

 


 


 
  
  
  
  
 


 
  
   
  

  
  

   
   
  

 

 
  
  
   
   
  
 

 
  
  
  
 

 

 
  
  
    
   
   
   
      
   
   
  
 

 
  
  
   
   
  
 

 
  
   
   
  
 



 
  
  
  
       
  
 



 
  
  
  
  
  
  
   
    
   
  
 

 
  
  
  
  
  
  
 

 
  
  
  
  
  
  
  
  
 

 
  
  
 


 
  
  
  
 

 
  
  
  
  
  
  
  
  

 


Tuesday, 24 January 2012

Implementing virtual host in tomcat

Implementing virtual host in tomcat
Implementing Virtual Host in Tomcat

Say you have Java web application and you want to have “myApp-local.zohaib.umair.com” as a URL to access in tomcat. If you open up conf/server.xml you will notice that tomcat comes with default Host called “localhost” with the appBase “webapps” where you install web applications for default localhost host.

<Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">
And you will also find that URL for the default application becomes:
And for the other sub-context deployed on this host becomes:

1) conf/server.xml configuration:


<Host appBase="vhosts/myApp-local.zohaib.umair.com"
name="myApp-local.zohaib.umair.com" unpackWARs="true" autoDeploy="true">

<!—If you want to log -->
      <Logger className="org.apache.catalina.logger.FileLogger"
            prefix="zohaib_log" suffix=".txt" timestamp="true" verbosity="4" />

      <Alias>myApp-local.zohaib.umair.com</Alias>
      <Alias>www.anotherAlias.net.au</Alias>
      <Valve className="org.apache.catalina.valves.AccessLogValve"
      directory="logs" prefix="myApp-local.zohaib.umair.com_access_log."
      suffix=".txt" pattern="common" resolveHosts="false" />

</Host>

Under ${tomcat-home} folder you need to create a folder vhosts/myApp-local.zohaib.umair.com as specified in above server.xml configuration. Here you actually place your ROOT.war.
Note ROOT.war is actually tomcat's convention. And conceptually you are actually creating a host and tomcat needs to know which is a default root war for that host. Therefore you must follow that convention.

In above configuration you are telling tomcat:That your defualt (ROOT.war) can be accessible via myApp-local.zohaib.umair.com or www.anotherAlias.net.au. Your default war (i.e ROOT.war) is located under ${tomcat}/vhosts/myApp-local.zohaib.umair.com. It could be war or exploded folder. And You want to log messages in zohaib_log.txt file with timestamp.


2) ${tomcat-home}/conf/Catalina/myApp-local.zohaib.umair.com/ROOT.xml


Under ${tomcat-home}/conf/Catalina you have to create folder myApp-local.zohaib.umair.com and in that folder you need to place ROOT.xml. Your ROOT.xml should be similar as follows. Main thing is you need to define CONTEXT:


<?xml version='1.0' encoding='utf-8'?>

<Context allowLinking="true" displayName="MyApp" docBase="ROOT.war"
     path="" workDir="work/Catalina/myApp-local.zohaib.umair.com/_">

<Resource name="myOracle" auth="Container" type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver" url="jdbc:oracle:thin:@servername:1522:5MyDatabase"
username="zohaib" password="zohaib" removeAbandoned="true"
removeAbandonedTimeout="60" logAbandoned="true" maxActive="150"
maxIdle="20" maxWait="5000" validationQuery="select 1 from dual"
testOnBorrow="true" testOnReturn="true" testWhileIdle="true"
timeBetweenEvictionRunsMillis="1800000" numTestsPerEvictionRun="3"
minEvictableIdleTimeMillis="1800000" />

</Context>

3) Windows hosts file


If you are on windows and if you are running locally then you need to bind your alia to your IP in
C:\Windows\System32\drivers\etc\hosts
10.3.22.2                                         myApp-local.zohaib.umair.com
10.3.22.2                                         www.anotherAlias.net.au

Assume 10.3.22.2 is your IP and if you have deployed war you should able to access your app from above URLs