The Blog
Tomcat secure sessions with AJP and HTTP protocols using Apache proxy balancer
published May 20, 2011
During this week I have been digging into Apache AJP protocol and how it communicates with Tomcat. Especially, I have been interested in knowing how SSL works in different Tomcat connector setups. Once again in hindsight everything is so clear but had many desperate moments during these days :) Anyways, you should first check mod_proxy balancer configurations, and ajp protocol.
Basically, I have tried two different solutions:
1) Apache proxy balancer using HTTP
<Proxy balancer://liferaycluster>
BalancerMember http://node1 route=node1
BalancerMember http://node2 route=node2
ProxySet stickysession=ROUTEID
</Proxy>
2) Apache proxy balancer using AJP
<Proxy balancer://liferaycluster>
BalancerMember ajp://node1 route=node1 ping=3
BalancerMember ajp://node2 route=node2 ping=3
ProxySet stickysession=ROUTEID
</Proxy>
Benefit of using AJP is the “ping” setting which Apache uses to check whether Tomcat is up or down and does more sophisticated load balancing based on that information. However, things become more tricky in Tomcat connector configurations when checking whether JSESSION will end up to be “secure” or “not”. In HTTP connector you can define secureness of your connector like so:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="false" scheme="https" secure="true" proxyPort="443"/>
But if you define connector with AJP protocol:
<Connector port="8443" protocol="AJP/1.3" SSLEnabled="false" scheme="http" secure="false" proxyPort="443"/>
“Secure” setting will not have any effect to JSESSIONID cookie. However, it does have an effect to function call “ServletRequest.isSecure()”. Go figure.
It seems that AJP protocol contains boolean value wheter initial connection to Apache was secure or not and that value is passed to Tomcat which uses that information to create user session cookie.
If you need an AJP setup where JSESSIONID should not be secure even if initial connection was through HTTPS you can do Apache haxing to remove Secure setting from cookie like so:
Header edit "Set-Cookie: JSESSIONID=" Secure " "
This will replace word Secure with empty string from JSESSIONID cookie. This is not the most clever thing to do because now your session is open for hijacking.
One click deployment to clustered Liferay with Jenkins
published April 27, 2011
During last year, we have built pretty cool one click deployment system with Jenkins. Environment has been created little by little, but when decision was made to cluster Liferay and in addition to serve our 15.000 lines of JavaScript code from Apache, it was pretty clear that manual installations would be a pain. So we built environment like this:
Developer can initiate (1) portlet build from the Jenkins CI GUI. Jenkins runs (2) Ant build, unit tests, selenium tests and builds multiple war packages. If build is successful Jenkins first copies (3) our JavaScript framework to Apache and then deploys (4) portlet wars to clustered liferay environment. All this with one click.
Configuration is pretty simple, each copy step is run as a shell script like so:
./deployFrameworkToApache.sh;
./deployPortletsToNode1.sh;
./deployPortletsToNode2.sh;
I have to give credit to Jenkins, it is really easy to configure.
Liferay clustering checklist
published April 21, 2011
Yesterday our team finished clustering of our Liferay portal environment. In case I have to do this again, I decided to write a small checklist what should be taken into a consideration when clustering. Official Liferay clustering guide can be found here.
Updated May 6, 2011: added ajp configurations.
Updated May 20, 2011: Check also how Apache AJP protocol works.
1. Ensure that you have same JRE/JDK on both cluster nodes.
2. Check that all Liferay nodes can access your database (or database cluster) and it allows connections from these hosts.
3. Ensure that load balancer can forward requests to both nodes and firewalls won’t block access.
4. Check that all of cluster nodes are able to send email using your configured SMTP server (e.g. with telnet).
5. Install same version of Liferay to all cluster nodes.
6. If you need session fail over, configure that.
7. Configure tomcat connectors “secure” and “unsecure” to use ajp protocol like so:
<Connector address="xx.xx.xx.xx" port="8009" protocol="AJP/1.3" ... />
<Connector address="xx.xx.xx.xx" port="8443" protocol="AJP/1.3" ... />
8. Configure properties “net.sf.ehcache.configurationResourceName” and “ehcache.multi.vm.config.location” correctly to portal-ext.properties.
9. Move your Lucene index to database or if that is not possible, to shared NFS mount. In case of shared NFS mount, linux UIDs for Liferay user must be equal in all nodes so that Linux file permissions work correctly. Liferay user must be able to write to Lucene directory.
10. Move your document library to shared NFS mount or to database. Same rules apply as above.
11. Ensure that your configured Lucene index and document library paths point to correct location in portal-ext.properties.
12. Start your cluster nodes.
13. Check that mod_proxy_ajp module is loaded by apache.
14. Configure Apache load balancer like so:
Proxy balancers:
<Proxy balancer://liferaycluster>
BalancerMember ajp://node1:8009 route=node1 ping=5 loadfactor=1
BalancerMember ajp://node2:8009 route=node2 ping=5 loadfactor=1
ProxySet stickysession=ROUTEID
</Proxy>
<Proxy balancer://secureliferaycluster>
BalancerMember ajp://node1:8443 route=node1 ping=5 loadfactor=1
BalancerMember ajp://node2:8443 route=node2 ping=5 loadfactor=1
ProxySet stickysession=ROUTEID
</Proxy>
This inside your :80 virtual host:
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
ProxyPass /group balancer://secureliferaycluster/group/
ProxyPassReverse /group balancer://secureliferaycluster/group/
ProxyPass / balancer://liferaycluster/
ProxyPassReverse / balancer://liferaycluster/
This inside your :443 virtual host:
ProxyPass /group balancer://secureliferaycluster/group/
ProxyPassReverse /group balancer://secureliferaycluster/group/
ProxyPass / balancer://liferaycluster/
ProxyPassReverse / balancer://liferaycluster/
That’s it!
Liferay – Deployment will start in a few seconds
published October 7, 2010
And then nothing happens. I Run into this situation today, where first deployment of portlet works just fine but then following ones do nothing. Tomcat catalina.out just says:
11:07:47,534 INFO [PortletAutoDeployListener:87] Portlets for [..war..] copied successfully. Deployment will start in a few seconds.
No files copied, no nothing. This is how I got it working (try step 5. first as it seems to solve problem):
1. Turn on Liferay debugging from admin console
Now log keeps saying:
11:58:09,542 DEBUG [BaseExplodedTomcatListener:138] [..war..] does not have a matching extension
2. Turn on Tomcat logging by setting “org.apache.catalina.level = ALL” to Tomcat /conf/logging.properties
There is loads of stuff, did not find anything interesting.
3. See what files are modified after deploy
-bash-3.2$ find . -mmin -2
./liferay/deploy
./liferay/tomcat-6.0.18/logs/catalina.out
./liferay/tomcat-6.0.18/logs/catalina.2010-10-07.log
Now that is weird. “Deployed” war just vanishes after copying.
4. Start removing stuff from war
Removed web.xml, liferay-portlet.xml, portlet.xml etc. from war file. Nothing helped.
5. Made a complete copy of a war and deployed that
Now this seems to work! After this I deployed old version. Also that worked now fine!?
Really weird, but that copy seemed to somehow solve the problem.
Environment:
Red Hat Enterprise Linux Server release 5.5 (Tikanga)
Java(TM) SE Runtime Environment (build 1.6.0_13-b03)
Liferay 5.2.2 CE
Tomcat 6.0.18
Is someone knows why it works this way, please comment…
New version of Paikkatietoikkuna.fi released
published June 4, 2010
Yesterday, National Land Survey of Finland released a new version of paikkatietoikkuna.fi. Service contains (amongst other things) a google-maps-like rich internet application built on top of Liferay. This portal relies heavily on JavaScript frameworks such as OpenLayers, Ext JS and JQuery. There are some important things to consider when building a RIA and I am planning to write a separate blog about it later. In the mean time, go check:
http://www.paikkatietoikkuna.fi/ and
http://www.paikkatietoikkuna.fi/web/fi/kartta
mod_rewrite 101
published May 11, 2010
mod_rewrite is a popular apache module for rewriting urls and making redirects. I decided to write small introduction about it, since I had to configure it on project test server. Reason why we are using it, is our upcoming release in which we will need to forward our customers to new liferay community instead of default /web/guest.
So, after rewrite engine is turned on from apache configuration, it will filter all matched requests and apply special rules for it. Request is passed through this chain of rules and if match is found, redirect is sent by apache.
mod_rewrite’s work horses are RewriteRule and RewriteCond directives which are used to build rule chain. Processing works so that
1) config files and .htaccess files are parsed for RewriteRules from top to bottom.
2) First RewriteRule is selected and request is compared against RewriteRule’s pattern.
3) If match is found and there are RewriteCond elements introduced, they are tested against the request.
4) If conditions match, redirect to new rewritten url is made.
5) If there was no match, request is passed onwards to next RewriteRule in chain, if such exist.

Configurations
Below is a simple configuration for redirect
# Turn on rewrite engine processing
RewriteEngine On
# Write log here
RewriteLog /var/log/httpd/rewrite.log
# Log everything
RewriteLogLevel 9
# Redirect context root to new community /web/new/
RewriteRule ^/$ http://%{SERVER_NAME}/web/new/
# Do not allow access to old /web/guest
RewriteRule ^/web/guest(.*)$ http://%{SERVER_NAME}/web/new/
There is loads of stuff you can do with this module, check it out.
Liferay front-end performance tuning
published February 1, 2010
As we are getting over 200 000 unique visitors on a busy day, we really must take a full advantage of the Liferay caching. In order to understand caching in Liferay 5.2.3, I had to dig pretty deep. There are multiple ways to increase the portal performance but the focus here will be the Liferay front-end.
The Liferay front-end caching is based on servlet filters and it basically provides four ways to enhance performance:
- HTTP header based caching
- Ehcache based caching
- HTTP response Minifier
- HTTP response gzipping

HTTP Header based caching
Liferay provides “com.liferay.portal.servlet.filters.header.HeaderFilter”, which can be used to manipulate HTTP cache-control. This your first line of defence.
Ehcache based caching
This one is the most tricky one. By default, Liferay provides “com.liferay.portal.servlet.filters.cache.CacheFilter” for caching requests in the Ehcache. Unfortunately, Ehcache configurations are buried deep. If you have Liferay source code, you should take a peek of files under “/portal/portal-impl/src/ehcache/”, especially files with a “liferay” prefix. Usage of these configuration files are configured in a portal.properties file using keys “ehcache.single.vm.config.location” and “ehcache.multi.vm.config.location”.
Underneath, The CacheFilter uses named cache “com.liferay.portal.servlet.filters.cache.CacheUtil” to store responses, which has time to live set to a one hour. The CacheFilter constructs cache keys like “HTTP:///WEB/FI/FRONTPAGE?NULL#FI_FI#OTHER#TRUE” from the request and stores rendered bytes into the Ehcache for later use.
It is configured to include specific resources in web.xml. If you need custom caching for your pages, you can do it with the CacheFilter.
HTTP response gzipping
By gzipping the response, round trip response time will be shorter. See a sample on SteveShoulds.com. Gzipping is done using class “com.liferay.portal.servlet.filters.gzip.GZipFilter”.
HTTP response Minifier
Liferay provides “com.liferay.portal.servlet.filters.minifier.MinifierFilter” which can be used to minify responses. It uses Yahoo’s YUI Compressor to compress e.g. css and javascript files.
Configurations
All filters are defined in web.xml and are already pre-configured. In order to change configurations you will need Liferay source code. It is easier to understand configurations by looking at the code.
Subscribe to RSS feed
The Tag Cloud
Agile Business Coaching Coding horror Conference Customer Design of Experiments Future Group dynamics ITIL It should not be that hard Java EE Kanban Leadership Lean Liferay Methodologies Natural UI Performance tuning Process Productivity Quality Retrospective RIA Scrum Six Sigma Social psychology Software Software architecture Testing This is great TOGAF
WP Cumulus Flash tag cloud by Roy Tanck and Luke Morton requires Flash Player 9 or better.
Samuli's Links
The Blog Archive
February 2012 (1)
January 2012 (1)
November 2011 (1)
June 2011 (2)
May 2011 (1)
April 2011 (2)
March 2011 (2)
February 2011 (1)
January 2011 (1)
December 2010 (1)
November 2010 (1)
October 2010 (3)
September 2010 (3)
August 2010 (5)
July 2010 (2)
June 2010 (3)
May 2010 (4)
April 2010 (2)
March 2010 (6)
February 2010 (7)
January 2010 (3)
December 2009 (7)
November 2009 (6)


