Web app security using Struts, servlet filters, and custom taglibs

Ready-made components easily add security to your Web projects

Web-based business applications need stringent security regulations. Within an application, each different role requires a predetermined set of access rights. In this article, Swaminathan Radhakrishnan explains how you can use Struts, taglibs, and servlet filters to develop a powerful and flexible security model that can be used directly by almost any Web-based business application.

Share:

Swaminathan Radhakrishnan (SwaminathanR@infosys.com), Analyst, Infosys Technologies Ltd.

Swaminathan Radhakrishnan has more than six years of industry experience and is currently working as an analyst for Infosys Technologies Ltd. He holds master's degrees in both software systems and mathematics. He has been involved with J2EE since its inception and is currently working on the design of a large-scale mortgage fulfillment application. Contact him at SwaminathanR@infosys.com.



02 September 2004

Enterprise-level business applications need rigorous security regulations with varying roles; each role also requires its own set of access control lists. These roles become more important in Web-based applications, which are accessible to a wider audience. In most cases, application security must control access to each attribute that's visible on the screen.

In this article, you will develop a generic security solution that can be used by most enterprise-level Web applications. You will address the problem of Web application security by breaking it into two smaller, manageable units:

  • Page-level security, which involves access control at a page level
  • Attribute-level security, which involves access control at an attribute level

Why split the problem along these lines? You can solve these two problems using different technologies in the J2EE space. As you may have guessed by now, page-level security is coarse-grained security, in which the user either is allowed or denied access to a particular page. On the other hand, attribute-level security is enforced at a very granular level, with security checks performed on each attribute that's displayed on the screen.

In a typical organization, many users play multiple roles, and a good security architecture recognizes this. Thus, you can assume that your users are allowed to play multiple roles within the application. With this scenario as the project, and already split into manageable units, you're ready to delve right into the solution.

The Intercepting Filter pattern

The servlet filters introduced with version 2.3 of the Java Servlet specification lend themselves towards a solution for the page-level security problem. I will detail the workings of Servlet filters here; you can download the Servlet 2.3 specs (see Resources) and learn more about them. You will write a security filter that performs the necessary checks to ensure that the user accessing a page is allowed to view that page. Because the security check must be performed for each user, you will encapsulate this logic into a helper Java class and store it in the user's session. For the sake of performance, you will cache the user's security profile into this class so you do not have to make a database call every time a request is made to the application. In this application, security role information is stored in a database, but you could easily rewrite you code to store it somewhere else, like in an XML file. I will not get into the details of the security schema either, as this can be specific to each application. The security class is an implementation of the SecurityHelper interface, which is illustrated in Listing 1.

Listing 1. The SecurityHelper interface
   ...
   public interface SecurityHelper {
     //method to check page level access 
     public boolean isAccessAllowed(String uri);

     //method to check if the attribute can be viewed by the user
     public boolean isViewableField(String page, String attribute);

     //method to check if the attribute can be edited by the user
     public boolean isEditableField(String page, String attribute);

     //method to refresh the cached user roles if there is some change
     public void refreshCache();
   }

The SecurityFilter class uses the SecurityHelper class, illustrated in Listing 2, to perform the page-level checks. The method isAccessAllowed(uri) is used to see if a user has permission to view or modify the page specified by uri. The actual page that is displayed can vary depending on the result of processing. However, I assume here that each individual URI will, when passed to isAccessAllowed(), result in one of a related set of pages; if it does not, then you can modularize the application to achieve this effect. To perform the security checks, override the Java Servlet specification's doFilter() method, as shown in Listing 2.

Listing 2. The SecurityFilter class
  ....
  public class SecurityFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse res,
                    FilterChain chain) throws IOException, ServletException {
        ...
        //Get the user's security profile of the user from the session 
        //If the session is invalid, redirect to some login/invalid page.
        SecurityHelper userSecObj = session.getAttribute(SECURITY_PROFILE);
        ...
        //Compare the current URI with the access associated with the access 
        //to that URI for the role using the userSecObj. 
        accessAllowed = userSecObj.isAccessAllowed(requestUri);
        if(accessAllowed) {
          //If the user is allowed access to the URI, let the flow proceed as normal
          chain.doFilter(request, response);
        } 
        else{
          //if the user is not allowed access, you can redirect him to an error page.
          response.sendRedirect("AccessDenied.jsp");
        }
    }
      ...
  }

Listing 2 is the core of the page-level filter. This code assumes that the user's profile (or role) is already in the session when the request comes to the filter. Since you are not assuming any single form of authentication, you can use this model in conjunction with tools like SiteMinder (see Resources), which can do the authentication for you. You get the URI from the request object. You then compare the access permissions that the user's current roles have for the requested URI and proceed according to those permissions. Note that you can make this comparison with a list of user roles, if the application mandates that each user play multiple roles; the logic for that would be embedded in the implementation for the SecurityHelper class.

Now that you have taken care of the page-level security, I'll move on to the second part of the challenge, which is to ensure that the user does not view or modify any attribute that he or she should not have access to.


JSP custom tags and Struts

You will develop custom JSP tags to achieve field-level security checks. (If you're unfamiliar with custom JSP tags, check out the tutorials on the subject listed in Resources.) You will use custom security tags for each type of component that you plan to display, such as a combo box or a text field. You will use the SecurityHelper class outlined in Listing 1 for the access rights checks. You will also leverage the tags developed in Struts to build custom security tags. Struts has implementations for most HTML tags and supports most attributes that are required for these tags. The SecurityHelper class methods isEditableField() and isViewableField() hase the logic for ensuring that the displayed field has the required permission for the roles that the user plays, and makes the component visible or disabled, accordingly.

Listing 3. The SecurityCombo class
    ....
    public class SecurityComboTag extends org.apache.struts.taglib.html.SelectTag {
        //this attribute stores the attribute that's being shown on the screen.
        private String attribute;
        //this attribute stores the page that's being shown
        private String page;
        ...
        public int doStartTag() throws JspException{
            //check the access using the SecurityHelper class
            //Helper instance is obtained from the session
            ...
            isViewable = securityHelper.isViewableField(page, attribute);
            if(!isViewable) {
                return SKIP_BODY;
	    }
	    isModifiable = securityHelper.isViewableField(page, attribute);
            if(!isModifiable) {
                setDisabled(true);
            }
	    ...	    
        }
    }

Listing 3 shows a sample implementation for a drop-down box. The class has two attributes: one for storing the name of the attribute that's currently being rendered using the select tag, and one for the page on which the tag is present. You then pass on the page and the attribute to the SecurityHelper class's methods to see if the user is allowed to view and/or modify the particular attribute, and change the display accordingly. Since this piggybacks onto the Struts implementation, you do not have to render the tag, but can just concentrate on the security aspect of it. Also, all the security logic is embedded in the implementation of the SecurityHelper class, thus keeping the security check code in a central place.


Running the code

To try out the security framework outlined here, you need a Web container that supports Servlets 2.3 or higher. Apache Tomcat works for this purpose; get the download info for it from Resources. The latest version of Tomcat has the required support for this security implementation. The framework also relies on the taglibs that are defined in Apache Struts; you can download this from Resources as well. Finally, if you want to look at the skeleton of the code samples given above, click the Code button at the top or bottom of this article. The sample zip file, wa-webappcode.zip, contains SecurityHelper.java, SecurityFilter.java, and SecurityCombo.java.


In conclusion

In this article, you have developed a powerful Web-based security architecture that is flexible enough to cater to a wide range of Web-based applications. You have also leveraged existing technologies such as Struts, which have helped maintain a clean separation of security and presentation code. You can also plug the security model into any existing application; it works well with third-party authentication providers.

Attribute-level security, although a useful feature in most applications, is often ignored because of the effort involved in its implementation and the degrading effect it has on application performance. The architecture defined in this article makes it easy to implement this useful feature without compromising on performance. The architecture also helps you maintain a clean separation between the security requirements and the functional requirements of the application. You, as the application developer, can concentrate on developing the business functionality without worrying about the security aspects, and your application is easier to maintain.


Download

DescriptionNameSize
Code samplewa-webappcode.zip2KB

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Web development on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=32202
ArticleTitle=Web app security using Struts, servlet filters, and custom taglibs
publish-date=09022004