Skip to main content

Summary of new Security Features in Servlet 3.0

Posted by kumarjayanti on December 28, 2009 at 3:41 AM PST

Servlet 3.0 specification which is part of JavaEE 6 has many new features and some of them are in the area of security. The  post by Ron Monzillo gives a high level summary of the security features that he added in the Servlet 3.0 specification.  In this post i would like to focus on the aspect of Programmatically adding and configuring security for the servlet. Additionally i would provide links to other posts by me and team members on new security features of servlet 3.0.  You can access more information about the API's from the JavaEE 6 Javadocs here.

The ability to programmatically add a servlet to a context is useful for framework developers. For example a framework could declare a controller servlet using this method. The return value of this method is a ServletRegistration or a ServletRegistration.Dynamic object which further allows you to setup the other parameters of the servlet like init-params, url-mappings, security-constraints etc.

The addServlet() method on ServletRegistration.Dynamic can be called from a ServletContextListener and it allows adding a new servlet to the context. Then you can add servlet url-mappings and finally add the security constraints for the servlet by calling setServletSecurity.  The API class that holds the security-constraints is calledjavax.servlet.ServletSecurityElement.  

Quoting from the specification : "The javax.servlet.ServletSecurityElement argument to setServletSecurity is analogous in structure and model to the ServletSecurity interface of the @ServletSecurity annotation. As such, the mappings defined in Section 13.4.1.2, “Mapping @ServletSecurity to securityconstraint” on page 13-126, apply analogously to the mapping of a ServletSecurityElement with contained HttpConstraintElement and HttpMethodConstraintElement values, to its equivalent representation".

 In short the ServletSecurityElement can be constructed using a HttpConstraintElement which can specify the http-method independent security. Specifically there are different constructors that allow specifying the RolesAllowed (list of roles), the Transport guarantee value (CONFIDENTIAL, NONE) and the EmptyRoleSemantic (PERMIT, DENY). The value of the EmptyRoleSemantic indicates the default authorization semantic that applies (only) when rolesAllowed returns an-empty array.  There is one constructor which takes all the three things as arguments and as is obvious it would throw an IllegalArgumentException if the EmptyRoleSemantic is set to DENY but there is a non empty list of roles supplied to it.

So here is some sample code developed using NetBeans 6.8 M2. First  i would show the servlet which we are going to add programmatically :


package test;

.....

public class NewServlet extends HttpServlet {



    @Override

    public void init() throws ServletException {

    }



    @Override

    protected void doGet(HttpServletRequest req, HttpServletResponse res) 

    throws IOException, ServletException {

        PrintWriter writer = res.getWriter();

        writer.write("GET :Hello, " + req.getRemoteUser() + "\n");

    }

    @Override

    public void doPost(HttpServletRequest req, HttpServletResponse res)

    throws IOException, ServletException {

        PrintWriter writer = res.getWriter();

        writer.write("POST :Hello, " + req.getRemoteUser() + "\n");

    }



    @Override

    protected void doTrace(HttpServletRequest req, HttpServletResponse res) 

    throws IOException, ServletException {

        PrintWriter writer = res.getWriter();

        writer.write("TRACE :Hello, " + req.getRemoteUser() + "\n");

    }

}

And here is the ServletContextListener which adds the above servlet into the context using addServlet method on

ServletRegistration.Dynamic. 



package test;

.....

@WebListener()

public class NewServletListener implements ServletContextListener {



    public void contextInitialized(ServletContextEvent sce) {

        System.out.println("NewServletListener.contextInitialized called");

        try {

            ServletContext sc = sce.getServletContext();

            Class servletCl =

                    (Class) Class.forName("test.NewServlet");

            NewServlet servlet = sc.createServlet(servletCl);

            ServletRegistration.Dynamic sr =

                    (ServletRegistration.Dynamic) sc.addServlet("test.NewServlet", servlet);

            sr.addMapping("/newServlet");

            //create a security constraint element

            HttpConstraintElement constraint = new HttpConstraintElement();

            List methodConstraints =

            new ArrayList();

            //Allow GET access only to a user in role javaee

            methodConstraints.add(new HttpMethodConstraintElement("GET",

                new HttpConstraintElement(TransportGuarantee.NONE, new String[]{"javaee"})));

            //Allow POST access only to a user in role javaee and when the Transport is Secure

            methodConstraints.add(new HttpMethodConstraintElement("POST",

                new HttpConstraintElement(TransportGuarantee.CONFIDENTIAL, new String[]{"javaee"})));

            //Deny Trace access.

            methodConstraints.add(new HttpMethodConstraintElement("TRACE",

                new HttpConstraintElement(EmptyRoleSemantic.DENY)));

            ServletSecurityElement servletSecurityElement =

                new ServletSecurityElement(constraint, methodConstraints);

            //set the Servlet Security Constraints on ServletRegistration.Dynamic

            sr.setServletSecurity(servletSecurityElement);

        } catch (Exception e) {

            sce.getServletContext().log("Error during contextInitialized");

            throw new RuntimeException(e);

        }



    }



    public void contextDestroyed(ServletContextEvent sce) {

        //NOP;

    }

}



The comments in the code above show what security-constraints are being added. Note that we used the default constructor for HttpConstraintElement this would set the EmptyRoleSemantic value to PERMIT, which means allow access to all. It is equivalent to a element with no .  And then the code above creates  a list of HttpMethodConstraintElement's which specifies the method level security constraints. 

Deploy the attached Netbeans project and specify the following URL in the browser to exercise the doGet method :

http://localhost:8080/DynamicServlet/newServlet

Note that the servlet that was added from the context listener had a url-mapping to /newServlet.  Since we have specified that GET access should be allowed only for users in role "javaee" so the container would force an authentication here. Before deploying  the sample make sure you create a new File User in the adming console and make sure that the user belongs to a group with name "javaee". Then enable Default Principal to Role Mapping under the Security Tab in the admin-console.

Other Security Features in Servlet 3.0

My previous post shows the use of @ServletSecurity element and my team member nithya has posted information on two other features.

 

1. The authenticate() method on HttpServletRequest

2. The http-method-omission element

There is another method on javax.servlet.HttpServletRequest  which we have not talked about :
public void login(String username, String password)  throws ServletException; here is the javadoc for this method :


 

void login(java.lang.String username,
           java.lang.String password)
           throws ServletException
Validate the provided username and password in the password validation realm used by the web container login mechanism configured for the ServletContext.

This method returns without throwing a ServletException when the login mechanism configured for the ServletContext supports username password validation, and when, at the time of the call to login, the identity of the caller of the request had not been established (i.e, all of getUserPrincipal, getRemoteUser, and getAuthType return null), and when validation of the provided credentials is successful. Otherwise, this method throws a ServletException as described below.

When this method returns without throwing an exception, it must have established non-null values as the values returned by getUserPrincipal, getRemoteUser, and getAuthType

Parameters:
username - The String value corresponding to the login identifier of the user.
password - The password String corresponding to the identified user.
Throws:
ServletException - if the configured login mechanism does not support username password authentication, or if a non-null caller identity had already been established (prior to the call to login), or if validation of the provided username and password fails.
Since:
Servlet 3.0

 


The login method of the HttpServletRequest interface provides an alternative means for an application to control the look and feel of it’s login screens (as an alternative to Form-Based Login). 

 NOTE: an bug on this site is preventing me from attaching the sample code. Will get back once the bug is fixed.

Related Topics >>