LazyAdminTomcat
From JQuantLib
Contents |
Overview
In this article we will install Tomcat 6.0.20 on Debian and configure it to authenticate against OpenLDAP.
We will configure Tomcat multi instances, which means that binaries will be installed in one location whilst data will be installed in another location. In spite we don't need several Tomcat instances at the moment, this strategy saves disk space as daily backups saves only the data area and leaves binaries to be saved by monthly backups.
Requirements
Essential
- Debian Lenny
- JRE 1.6.0_16
Recommended
- Ant 1.7.1 and Maven 2.2.1
Installation
Definitions
# define product and version
product=apache-tomcat
version=6.0.20
# define download location and archive
download=/mnt/nfs01/public/software/java/${product}-${version}
archive=http://mirror.public-internet.co.uk/apache/tomcat/tomcat-6/v${version}/bin/${product}-${version}.tar.gz
# define CATALINA_HOME and CATALINA_BASE
CATALINA_HOME=/srv/JavaIDE/${product}-${version}
CATALINA_BASE=/srv/tomcat
# define location of JDK
JAVA_HOME=/srv/JavaIDE/jdk-6u16-linux-i586
# additional definitions (optionsl)
ANT_HOME=/srv/JavaIDE/apache-ant-1.7.1
M2_HOME=/srv/JavaIDE/apache-maven-2.2.1
Download
# download Tomcat
mkdir -p ${download}
cd ${download}
wget ${archive}
Uncompress and adjust ownership
mkdir -p ${CATALINA_HOME}
cd ${CATALINA_HOME}/../
tar xvzf ${download}/${product}-${version}.tar.gz
chown -R www-data:www-data ${CATALINA_HOME}
Create separate CATALINA_BASE, copying directories from CATALINA_HOME
mkdir -p ${CATALINA_BASE}
for dir in conf logs temp webapps work ;do
cp -r ${CATALINA_HOME}/${dir} .
done
Create shell script which defines environment variables
mkdir -p ${CATALINA_BASE}/bin
cd ${CATALINA_BASE}/bin
cat << EOD > setpath.sh
#!/bin/bash
JAVA_HOME=${JAVA_HOME}
export JAVA_HOME
# needed by OpenSSO :: reserved for future
#JAVA_OPTS="\${JAVA_OPTS} -Xmx1536m -XX:MaxPermSize=128m"
#JAVA_OPTS="\${JAVA_OPTS} -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dcom.iplanet.am.cookie.c66Encode=true"
#export JAVA_OPTS
# define Ant and Maven, to be used by Continuum (optional)
ANT_HOME=${ANT_HOME}
M2_HOME=${M2_HOME}
export ANT_HOME M2_HOME
# define Tomcat environment variables
CATALINA_HOME=${CATALINA_HOME}
CATALINA_BASE=${CATALINA_BASE}
CATALINA_OPTS="-Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog -Dorg.apache.commons.logging.simplelog.defaultlog=debug"
export CATALINA_HOME CATALINA_BASE CATALINA_OPTS
EOD
chmod 755 setpath.sh
Create Tomcat Service script
mkdir -p ${CATALINA_BASE}/bin
cd ${CATALINA_BASE}/bin
cat << EOD > tomcat6.0
#!/bin/sh
### BEGIN INIT INFO
# Provides: tomcat
# Required-Start:
# Required-Stop:
# Default-Start: 2 3 4 5 S
# Default-Stop: 0 1 6
# Short-Description: Tomcat
# Description: Tomcat 6.0.20
### END INIT INFO
source ${CATALINA_BASE}/bin/setpath.sh
export CATALINA_OPTS="-Dappserver.home=$CATALINA_HOME -Dappserver.base=$CATALINA_BASE"
if [ X\$1 == "Xstart" ] ;then
su www-data -c \${CATALINA_HOME}/bin/startup.sh
elif [ X\$1 == "Xstop" ] ;then
su www-data -c \${CATALINA_HOME}/bin/shutdown.sh
elif [ X\$1 == "Xrestart" ] ;then
su www-data -c \${CATALINA_HOME}/bin/shutdown.sh
sleep 5
su www-data -c \${CATALINA_HOME}/bin/startup.sh
fi
EOD
chmod 755 tomcat6.0
Define and install Tomcat service
# create symlink to service script
if [ -e /etc/init.c/tomcat6.0 ] ;then
rm /etc/init.c/tomcat6.0
fi
ln -s ${CATALINA_BASE}/bin/tomcat6.0 /etc/init.d/tomcat6.0
# install service
update-rc.d tomcat6.0 defaults
Initial test
/etc/init.d/tomcat start
You should be able to see the default installation at http://www.jquantlib.org:8080/
Configuration
Here we will adjust conf/server.xml file in order to authenticate against OpenLDAP.
It's also necessary to adjust web.xml file of Tomcat Manager in order to provide an authentication form.
Adjust server.xml for LDAP authentication
Below we show how our ${CATALINA_BASE}/conf/server.xml files looks like. We removed all noisy comments and we left only those comments which are important to understand what changes were done.
<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<!-- ========================== REMOVED ==================================
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
=========================================================================-->
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<!-- ========================== REMOVED ==================================
<!--Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/-->
=========================================================================-->
<!-- ========================== ADDED ==================================
<Realm className="org.apache.catalina.realm.JNDIRealm"
connectionURL="ldap://ldap:389"
connectionName="cn=proxyagent,dc=jquantlib,dc=org"
connectionPassword="sorry-but-i-cannot-tell-you-what-my-password-is"
userPattern="uid={0},ou=people,dc=jquantlib,dc=org"
userSearch="(uid={0})"
roleBase="ou=group,dc=jquantlib,dc=org"
roleName="cn"
roleSearch="(uniqueMember={0})"
debug="99"
/>
<!-- ========================== NOTE =============================================
NOTE: Remove attribute "userPassword" otherwise Tomcat does not authenticate :(
SEE: http://www.mail-archive.com/users@tomcat.apache.org/msg65377.html
// userPassword="userPassword"
================================================================================== -->
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>
</Host>
</Engine>
</Service>
</Server>
In particular, notice that attribute userPassword must never be defined!.
See this article
Define an authentication form for Tomcat Manager webapp
In order to perform authentication against OpenLDAP, we choosen FORM authentication, which means that we need to define a form for authentication and also define a form for error messages. At the moment we use a very simple form borrowed from Tomcat samples but in future we can define a better form intended to provide enterprise wide authentication to all applications, probably employing single-sign-on.
cd ${CATALINA_BASE}/webapps/manager
cat << EOD > login.jsp
<html>
<head>
<title>Tomcat Manager</title>
<style>
<!--
BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;font-size:12px;}
H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;}
PRE, TT {border: 1px dotted #525D76}
A {color : black;}
A.name {color : black;}
-->
</style>
</head>
<body>
<h1>Tomcat Manager</h1>
<form method="POST" action="j_security_check">
<table border="0" cellspacing="5">
<tr>
<th align="right">Username:</th>
<td align="left"><input type="text" name="j_username"></td>
</tr>
<tr>
<th align="right">Password:</th>
<td align="left"><input type="password" name="j_password"></td>
</tr>
<tr>
<td align="right"><input type="submit" value="Log In"></td>
<td align="left"><input type="reset"></td>
</tr>
</table>
</form>
</body>
</html>
EOD
We'd better define another error page too, so that users will be aware that authentication is being done against OpenLDAP.
cp -p 401.jsp 401.jsp.OLD
cat << EOD > 401.jsp
<!--
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.
-->
<%
response.setHeader("WWW-Authenticate", "Basic realm=\"Tomcat Manager Application\"");
%>
<html>
<head>
<title>401 Unauthorized</title>
<style>
<!--
BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;font-size:12px;}
H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;}
PRE, TT {border: 1px dotted #525D76}
A {color : black;}A.name {color : black;}
-->
</style>
</head>
<body>
<h1>401 Unauthorized</h1>
<p>
You are not authorized to view this page.<br/>
Please examine your LDAP configuration and make sure that the username you are
trying to authenticate to belongs to group <tt>manager</tt>.
</p>
<p>
For more information - please see
<a href="http://www.jquantlib.org/index.php?title=LazyAdminTomcat">Tomcat authentication against OpenLDAP</a>.
</p>
</body>
</html>
EOD
chmod 644 login.jsp 401.jsp
chown www-data:www-data login.jsp 401.jsp
Adjust web.xml of Tomcat Manager webapp
Observe that we commented out a block which defines BASIC authentication and we replaced by another block which defines FORM authentication. Notice also that we are using role manager which means that the authenticated user must belong to group manager in order to be accepted.
cd ${CATALINA_BASE}/webapps/manager/WEB-INF
cp -p web.xml web.xml.OLD
cat <<EOD > web.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>Tomcat Manager Application</display-name>
<description>
A scriptable management web application for the Tomcat Web Server;
Manager lets you view, load/unload/etc particular web applications.
</description>
<servlet>
<servlet-name>Manager</servlet-name>
<servlet-class>org.apache.catalina.manager.ManagerServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>HTMLManager</servlet-name>
<servlet-class>org.apache.catalina.manager.HTMLManagerServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>Status</servlet-name>
<servlet-class>org.apache.catalina.manager.StatusManagerServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>JMXProxy</servlet-name>
<servlet-class>org.apache.catalina.manager.JMXProxyServlet</servlet-class>
</servlet>
<!-- Define the Manager Servlet Mapping -->
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/list</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/expire</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/sessions</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/start</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/stop</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/install</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/remove</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/deploy</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/undeploy</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/reload</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/save</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/serverinfo</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/resources</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Status</servlet-name>
<url-pattern>/status/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>JMXProxy</servlet-name>
<url-pattern>/jmxproxy/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>HTMLManager</servlet-name>
<url-pattern>/html/*</url-pattern>
</servlet-mapping>
<!-- Define a Security Constraint on this Application -->
<security-constraint>
<web-resource-collection>
<web-resource-name>HTMLManger and Manager command</web-resource-name>
<url-pattern>/jmxproxy/*</url-pattern>
<url-pattern>/html/*</url-pattern>
<url-pattern>/list</url-pattern>
<url-pattern>/expire</url-pattern>
<url-pattern>/sessions</url-pattern>
<url-pattern>/start</url-pattern>
<url-pattern>/stop</url-pattern>
<url-pattern>/install</url-pattern>
<url-pattern>/remove</url-pattern>
<url-pattern>/deploy</url-pattern>
<url-pattern>/undeploy</url-pattern>
<url-pattern>/reload</url-pattern>
<url-pattern>/save</url-pattern>
<url-pattern>/serverinfo</url-pattern>
<url-pattern>/status/*</url-pattern>
<url-pattern>/roles</url-pattern>
<url-pattern>/resources</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
<!-- Define the Login Configuration for this Application -->
<!-- login-config>
<auth-method>BASIC</auth-method>
<realm-name>Tomcat Manager TEST</realm-name>
</login-config -->
<login-config>
<auth-method>FORM</auth-method>
<realm-name>Form-Based Authentication Area</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/401.jsp</form-error-page>
</form-login-config>
</login-config>
<!-- Security roles referenced by this web application -->
<security-role>
<description>
The role that is required to log in to the Manager Application
</description>
<role-name>manager</role-name>
</security-role>
<error-page>
<error-code>401</error-code>
<location>/401.jsp</location>
</error-page>
</web-app>
EOD
chmod 644 web.xml
Final procedures
Double checking permissions and authorizations
chown -R www-data:www-data ${CATALINA_HOME} ${CATALINA_BASE}
chmod -R o-rwx ${CATALINA_HOME} ${CATALINA_BASE}
Final test
/etc/init.d/tomcat6.0 restart
Now visit http://www.jquantlib.org:8080/manager/html. If everything is ok, the router is properly forwarding requests to our server, etc... you should see an authentication form. Make sure you enter a username which has manager role, which means that such user dn must be memberOf the group dn manager.
Resources
Richard Gomes 00:43, 8 September 2009 (UTC)

