Designing and Developing Secure Java EE Applications using GlassFish Security

October 6, 2010

Java / J2EE

«»

Developing the Presentation layer


The Presentation layer is the closest layer to end users when we are developing
applications that are meant to be used by humans instead of other applications. In
our application, the Presentation layer is a Java EE web application consisting of the
elements listed in the following table. In the table you can see that different JSP files
are categorized into different directories to make the security description easier.



Now that our application building blocks are identified we can start implementing
them to complete the application. Before anything else let’s implement JSP files that
provides the conversion GUI. The directory layout and content of the Web module is
shown in the following figure:



Implementing the Conversion GUI


In our application we have an index.jsp file that acts as a gateway to the entire
system and is shown in the following listing:



<html>
<head><title>Select A conversion</title></head>
<body><h1>Select A conversion</h1>
<a href=”auth/login.html”>Login</a>
<br/>
<a href=”jsp/toCenti.jsp”>Convert Meter to Centimeter</a>
<br/>
<a href=”jsp/toInch.jsp”>Convert Meter to Inch</a>
<br/>
<a href=”jsp/toMilli.jsp”>Convert to Millimeter</a><br/>
<a href=”auth/logout.jsp”>Logout</a>
</body>
</html>


Implementing the Converter servlet


The Converter servlet receives the conversion value and method from JSP files and
calls the corresponding method of a session bean to perform the actual conversion.
The following listing shows the Converter servlet content:



@WebServlet(name=”Converter”, urlPatterns={“/Converter”})
public class Converter extends HttpServlet {
@EJB
private ConversionLocal conversionBean;
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
System.out.println(“POST”);
response.setContentType(“text/html;charset=UTF-8″);
PrintWriter out = response.getWriter();
try{
int valueToconvert =
Integer.parseInt(request.getParameter(“meterValue”));
String method = request.getParameter(“method”);
out.print(“<hr/> <center><h2>Conversion Result is: “);
if (method.equalsIgnoreCase(“toMilli”)) {
out.print(conversionBean.toMillimeter(valueToconvert));
} else if (method.equalsIgnoreCase(“toCenti”)) {
out.print(conversionBean.toCentimeter(valueToconvert));
} else if (method.equalsIgnoreCase(“toInch”)) {
out.print(conversionBean.toInch(valueToconvert));
}
out.print(“</h2></center>”);
}catch (AccessLocalException ale) {
response.sendError(401);
}finally {
out.close();
}
}
}


Starting from the beginning we are using annotation to configure the servlet
mapping and servlet name instead of using the deployment descriptor for it. Then
we use dependency injection to inject an instance of Conversion session bean into
the servlet and decide which one of its methods we should invoke based on
the conversion type that the caller JSP sends as a parameter. Finally, we catch
javax.ejb.AccessLocalException and send an HTTP 401 error back to inform
the client that it does not have the required privileges to perform the requested
action. The following figure shows what the result of invocation could look like:



Each servlet needs some description elements in the deployment descriptor or
included as deployment descriptor elements.


Implementing the conversion JSP files is the last step in implementing the functional
pieces. In the following listing you can see content of the toMilli.jsp file.



<html>
<head><title>Convert To Millimeter</title></head>
<body><h1>Convert To Millimeter</h1>
<form method=POST action=”../Converter”>Enter Value to
Convert: <input name=meterValue>
<input type=”hidden” name=”method” value=”toMilli”>
<input type=”submit” value=”Submit” />
</form>
</body>
</html>


The toCenti.jsp and toInch.jsp files look the same except for the descriptive
content and the value of the hidden parameter which will be toCentiand toInch
respectively for toCenti.jsp and toInch.jsp.


Now we are finished with the functional parts of the Web layer; we just need to
implement the required GUifor security measures.


Implementing the authentication frontend


For the authentication, we should use a custom login page to have a unified look
and feel in the entire web frontend of our application. We can use a custom login
page with the FORM authentication method. To implement the F ORM authentication
method we need to implement a login page and an error page to redirect the users to
that page in case authentication fails. Implementing authentication requires us to go
through the following steps:



  • Implementing login.html and loginError.html

  • Including security description in the web.xml and sun-web.xml or
    sun-application.xml


Implementing a login page


In FORM authentication we implement our own login form to collect username
and pa ssword and we then pass them to the container for authentication. We
should let the container know which field is username and which field is password
by using standard names for these fields. The username field is j_ username and the
password field is j_ password. To pass these fields to container for authentication
we should use j_security_check as the form action. When we are posting to
j_ security_check the servlet container takes action and authenticates the included
j_username and j_password against the configured realm. The listing below shows
login.html content.



<form method=”POST” action=”j_security_check”>
Username: <input type=”text” name=”j_username”><br />
Password: <input type=”password” name=”j_password”><br />
<br />
<input type=”submit” value=”Login”>
<input type=”reset” value=”Reset”>
</form>


The following figure shows the login page which is shown when an unauthenticated
user tries to access a restricted resource:



Implementing a logout page


A user may need to log out of our system after they’re finished using it. So we need
to implement a logout page. The following listing shows the logout.jsp file:



<%
session.invalidate();
%>
<body>
<center>
<h1>Logout</h1>
You have successfully logged out.
</center>
</body>


Implementing a login error page


And now we should implement LoginError.html, an authentication error page to
inform user about its authentication failure.



<html>
<body>
<h2>A Login Error Occurred</h2>
Please click <a href=”login.html”>here</a> for another try.
</body>
</html>


Implementing an access restricted page


When an authenticated user with no required privileges tries to invoke a session
bean method, the EJB container throws a javax.ejb.AccessLocalException. To
show a meaningful error page to our users we should either map this exception to
an error page or we should catch the exception, log the event for audition purposes,
and then use the sen dError() method of the Htt pServletResponse object to send
out an error code. We will map the HTTP error code to our custom web pages with
meaningful descriptions using the web.xml deployment descriptor. You will see
which configuration elements we will use to do the mapping. The following snippet
shows AccessRestricted.html file:



<body>
<center> <p>You need to login to access the requested
resource. To login go to <a href=”auth/login.html”>Login
Page</a></p></center>
</body>


Configuring deployment descriptors


So far we have implemented required files for the FORM-based authentication and
we only need to include required descriptions in the web.xml file. L ooking back
at the application requirement definitions, we see that anyone can use meter to
centimeter conversion functionality and any other functionality that requires the user
to login. We use three different HTML pages for different types of conversion. We do
not need any constraint on toC entimeter.html therefore we do not need to include
any definition for it. Per application description, any employee can access the
toMilli.jsp page. Defining security constraint for this page is shown in the
following listing:



<security-constraint>
<display-name>You should be an employee</display-name>
<web-resource-collection>
<web-resource-name>all</web-resource-name>
<description/>
<url-pattern>/jsp/toMillimeter.html</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>DELETE</http-method>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>employee_role</role-name>
</auth-constraint>
</security-constraint>


We should put enough constraints on the toInch.jsp page so that only managers
can access the page. The listing included below shows the security constraint
definition for this page.



<security-constraint>
<display-name>You should be a manager</display-name>
<web-resource-collection>
<web-resource-name>Inch</web-resource-name>
<description/>
<url-pattern>/jsp/toInch.html</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>manager_role</role-name>
</auth-constraint>
</security-constraint>


Finally we need to define any role we used in the deployment descriptor. The
following snippet shows how we define these roles in the web.xml page.



<security-role>
<description/>
<role-name>manager_role</role-name>
</security-role>
<security-role>
<description/>
<role-name>employee_role</role-name>
</security-role>


Looking back at the application requirements, we need to define data constraint
and ensure that username and passwords provided by our users are safe during
transmission. The following listing shows how we can define the data constraint
on the login.html page.



<security-constraint>
<display-name>Login page Protection</display-name>
<web-resource-collection>
<web-resource-name>Authentication</web-resource-name>
<description/>
<url-pattern>/auth/login.html</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<user-data-constraint>
<description/>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>


One more step and our web.xml file will be complete. In this step we define an
error page for HTML 401 error code. This error code means that application server
is unable to perform the requested action due to negative authorization result. The
following snippet shows the required elements to define this error page.



<error-page>
<error-code>401</error-code>
<location>AccessRestricted.html</location>
</error-page>


Now that we are finished with declaring the security we can create the conversion
pages and after creating these pages we can start with Business layer and its
security requirements.


Specifying the security realm


Up to this point we have defined all the constraints that our application requires
but we still need to follow one more step to complete the application’s security
configuration. The last step is specifying the security realm and authentication.
We should specify the FORM authentication and per-application description;
authentication must happen against the company-wide LDAP server.


Here we are going to use the LDAP security realm LDAPRealm which we created in
Chapter 2. We need to import a new LDIF file into our LDAP server, which contains
groups and users definition required for this chapter. To import the file we can use
the following command, assuming that you downloaded the source code bundle
from https://www.packtpub.com//sites/default/files/downloads/9386_
Code.zip and you have it extracted.



import-ldif –ldifFile path/to/chapter03/users.ldif
–backendID userRoot –clearBackend –hostname 127.0.0.1 –port 4444 –
bindDN cn=gf\ cn=admin –bindPassword admin –trustAll –noPropertiesFile


The following table show users and groups that are defined inside the
users.ldif file.



We used OpenDS for the realm data storage and it had two users, one in the
employee group and the other one in the manager group. To configure the
authentication realm we need to include the following snippet in the
web.xml file.



<login-config>
<auth-method>FORM</auth-method>
<realm-name>LDAPRealm</realm-name>
<form-login-config>
<form-login-page>/auth/login.html</form-login-page>
<form-error-page>/auth/loginError.html</form-error-page>
</form-login-config>
</login-config>


If we look at our Web and EJB modules as separate modules we must specify the role
mappings for each module separately using the GlassFish deployment descriptors,
which are sun-web.xml and sun-ejb.xml. But we are going to bundle our modules
as an Enterprise Application Archive (EAR) file so we can use the GlassFish
deployment descriptor for enterprise applications to define the role mapping
in one place and let all modules use that definitions. The following listing shows
roles and groups mapping in the sun-application.xml file.



<sun-application>
<security-role-mapping>
<role-name>manager_role</role-name>
<group-name>manager</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>employee_role</role-name>
<group-name>employee</group-name>
</security-role-mapping>
<realm>LDAPRealm</realm>
</sun-application>


The security-role-mapping element we used in sun-application.xml has the
same schema as the security-role-mapping element of the sun-web.xml and
sun-ejb-jar.xml files.


You should have noticed that we have a realm element in addition to role mapping
elements. We can use the realm element of the sun-application.xml to specify
the default authentication realm for the entire application instead of specifying it
for each module separately.

email

«»

Comments

comments