DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Coding
  3. Java
  4. Using JASPIC to Secure a Web Application in GlassFish

Using JASPIC to Secure a Web Application in GlassFish

Andy Overton user avatar by
Andy Overton
·
Feb. 17, 15 · Interview
Like (2)
Save
Tweet
Share
8.95K Views

Join the DZone community and get the full member experience.

Join For Free

Introduction

In this blog post I will provide a brief introduction to JASPIC and then take a walk through setting up a basic demo using JASPIC to secure a simple web application in GlassFish.

What is JASPIC?

JASPIC stands for Java Authentication Service Provider Interface for Containers. The original JSR for JASPIC was created back in 2002 but it wasn't completed until 2007 and wasn't included in Java EE until Java EE 6 back in 2009.

JSR 196 defines a standard service-provider interface (SPI) and standardises how an authentication module is integrated into a Java EE container. It is supported by all the popular web containers and is mandatory for the full Java EE 6 profile. It provides a message processing model and details a number of interaction points on the client and server.

A compatible web container will use the SPI at these points to delegate the corresponding message security processing to a server authentication module (SAM).

Walk-through

I will be using the following software whilst doing this walk-through. If you are using different versions then you may see different results.

  • Ubuntu 14.04 LTS
  • Eclipse Luna (with Glassfish Tools - available here - http://marketplace.eclipse.org/content/glassfish-tools-luna
  • JDK 1.7.0_25
  • GlassFish 4.1
Creating the Runtime Environment
First of all, we will create a runtime environment so we can run GlassFish from within Eclipse. In order to do so:

In Eclipse go to:

  • File->New->Other->Server
  • Select Glassfish 4
  • Set the JDK
  • Set the Server directory to <GF_INSTALL_DIR>/glassfish
  • All other defaults should be OK.
Creating the web application
OK. So, next we will create a very basic web-app consisting of a single servlet.
In Eclipse go to:
  • File -> New -> Dynamic Web Project
  • Name - JASPICTest
  • Make sure the Target runtime is GlassFish 4.
  • Press Next twice to accept the defaults and then select Generate web.xml deployment descriptor on the last page.
  • Click Finish.
Right-click on your newly created project and select New → Servlet:
  • package - uk.co.c2b2
  • Class Name - TestServlet
  • Click Next and Finish

This will create a basic servlet. Add the following code to the doGet method:

try
{
 out.println("<html>");
 out.println("<head>");
 out.println("<title>Test Servlet</title>"); 
 out.println("</head>");
 out.println("<body>");
 out.println("You have accessed TestServlet at " + request.getContextPath () + "<br>");
 
 Principal userPrincipal = request.getUserPrincipal();
 boolean adminUser = request.isUserInRole("admin");
 String userName;
 
 if (userPrincipal != null)
 {
  userName = userPrincipal.getName();
 }
 else
 {
  userName = "Unknown User";
 }
 
 out.println("You are currently authenticated as: " + userName + "<br>");
 
 if (adminUser)
 {
  out.println("<br>As you're admin you can view this.<br>");
 }
 else
 {
  out.println("<br>Sorry, you're not admin. Nothing to see here.<br>");
 }
 
 out.println("</body>");
 out.println("</html>");
}
finally
{
 out.close();
}

This is very basic but will allow us to see the relevant authentication data being returned by the server.

Testing your application

Start your GlassFish server - Right click on your server and click Start. (Note - If you can't see the Servers tab ensure you have the Java EE perspective open).

To run your servlet right click on TestServlet, select Run As -> Run on Server.

Make sure your GlassFish server is selected and hit Finish. Click on Always use this server when running this project to make things simpler in future.

Go to: http://localhost:8080/JASPICTest/TestServlet and you should get the following response:

You have accessed TestServlet at /JASPICTest2

You are currently authenticated as: Unknown User

Sorry, you're not admin. Nothing to see here.

Creating the Server Authentication Module

The Server Authentication Module (SAM) must implement the javax.security.auth.message.module.ServerAuthModule interface as defined by JSR 196. The interface can be found here:

https://docs.oracle.com/javaee/6/api/javax/security/auth/message/module/ServerAuthModule.html

The SAM is invoked indirectly by the message processing runtime at the validateRequest and secureResponse interaction points.

Create a new Java project - TestAuthModule. Right click project, select Build Path-> Configure Build Path->Libraries. Click Add External JARs.

Add the following dependencies:

javax.servlet-api.jar
javax.security.auth.message-api.jar

Both can be found in:

<GF_INSTALL_DIR>/glassfish/modules

These will only be used to compile the code, you don't need to package them up as the web container will already contain copies.

Right click on your new project and create a new Java class TestAuthModule which implements the interface - javax.security.auth.message.module.ServerAuthModule

For now we won't add in anything aside from replacing the auto-generated validateRequest method with the following:

public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject,
   Subject serviceSubject) throws AuthException
{
    System.out.println("validateRequest called");
  
    return AuthStatus.SUCCESS;
}

Export your new project as a jar file. Right click on the TestAuthModel project, select Export->Java->JarFile. Remove the classpath and project resources and call the output file TestAuthModule.jar. Export the jar file to <GF_INSTALL_DIR>/glassfish/lib. Restart Glassfish.

Configuring the SAM

Next up we need to create a message security provider in GlassFish and then link this to our web app.

Go to the GlassFish admin console:

http://localhost:4848

  • Go to Configurations->server-config->Security->Message Security
  • Select HttpServlet
  • Select the Providers tab. Click New.
  • Provider ID - TestSAM
  • Provider Type - server
  • Class Name - uk.co.c2b2.TestAuthModule

Updating the web app

In the JASPICTest app, edit glassfish-web.xml. Add the following to indicate that the TestSAM you have just set up should be used for this app.

<glassfish-web-app httpservlet-security-provider="TestSAM">
Testing the changes
In Eclipse - Right click on TestServlet and select Run As -> Run On Server
You should now see in the Glassfish console output:
INFO: validateRequest called
This shows that Glassfish our SAM is now being used.

Locking down resources

OK, so at the moment we have a web app that is linked to our SAM but we haven't actually said to secure anything and even if we did our SAM simply authenticates anyone!

So, lets implement some (albeit very basic) security.

NOTE - This is only for demo purposes and to show how JASPIC works, it is most definitely not intended to be a way of doing security!.

First of all, let's lock down our servlet. We want to lock it down to only users with the role admin or standard. To do so, add the following to the application web.xml:

<security-constraint>
 <web-resource-collection>
  <web-resource-name>JASPICTest</web-resource-name>
  <url-pattern>/*</url-pattern>
 </web-resource-collection>
 <auth-constraint>
  <role-name>standard</role-name>
  <role-name>admin</role-name>
 </auth-constraint>
</security-constraint>

<security-role>
 <role-name>standard</role-name>
</security-role>
<security-role>
 <role-name>admin</role-name>
</security-role>

There is one additional (rather ugly) step we need to do to make our app work. In order for GlassFish to accept the roles that our authentication module puts into the JAAS Subject we have to map them to groups.

In order to do so, add the following to glassfish-web.xml

<security-role-mapping>
        <role-name>standard</role-name>
 <group-name>standard</group-name>
</security-role-mapping>
<security-role-mapping>
 <role-name>admin</role-name>
 <group-name>admin</group-name>
</security-role-mapping>

Next up we will alter our SAM and implement the methods. Each of the methods is implemented as follows:

  • initialize - Simply takes the CallBackHandler and instantiates our local handler.
  • getSupportedMessageTypes - Returns the HTTP servlet request and response types.
  • secureResponse - Simply returns Success.
  • cleanSubject - Clears all principals from the Subject.

validateRequest - This is the main method of interest. In order to pass in the user and role I have just added them as servlet request parameters for testing purposes. This method extracts those values and then calls authenticateUser.

authenticateUser - NOTE - This method doesn't actually do any authentication! It simply takes the user and group, creates callback classes from them and passes them to the callback handler. 

Once we have added the above our TestAuthModule looks like this:

public class TestAuthModule implements ServerAuthModule
{
 @SuppressWarnings("rawtypes")
 protected static final Class[] supportedMessageTypes = new Class[] {
  HttpServletRequest.class, HttpServletResponse.class };

 private CallbackHandler handler;

 public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy,
  CallbackHandler handler, @SuppressWarnings("rawtypes") Map options) throws AuthException
 {
  System.out.println("initialize called.");
  this.handler = handler;
 }

 @SuppressWarnings("rawtypes")
 public Class[] getSupportedMessageTypes()
 {
  return supportedMessageTypes;
 }

 public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject,
  Subject serverSubject) throws AuthException
 {
  HttpServletRequest request = (HttpServletRequest)messageInfo.getRequestMessage();
  
  String user = request.getParameter("user");
  String group = request.getParameter("group");
  
  System.out.println("validateRequest called.");
  System.out.println("User = " + user);
  System.out.println("Group = " + group);
  
  authenticateUser(user, group, clientSubject, serverSubject);

  return AuthStatus.SUCCESS;
 }

 public AuthStatus secureResponse(MessageInfo msgInfo, Subject service) throws AuthException
 {
  System.out.println("secureResponse called.");
  return AuthStatus.SEND_SUCCESS;
 }

 public void cleanSubject(MessageInfo msgInfo, Subject subject) throws AuthException
 {
  if (subject != null)
  {
   subject.getPrincipals().clear();
  }
 }
 
 private void authenticateUser(String user, String group, Subject clientSubject,
  Subject serverSubject)
 {
  System.out.println("Authenticating user " + user + " in group " + group);
  
  CallerPrincipalCallback callerPrincipalCallback = new CallerPrincipalCallback(clientSubject,
   user);

  GroupPrincipalCallback groupPrincipalCallback = new GroupPrincipalCallback(clientSubject,
   new String[] { group });

  try
  {
   handler.handle(new Callback[] { callerPrincipalCallback, groupPrincipalCallback });
  }
  catch (Exception e)
  {
   e.printStackTrace();
  }
 }
}

Testing

Now all we need to do is test our new module. First of all build it, jar it up and copy it over to <GF_INSTALL_DIR>/glassfish/lib as before. Restart Glassfish. Now we can test by passing in different dummy credentials. You should see the following:

If you go to:

http://localhost:8080/JASPICTest/TestServlet?user=Andy&group=standard
You should see the "Sorry, you're not admin. Nothing to see here." message.

If you go to:

http://localhost:8080/JASPICTest/TestServlet?user=Andy&group=admin

You should see the "As you're admin you can view this." message.

And if you go to:

http://localhost:8080/JASPICTest/TestServlet?user=Andy&group=xxx

You should see a HTTP Status 403 - Forbidden message.

Wrapping Up

Hopefully this has given you a taster of how to use JASPIC to secure your applications and you can see how relatively straightforward it is to put the basic building blocks in place. If you're looking for an example of a SAM that does authentication then there is one available from Oracle here:

http://docs.oracle.com/cd/E19798-01/821-1752/gizeb/index.html

Although JASPIC is yet to take off it's a good first step towards standardising security in web containers and avoids the need for each to have their own proprietary solution, although there is still the issue of different containers using different deployment descriptors hindering the portability of apps.

GlassFish Web Service application security Web application Java EE app Java (programming language) authentication Service provider interface

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Securing Cloud-Native Applications: Tips and Tricks for Secure Modernization
  • Beyond Coding: The 5 Must-Have Skills to Have If You Want to Become a Senior Programmer
  • Key Elements of Site Reliability Engineering (SRE)
  • Use AWS Controllers for Kubernetes To Deploy a Serverless Data Processing Solution With SQS, Lambda, and DynamoDB

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: