© Copyright Marcus Green 2007
5.2)In the deployment descriptor, declare a security constraint, a Web resource, the transport guarantee, the login configuration, and a security role.
Apache Tomcat ships with the management application disabled. To learn more about how to configure for security take a look at the url http://localhost:8080/tomcat-docs/manager-howto.html
on your system. This gives you instructions on how to edit the appropriate files to allow you to administer your local installation through a web interface. If you are using the Netbeans IDE (which I recommend you do), then you can go to the runtime tab of the project and select servers and then click on Tomcat. If you select the context menu (right mouse click) click the view admin console option. This will launch your default web browser and allow you to edit the tomcat-users.xml file through a web forms interface. This is far easier than directly editing the file with an editor.
Although security constraints are stored in the deployment descriptor (WEB.XML) and are mandated by the JSP/Servlet specification, users and roles are vendor implemented. Because of this you will not be asked about configuring users and roles in the exam, but for the purpose of experimenting with the technology you need to know how to do this. Users and roles can be set up in Apache tomcat by editing the file
\conf\tomcat-users.xml
Which lives under the tomcat root directory.
|
|
Users and role configuration is not part of the JSP/Servlet specification. |
Here is an example of how to configure the tomcat-users.xml file
<?xml version='1.0' encoding='utf-8'?> <tomcat-users> <user username="marcus" password="password" roles="tomcat"> </tomcat-users>
Rather than assign permission on a user by user basis, they are assigned to a role. The concept of role is very similar to that of job role, or role on a network. Thus you might have a role of admin which allows a user to see the administrative part of the system and a role of guest which has a very restricted access to the system.
The authentication mechanism is specified in the deployment descriptor (WEB.XML) under the <login-config> tag. The following snippet shows how a web application could be configured to use the FORM based authentication system.
<web-app> ... <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/loginform.html</form-login-page> <form-error-page>/loginerror.html</form-error-page> <form-login-config> </login-config> ... </web-app>
The following deployment descriptor (WEB.XML) is designed to show an easily setup access control to a plain Servlet using the BASIC authentication method.
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <login-config> <!-- uses ugly system generated forms, no encyrption --> <auth-method>BASIC</auth-method> <realm-name>Basic Authentication Example</realm-name> </login-config> <servlet> <servlet-name>SecuredServlet</servlet-name> <servlet-class>com.examulator.SecuredServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>SecuredServlet</servlet-name> <url-pattern>/SecuredServlet</url-pattern> </servlet-mapping> <security-constraint> <web-resource-collection> <web-resource-name>Sensitive</web-resource-name> <url-pattern>/SecuredServlet</url-pattern> </web-resource-collection> <auth-constraint> <!-- container specific role, e.g. in tomcat it --> <!-- is defined in tomcat-users.xml.A role-name --> <!-- like adminstrator or manager would be more --> <!--sensible, but tomcat comes with a role of --> <!--tomcat & username/password of tomcat/tomcat--> <role-name>tomcat</role-name> </auth-constraint> </security-constraint> </web-app>
The sub-elements of the security-constraint tag allow the use of declarative security to control what data (in the form of URL's) are to have access restricted and which HTTP methods are to be restricted. Thus you might typically define
<web-resource-collection>
<web-resource-name>Sensitive</web-resource-name>
<url-pattern>/SecuredServlet</url-pattern>
<http-method>POST</http-method>
</web-resource-collection> There are some peculiarities when it comes to defining which methods are restricted, because if no methods at all are listed then the constraint will apply to all HTTP methods, but if any one method is listed, then only that method will be restricted. That was a long sentence, so try reading it again as it covers something that is counter-intuitive and may well come up on the exam. What will happen if you attempt to access SecuredServlet through an HTTP GET request given the following deployment descriptor (WEB.XML)? Note the use of <role-name>*</role-name> which will match against all defined roles.
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <login-config> <!-- uses ugly system generated forms, no encyrption --> <auth-method>BASIC</auth-method> <realm-name>Basic Authentication Example</realm-name> </login-config> <servlet> <servlet-name>SecuredServlet</servlet-name> <servlet-class>com.examulator.SecuredServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>SecuredServlet</servlet-name> <url-pattern>/SecuredServlet</url-pattern> </servlet-mapping> <security-constraint> <web-resource-collection> <web-resource-name>Sensitive</web-resource-name> <url-pattern>/SecuredServlet</url-pattern> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>*</role-name> </auth-constraint> </security-constraint> </web-app>
You can think of the auth-constraint tag as meaning “authorisation constraint”. The auth-constraint tag can contain one or more role-name tags that define the users in which roles (think job or position or usergroup) can access the resource. Note that if you have an empty <auth-constraint> tag, e.g. </auth-constraint> or <auth-constraint></auth-constraint> then no users will be able to access the resource.
|
|
An empty auth-constraint tag means no users will be able to access the resource. |
To quote from the servlet spec
“If no roles are defined, no user is allowed access to the portion of the web application described by the containing security-constraint."
For the purpose of the exam you need to know what will happen where you have overlapping security constraints. For example, what happens if you have security constraints that contradict each other, i.e. one grants permission to a single role but another grants it to everyone?. A sensible answer to this might be “fire the programmer”, but this is exam certification world, not real world so pay attention 007.
As you might expect plain auth-constraints to muliple roles just give each role the expected permission. Thus given the following example
<security-constraint>
<web-resource-collection>
<web-resource-name>Sensitive</web-resource-name>
<url-pattern>/SecuredServlet</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Sensitive</web-resource-name>
<url-pattern>/SecuredServlet</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
Members of the manager and the admin roles would have access to the resource but nobody else. So what who would be able to access the resource with the following constraints (note the asterix)?
<security-constraint>
<web-resource-collection>
<web-resource-name>Sensitive</web-resource-name>
<url-pattern>/SecuredServlet</url-pattern>
</web-resource-collection>
<auth-constraint>
<auth-constraint>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Sensitive</web-resource-name>
<url-pattern>/SecuredServlet</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
As you might guess everyone would be able to access the resource as the asterix overrides the explicit role name. If you have an security-constraint with no auth-constraint element then everyone gets access. Thus with the following (unlikely) configuration
<security-constraint>
<web-resource-collection>
<web-resource-name>Sensitive</web-resource-name>
<url-pattern>/SecuredServlet</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Sensitive</web-resource-name>
<url-pattern>/SecuredServlet</url-pattern>
</web-resource-collection>
</security-constraint>
The second security-constraint will override the first one and it will be possible to access the SecuredServlet without restriction.
As mentioned previously, if you have an empty auth-constraint nobody has access. It is well worthwhile re-reading that last section and experimenting with permissions in Tomcat as it is not the most obvious of topics.
The user-data-constraint tag has two sub elements, a description tag and a transport-guarantee tag. The possible values for transport-guarantee are
NONE
INTEGRAL
CONFIDENTIAL
In practice the values INTEGRAL and CONFIDENTIAL mean that connections will be made over SSL (Secure Sockets Layer), i.e. The HHTPS protocol. Setting up your server for SSL is a fairly tricky business so I recommend you take it as given that this tag works as described.
In theory the INTEGRAL attribute mandates that data is checked for correctness and CONFIDENTIAL means that the data cannot be read if it is intercepted, which in practice means it is encrypted. Take another look at objective 5.2 for more coverage of these concepts.
As a general guide it is preferable to keep security out of the Java code. Modifying the XML in the deployment descriptor is something that can be relatively easily learnt and understood by non-programmers and it is unlikely to introduce bugs in code. Programmatic security, i.e. method calls embedded in servlets requires the understanding of a programmer, is not centralised and runs the risk of introducing bugs in code, it is generally a more complex approach than declarative security.
Having said all of that there are situations when declarative security simply does not off enough flexibility. An example could be where the access given to a user is based on a customers credit (i.e. If they have topped up with an online payment) or on what score they have in a game. Where a users access can change dynamically, programmatic security can be the preferred option. Fortunately programmatic security works hand in hand with declarative security.
isUserInRole is a method of the HttpServletRequest interface and according to the API docs
Returns a boolean indicating whether the authenticated user is included in the specified logical "role". Roles and role membership can be defined using deployment descriptors. If the user has not been authenticated, the method returns false
http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/
http/HttpServletRequest.html#isUserInRole(java.lang.String)
This method can be used to control access to limited area of a method, and so is part of the authorisation system. Rather than being a separate security system it is more like the ability to customise how the declarative security works.
isUserInRole should only be called once the user has been authenticated. If the user has not been authenticated the method will return false. The isUserInRole method takes a String argument representing a role defined in the deployment descriptor, thus you might have a call as follows.
This method is a method of the HttpServletRequest interface and can be used to determine if a client has been authenticated (has proven they are who they say they are)
According to the API DOCS the getRemoteUser method
“Returns the login of the user making this request, if the user has been authenticated, or null if the user has not been authenticated. Whether the user name is sent with each subsequent request depends on the browser and type of authentication. Same as the value of the CGI variable REMOTE_USER.”
If no user has been authenticated the getRemoteUser method returns null
One of the problems with programmatic security is that there is an implication that the role names must be embedded within the java code, which is generally not considered a good thing. The <security-role-ref> tag allows you to get around this, by allowing the creation of aliases for roles. In fact it might have made sense for this tag to have been named <security-role-alias>. This tag is used in the deployment descriptor as follows.
<servlet>
<servlet-name>SecuredServlet</servlet-name>
<servlet-class>com.examulator.SecuredServlet</servlet-class>
<security-role-ref>
<role-name>hardcodedrole</role-name>
<role-link>tomcat</role-link>
</security-role-ref>
</servlet>
<security-role>
<role-name>tomcat</role-name>
</security-role>
Note how the role that is managed by the container (tomcats tomcat-users.xml file if the container is Apache tomcat) must be explicitly declared via the security-role tag. The security-roles-ref tag (think alias) is declared within the opening tag of the resource that is being secured, in this case the SecuredServlet resource.
An example of where you might use the aliasing of roles is where you are creating servlet code for multiple organisations that use different job role titles. For example one organisation might call the person who can see other peoples salaries an admin, another administrator, another manager and another might call them a supervisor. By using <security-role-ref> in conjunction with isUserInRole the same code can be used for each organisation by only editing the deployment descriptor. The code can be as follows.
if(request.isUserInRole("hardcodedrole")){
out.print("<h3> Yes you are allowed in this role</h3>");
}
Here is that code in the context of a small and mindless Servlet example.
package com.examulator;
import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class SecuredServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet SecuredServlet</title>");
out.println("</head>");
out.println("<body>");
if(request.isUserInRole("hardcodedrole")){
out.print("<h3> Yes you are allowed in this role</h3>");
}
out.println("<h1>SecuredServlet</h1>");
out.println("</body>");
out.println("</html>");
out.close();
}
}
Other sources
OnJava covers Tomcat realms
http://www.onjava.com/pub/a/onjava/2001/07/24/tomcat.html
Declarative Web Application Security by Marty
Hall
http://www.phptr.com/articles/printerfriendly.asp?p=26139
The API docs for HTTPServletRequest http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/http/HttpServletRequest.html
This objective according to Mikalai Zaikin
http://java.boot.by/wcd-guide/ch05s02.html