TDS Tutorial: Basic Tomcat and TDS Security

Notice: This section is out of date with respect to recent version of Tomcat

For a more up-to-date version of this content, please follow the TDS 5.0 guide starting at https://docs.unidata.ucar.edu/tds/5.0/userguide/tomcat_permissions.html

Tomcat manager Application: A Word Of Caution

About the manager application

More about manager

For more information about the Tomcat manager application, see the Tomcat Manager App HOW-TO documentation.

  • "Free" web application that comes with Tomcat distribution.
  • Lives in the manager directory in the Tomcat webapps/ directory.
  • Allows Tomcat administrators to deploy, undeploy, or reload web applications such as the TDS without having to shut down and restart Tomcat.
  • Provides server status statistics for the JVM and each connector you have configured in server.xml.

Accessing the Tomcat manager application

Changes to the manager application

The manager application URLs and roles has been re-structured. See the Tomcat Migration guide for more information.

Attempt to access the Tomcat manager application in your browser: http://localhost:8080/manager/html/. You will be prompted to login via BASIC authentication, which will end in failure since we do not yet have permission to access the manager application:

Manager app with 401 response code

Based on what we know about Tomcat configuration, which file in the Tomcat conf/ directory should we edit to grant ourselves access to the manager application?

Granting access to the manager application

  1. Modify tomcat-users.xml to add a user element.
  2. Using your favorite editor, open ${tomcat_home}/conf/tomcat-users.xml :

    $ vi tomcat-users.xml
    

    The roles of "manager-gui", "manager-status", "manager-script", and "manager-jmx" are pre-defined in Tomcat 7.

    Now add a new user by adding a user element. Create a username and password for the new user and specify manager-gui as one of the roles (in this example we are creating a user called 'admin' with a corresponding password of 'secret'):

    <tomcat-users>
        <role rolename="manager-gui"/>
        <user username="admin" password="secret" roles="manager-gui"/>   
    </tomcat-users>
    
  3. Restart Tomcat and log into the manager application.
  4. Keep in mind

    Changes to tomcat-users.xml do not take effect until Tomcat is restarted.

    Attempt to access the manager application again (http://localhost:8080/manager/html/), this time logging in using the name and password specified in tomcat-users.xml :

    Tomcat manager application

    Thinking ahead

    To gain access to restricted parts of the TDS, you will perform the same steps you used to grant yourself access to the manager application.

    Voilà! You should have access to the manager application.

Troubleshooting tips

  • Check the XML syntax in tomcat-users.xml to make sure it is well-formed and without error.
  • Did you restart Tomcat after you made your changes to tomcat-users.xml ?
  • Any errors will be reported in the Tomcat logs/catalina.out file.

Caveat of the manager application

PermGen info

For a really good description of the issue, see this series of three articles:

The dreaded java.lang.OutOfMemoryError: PermGen space failure error:

  • The issue: The "PermGen" error happens when the JVM runs out of memory in the permanent generation. (Default PermGen size differs among Sun JDK versions, but the upper limit is typically 64MB.)
  • The cause: Objects in the permanent generation are never garbage collected. When redeploying your web application using the Tomcat manager application, your WAR file is unpacked and parts of the class file definition are loaded into PermGen space, like string constants.
  • The symptom: The PermGen error will manifest itself in a sluggish Tomcat manager application that never completes a task, and the java.lang.OutOfMemoryError: PermGen space failure error being displayed in ${tomcat_home}/logs/catalina.out
  • A temporary fix: You can add the -XX:MaxPermSize switch to $JAVA_OPTS to increase the amount of memory allocated for the permanent generation, However this is only postponed the inevitable, as even an increased memory in permanent generation will eventually fill up. When this happens, you will need to stop/start Tomcat at this point. For this reason, you may want to restart Tomcat whenever you redeploy TDS or another webapp.

Using Digested Passwords

The problem of passwords in clear text

Tomcat Realms

The Tomcat documentation contains a wealth of information about the different Tomcat Realms.

  • Passwords stored in clear text are a vulnerability if the host is compromised.
  • Better to have the passwords encrypted using a cryptographic hash functions (SHA, MD2, or MD5) and then stored in tomcat-users.xml file in the Tomcat conf/ directory.
  • Tomcat can be configured to support digested passwords (this is not the default setting).
  • How it works: When a client makes a request Tomcat will tell the client that a digested password is required. Based on this dialog, the client will automatically digest the password entered by the user.

Configure Tomcat to use digested passwords

  1. First we need to enable digest passwords support in Tomcat by modifying a couple of Tomcat Realms in the server.xml file in the Tomcat conf/ directory.
  2. A Tomcat Realm represents a "database" of usernames, passwords, and roles assigned to tomcat users.

    Realm Name Purpose
    UserDatabaseRealm The UserDatabaseRealm is enabled by default and reads clear text user password information stored in tomcat-users.xml.
    MemoryRealm The MemoryRealm reads the user password information stored in the tomcat-users.xml in a specified encrypted format.

    Open the server.xml with your favorite editor:

    $ vi server.xml
    

    Locate the UserDatabaseRealm (right above the Host element) and comment it out:

    <!-- 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 name="localhost"  appBase="webapps"
          unpackWARs="true" autoDeploy="true"
          xmlValidation="false" xmlNamespaceAware="false">
    

    Now add the following MemoryRealm information inside the Host element:

    <!-- 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 name="localhost"  appBase="webapps"
          unpackWARs="true" autoDeploy="true"
          xmlValidation="false" xmlNamespaceAware="false">
    
        <Realm className="org.apache.catalina.realm.MemoryRealm"
          digest="SHA" />
    
  3. Create a SHA encrypted version of your password.
  4. Tomcat provides a script ( ${tomcat_home}/bin/digest.sh ) that will encrypt a password string according to the algorithm specified. Use this script as follows with the password you made for yourself previously:

    $ /home/tds/apache-tomcat-6.0.32/bin/digest.sh -a SHA secret
    secret:e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4
    
  5. Update tomcat-users.xml.
  6. Replace your clear-text password in tomcat-users.xml with the encrypted version:

    <tomcat-users>
        <role rolename="manager-gui"/>
        <user username="admin" password="e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4" roles="manager-gui"/>
    </tomcat-users>
    
  7. Verify digest passwords have been successfully enabled in Tomcat.
  8. BASIC authentication

    Since we are using BASIC authentication, you will need to clear any authenticated sessions in your browser to test whether digested passwords have been enabled.

    Restart Tomcat and verify digest passwords have been successfully enabled by logging into the Tomcat manager application using your password in clear text: http://localhost:8080/manager/html/

    Troubleshooting tips

    • Check the XML syntax in tomcat-users.xml and server.xml to make sure it is well-formed and without error.
    • Did you restart Tomcat after you made your changes to tomcat-users.xml and server.xml ?
    • Any errors will be reported in the catalina.out file in the Tomcat logs/ directory.
    • You do not need to type the encrypted version of your password into the browser (the browser auto-magically encrypts your password for you before it transmits it to the server).

Exercise One: Configure Tomcat to use digested passwords

  1. Using the steps outlined above, enable digested passwords in Tomcat.

Enabling SSL Encryption

About Secure Sockets Layer (SSL)

How SSL works

For more information on how SSL works, Wikipedia details the steps involved during an SSL transaction.

  • Secure Sockets Layer (SSL) is a cryptographic protocol that provides security and data integrity for communications over TCP/IP networks.
  • SSL allows applications to communicate across a network in a way designed to prevent eavesdropping, tampering, and message forgery.
  • SSL uses a cryptographic system that uses two keys to encrypt data: a public key known to everyone and a private or secret key known only to the recipient of the message.
  • By convention, URLs that require an SSL connection start with https instead of http.

SSL certificates

  • A public key certificate is an electronic document which incorporates a digital signature to bind together a public key with identity information of the certificate user.
  • The certificate can be used to verify that a public key belongs to an individual.
  • The digital signature can be signed by a Certificate Authority (CA) or the certificate user (a self-signed certificate).
  • Unidata recommends the use of a certificate signed by a Certificate Authority (CA).

Accessing the TDS remote management tool

Other than the compelling security reasons, you will want to enable SSL to take advantage of the TDS remote management tool which (out-of-the-box) requires SSL in order to access: http://localhost:8080/thredds/admin/debug

  1. Configure Tomcat to enable SSL and use the self-signed certificate.
  2. Based on what we know about Tomcat configuration, which file in ${tomcat_home}/conf should we edit to to enable SSL?

    Open ${tomcat_home}/conf/server.xml with your favorite editor:

    $ vi server.xml
    

    Locate the Java HTTP/1.1 Connector listening on port 8080 and verify it is redirecting SSL traffic to port 8443:

    <Connector port="8080" protocol="HTTP/1.1"
                  connectionTimeout="20000"
                  redirectPort="8443" />
    

    Find and uncomment the SSL HTTP/1.1 Connector listening on port 8443 to activate this connector:

    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
                  maxThreads="150" scheme="https" secure="true"
                  clientAuth="false" sslProtocol="TLS" />
    

    Add a keystoreFile attribute to the SSL HTTP/1.1 Connector to tell Tomcat where to find the keystore:

    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
                  maxThreads="150" scheme="https" secure="true"
                  clientAuth="false" sslProtocol="TLS" keystoreFile="/home/tds/tds/apache-tomcat-6.0.32/conf/keystore" />
    

    Since we opted to not use the default keystore password , we need to specify the new password so Tomcat can open the file:

    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
                  maxThreads="150" scheme="https" secure="true"
                  clientAuth="false" sslProtocol="TLS" keystoreFile="/home/tds/tds/apache-tomcat-6.0.32/conf/keystore" keystorePass="foobar" />
    

    Finally, verify the AprLifecycleListener is uncommented (found near the top of the file):

    <!--APR library loader. Documentation at /docs/apr.html -->
    <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
    
  3. Verify SSL has been enabled.
  4. Restart Tomcat:

    $ ${tomcat_home}/bin/shutdown.sh
    $ ${tomcat_home}/bin/startup.sh
    

    Verify Tomcat is listening on port 8443 by running the netstat command:

    $ netstat -an | grep tcp
    

    man netstat

    Run man netstat in your terminal window to learn more about this command.

    netstat (short for network statistics) is available on Unix, Unix-like, and Windows NT-based operating systems. It is a command-line tool that displays:

    • network connections (both incoming and outgoing)
    • routing tables
    • and a number of network interface statistics

    Look for the following in the output:

    tcp        0      0 127.0.0.1:8443               0.0.0.0:*                   LISTEN
    

    Troubleshooting tips

    • Check the XML syntax in server.xml to make sure it is well-formed and without error.
    • When generating the self-signed certificate, the last password (the key password ) and keystore password should be the same ( changeit ). If they differ, Tomcat cannot open the keystore and you will get this error: java.io.IOException: Cannot recover key .
    • Did you restart Tomcat after you made your changes to server.xml ?
    • Did you specify the full path to the keystore file in server.xml ?

Exercise Four: Grant yourself access to the TDS remote management tool

  1. Using the steps outlined above, create a self-signed certificate and enable SSL in Tomcat.
  2. Modify ${tomcat_home}/conf/tomcat-users.xml to add a new role with the rolename attribute of tdsConfig , and add this role to your list of roles:
  3. <tomcat-users>
        <role rolename="manager"/>
        <role rolename="tdsConfig"/>
        <user username="admin" password="e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4" roles="manager,tdsConfig"/>
    </tomcat-users>
    
  4. Restart Tomcat and try to access the TDS remote management tool: http://localhost:8080/thredds/admin/debug/
  5. SSL warning for self-signed certificate

Configuring web applications for SSL

How did Tomcat know to use SSL for the TDS remote management tool?

Where, in any of the configuration changes you made to ${tomcat_home}/conf/server.xml or ${tomcat_home}/conf/tomcat-users.xml , did you explicitly specify that TDS remote management tool must be accessed via SSL?

The missing piece: /WEB-INF/web.xml

  • This is specified in the web application deployment descriptor, aka web.xml.
  • Deployment descriptors are found in the WEB-INF directory of the web application: <application name>/WEB-INF/web.xml.
  • By convention, Tomcat and other servlet containers will read the web application deployment descriptors for initialization parameters and container-managed security constraints upon application deployment.
  • The TDS has been pre-configured to require that SSL encryption is enabled in order to access the remote management tool.

Looking at the TDS deployment descriptor

  1. Have a look at the deployment descriptor that comes with the TDS.
  2. Navigate to the unpacked thredds directory in ${tomcat_home}/webapps , and view the file:

    $ cd /home/tds/tds/apache-tomcat-6.0.32/webapps/thredds
    $ less WEB-INF/web.xml
    
  3. Look for a reference to the TDS remote management tool's URL ( /admin/debug ).
  4. Near the bottom of the deployment descriptor you will find this entry:

      <!-- This allows "remote configuration":
        /thredds/admin/debug gives access to various debug and status info.
        /thredds/admin/content/ -> "{tomcat_home}/content/thredds/"
        /thredds/admin/root/ -> "{tomcat_home}/webapps/thredds/" DISABLED
        /thredds/admin/dataDir/path -> "{dataRoot(path)}/webapps/thredds/"  DISABLED
       -->
      <security-constraint>
        <web-resource-collection>
          <web-resource-name>sensitive read access</web-resource-name>
          <url-pattern>/admin/*</url-pattern>
          <http-method>GET</http-method>
          <!-- http-method>PUT</http-method -->
        </web-resource-collection>
        <auth-constraint>
          <role-name>tdsConfig</role-name>
        </auth-constraint>
        <user-data-constraint>
          <transport-guarantee>CONFIDENTIAL</transport-guarantee>
          </user-data-constraint>
      </security-constraint>
    

    Configuration help

    For more information on how to configure security requirements for a web application in a deployment descriptor, see: Defining Security Requirements for Web Applications.

    • The <user-data-constraint> establishes a requirement that the constrained requests be received over a protected transport layer connection. This guarantees how the data will be transported between client and server.
    • <transport-guarantee> choices for type of transport guarantee include NONE , INTEGRAL , and CONFIDENTIAL :
      1. Specify CONFIDENTIAL when the application requires that data be transmitted so as to prevent other entities from observing the contents of the transmission. (E.g., via SSL.)
      2. Specify INTEGRAL when the application requires that the data be sent between client and server in such a way that it cannot be changed in transit.
      3. Specify NONE to indicate that the container must accept the constrained requests on any connection, including an unprotected one.

Enabling SSL for the Tomcat manager application

  1. Modify the deployment descriptor of the Tomcat manager application.
  2. Using your favorite editor, open the deployment descriptor for the Tomcat manager application:

    $ vi /home/tds/tds/apache-tomcat-6.0.32/webapps/manager/WEB-INF/web.xml
    

    Locate the <security-constraint> element (near the bottom of the file):

      <!-- 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>
           <!-- NOTE:  This role is not present in the default users file -->
           <role-name>manager</role-name>
        </auth-constraint>
      </security-constraint>
    

    The comment in the <auth-constraint> element is no longer correct:

    <!-- NOTE: This role is not present in the default users file -->

    (Since we've already added the role of manager to the tomcat-users.xml file, we might as well remove the comment.)

    Add a <user-data-constraint> with a <transport-guarantee> of CONFIDENTIAL to enable port-forwarding to port 8443:

      <!-- 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>
        <user-data-constraint>
         <transport-guarantee>CONFIDENTIAL</transport-guarantee>
         </user-data-constraint>
      </security-constraint>
    
  3. Verify SSL has been enabled for the Tomcat manager application.
  4. Restart Tomcat and verify SSL has been enabled for the Tomcat manager application: http://localhost:8080/manager/html/

    Tomcat manager authentication prompt

    Troubleshooting tips

    • Check the XML syntax in web.xml to make sure it is well-formed and without error.
    • Did you specify a <transport-guarantee> of CONFIDENTIAL ?
    • Did you restart Tomcat after you made your changes to web.xml ?

Exercise Five: Enable SSL for the Tomcat manager application.

  1. Using the steps outlined above, enable SSL for the Tomcat manager application.

Additional Security Configuration

Additional resources

We have compiled a list of a few additional steps you should take to help secure Tomcat and your TDS server. This is not a complete laundry list of security fixes! Please use it as a starting point when securing your server.


THREDDSThis document is maintained by Unidata staff. Please send comments to THREDDS support.