Setting Up SSL on Tomcat In 3 Easy Steps

This works partly: http://www.avajava.com/tutorials/lessons/how-do-i-set-up-ssl-on-tomcat.html

1)

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:

3. Configuring your web application to work with SSL

In order to do this for our test, take any application which has already been deployed successfully in Tomcat and first access it through http and https to see if it works fine. If yes, then open the web.xml of that application and just add this XML fragment before web-app ends i.e </web-app>

<security-constraint>
< web-resource-collection>
< web-resource-name>securedapp</web-resource-name>
< url-pattern>/*</url-pattern>
< /web-resource-collection>
< user-data-constraint>
< transport-guarantee>CONFIDENTIAL</transport-guarantee>
< /user-data-constraint>
< /security-constraint>

Explanation of the fragment is beyond the scope of this tutorial but all you should notice is that the /* indicates that now, any resource in your application can be accessed only with https be it Servlets or JSP’s. The term CONFIDENTIAL is the term which tells the server to make the application work on SSL. If you want to turn the SSL mode for this application off then just turn don’t delete the fragment. Just put the value as NONE instead of CONFIDENTIAL. That’s it!

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

<!–

Licensed to the Apache Software Foundation (ASF) under one or more

contributor license agreements. See the NOTICE file distributed with

this work for additional information regarding copyright ownership.

The ASF licenses this file to You under the Apache License, Version 2.0

(the "License"); you may not use this file except in compliance with

the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software

distributed under the License is distributed on an "AS IS" BASIS,

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and

limitations under the License.

–><!– Note: A "Server" is not itself a "Container", so you may not

define subcomponents such as "Valves" at this level.

Documentation at /docs/config/server.html

–><Server port="8005" shutdown="SHUTDOWN">

<!–APR library loader. Documentation at /docs/apr.html –>

<Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/>

<!–Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html –>

<Listener className="org.apache.catalina.core.JasperListener"/>

<!– Prevent memory leaks due to use of particular java/javax APIs–>

<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>

<!– JMX Support for the Tomcat server. Documentation at /docs/non-existent.html –>

<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"/>

<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>

<!– Global JNDI resources

Documentation at /docs/jndi-resources-howto.html

–>

<GlobalNamingResources>

<!– Editable user database that can also be used by

UserDatabaseRealm to authenticate users

–>

<Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>

</GlobalNamingResources>

<!– A "Service" is a collection of one or more "Connectors" that share

a single "Container" Note: A "Service" is not itself a "Container",

so you may not define subcomponents such as "Valves" at this level.

Documentation at /docs/config/service.html

–>

<Service name="Catalina">

<!–The connectors can use a shared executor, you can define one or more named thread pools–>

<!–

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"

maxThreads="150" minSpareThreads="4"/>

–>

<!– A "Connector" represents an endpoint by which requests are received

and responses are returned. Documentation at :

Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)

Java AJP Connector: /docs/config/ajp.html

APR (HTTP/AJP) Connector: /docs/apr.html

Define a non-SSL HTTP/1.1 Connector on port 8080

–>

<Connector connectionTimeout="20000" port="80" protocol="HTTP/1.1" redirectPort="443"/>

<!– A "Connector" using the shared thread pool–>

<!–

<Connector executor="tomcatThreadPool"

port="8080" protocol="HTTP/1.1"

connectionTimeout="20000"

redirectPort="8443" />

–>
<!– Define a SSL HTTP/1.1 Connector on port 8443

This connector uses the JSSE configuration, when using APR, the

connector should be using the OpenSSL style configuration

described in the APR documentation –>

<!–

new

–>

<Connector SSLEnabled="true" clientAuth="false" keystoreFile="${user.home}\.keystore" keystorePass="changeit" maxThreads="150" port="443" protocol="HTTP/1.1" scheme="https" secure="true" sslProtocol="TLS"/>

<!– Define an AJP 1.3 Connector on port 8009 –>

<Connector port="8009" protocol="AJP/1.3" redirectPort="443"/>

 

<!– An Engine represents the entry point (within Catalina) that processes

every request. The Engine implementation for Tomcat stand alone

analyzes the HTTP headers included with the request, and passes them

on to the appropriate Host (virtual host).

Documentation at /docs/config/engine.html –>

<!– You should set jvmRoute to support load-balancing via AJP ie :

<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">

–>

<Engine defaultHost="localhost" name="Catalina">

<!–For clustering, please take a look at documentation at:

/docs/cluster-howto.html (simple how to)

/docs/config/cluster.html (reference documentation) –>

<!–

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

–>

<!– The request dumper valve dumps useful debugging information about

the request and response data received and sent by Tomcat.

Documentation at: /docs/config/valve.html –>

<!–

<Valve className="org.apache.catalina.valves.RequestDumperValve"/>

–>

<!– This Realm uses the UserDatabase configured in the global JNDI

resources under the key "UserDatabase". Any edits

that are performed against this UserDatabase are immediately

available for use by the Realm. –>

<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>

<!– Define the default virtual host

Note: XML Schema validation will not work with Xerces 2.2.

–>

<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">

<!– SingleSignOn valve, share authentication between web applications

Documentation at: /docs/config/valve.html –>

<!–

<Valve className="org.apache.catalina.authenticator.SingleSignOn" />

–>

<!– Access log processes all example.

Documentation at: /docs/config/valve.html –>

<!–

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"

prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>

–>

<Context docBase="QBW-Web-Parent" path="/QBW-Web-Parent" reloadable="true" source="org.eclipse.jst.jee.server:QBW-Web-Parent"/></Host>

</Engine>

</Service>

</Server>