Web Application Deployment Descriptors - "web.xml"
The "
web.xml
" contains the deployment descriptors. There are two sets of web.xml
:$CATALINA_HOME\conf\web.xml
: applicable to ALL webapps.ContextRoot\WEB-INF\web.xml
: applicable to the specific web context. It overrides the global setting, if any.
The complete specification for "
web.xml
" can be found in the "Java Servlet Specification" under "Deployment Descriptor".Tomcat's Manager
Read "Apache Tomcat - Manager App HOW-TO" @ "webapps/docs/manager-howto.html".
Tomcat webapp manager allows you to deploy a new web application; start, stop, reload or un-deploy an existing one, without having to shut down and restart the server.
To enable Tomcat manager, edit "
$CATALINA_HOME\conf\tomcat-users.xml
" to include a role called "manager
" and a user with "manager
" role.<role rolename="manager"/> <user username="tomcatmanager" password="xxxx" roles="manager,manager-script,admin"/>
Use
http://localhost:8080/manager/html
to invoke manager web application.Tomcat with SSL
SSL, or Secure Socket Layer, allows web browsers and web servers to communicate over a secured connection. Tomcat provides built-in support for SSL. Before you attempt to turn on the SSL support, make sure that your tomcat is running fine for HTTP without SSL.
Read:
- "SSL Configuration How-to" of Tomcat Documentation @ "
$CATALINA_HOME\webapps\docs\ssl-howto.html
". - "keytool - Key and Certificate Management Tool" @ JDK documentation.
The steps to turn on SSL support are:
Step 1: Check your JDK version. Tomcat's SSL uses Java Secure Socket Extension (JSSE), which has been integrated into JDK since 1.4.
Step 2: Prepare the Tomcat's server certificate, using the JDK's key and certificate management tool called "
keytool
" (in "$JAVA_HOME\bin
" ), as follows:> keytool
... display the help menu ...
> keytool -genkey -alias tomcat -keyalg RSA -keystore d:\tomcat\conf\.keystore
Enter keystore password: xxxxxxxx
Re-enter new password: xxxxxxxx
What is your first and last name?
[Unknown]:
What is the name of your organizational unit?
[Unknown]:
What is the name of your organization?
[Unknown]:
What is the name of your City or Locality?
[Unknown]:
What is the name of your State or Province?
[Unknown]:
What is the two-letter country code for this unit?
[Unknown]:
Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
[no]: y
Enter key password for <tomcat>
(RETURN if same as keystore password):
- The "
-genkey
" option is used to generate a public-private key pair. The public key is wrapped into an X.509 v1 self-signed certificate. The certificate and the private key are stored in a new keystore entry identified by the alias. In our case, the alias name must be "tomcat
". - The "
-keyalg
" option specifies the key generation algorithm. RSA public key algorithm is used in this case. - The "
-keystore
" option specifies the name and location of the key store file. - The password for
<tomcat>
must be the same as the keystore (i.e., hit enter for the last question).
Step 3: Enable SSL support for Tomcat. SSL is built into Tomcat. The Tomcat's configuration file commented out the SSL configuration directive. Uncomment them by removing the
<!--
and -->
around the SSL Coyote HTTP/1.1 Connector as follows:<!-- 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 -->
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
SSLEnabled="true" maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="d:\tomcat\conf\.keystore"
keystorePass="passwordOfKeyStore" />
Note that the SSL (or HTTPS) is running on port 8443 instead of its default port number 443.
Add in the
keystoreFile
and keyStorePass
attributes. The keystoreFile
attribute specified the location of the keystore file. The keyStorePass
provides the password for accessing the keystore file.
Step 4: Start your tomcat (run "
$CATALINA_HOME\bin\startup.bat
"). After that, start a web browser and issue an HTTPS request as follows:https://localhost:8443
User Authentication in Tomcat
Read Tomcat documentation "Realm Configuration HOW-TO" (@ "
$CATALINA_HOME\webapps\docs\realm-howto.html
") and "Java EE 5 Tutorial", Part IV "Services", Chapters 28-30 on Security.
In Information Security:
- Access control deals with identifying which resources require protection, and which users (roles) are authorized to access the protected resources.
- Authentication deals with verifying users' credential, i.e., ensuring the user is "who he said he is". User's credential is typically provided in the form of username/password. Other means include biometrics (finger-prints, retina) and digital certificates.
- Confidentiality deals with the encryption of the transmitted data over the network. This is often carried out via employing HTTP over SSL (Secure Socket Layer), known as HTTPS.
- Message Integrity: message is not tempered during transmission (via message digest or hash).
- Non-repudiation: If he/she has sent a message, he/she cannot deny (via public-key or digital certificate).
In Tomcat's web applications, a user is identified via username/password. A user is assigned role(s) (e.g., manager, admin, user, etc). Tomcat grants access for web application to role(s), instead of individual users. A realm is a database or file, which contains user information such as username/password, and roles.
Tomcat supports the following types of realm:
UserDatabaseRealm
: user information kept in a XML file "conf\tomcat-users.xml
", accessed via JDNI (Java Naming and Directory Interface).JDBCRealm
: user information kept in a relational database such as MySQL, accessed via JDBC.- others.
You can used the
<realm>
element to configure a realm in "conf\server.xml
". <realm>
element can be placed in <engine>
, <host>
, or <context>
, which determines the scope of the <realm>
- all virtual hosts under the engine, a particular host, or a particular web application.
"Declarative security" is handled by the server. The server-side programs (servlets, JSPs) do not need any security-aware code. That is, the security control is totally transparent to the server-side programs.
UserDatabaseRealm
UserDatabaseRealm
stores user information in a XML file and accessed via JNDI. By default, the XML file is "$CATALINA_HOME\conf\tomcat-users.xml
".
Tomcat provide a JSP example to configure
UserDatabaseRealm
in "WEB-INF\examples\jsp\security\protected
", accessed via http://localhost:8080/examples/jsp/security/protected/index.jsp". Let us study this example.
"conf\server.xml
"
Tomcat enables
UserDatabaseRealm
, in default installation, with the following configuration directives in "server.xml
". It defines a JDNI named "UserDatabase
" to the file "conf\tomcat-users.xml
". The UserdatabaseRealm
is defined within the <Engine>
elements, and thus applicable to all the virtual hosts and web applications, under this server.<Server ...... > <!-- Global JNDI resources --> <GlobalNamingResources> <!-- Editable user database that can also be used by UserDatabaseRealm to authenticate users --> <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"> <Engine name="Catalina" defaultHost="localhost"> <!-- 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" /> <Host name="localhost" ...... ...... </Host> </Engine> </Service> </Server>
"conf\tomcat-users.xml
"
Recall that a user is identified via username/password. A user is assigned role(s). Accesses for web applications are granted to role(s) instead of individual users. "
Tomcat-users.xml
" contains the following roles and username/password, but commented-out. Uncomment them for testing the example.<?xml version="1.0" encoding="ISO-8859-1" ?> <tomcat-users> <role rolename="tomcat" /> <role rolename="role1" /> <user username="tomcat" password="tomcat" roles="tomcat" /> <user username="both" password="tomcat" roles="tomcat,role1" /> <user username="role1" password="tomcat" roles="role1" /> </tomcat-users>
"ContextRoot\WEB-INF\web.xml
"
For the "examples" web context, the security roles are defined using
<security-constraint>
element in "examples\WEB-INF\web.xml
" as follows. The URL pattern /jsp/security/protected/*
(GET, POST, DELETE, PUT methods) are accessible by users having roles of tomcat
and role1
only.<web-app ......> ...... <security-constraint> <display-name>Example Security Constraint</display-name> <web-resource-collection> <web-resource-name>Protected Area</web-resource-name> <!-- Define the context-relative URL(s) to be protected --> <url-pattern>/jsp/security/protected/*</url-pattern> <!-- If you list http methods, only those methods are protected --> <http-method>DELETE</http-method> <http-method>GET</http-method> <http-method>POST</http-method> <http-method>PUT</http-method> </web-resource-collection> <auth-constraint> <!-- Anyone with one of the listed roles may access this area --> <role-name>tomcat</role-name> <role-name>role1</role-name> </auth-constraint> </security-constraint> <!-- Default login configuration uses form-based authentication --> <login-config> <auth-method>FORM</auth-method> <realm-name>Example Form-Based Authentication Area</realm-name> <form-login-config> <form-login-page>/jsp/security/protected/login.jsp</form-login-page> <form-error-page>/jsp/security/protected/error.jsp</form-error-page> </form-login-config> </login-config> <!-- Security roles referenced by this web application --> <security-role> <role-name>role1</role-name> </security-role> <security-role> <role-name>tomcat</role-name> </security-role>
Form-based Authentication Method
The above example uses FORM-based authentication method, defined in element
<login-config>
. All accesses to the protected URL (http://localhost:8080/examples/jsp/security/protected/*
) will be redirected to the login.jsp
page (defined in <form-login-page>
), which prompts user for the credential. For example, if a user requests for http://localhost:8080/examples/jsp/security/protected/index.jsp
, the login.jsp
will be displayed.
The
login.jsp
page shall contain a html <form>
(thus called Form-based authentication):<html> <head><title>Login Page for Examples</title></head> <body> <form method="POST" action='<%= response.encodeURL("j_security_check") %>' > Username:<input type="text" name="j_username"> Password:<input type="password" name="j_password"> <input type="submit" value="Log In"> </form> </body> </html>
The login page shall submit the username and password in parameters
j_username
and j_password
to j_security_check
. You should use <input type="password" ...>
for the password text field, which will display the password as *'s. The response.encodeURL(URL)
encodes the specified URL by including the session ID if URL-rewriting is used for session tracking; it returns the URL unchanged if cookie is used. For robust session tracking, all URLs emitted by server-side programs (servlet/JSP) should be run through this method.
If login fails, user will be redirected to
error.jsp
page, for example,<html> <head><title>Error Page For Examples</title></head> <body> Invalid username and/or password, please try again <a href='<%= response.encodeURL("index.jsp") %>'>again</a>. </body> </html>
If login succeeds, the user will get the page he requested for. Study the "
examples\jsp\security\protected\index.jsp
" source.- To logoff, terminate the current session via
session.invalidate()
. - You can use
request.getRemoteUser()
to get the authenticated login username;request.getUserPrincipal()
to get ajava.security.Principal
object containing the name of the current authenticated user;request.isUserInRole(role)
to check if the authenticated user is included in the specifiedrole
.
HTTPS
The username and password send in form data are in clear text, and susceptible to eavesdropping. Hence, it is important to encrypt the transport by turning on SSL (HTTPS). Read "Tomcat with SSL" on how to setup Tomcat with SSL.
To enforce user to use secure transport (HTTPS), add a
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
, inside the <security-constraint>
, as follows:<security-constraint>
<display-name>Example Security Constraint</display-name>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/jsp/security/protected/*</url-pattern>
......
</web-resource-collection>
<auth-constraint>
<role-name>tomcat</role-name>
......
</auth-constraint>
<!-- must use SSL for secure transport -->
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
All accesses to http at port 8080 (e.g., http://localhost:8080/examples/jsp/security/protected/index.jsp) will be redirected to https at port 8443 (e.g., https://localhost:8443/examples/jsp/security/protected/index.jsp).
HTTP Basic Authentication
Other than Form-based authentication, you could use the Basic Authentication Scheme available in HTTP server to authenticate user. Change the
<login-config>
's <auth-method>
to BASIC
, instead ofFORM
.<login-config> <auth-method>BASIC</auth-method> <realm-name>Example Basic Authentication Area</realm-name> </login-config>
Again, Basic Authentication sends the username and password in clear text. It is totally insecure, unless you should use a secure transport (HTTPS).
HTTP Digest Authentication
Tomcat also support HTTP Digest Authentication Scheme to authenticate user. Change the
<login-config>
's <auth-method>
to DIGEST
. Instead of sending password in clear text, the digest of password is send to the server. Digest authentication is more secure.<login-config> <auth-method>BASIC</auth-method> <realm-name>Example Basic Authentication Area</realm-name> </login-config>
JDBCRealm
In
JDBCRealm
, user information kept in a relational database such as MySQL, accessed via JDBC.Setting up Database
We shall set up our user database in MySQL. Read "How to install MySQL".
The following script can be used to set up the user database. Two tables are required: a
users
table containing username and password, and a user_roles
containing username and the role assigned.create database tomcat_users; use tomcat_users; create table users ( username varchar(15) not null primary key, password varchar(15) not null ); create table user_roles ( username varchar(15) not null, role varchar(15) not null, primary key (username, role) ); insert into users values ('tomcat', 'tomcat'), ('both', 'tomcat'), ('role1', 'tomcat'); insert into user_roles values ('tomcat', 'tomcat'), ('role1', 'role1'), ('both', 'tomcat'), ('both', 'role1');
JDBC Driver
Next, copy the MySQL's JDBC driver ("
mysql-connector-java-5.1.xx-bin.jar
") into Tomcat's lib ("$CATALINA_HOME\lib
").
"conf\server.xml
"
<Realm className="org.apache.catalina.realm.JDBCRealm" debug="99" driverName="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost/tomcat_users?user=dbuser&password=dbpass" userTable="users" userNameCol="username" userCredCol="password" userRoleTable="user_roles" roleNameCol="role" />
"ContextRoot
\WEB-INF\web.xml
"
Same as
UserDatabaseRealm
.Authentication Methods
Same as
UserDatabaseRealm
, you can use FORM
, BASIC
or DIGEST
authentication method.Testing
You need to start MySQL server before starting the Tomcat Server.
Setting up Database Connection Pooling in Tomcat
Configuring Virtual Hosts
To set up a virtual host called "www.mytest.com" (suppose that you have registered this hostname with at static IP address). Include the following
<Host>
element in server.xml
under the Engine Catalina
:<Engine name="Catalina" > <Host name="localhost .....> ...... </Host> <Host name="www.mytest.com" appBase="webapps_mytest.com" unpackWARs="true" autoDeploy="true" > <Alias>mytest.com</Alias> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="mytest.com_access_log." suffix=".log" pattern="%h %l %u %t "%r" %s %b" resolveHosts="false" /> </Host> </Engine>
The above lines configure a virtual host with hostname "
www.mytest.com
", with webapps base directory at "$CATALINA_HOME\webapps_mytest.com
". We also define a alias called "mytest.com
". That is, this host can be accessed via http://www.mytest.com:port
or http://mytest.com:port
. We also define a Valve
, which intercepts the request message to write a log entries (similar to localhost
).
Next:
- Create a directory "
webapps_mytest.com
" under$CATALINA_HOME
, according to theappBase
. - Create a web application called
ROOT
, by creating a directoryROOT
under the "webapps_mytest.com
". Recall thatROOT
was configured with an empty string URL. In other words,http://www.mytest.com:port/
accesses theROOT
application. - Create a directory "
www.mytest.com
" under "conf\Catalina
". - Write a welcome page called "
index.html
" and save it in "webapps_mytest.com\ROOT
".<html> <head><title>Testing Virtual Host</title></head> <body> <h1>It's work on virtual host</h1> </body> </html>
To test the virtual host, without registering the hostname with an ISP, edit "
C:\Windows\System32\drivers\etc\hosts
" to include the following lines (required administrative authority):127.0.0.1 www.mytest.com 127.0.0.1 mytest.com
These lines maps host names
www.mytest.com
and mytest.com
to IP address 127.0.0.1, which is the localhost. As the IP software checks the host
file before asking Domain Name Service (DNS) to resolve a host name, you willl be able to test your virtual host.
Now, you are ready to test the virtual hosts. Start the Tomcat server and issue these URL:
http://www.mytest.com:8080 http://mytest.com:8080 http://www.mytest.com:8080/ http://mytest.com:8080/ http://www.mytest.com:8080/index.html http://mytest.com:8080/index.html