Saturday, May 29, 2010

Tomcat – Container Managed Security

If you are a web developer, then I will not think twice before saying that you must have used Tomcat knowingly or unknowingly for deploying your web applications.

For me, Tomcat is a pretty basic web server, which mainly serves as a JSP/Servlet Container. Today, we explore some basic security features that are provided by the container itself. There are different ways in which this authentication can be provided. In this blog entry, we will try to understand and implement Basic & Form-based Authentication using MemoryRealm.

What’s a Realm?

According to the Tomcat specification, a Realm is a "database" of usernames and passwords that identify valid users of a web application (or set of web applications), plus an enumeration of the list of roles associated with each valid user. Obviously, there are many ways to specify the valid username-password combinations and the associated roles. We will use something known as MemoryRealm, which uses a file: tomcat-users.xml to specify this database.

Steps to Enable Authentication

  1. Change the configuration file (server.xml) of the Tomcat Server to specify the realm that you will use
  2. Change the tomcat-users.xml file to list the valid username-passwords and the associated roles
  3. Change the deployment descriptor (web.xml) for your web application to reflect security constraints needed by the application.

Step1: Change server.xml of Tomcat

The default server.xml has the UserDatabaseRealm enabled as shown below:

 serverXml

Note: This can change depending on the versions of the Tomcat, but for Tomcat 5.5 and Tomcat 6, it is the default one. We change it to use MemoryRealm by commenting the previous line and adding the following declaration as shown below:

serverXmlChanged

Step2: Change tomcat-users.xml of Tomcat

The default tomcat-users.xml file, which is present at $CATALINA_HOME/conf/tomcat-users.xml  where $CATALINA_HOME is the directory in which your Tomcat server is installed, looks like:

tomcatUsers

To this, add your own role and associate with it, some valid combination of username and password as done below:

tomcatUsersChanged

Step3: Change web.xml of your web application

So far, we have made changes in the Tomcat server itself, its time we must modify our application to reflect the security constraints that we want. To do so, we add the following to our web.xml file:

a) Security Constraints as per the need

securityConstraint

Here, We specify that in order to access any URL in our application which comes after http://{context_App}/jsp/…  should be password-protected. Also, we associate a role with it, so users associated with that role can only access these URLs now.

b) Declaring the Security Role

securityRole

c) Specifying the Type of Authentication

basicAuthntication

We tell Tomcat that we want to use BASIC authentication for our web application and the realm that we will use will use your tomcat-users.xml file. 

That’s it. All you need to do now, is to restart Tomcat and check whether this works or not. Obviously you need to create a basic web application to deploy onto the Tomcat , for which you have specified the security constraints. You can download my test web application here. (Provide a Link)…………………

This was pretty basic stuff, but it has several limitations. For one, this is not suitable for production environments and we must use FORM-based authentication instead of BASIC. Secondly, it is not a good practice to use clear-text passwords in tomcat-users.xml file. We can save the encrypted password (encrypted by any algorithm like SHA, MD2, MD5 etc) supported by the realm.

Changes to overcome limitations

1. Use Digested Passwords

Obviously, storing passwords in clear-text readable format in tomcat-users.xml cannot be considered safe or practical. In a production environment, it is essential to use some encryption to provide security. Tomcat provides us with several digest algorithms (SHA, MD2, MD5 etc) supported by MessageDigest class. To enable it, change the realm declaration in server.xml of Tomcat to the following:

memoryRealmMD5

Also, change the password you specified in tomcat-users.xml to the encrypted version of the original password, by using RealmBase class. You can find this class in catalina.jar in $CATALINA_HOME/lib directory. Use it as follows: RealmBase.digest(“password”, “MD5”, null) . Now, restart your Tomcat and test your authentication.

2. Use FORM-based Authentication

Since using BASIC authentication, you have very little control over the authentication/login method used by Tomcat and it is not considered practical for production environment. So we demonstrate another way: FORM-based authentication. The whole setup remains same, only you can provide your own custom login and error pages (with your company logo and whatever you want) instead of just popping up a window (as done by Tomcat in BASIC mode)

We will change the <login-config> element declared in your application’s web.xml as follows:

form-login-config

We will now add login.jsp and error.jsp to our application. login.jsp is used to authenticate the user: hence it would provide a form while error.jsp is the page to which user is redirected in case of an error: invalid username-password.

login.jsp will have at least a login field with name as “j_username” and password field with name as “j_password”. This must be same so that tomcat can identify the password and login fields in the form. Also the action of the form must be “j_security_check”. You can find the link to download the whole project at the end. My authentication page looks like this, which I believe is much better and safer than basic mode.

authenticate

Still, we have one limitation:

Any changes made to the file: tomcat-users.xml will be reflected only when the Tomcat server is restarted. So, if you add a new username-password combination to it, you must restart Tomcat in order to have its effect. We can also overcome this limitation by specifying the username-password and roles in a database table and using a JDBCRealm instead of MemoryRealm. You can download entire project from here.

Sunday, May 23, 2010

Flex Remoting with Java Part 2

In the last blog entry, I wrote about setting up a simple Flex Application and integrating it with Java so as to be able to make Remote Calls to Java Methods and display the result in Flex.

Today, we are going to make those efforts valuable by seeing how a user-defined object can be passed between Java & Flex. We will create a Employee List in Java and show it in a DataGrid in Flex. As Simple as that. To start with, you must have all the environment setup as explained here.

RPC with User Defined Objects

To be able to do so, we must create classes in both ActionScript and Java and bind them together as shown below:

Employee.java

EmployeeJava

Employee.as

EmployeeAS

The Java and the ActionScript file have the same attributes and they map to each other using Flex Metadata: RemoteClass(alias=””) which maps the java object returned from server to ActionScript object which can be displayed. This metadata tag used in ActionScript Class (Employee.as) specifies the fully qualified name of the corresponding Java Class. We now create a Utility class for getting Employee details:

EmployeeUtils.java

EmployeeUtils

Here, we have hard-coded the Employees Data, but it is as easy to get these employees from a database by firing a query. We now make a RPC call from Flex to get this list so that we can display it in a DataGrid.

getAllEmployees

We create a RemoteObject in Flex and specify a destination “employee” which is present in a remoting-config.xml to specify the Java Class file to look for methods called (getAllEmployees) using this RemoteObject. Part of flex-config.xml which specifies this looks like:

remotingConfig 

We specify the result and fault handlers with the remote object, which are called when result or fault occurs. In the result handler function, we save the result in a ArrayCollection, which we bind with our DataGrid as shown below:

employeeDatagrid

We set the dataProvider property of our DataGrid component to __employeeList, which is a bindable ArrayCollection which contains the result data. The advantage of making the ArrayCollection as bindable is that any changes made to this ArrayCllection (due to any event) is reflected in our DataGrid automatically.

When we run this example, we get a DataGrid as shown below:

output

Again this is not a best-way to code your flex application. The intent was to show how user-defined objects can be passed between Java & Flex. In practice and in large scale application, we would use tested frameworks like Cairngorm or PureMVC.

Wishing you very Happy Coding with Flex :-)