LazyAdminTomcat

From JQuantLib

Jump to: navigation, search

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)