Friday, 28 September 2012

Securing Web Applications with Spring Security

This post will demonstrate how to configure a web application with Spring Security. In our experience Spring Security provides a far more elegant approach to security than the standard JEE spec.

Assuming a web application has been developed using Spring MVC, there will be a web.xml file and a number of Spring configuration files. To enable Spring Security, we need to configure the Spring DelegatingFilterProxy filter in the web.xml.



    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


This filter is a proxy that delegates to a Spring-managed bean that implements the Filter interface. The name of the filter matches the name of the bean in the Spring context file. The security filter chain intercepts requests and enforces any security requirements specified in the Spring context file as shown below:


<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    <!-- HTTP security configurations -->
    <http auto-config="true" use-expressions="true">
        <form-login login-processing-url="/resources/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t" />
        <logout logout-url="/resources/j_spring_security_logout" />
        <!-- Configure these elements to secure URIs in your application -->


        <intercept-url pattern="/admin/authoriseusers/**" access="hasRole('ROLE_ADMIN')" />

        <intercept-url pattern="/member/**" access="isAuthenticated()" />
        <intercept-url pattern="/resources/**" access="permitAll" />
        <intercept-url pattern="/**" access="permitAll" />
    </http>
    <!-- Configure Authentication mechanism -->
    <authentication-manager alias="authenticationManager">
        <!-- SHA-256 values can be produced using 'echo -n your_desired_password | sha256sum' (using normal *nix environments) -->
        <authentication-provider>
            <password-encoder hash="sha-256" />
            <user-service>
                <user name="admin" password="8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918" authorities="ROLE_ADMIN" />
                <user name="user" password="04f8996da763b7a969b1028ee3007569eaf3a635486ddab211d512c85b9df8fb" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>
</beans:beans>

This shows a sample security configuration with an in-memory userstore. Note that the Spring Security uses its own XML namespace that has been declared as the default namespace at the beginning of the context file. It then sets up the http security with form-based login and a number of intercept-url elements that specify which paths should be secured and which roles granted access. This is where all the access control requirements can be configured. There are additional properties that can specify the HTTP method that needs to be secured for the given URI. Next we configure an authentication manager with an authentication provider that basically controls how users will be authenticated by Spring Security. In this case, it is simply using an in-memory authentication provider where user's have been defined with their name, password and roles.

The http form-login configuration specifies the login-page and the url for the page to display on authentication failure. The excerpt below shows the form from the login page. Note the form's action property.


<form action="/resources/j_spring_security_check" method=post>
  <div>
    <label for="j_username">Please Enter Your Name:</label>
  </div>
  <div>   
    <input id="j_username" type="text" name="j_username" size="25">
  </div>
  <div>
    <label for="j_password">Please Enter Your Password:</label>
  </div>
  <div>
    <input type="password" size="15" name="j_password">
  </div>
  <div>
       <input type="submit" value="Submit">
       <input type="reset" value="Reset">
    </div>
</form>
 


Now whenever an user accesses one of the secured URIs, Spring Security will require the user to login via the configured login page. On submitting the credentials, Spring Security will authenticate using the configured authentication provider.

Using an in-memory user store only serves demonstration purposes and so the following section shows a how a custom authentication provider can be specified that allows control over how users are authenticated.



  <beans:bean id="myAuthenticationProvider" class="javaworkbench.usermanagement.authentication.AuthenticationProvider" />

  <!-- Configure Authentication mechanism -->
  <authentication-manager alias="authenticationManager" >
    <authentication-provider ref="myAuthenticationProvider" />
  </authentication-manager>


The custom AuthenticationProvider class extends a base Spring AuthenticationProvider that responds to UsernamePasswordAuthenticationToken authentication requests.


public class AuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

       @Autowired
       private IdentityManager identityManager;

       @Override
       protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authenticationToken)
                     throws AuthenticationException {

       }

       @Override
       protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authenticationToken)
                     throws AuthenticationException {

              String password = authenticationToken.getCredentials().toString();
              User user = identityManager.authenticateAndRetrieveUser(username, password);

              return user;
       }

}


The custom AuthenticationProvider delegates to an IdentityManager that is an interface with implementations for retrieving user data from LDAP and JDBC relational databases.

We have just scratched the surface of Spring Security by showing a basic example. Spring Security provides a great deal of flexibility through various configuration options.

Tuesday, 20 March 2012

Hibernate Caching

Hibernate provides three different caching mechanisms; first-level, second-level and query cache. Understanding how to use the caching mechanisms is important to enhance performance. Incorrectly configuring caching could lead to degrading performance. This post gives a conceptual understanding of how Hibernate caching works. 

The configuration of caching is provided by the Hibernate documentation.

First-level Cache
The Hibernate Session is a unit of work representing a transaction at the database level. When a session is created and Hibernate entities modified, Hibernate will not update the underlying database tables immediately. Instead it will keep track of the changes and perform a reduced number of SQL statements at the end of the session. For example, if an entity is modified several times within the same session, Hibernate will generate only one SQL update statement at the end of the session containing all the changes.

Second-level Cache 
The second-level cache is associated with the SessionFactory rather than each Session and it is not enabled by default. The second-level cache doesn't store instances of an entity (to prevent trips to the database when the entity is requested); rather it stores a dehydrated state of the entity. Conceptually this can be thought of as a Map which contains the entity's id as the key and and an array of the properties as value. 

As an example lets assume we have the following Employee entity:


public class Employee {
  private Employee manager;
  private String forename;
  private String surname;
  private Set<Employee> staff;
  //setters and getters
}

Hibernate will cache the records as such:

Conceptual Employee Data Cache

Id  [forename, surname, manager, [staff] ]
1 [ “John”, “Smith”, null, [2, 3] ]
2 [“Sarah”,”Brown”, 1, [] ]
3 [“Gavin”, “Adams” 1, [] ]


So if the Employee with id 1 is queried from the database without the cache, it would result in the following queries:


select * from Employee where id=1 ; load the employee with id 1
select * from Employee where manager_id=1 ; load the staff of 1 (will return 2, 3)
select * from Employee where manager_id=2 ; load any potential staff of 2 (will return none)
select * from Employee where manager_id=3 ; load any potential staff of 3 (will return none)


With the cache enabled, there would be no SQL select statements executed. If however, the associations were not cached then it would result in all the queries except the first. Therefore, it is best to cache associations whenever possible. 

The above queries were based on using the entity identifier. If the query were more complex such as by forename then Hibernate must still issue a select statement to retrieve the identifier of the entity before the cache can be queried for associations.
 
//Complex query
Query query = session.createQuery("from Employee as e where e.forename=?");
query.setString(0, "John");
List l = query.list();

//single SQL select statment to retrieve id.
select * from Employee where forename='John'

This mandatory select statement to retrieve the id is where the query cache can be used.

Query Cache
The query cache is responsible for caching queries and their results. This is only useful for queries that are run frequently with the same parameters. Conceptually the query cache works similarly to the caching of associations in the second-level cache; the query and parameters are stored as a key, with the value being a list of identifiers for that query. These identifiers are then used to query the second-level cache for a given entity which is then hydrated.

Monday, 12 December 2011

Multiple Eclipse Workspaces

When working with multiple workspaces in Eclipse, it is very helpful to know which IDE window is using which workspace. You can show workspace location in your Eclipse title bar by passing the -showlocation parameter to the Eclipse executable or modifying the eclipse.ini config file.

Wednesday, 12 October 2011

Using Oracle XMLQuery and XML-24509: (Error) Duplicated Definition

Recently I was asked to investigate how static configuration data between multiple deployments of an enterprise application could be managed more easily. The requirement was to be able to extract the required information form an Oracle database so that configuration data between two deployments could be compared. Additionally, if the configuration data along with the relationship between tables could be captured, it would streamline the process of populating a database for a new deployment.

Oracle provides some nice features for working with XML. There is the option of using PL/SQL and the DBMS_XMLQUERY package or the corresponding OracleXMLQuery Java class.

The OracleXMLQuery class provides an API to retrieve the results of an SQL query as XML. Therefore, I developed a class which would use the OracleXMLQuery and write the results to a file. The query was defined in a Spring context file and injected along with the javax.sql.DataSource. Now it came to the task of writing a test to validate if my class was working. Following the popular approach of testing with Spring and JUnit, I created a test class and a corresponding test context file.


Unfortunately the test would not execute and instead I was presented with the following error:
<Line 43, Column 57>: XML-24509: (Error) Duplicated definition for: 'identifiedType'

<Line 60, Column 28>: XML-24509: (Error) Duplicated definition for: 'beans'

<Line 157, Column 34>: XML-24509: (Error) Duplicated definition for: 'description'

<Line 169, Column 29>: XML-24509: (Error) Duplicated definition for: 'import'

<Line 191, Column 28>: XML-24509: (Error) Duplicated definition for: 'alias'

<Line 220, Column 33>: XML-24509: (Error) Duplicated definition for: 'beanElements'

<Line 235, Column 44>: XML-24509: (Error) Duplicated definition for: 'beanAttributes'

<Line 510, Column 43>: XML-24509: (Error) Duplicated definition for: 'meta'

<Line 518, Column 35>: XML-24509: (Error) Duplicated definition for: 'metaType'

The problem was that the Oracle XDK which provides the XML Java classes makes use of the Oracle xmlparserv2.jar file to parse XML. This has issues with parsing Spring XSD files and produces the above errors. Spring relies on Apache xerces library. Therefore the solution in this case was to configure Spring not to use the Oracle xml parser via a system property.


System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");


Adding the above code to my test class' @BeforeClass method fixed the issue.

Friday, 19 August 2011

Set up JBPM – Oracle - Tomcat 6

1. Add transaction and Resource information after 'WatchedResource' line in TOMCAT_HOME/conf/context.xml as shown below. This step is required to create a datasource in tomcat

<WatchedResource>WEB-INF/web.xml</WatchedResource>

<Transaction factory ="bitronix.tm.BitronixUserTransactionObjectFactory" />

<Resource name="jdbc/testDS1" auth="Container" type="javax.sql.DataSource" maxActive="15" maxIdle="2" maxWait="10000" logAbandoned="true"username="username" password="password" driverClassName=" oracle.jdbc.OracleDriver" url="jdbc:oracle:thin:@yourdatabaseurl:port:db"/>


2. Create 'resource.properties' in TOMCAT_HOME/conf and add following as shown below.
resource.ds1.className=bitronix.tm.resource.jdbc.lrc.LrcXADataSource
resource.ds1.uniqueName=jdbc/testDS1
resource.ds1.minPoolSize=0
resource.ds1.maxPoolSize=5
resource.ds1.driverProperties.driverClassName=oracle.jdbc.OracleDriver

3. Copy oracle ojdbc14.jar into the ‘tomcat/lib’ and ‘jbpm-installer/runtime’ folder for oracle driver.

4. Modify hibernate.cfg.xml in TOMCAT_HOME\webapps\gwt-console-server\WEB-INF\classes\META-INF to include Oracle connection details and comment the h2 details.
Note: Its better to change into the WAR (gwt-console-server.war) itself so can be deployed on different instances.

Replace the session-factory tag from below
<session-factory>
<!-- h2 Database connection settings -->
<!--property name="connection.url">jdbc:h2:file:/NotBackedUp /data/mydb</property-->
<!--
<property name="connection.driver_class">org.h2.Driver</property>
<property name="connection.url">jdbc:h2:tcp://localhost/~/test</ property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>
<property name="connection.pool_size">1</property>
<property name="dialect">org.hibernate.dialect.H2Dialect</property>
-->
<!-- Oracle Database connection settings -->
<property name="connection.driver_class"& gt;oracle.jdbc.OracleDriver</property>
<property name="connection.url">
jdbc:oracle:thin:@yourdatabaseurl:port:db</property>
<property name="connection.username">username</property>
<property name="connection.password">password</property>
<property name="connection.pool_size">1</property>
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</ property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread& lt;/property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class"& gt; org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">false</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
<mapping resource="AuditLog.hbm.xml"/>
</session-factory>

5. Make sure the jbpm-human-task-5.0-SNAPSHOT.jar is in TOMCAT_HOME/webapps/gwt-console-server/WEB-INF/lib (5.1 full installer zip contains this jar in the gwt-console-server web-inf lib) OR if not present then download and copy jbpm-human-task-5.0-SNAPSHOT.jar to TOMCAT_HOME/webapps/gwt-console-server/WEB-INF/lib

6. Make sure the jbpm-bam-5.0-SNAPSHOT.jar is in TOMCAT_HOME/webapps/gwt-console-server/WEB-INF/lib (5.1 full installer zip contains this jar in the gwt-console-server web-inf lib) OR if not present then download and copy copy jbpm-bam-5.0-SNAPSHOT.jar to TOMCAT_HOME/webapps/gwt-console-server/WEB-INF/lib

7. Add or Replace oracle connection details in persistence.xml of TOMCAT_HOME\webapps\gwt-console-server\WEB-INF\classes\META-INF.

<persistence-unit name="org.jbpm.persistence.jpa">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:jdbc/testDS1</jta-data-source>
<mapping-file>META-INF/JBPMorm.xml</mapping-file>
<class>org.drools.persistence.session.SessionInfo</class>
<class>org.drools.persistence.processinstance.ProcessInstanceInfo</class>
<class>org.drools.persistence.processinstance.WorkItemInfo</class>
<class>org.jbpm.process.audit.ProcessInstanceLog</class>
<class>org.jbpm.process.audit.NodeInstanceLog</class>
<class>org.jbpm.process.audit.VariableInstanceLog</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.max_fetch_depth" value="3"/>
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>


8. Modify the jbpm-bam-5.1.0.Final.jar/hibernate.cfg.xml of to add the oracle connection properties. Replace the session-factory with the following xml.

<session-factory>
<!-- h2 Database connection settings -->
<!--property name="connection.url">jdbc:h2:file:/NotBackedUp/data/mydb</property-->
<!--
<property name="connection.driver_class">org.h2.Driver</property>
<property name="connection.url">jdbc:h2:tcp://localhost/~/test</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>
<property name="connection.pool_size">1</property>
<property name="dialect">org.hibernate.dialect.H2Dialect</property>
-->
<!-- Oracle Database connection settings -->
<property name="connection.driver_class">oracle.jdbc.OracleDriver</property>
<property name="connection.url">
jdbc:oracle:thin:@yourdatabaseurl:port:db</property>
<property name="connection.username">username</property>
<property name="connection.password">password</property>
<property name="connection.pool_size">1</property>
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">false</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
<mapping resource="AuditLog.hbm.xml"/>
</session-factory>


9. Make sure all the above modified jars (jbpm-bam-5.1.0.Final.jar, jbpm-human-task-5.1.0.Final.jar) are also present/copied to the jbpm-installer/runtime folder before running ‘ant start.human.task’ from jbpm-installer. On running the task, all the tables will be created in oracle schema.

Set up the JBPM suite on tomcat 6

1. Download tomcat 6 from apache website tomcat-6.0.32.zip and unzip in a folder.
2. Change the TOMCAT_HOME, CATALINA_HOME env variable pointing to the new tomcat folder.
3. Download jbpm-5.1.0.Final-installer-full.zip from jboss site unzip into a folder.
a. Go into the lib folder, which will have 6 more files in it. 2 wars and 6 zip files.
4. copy 2 wars into the tomcat-home/webapps. Rename of war is required as per below names otherwise all the applications does not start properly.
a. Rename the designer-1.0.0.052-jboss.war to designer.war
b. Rename the guvnor-distribution-wars-5.2.0.Final-jboss-as-5.1.war to drools-guvnor.war
c. Unzip jbpm-5.1.0.Final-gwt-console.zip into the webapps. This zip contains 2 more wars.
d. Rename jbpm-gwt-console-server-5.1.0.Final.war to gwt-console-server.war
e. Rename jbpm-gwt-console-5.1.0.Final.war to jbpm-console.war
5. At this point, if tomcat is restarted, the complete suit is ready to work on. Go to tomcat manager (localhost:8080) and try launching drools-guvnor and jbpm-console. All the functionality does not work with IE so use firefox. It may ask to install google frame. Accept and continue.
6. To login into jbpm console, create few users into tomcat-users.xml as below.






Thursday, 18 August 2011

Drop all tables from schema

Run below code to drop all the tables from schema.

BEGIN

FOR i IN (SELECT table_name FROM user_tables)
LOOP
EXECUTE IMMEDIATE('DROP TABLE ' || user || '.' || i.table_name || ' CASCADE CONSTRAINTS');
END LOOP;
END;