Declarative SecurityS2C Home « Declarative Security
Securing our web applications is one of the most important parts of web development and considering that anyone with an internet connection and a browser can access them, we need to ensure our security is up to the task. We can secure our web applications declaratively via the DD without using any code or using a combination of declarative and programmatic security. In the first of two lessons on security we look at securing our web applications declaratively via the DD without having to change a single line of code.
Within web applications there are four topics which cover the various areas of web security these being: authentication, authorization, confidentiality and data integrity. We talk about each area of web security in the following sections in much more detail.
AuthenticationTop
Authentication is about providing a means whereby two communicating entities; which in terms of Java we can think of as client using a web browser to point to a resource on our server and the container verifying the said resource is available to this client. The communicating entities could also be resources communication with each other, but the above analogy will do for this lesson.
Authentication is generally achieved by sending the client a form where they have to fill in a username and password. The form can be declared declaratively, via the DD, which then uses HTTP protocol to create a form, which varies dependant upon the browser being used. This might not be acceptable for customer facing authentication but is fine for internal authentication. We can also create a custom form programmatically and we look at the DD entry for this below how we go about coding a custom form in the Programmatic Security lesson.
The container then validates entries in these two fields against a vendor specific user file, which for Tomcat would be the tomcat-users.xml
file found within the conf
directory, or from records held on a relational database or LDAP system.
The following code shows the contents of the tomcat-users.xml
file after removing all the comments and uncommenting the file. We have rolenames followed by a username and password and
the roles applicable to that user which can be multiple roles. The actual layout will differ between different server vendors but the idea is the same, we authenticate a user via their username
and password and we authorize them using constraints within the DD, which we look at in the next section. You can think of a role in terms of the access a user has to a web application.
<?xml version='1.0' encoding='utf-8'?>
<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>
The above tomcat-users.xml
file is perfect for our security lesson but not really suitable for a production environment as we would need to change this file every time we got a new
user. Make sure you change and save the file as above or the examples later in the lesson won't work.
Authentication TypesTop
To implement authentication within our web applications we need to add entries to the DD for the type of authentication we require. The top-level <login-config> element is used to declare that authentication is required. Within the <login-config> element, we can enter an optional authentication method, the optional realm name that should be used for this application and the attributes that are needed by the form login mechanism. Depending on the container the <auth-method> sub-level element can be delimited with commas as a fallback mechanism if the initial authentication method is unavailable. We discuss the four authentication types and the options available for each below.
BASIC AuthenticationTop
Basic authentication is the default and uses the Base64 algorithm to encrypt the user and password fields. Base64 is a weak encryption but is the HTTP standard so all browsers and containers support
it. There is no need to code any programmatic security for basic authentication as HTTP provides the login mechanism. This also means that if your login screen is client facing this may not be
an acceptable business choice. The <auth-method> sub-level element is optional and can only
appear once within the top-level <login-config> element and should be set to BASIC
(all uppercase) for basic authentication. The <realm-name> sub-level element is optional and
can only appear once within the top-level <login-config> element and contains the registry
used to store user account information or in the case of our test server a message to display on the login form. The following code snippet shows a DD entry for basic authentication.
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Authorized Users Only</realm-name>
</login-config>
DIGEST AuthenticationTop
Digest authentication is a much stronger encryption type than Base64 and generally uses the MD5 algorithm to encrypt the user and password fields. Digest authentication is an optional type for
browsers and containers and so the interpretation and encryption can vary between vendors and so to use this authentication type effectively you need to make sure all your clients software is compatible.
There is no need to code any programmatic security for the digest authentication, as if the browser supports digest, HTTP provides the login mechanism. This also means that if your login screen is
client facing this may not be an acceptable business choice. The <auth-method> sub-level element
can only appear once within the top-level <login-config> element and should be set to
DIGEST
(all uppercase) for digest authentication. The <realm-name> sub-level
element is optional and can only appear once within the top-level <login-config>
element and contains the registry used to store user account information. The following code snippet shows a DD entry for digest authentication.
<login-config>
<auth-method>DIGEST</auth-method>
<realm-name>Authorized Users Only</realm-name>
</login-config>
FORM AuthenticationTop
Form-based authentication allows us to customize the appearance of a login page that is customer facing. When declaring this type of authentication we also have to include an error page; both pages
can be HTML or JSP pages. When using FORM authentication on initial entry to a constrained resource the login page is displayed. If the login is successful the constrained resource is sent, otherwise
the user is sent the error page. The <auth-method> can only appear once within the top-level
<login-config> element and should be set to FORM
(all uppercase) for form-based
authentication. The <form-login-config> must be present, is only applicable to the FORM
authentication type and can only appear once within the the top-level <form-login-config> element.
Within <form-login-config>, the <login-config-page> and
<login-error-page> sub-level elements are both mandatory, must appear only once and represent
HTML or JSP pages to display where appropriate. The following code snippet shows a DD entry for form-based authentication.
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>login.html</form-login-page>
<form-error-page>error.html</form-error-page>
</form-login-config>
</login-config>
CLIENT-CERT AuthenticationTop
Client certificate authentication uses digital certificates to achieve authentication. This method of authentication uses private/public key cryptography between the concerned parties. The private key is held safely by the digital certificate owner who can be trusted as their certificate has been digitally signed by a trusted certificate issuer. The digital certificate owner can then publish his public key knowing that any transmissions he receives can only be decrypted by his private key and also that any transmissions he sends using his private key can only be decrypted via the public key. This makes client certificate authentication the most protective authentication mechanism but also the hardest to set up initially. The following code snippet shows a DD entry for client certificate authentication.
<login-config>
<auth-method>CLIENT-CERT</auth-method>
</login-config>
AuthorizationTop
Authorization works alongside authentication and allows us as programmers to decide which parts of our web application are available to which users (roles) using constraints declared within the DD. For example we may want our user to be able to browse through our goods and then enforce security if they want to buy something. This is done declaratively using the <security-constraint> top-level element which encompasses three sub-level elements, <web-resource-collection>, <auth-constraint> and <user-data-constraint> all of which can contain sub-level elements. We look at each of these elements in much greater detail below and the rules which apply to them.
The <web-resource-collection> ElementTop
Every <security-constraint> and you can have many, must contain at least one <web-resource-collection> sub-level element, which can itself consist of up to four sub-level elements these being; <web-resource-name> which is mandatory, appears once and has no specific function apart from describing the group being collected together. The optional <description> sub-level element which can be repeated as often as you want to describe this web resource collection. The <url-pattern> which is mandatory, can appear once or many times and works the same as all the other URL pattern matchers we have seen. Finally there is the <http-method> which is optional and can be repeated as often as you wish to constrain which type of http methods can be used.
- Valid values for <http-method> are
DELETE
,GET
,HEAD
,OPTIONS
,POST
,PUT
andTRACE
and be all uppercase. - If any HTTP method is specified then all other HTTP methods not specified that your servlet supports are unconstrained and can be accessed by anyome regardless of the roles specified in <auth-constraint>.
- If no HTTP methods specified all HTTP methods are constrained and can only be accessed by the roles specified in <auth-constraint>.
The following code snippet shows a single security constraint containing a web resource collection.
<security-constraint>
<web-resource-collection>
<web-resource-name>ViewBooks</web-resource-name>
<url-pattern>/</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
</security-constraint>
The <auth-constraint> ElementTop
Every <security-constraint> can contain 0 or 1
<auth-constraint>
sub-level element, which can itself consist of up to two sub-level elements these being; the optional <description>
sub-level element which can be repeated as often as you want to describe this authority constraint. The optional <role-name>
sub-level element which can be repeated as often as you want and specifies the roles allowed to access the constraints held within the <web-resource-collection>
element. The <auth-constraint> element must follow the <web-resource-collection> element.
- If no <auth-constraint> element is specified or is empty the container must allow unauthorized access to the URLs specifed within the <web-resource-collection> element.
- If the <auth-constraint> element is present and not empty then the container must perform authentication for the URLs specifed within the <web-resource-collection> element.
- If the <auth-constraint> element is present and the <role-name>
sub-level element is present and contains the special value
*
then all users are allowed. - Any role names specified within the <role-name> sub-level element are case-sensitive.
The following code snippet shows a single security constraint containing a web resource collection and the authentication constraint highlighted.
<security-constraint>
<web-resource-collection>
<web-resource-name>ViewBooks<web-resource-name>
<url-pattern>/</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>tomcat</role-name>
<role-name>role1</role-name>
</auth-constraint>
</security-constraint>
The <user-data-constraint> ElementTop
Every <security-constraint> can contain 0 or 1
<user-data-constraint>
sub-level element, which can itself consist of up to two sub-level elements these being; the optional <description>
sub-level element which can be repeated as often as you want to describe this authority constraint. The mandatory <transport-guarantee>
which must appear only once.
If present the <user-data-constraint> sub-level element must follow the <web-resource-collection> and <auth-constraint> sub-level elements.
Valid values for the mandatory <transport-guarantee> sub-level element are as follows:
NONE
- Which is the default and means the data is not protected during transit.INTEGRAL
- Which means the data must not be modified during transit.CONFIDENTIAL
Which means the data must be hidden from view during transit.
The following code snippet shows a single security constraint containing a web resource collection, an authentication constraint and the user data constraint highlighted.
<security-constraint>
<web-resource-collection>
<web-resource-name>ViewBooks<web-resource-name>
<url-pattern>/</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>tomcat</role-name>
<role-name>role1</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
Data IntegrityTop
Data integrity is about ensuring that transmitted data is not intercepted by a third party and modified during transit. This is generally achieved using HTTPS over SSL, which acts as a protected transport layer and is available when using any compliant EE5 container.
We declare data integrity declaratively within the <transport-guarantee> sub-level element of the <user-data-constraint> sub-level element. The following code snippet shows how to declare data integrity.
<security-constraint>
...
<user-data-constraint>
<transport-guarantee>INTEGRAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
ConfidentialityTop
Confidentiality is a guarantee that transmitted data is kept private from any third party during transit. This is generally achieved using HTTPS over SSL, which acts as a protected transport layer and is available when using any compliant EE5 container. In practice this means that data integrity and confidentiality are achieved using the same process and achieve the same results regardless of the transport guarantee used.
We declare confidentiality declaratively within the <transport-guarantee> sub-level element of the <user-data-constraint> sub-level element. The following code snippet shows how to declare confidentiality.
<security-constraint>
...
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
Declaring Security RolesTop
The final part of declarative security involves declaring the security roles that are present in the vendor specific users file. To do this we use the top-level <security-role> element, which can itself consist of up to two sub-level elements these being; the optional <description> sub-level element which can be repeated as often as you want to describe the security roles present. The <role-name> sub-level element which is mandatory, can appear once or many times and mirrors the role names held in the vendor-specific users file which are in use for this web application.
The following code snippet shows an example of the top-level <security-role> element.
<security-role>
<role-name>tomcat</role-name>
<role-name>role1</role-name>
</security-role>
Example Of Declarative SecurityTop
Now we have seen all the aspects of declarative security it is time to see how we can use these DD entries to protect our web applications. To achieve this we will use the bookchoice
web application we developed in the Session Management Part 3 lesson and change the DD within the deployed web application.
If you didn't do so earlier in the lesson change and save the tomcat-users.xml
file by removing all the comments and uncommenting the file as below. In my case the tomcat-users.xml
file can be found in:
C:\apache-tomcat-6.0.37\conf
<?xml version='1.0' encoding='utf-8'?>
<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>
Coding The DDTop
Go to your Tomcat installation for the the bookchoice
web application, which in my case is:
C:\apache-tomcat-6.0.37\webapps\bookchoice\WEB-INF
Within the WEB-INF
folder open up the web.xml
file for editing and cut and paste the following XML, replacing the existing contents.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
<servlet>
<servlet-name>bookWishList</servlet-name>
<servlet-class>controller.WishListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>bookWishList</servlet-name>
<url-pattern>/book</url-pattern>
<url-pattern>/bookDetails</url-pattern>
<url-pattern>/wishList</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>ViewBooks</web-resource-name>
<url-pattern>/</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>tomcat</role-name>
<role-name>role1</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>tomcat</role-name>
<role-name>role1</role-name>
</security-role>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Authorized Users Only</realm-name>
</login-config>
</web-app>
Save the web.xml
file in the WEB-INF
folder.
Before we test the servlet we will go through the updated web.xml
file and explain what we are trying to achieve with the security elements we have added. Within our security constraint
we create a web resource collection with the name ViewBooks
and are using the default match URL mapping to catch everything within this web applications context path. We are restricting
access on the GET
HTTP method so any other HTTP methods within the web application have unrestricted access.
We then specify the authentication constraints to be used in conjunction with our web resource collection so that only users with the role of tomcat
and role1
can use the
web application.
After this we specify the security roles in use for the the web application, which are tomcat
and role1
.
In Tomcat if you leave this element out the web application will still be protected but you will get a warning in the Tomcat logs for any authentication roles that have been constrained as follows:
Our final declarative specifies that we are going to use the BASIC
authentication type and we will display the text Authorized Users Only
on the login screen that is created by the
HTTP 1.1 protocol
Testing Our ServletTop
Open a command prompt and change the directory to the location of our Tomcat bin directory and then type in startup
(Windows 7) or startup.sh
(Linux/Unix/OSX).
Press Enter and the Tomcat server should open up in a new window.
You can also start up Tomcat by double-clicking the startup
batch file within your Tomcat /bin
folder.
With Tomcat up and running type the following into your web browser address bar and press enter:
http://localhost:8080/bookchoice/book
The following screenshot shows the results of typing the above into the Chrome web browser address bar and pressing enter.
As you can see the browser has popped up an authentication screen for us to enter a username and password in.
To enter the application type in role1
or tomcat
in the User Name:
field and tomcat
in the Password:
field and press enter. You
will then be able to use the application as you are now authenticated.
Layering SecurityTop
What if we wanted to layer our security so that all authenticated users can use the GET
HTTP method but only certain users can use the POST
HTTP method to add to a wish
list, how would we go about this? Well we can add another security constraint to only allow users within a certain role to update wish lists. As we have already seen, this can be done declaratively using the DD.
Updating The DDTop
Go to your Tomcat installation for the the bookchoice
web application, which in my case is:
C:\apache-tomcat-6.0.37\webapps\bookchoice\WEB-INF
Within the WEB-INF
folder open up the web.xml
file for editing and cut and paste the following XML, replacing the existing contents.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
<servlet>
<servlet-name>bookWishList</servlet-name>
<servlet-class>controller.WishListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>bookWishList</servlet-name>
<url-pattern>/book</url-pattern>
<url-pattern>/bookDetails</url-pattern>
<url-pattern>/wishList</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>ViewBooks</web-resource-name>
<url-pattern>/</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>tomcat</role-name>
<role-name>role1</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>UpdateWishList</web-resource-name>
<url-pattern>/wishList</url-pattern>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>tomcat</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>tomcat</role-name>
<role-name>role1</role-name>
</security-role>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Authorized users only</realm-name>
</login-config>
</web-app>
Save the web.xml
file in the WEB-INF
folder.
Before we test the servlet we will go through the updated web.xml
file and explain what we are trying to achieve with the security elements we have added. We have added a new security
constraint within which we create another web resource collection with the name UpdateWishList
. We are using /wishList
for URL mapping to catch entries that go to the wish
list but are only restricting access on the POST
HTTP method. So looking at the wish list using the GET
HTTP method will work if the user is authenticated via the first
security constraint.
We then specify the authentication constraints to be used in conjunction with our web resource collection so that only users with the role of tomcat
can use the wish list when also
using the POST
HTTP method.
Retesting Our ServletTop
If yout Tomcat session is still open, close it so the new web.xml
file gets deployed. Open a command prompt and change the directory to the location of our Tomcat bin
directory and then type in startup
(Windows 7) or startup.sh
(Linux/Unix/OSX). Press Enter and the Tomcat server should open up in a new window.
You can also start up Tomcat by double-clicking the startup
batch file within your Tomcat /bin
folder.
With Tomcat up and running type the following into your web browser address bar and press enter:
http://localhost:8080/bookchoice/book
When the browser has popped up an authentication screen for us to enter a username and password, type in role1
in the User Name:
field and tomcat
in the
Password:
field and press enter. You will then be able to use the application as you are now authenticated. If you try and add to the wish list you will get the following screen in Chrome:
This is just what we want for users with the role1
role, they can view via the first security constraint, but can't update because of the second security constraint.
Ok, to make sure users with the tomcat
role can also update the wish list, close and reopen the browser window so we can redo authentication.
With Tomcat up and running type the following into your web browser address bar and press enter:
http://localhost:8080/bookchoice/book
When the browser has popped up an authentication screen for us to enter a username and password, type in tomcat
in the User Name:
field and tomcat
in the
Password:
field and press enter. You will then be able to use the application as you are now authenticated. If you try and add to the wish list there is no problem as you pass the
authentication and authorization constraints.
Lesson 6 Complete
In this lesson we looked at securing our web applications declaratively.
What's Next?
In the next lesson we look at securing our web applications programmatically.