Monday, June 23, 2008

Porting Container Managed Authentication (CMA) to Spring Security 2

Last week I ported one of my open source project from Container Managed Authentication (CMA) on Tomcat 6 to Spring Security 2, and decided to record some of my finding here. Spring Security 2 offers a wide range of support for different types of authentication mechanism and also allows you to centralize all security related configuration in your Spring context xml file, plus like its predecessor Acegi it allows you to fully customize every step of authentication process which is way more flexible comparing to CMA in my opinion. Enough introduction, here is the steps I performed for the porting.

Step 1 - Add Spring Security dependency in your POM:

If you are not using Maven, you need to download Spring Security library manually and add it to your project build path.

Step 2 - Remove CMA security configuration in your web.xml:

Including all security-constraint, login-config, and security-role elements in your web.xml file

Step 3 - Remove Tomcat security realm configuration:

My realm configuration was defined in META-INF/context.xml file in the WAR, but it could also be defined in server level conf/context.xml file.

note: till now your CMA configuration has been completely removed

Step 4 - Add Spring Security filter chain in your web.xml:




note: don't worry about where the chain is, for now ;-)

Step 5 - Create Spring Security context xml file




As you probably noticed already, two spring beans referred in this xml file have not been mentioned yet - authenticationService and passwordEncoderService. AuthenticationService is a custom class that implements UserDetailsService interface which is responsible for loading the user details for authentication purposes. You can use Hibernate if you have mapping setup for user and role entities already or lighter weight iBATIS or even raw JDBC call for the implementation. PasswordEncoderService class, implements PasswordEncoder interface, was created to help Spring Security compare encoded password, although Spring Security comes with some build-in encoders but I could not find a match for Tomcat's MD5+Hex (Base 16) style encoding therefore provided my own implementation, see Tomcat documentation and source code for details. Both beans are declared using annotation and autowiring.

Step 6 - Change your login form submit target

Change your login form submit from j_security_check to j_spring_security_check so it can be processed by Spring Security instead

Now you should be able to login as usual without changing anything in your database through Spring Security, but some of your pages might not be rendering correctly. That is because some of the method calls on HttpServletRequest do not return correct value anymore, such as getRemoteUser(), since default Tomcat HttpServletRequest implementation is not aware of Spring Security SecurityContext therefore you need to provide a wrapper class that can correctly translate these calls to return the right value. Luckily Spring Security has these wrappers build-in already, all you need to do is add an extra filter in the filter chain.

Final Step - Add securityContextHolderAwareRequestFilter


Now the porting is finally done. Hopefully through this example you can see the power and flexbility of Spring Security 2, with much simplified configuration comparing to Acegi it is indeed a well designed and robust security framework deserve much consideration .

Thursday, June 12, 2008

Be aware the implication when using Spring JMS template with JBoss Messaging

This is a daylog note that I keep for myself and share with anyone that is interested to know. We all know the convenience of using various of template classes that Spring framework provides, but seldom we pay much attention to the implication and implicit design choices made by Spring, and recently while working with JBoss Messaging I almost missed something critical due to this kind of implication.

JmsTemplate implementation for JMS 1.1 made a crucial design choice of relying on application container to providing JMS connection pooling and caching. According to the API document:

The ConnectionFactory used with this template should return pooled Connections (or a single shared Connection) as well as pooled Sessions and MessageProducers. Otherwise, performance of ad-hoc JMS operations is going to suffer.

Spring framework assumed that most of the application server will provide a pooled JMS connection, but apparently JBoss does not think so and even openly declared that they do not provide any support if you running into any problem using Spring JmsTemplate, in this JBoss Messaging Wiki page they mentioned:

The Spring JMSTemplate code employs several anti-patterns, like creating a new connection, session, producer just to send a message, then closing them again.


This not only results in very poor performance, but can also make you run out of operating system resources such as threads and file handles, since some of the connection resources are released asynchronously.


Please note that JBoss / Red Hat will not support people using the Spring JMSTemplate with JBoss Messaging apart from the one acceptable use case for the reasons outlined above.

That being said, I am not sure that JMSTemplate actually employs anti patterns, as serious as they mentioned, in my opinion its a rather a design choice that JBoss messaging decided not to support. The recommended solution for small scale JMS usage is to decorate your connection factory with SingleConnectionFactory, this factory always returns a shared single connection wrapper and ignores the close method, which will work for most of the low volume scenario. On top of that, the new JBoss Messaging clustered connection factories, when used with clustered destination, allows seamless fail-over using a single connection which
makes this a pretty reliable solution in a clustered JMS environment. For high volume scenario, my suggestion is to use JCA managed connection factory within JBoss application server or implement your own JMS connection factory bean with connection caching or pooling outside the container (check out open JCA container implementation - Jencks) to eliminate this problem, if you are determined to work with JMSTemplate implementation.

Other references:

Tuesday, June 03, 2008

How to hire cheaper talent and retain them

If you are wondering where you can find cheaper talent, check out Mr. Fowler's new hypothesis:

That's great now you got "cheaper" talent, but you will also realize that they are actually quite picky and keep jumping ships. Don't worry, the following post reveals the secret of retaining these "cheaper" talent (thanks to David for introducing this post).

People are not asset, the right people are!

Monday, June 02, 2008

TinyMCE the best replacement for Tomohawk inputHtml

Recently I upgrade one of my web application from JSF 1.1 to 1.2 core, and this specific application was built with MyFaces Core + Tomahawk + Facelet + Richfaces + Ajax4JSF. After the upgrade everything pretty much worked out-of-box, the only part that broke was the Tomahawk inputHtml component due to a known issue Tomahawk issue 1088, but since Tomahawk currently does not officially support JSF 1.2 there is really not much we can expect.

After this little setback, I did some research and found that TinyMCE seems to be a nice rich text editor implementation and based on the MyFaces Wiki documentation it turned out was a quite strightforward integration. Although I did end up had to do a little bit enhancement on top of the suggested implementation, the reason for the enhancement was because I had more than one text area on the page but I did not want to turn all of them into rich text editor. The only change I had to do was using 'editor_selector' instead of 'mode' while initializing the TinyMCE script.

mode : "textareas",
theme : "advanced",
editor_selector : "mceEditor",
width : "640",
height : "480"

After that all you need to do is just set your textArea style class to 'mceEditor', which will automatically convert your textArea to a nice rich text editor.

My environment info:

MyFaces - 1.2.2
Tomahawk - 1.1.6
Facelets - 1.1.11
Richfaces - 3.2.1.GA