Introduction and Scope
Security is often of great concern and should be high on the list of any project goals. It covers a vast domain and Apache Tomcat, which relates directly to Apache TomEE, is no different in this regard.
This first in a series of security related blog posts is not intended to be exhaustive, but aims at providing you with some insight into how Apache Tomcat and Apache TomEE security works. Apache TomEE provides much more than just Servlets or JSP’s, as it does when it comes to the security related elements.
The second post will focus more on TomEE specific security as applied to each Java EE component, in addition to the entire server domain.
The third post will detail advanced security features which are available out of the box that you may not need on a day to day basis, but will open the door to some additional concepts and enhancements that could be of greater benefit to your project.
The fourth and final security post will be dedicated to advice and best practices for a secure TomEE deployment. There are already several Tomcat blog posts dedicated to best practices, so this last post is intended to gather any valuable information and record everything in the same place.
So in targeting Apache Tomcat security I will provide additional advice directly related to Apache TomEE.
Let us start with Apache Tomcat security.
As a Servlet specification implementation, Apache Tomcat has a set of built in security features in order to implement the so called Container managed security. Check out the Servlet 3.0 and JavaServer Pages 2.2 Specifications implemented by Tomcat v7.x.
In computer security language, Tomcat implements the well known AAA (Authentication Authorization and Accounting). Due to the fact that it is not the primary goal of Tomcat the available features are somewhat limited, regardless of that it is still a pragmatic and sufficient answer to many cases. I have seen over and over projects drawing in complex security frameworks, implementing and then integrating heavy back-ends just for simple use cases.
Having a better view of what we can achieve with Tomcat built-in security can help you save a lot of time, leaving you to focus on something else.
Before going into details about Tomcat Realms and Authenticators we will have a quick tour around Security constraints in the Servlet specification.
The Servlet specification defines a portable way for applications to declare their security requirements. Ultimately that is what you can specify in the web.xml file (Web application deployment descriptor).
All security constraints are defined in the appropriately named element. This defines the access privileges to a collection of resources defined by the ‘url-pattern’ element.
For more information, see the Java EE 6 schema page, and look at the web-app XSD.
Here is an example:
<security-constraint> <display-name>Tomcat security constraints</display-name> <web-resource-collection> <web-resource-name>Protected resources</web-resource-name> <url-pattern>/private/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>admin</role-name> <role-name>user</role-name> </auth-constraint> </security-constraint> <security-role> <description>Administrator role</description> <role-name>admin</role-name> </security-role> <security-role> <description>User role</description> <role-name>user</role-name> </security-role>
The ‘security-role’ elements declare all roles used by the application.
The security constraints above are used to define the region of authorization, but prior to this a valid authentication must have been performed in order to challenge the apply user roles against the roles required to access a particular resource.
That part is managed through the element:
<login-config> <auth-method>BASIC</auth-method> <realm-name>Authentication for my secured application</realm-name> </login-config>
The ‘realm-name’ is used to calculate and distinguish the digested password when using DIGEST authentication.
As previously mentioned, the Servlet specification does not define how to connect to a user database (which is not necessarily an RDBMS). There is no set API, which is why Tomcat has created Realms and Authenticators. This is of course specific to Tomcat, but we will see in the episode #2 that it has also been extended to several Java EE components and integrated to TomEE.
A realm represents a 3-Tuple: username, password and roles. It is responsible for authenticating (or identifying particular situations) and loading the set of roles for the authenticating username.
Realms, like Tomcat Valves, can be applied to an Engine, Host or Context.
Tomcat realm documentation is extensive so I will not rephrase or copy / paste the available online documentation here. Please refer to the Realm configuration How-to page for more detailed information.
Common realms include:
- JNDIRealm: Do not use it in production as it is not thread safe.
- JAASRealm: Maybe the most commonly used in production.
- Combined Realm: Interesting delegate pattern applied to Tomcat Realms. Makes it possible to define more than one realm and use a fall-back mechanism. For example, a common use is to configure JAASRealm first and have a fall-back to use ‘tomcat-users.xml’.
- Lock Out Realm: This one extends the combined realm but adds DoS protection. After the configured amount of failed attempts the account will be locked for a period of time.
Authenticators are implemented as Tomcat valves. They usually extend org.apache.catalina.authenticator.AuthenticatorBase and are integrated directly in the process pipeline.
Depending on your configuration, Tomcat either uses the defined implementation or you can choose the one you want and add it as a valve in your context configuration.
The authenticator uses the realm that applies to the current request and delegates the authentication to it.
Depending on the security components involved, there are three different configuration files that may be involved:
- ‘WEB-INF/web.xml‘: The standard web application deployment descriptor. As previously mentioned, it holds all JavaEE constraints as per the Servlet specification
- ‘conf/server.xml‘: Global configuration of Apache Tomcat, and where you can configure the realm. Tomcat is based on a hierarchy of models (Server, Engine, Host, Context). The higher you add the realm, the higher scope it applies to. For instance, if you define the realm at the Context level, then the realm only applies to the current Context (ie. Web applications). If you configure a realm at the Engine level then it will apply to all Contexts of all Hosts of that Engine.
- ‘META-INF/context.xml‘: This file is part of the web archive (formally WAR file). It makes it possible to add context configuration and keep it consistent along with the application lifecycle. Basically, it holds one single Context element that extends or overrides the Context you can configure in the ‘conf/server.xml’ file I just mentioned above.
- ‘conf/jaas.config‘: The default location for the JAAS configuration file. The ‘appName’ attribute of the JAASRealm must match an entry in the ‘jaas.config’ file.
As mentioned previously, Tomcat automatically configures the appropriate Authenticator based on the web.xml defined constraints. If you do not need any authorization based on the web.xml configuration then you can still use the Tomcat authenticator by declaring the Authenticator as a Valve. It is not permitted to have more than one type of authenticator configured at a time and it must apply to only one Context. For example, you must choose between BASIC, CLIENT-CERT, FORM or DIGEST to deal with the container authentication, you cannot mix them.
Here is the basic pipeline using authenticators and realms before reaching the target Servlet context.
If you need to deal with SAML tokens or anything else you can of course easily implement your own realm and still reuse existing realms to find the user and perform the authentication.
preemptiveAuthentication attribute which belongs to the ‘Context’ tag makes it possible to force authentication irrespective to resource constraints configured in the ‘web.xml’.
You have just learned how to configure the minimal resource protection that is available ‘out of the box’ in Apache Tomcat, which is also directly applicable to Apache TomEE. Look forward to the next blog post, which will be dedicated to TomEE and how it reuses, extends and compliments the existing Apache Tomcat security mechanisms.