Monday, June 7, 2010

Tomcat Https and Eclipse

One of requirements in our project is requirement for HTTPS login form. However, bosses don't want to use HTTPS in every page, so I need to do three things: create SSL key, define HTTPS in tomcat and create such definitions in Spring Security XML, that redirects anonymious requests to login form and after that to home page.
Key definition is a step that you need only at development stage. Key is part of certificate that your server needs to send in response to any HTTPS request. The certificate defined by any of free tools you can download, is not trusted by browsers and you will see certificate warning, but you can ignore it, until production stage, where you should buy a real certificate from one of organizations that sell it.
Since we use Apache Tomcat 6, I've decided to use Java keytool to create the key. This utility is supplied with JRE and you don't need to download openSSL engine. After typing
%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA
in command line I've answered several questions and approved the data typed. Last question, about Tomcat Password, is important for next step. In the end of the process, a file named '.keystore' will be created in your user folder.
Default tomcat implementation that you have in eclipse don't support's version 2.2 of EL-expressions, that we use, and I don't want to change definitions when a project will be moved from development environment to production. So I didn't use default eclipse implementation of tomcat, but down loaded fresh Tomcat 6.0.26 from Apache website. It can be used both from eclipse and as standalone webserver, but eclipse overrides Tomcat configuration files with its own each time it noticed the change. Adding Tomcat to eclipse is simple: open Servers view, right click on it and choose 'New -> Server -> Tomcat v6.0 server'. You'll see Server runtime environment row and 'Add' link in the end of it. Click 'Add' and browse to your tomcat installation folder before you click 'Next' in 'New Server' dialog.
Now, you have eclipse project named 'Server' in any eclipse view, that shows list of projects in workspace. Open 'server.xml' file in this project and comment the element below:
<Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/>
The reason of this operation is, that tomcat supports three types of certificates JKS, PKCS11 and PKCS12 and you don't know what certificate will be bought in future. As you can guess from its name, JKS is supported by JAVA and for other types you need openSSL or other external SSL engine. Since I don't use openSSL, I've commented the listener defintion, but didn't remove it, because I don't know what certificate will be used at production stage.
At this moment, I need to define how tomcat will deal with HTTPS connections and what certificate it will use. There is a commented connector element in 'server.xml' that defines SSL for port 8443. You can remove comments and use it as basis, but you should add attributes that define location of key file and its password. In my case It was:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
keystoreFile="${user.home}\.keystore" keystorePass="igor"
clientAuth="false" sslProtocol="TLS" />
The value of keystorePass attribute should be the same value that was entered as 'tomcat password', during key definition.
This is the end of Tomcat definitions. Right-click your server in 'Servers view' and choose 'Clean' command. This, force Eclipse to refresh Tomcat definitions and web applications, including coping updated 'server.xml' into Tomcat folder. Sometimes Eclipse has a bad day and doesn't want to notice that 'server.xml' was changed. In this case you can remove Eclipse's internal copy of it manually. You should remove workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/conf/server.xml
for it. If it also doesn't helps, kill eclipse and go home.
The remaining part is Spring Security configuration. I'll give our example of http element of configuration file:
<http auto-config="false" access-denied-page="/accessDenied.jsf">
<intercept-url pattern="/enter.jsf" requires-channel="https"/>
<intercept-url pattern="/j_spring_security_check"
requires-channel="https"/>
<intercept-url pattern="/**" requires-channel="http"/>
<form-login login-processing-url="/j_spring_security_check"
login-page="/enter.jsf" default-target-url="/home.jsf"
authentication-failure-url="/enter.jsf" />
<session-management session-fixation-protection="none" />
</http>
The configuration above defines 'enter.jsf' as login form and interceptor-url defines that it should use HTTPS. Last 'intercept-url' element defines that all other URLs use HTTP. The 'intercept-url' element in middle, is less obvious. 'j_spring_security_check' is request URL for all Spring Security credentials validations, so it also should use HTTPS.
This configuration only defines the protocol used for each page, but doesn't defines role's access. Roles ans grants are managed by special filter, that also redirects all not authorized request to login form.
More detailed information about HTTPS definitions of Tomcat and Spring Security can be read at these locations:
Tomcat Site:
Spring Security reference, section 2.3.2:

1 comment:

  1. very helpfull Igor.I tried a lot from past 2 days.And googled a lot of sites about https.Only this one works out..cheers!!

    ReplyDelete