Tag: java

Apache Tomcat 6 and the HSM

Recently I’ve had some real fun with SafeNet HSM’s (Host Security Module or Hardware Security Module) and Tomcat 6 in the never ending process of PCIDSS compliance.  People are probably going to line up to stone me after saying this but PCIDSS is a really great effort to make things safe and secure for all of us.  In a lot of cases its the stick that drives organisations to adopt some good practices.  One of which is the use of HSM’s for all things from the crypt.

Now this little rant won’t walk you through PCI compliance, rather its just about my experiences getting Safenet Eracom Orange or Blue HSM to work within Tomcat.  Deployment is really easy:

  1. Install the latest version of Java,
  2. Install the Eracom Orange C runtime,
  3. Configure the Eracom Orange runtime to connect to the HSM,
  4. Configure the HSM with tokens, keys, certificates, users and whatever else you need,
  5. Install the Eracom Orange Java runtime,
  6. Install Apache Tomcat 6,
  7. Place the Eracom Orange ‘jprov.jar‘ Tomcat’s server shared lib directory ‘CATALINE_HOME/lib‘,
  8. Restart the Tomcat server if its already running or just start it if it is not,
  9. Deploy your webapp.

Apart from steps 7 and 8 simply follow the provider’s directions for all steps.  The key in this thing is that the ‘jprov.jar‘ archive must be loaded when Tomcat starts.  I imagine that it should be the same for other providers like for IBM’s toys.

Now for the development set up.  Simply follow the same steps as above but install the SDK’s for the Eracom and include ‘jprov.jar’ as a library in your development environment.  Typically your development environment will bundle the ‘jprov.jar‘ into the web application directory.  It won’t do any harm there but to get it to work properly it will need to be in the Tomcat server’s common library directory as detailed above.  In fact you don’t really need to install the SDK’s if you have an actual HSM to play with for development purposes, but the SDK’s do provide a software HSM simulator for those of us who don’t want the expense of buying one of these things for every developer on the floor.  Plus the SDK’s will give you a good deal of documentation too.

So you are all set up and ready to build the next great crypt.  Start by building a stand alone application to confirm that everything works before going any further. Lets get to the code:

/*
 * Crypt.java
 *
 * A simple class to provide basic SDES encryption and decryption
 */
package crypt;

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Properties;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;

/**
 *
 * @author mc
 */
public class Crypt {

  /**
   * Creates a 3DES key cipher with the parameters in the config, valid
   * modes are Cipher.ENCRYPT and Cipher.DECRYPT
   *
   * @param mode set the cipher to either encrypt or decrypt
   * @param config the configuration parameters for this application
   * @param log log to write debug output to
   * @return a cipher that should be used then nulled to be thrown away
   * @throws KeyStoreException
   * @throws NoSuchProviderException
   * @throws IOException
   * @throws NoSuchAlgorithmException
   * @throws CertificateException
   * @throws UnrecoverableKeyException
   * @throws NoSuchPaddingException
   * @throws DecoderException
   * @throws InvalidKeyException
   * @throws InvalidAlgorithmParameterException
   */
  private Cipher createCipher(int mode, Properties config, Log log)
    throws
      KeyStoreException,
      NoSuchProviderException,
      IOException,
      NoSuchAlgorithmException,
      CertificateException,
      UnrecoverableKeyException,
      NoSuchPaddingException,
      DecoderException,
      InvalidKeyException,
      InvalidAlgorithmParameterException {

    log.debug("Adding provider.");
    // will gracefully not add provider if provider already loaded
    Security.addProvider(
        new au.com.eracom.crypto.provider.ERACOMProvider());

    log.debug("Getting key store instance.");
    KeyStore store = KeyStore.getInstance(
        config.getProperty("crypt.keystore.type"),
        config.getProperty("crypt.keystore.provider"));
    log.debug("Loading key store.");
    store.load(null, null);

    log.debug("Retrieving key.");
    Key key = store.getKey(
        config.getProperty("crypt.keystore.entry"), null);

    log.debug("Generating cipher.");
    Cipher cipher = Cipher.getInstance(
        config.getProperty("crypt.transformation"),
        config.getProperty("crypt.provider"));

    log.debug("Creating initialisation vector.");
    IvParameterSpec i = new IvParameterSpec(Hex.decodeHex(
        config.getProperty("crypt.vector").toCharArray()));

    log.debug("Initialising cipher in the given mode.");
    cipher.init(mode, key, i);

    return cipher;
  }

  /**
   * Takes a string and returns its equivalent Base64 encrypted string.
   *
   * @param data string to be encrypted
   * @param config parameters for this application's encryption
   * @param log log to write debug output to
   * @return encrypted Base64 encoded form of the data string parameter
   * @throws NoSuchAlgorithmException
   * @throws NoSuchProviderException
   * @throws NoSuchPaddingException
   * @throws InvalidKeyException
   * @throws IllegalBlockSizeException
   * @throws BadPaddingException
   * @throws InvalidAlgorithmParameterException
   * @throws KeyStoreException
   * @throws IOException
   * @throws CertificateException
   * @throws UnrecoverableKeyException
   * @throws DecoderException
   */
  public String b46Encrypt(String data, Properties config, Log log)
    throws
      NoSuchAlgorithmException,
      NoSuchProviderException,
      NoSuchPaddingException,
      InvalidKeyException,
      IllegalBlockSizeException,
      BadPaddingException,
      InvalidAlgorithmParameterException,
      KeyStoreException,
      IOException,
      CertificateException,
      UnrecoverableKeyException,
      DecoderException {

    log.debug("Encrypting data.");
    byte[] encrypted =
        createCipher(Cipher.ENCRYPT_MODE, config, log).doFinal(
            data.getBytes());

    log.debug("Base64 encoding data.");
    String encoded = new String(Base64.encodeBase64(encrypted));

    return encoded;
  }

  /**
   * Takes a encrypted Base64 encoded string and returns its equivalent
   * decrypted string.
   *
   * @param data string to be encrypted
   * @param config parameters for this application's encryption
   * @param log log to write debug output to
   * @return encrypted Base64 encoded form of the data string parameter
   * @throws NoSuchAlgorithmException
   * @throws NoSuchProviderException
   * @throws NoSuchPaddingException
   * @throws InvalidKeyException
   * @throws IllegalBlockSizeException
   * @throws BadPaddingException
   * @throws InvalidAlgorithmParameterException
   * @throws KeyStoreException
   * @throws IOException
   * @throws CertificateException
   * @throws UnrecoverableKeyException
   * @throws DecoderException
   */
  public String b64Decrypt(String data, Properties config, Log log)
    throws
      NoSuchAlgorithmException,
      NoSuchProviderException,
      NoSuchPaddingException,
      InvalidKeyException,
      IllegalBlockSizeException,
      BadPaddingException,
      InvalidAlgorithmParameterException,
      KeyStoreException,
      IOException,
      CertificateException,
      UnrecoverableKeyException,
      DecoderException {

    log.debug("Base64 decoding data.");
    byte[] decoded = Base64.decodeBase64(data.getBytes());

    log.debug("Decrypting data.");
    byte[] decrypted =
        createCipher(Cipher.DECRYPT_MODE, config, log).doFinal(decoded);

    return new String(decrypted);
  }

}

So that’s it, very straight forward but lets take time to look at one or two points of interest.

In a nutshell functionally this is a class that can be used to encrypt and decrypt data using stored 3DES keys. Note that the configuration information is all passed in via the properties parameter. Also note that the class uses base64 encoding because its easier to play with and store strings. Generally you would also want to replace unsafe base64 characters too if the storage unit required it.

On the encryption front there are a few things to note too. Take a look at the includes, as far as the crypt mechanisms it uses only the standard Java imports and practices. There is only one thing that is specifically from the Safenet SDK, the loading of the provider class in the following snippet:

    // will gracefully not add provider if provider already loaded
    Security.addProvider(
        new au.com.eracom.crypto.provider.ERACOMProvider());

To complete the picture here is the main class and the configuration file to go with it. That’s the lot; three simple files and it should be all go to test your configuration.

/*
 * main.java
 *
 * Test application for the Eracom encryption devices.
 */
package crypt;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author mc
 */
public class Main {

  /**
   * @param args the command line arguments
   */
  public static void main(String[] args) throws IOException {

    Properties config = new Properties();
    Log log = LogFactory.getLog(Main.class);
    boolean encrypt = "encrypt".equalsIgnoreCase(args[0]);

    config.loadFromXML(new FileInputStream(args[1]));

    try {

      if(encrypt)
        System.out.println(
          new Crypt().b46Encrypt(args[2], config, log));
      else
        System.out.println(
          new Crypt().b64Decrypt(args[2], config, log)); 

    } catch(Exception e) {

      log.error(e.getLocalizedMessage(), e);
    }

  }

}




  
  ERACOM
  au.com.eracom.crypto.provider.ERACOMProvider
  DESede/CBC/PKCS5Padding
  AAAAAAAA00000000
  ERACOM
  CRYPTOKI
  KeyName

Once this is working it should be possible to use the same crypt class file in a Tomcat hosted web application with one slight adjustment. As the Tomcat service will load the provider you should not attempt to load the provider in your application. In fact if you try it will almost certainly fail as your application is unlikely, unless you have specifically configured it, will not have the privileges need to load classes. So just comment out the ‘Security.addProvider‘ call in the class.

So that’s it; all you needed to know to configure an HSM to start working with Tomcat. Simple wasn’t it? Now all you need to do is figure out how to use it to help you with PCIDSS and how to change the crypt file to suite your specific needs.


LDAP Attributes in JNDI

Almost everything that you do with LDAP concerns the retrieval and manipulation of attributes. Due to the extensible nature of attributes finding out their types and content can be quite involved. Here is a simple sample code snip to the very basic of attribute look up including type information.

    /**
     * printAttributes
     *
     * Prints the attributes listed in ats to the stream defined by s.  If ats
     * is null all attributes will be listed.  If ats is empty none will be
     * listed.
     *
     * example:
     *      String obj = "uid=admin,ou=system";
     *      String[] ats = {"uid","displayName"};
     *      printAttributes(ctx,obj,ats,System.out);
     *
     *
     * @param ctx initial directory context
     * @param obj object in directory to retrieve attributes for
     * @param ats attribute list of attribute names to retrieve, null for all
     * @param s stream to write the attributes to
     * @throws javax.naming.NamingException
     */
    public static void printAttributes(InitialDirContext ctx, String obj,
            String[] ats, PrintStream s) throws NamingException {

        Attributes a = ctx.getAttributes(obj, ats);
        NamingEnumeration e = a.getAll();

        while (e.hasMore()) {

            Attribute t = (Attribute)e.next();

            s.println("<attribute name=\"" + t.getID() + "\">");
            s.println("      <syntax>" + t.getAttributeSyntaxDefinition().getAttributes("") + "</syntax>");
            s.println("      <schema>" + t.getAttributeDefinition().getAttributes("") + "</schema>");
            NamingEnumeration f = t.getAll();

            while (f.hasMore()){

                Object z = f.next();
                s.println("      <value>" + z + "</value>");
            }

            s.println("</attribute>");
        }

    }

This produces output that looks something like this:


    <attribute name="cn">
      <syntax>{x-schema=X-SCHEMA: system, x-is-human-readable=X-IS-HUMAN-READABLE: true, numericoid=NUMERICOID: 1.3.6.1.4.1.1466.115.121.1.15}</syntax>
      <schema>{name=NAME: cn, commonName, substr=SUBSTR: caseIgnoreSubstringsMatch, x-schema=X-SCHEMA: system, syntax=SYNTAX: 1.3.6.1.4.1.1466.115.121.1.15, numericoid=NUMERICOID: 2.5.4.3, sup=SUP: name, desc=DESC: RFC2256: common name(s) for which the entity is known by, usage=USAGE: userApplications, equality=EQUALITY: caseIgnoreMatch}</schema>
      <value>developer</value>
    </attribute>

Batch Posting to a Website

Ok so this is mostly about me playing with the Google syntax highlighter.  Its basically some code I rattled up to post data from a | seperated list of post_variable|post_value pairs.  Read the code to find out more.  Its not a real solution to anything if you want to run tests or batch stuff use Junit, Maven or Ant.  But you can have fun with my limited toy if you like – but remember as always the code is GPL and will probably kill you so watch out!

/*
 * Batch processor that takes | delimitied lines of fields in a file and posts
 * them to an HTTP server printing out the message and response to std out.
 */

/*
 * TODO:
 * Could be extended to use a configuration file for inputs, logging and could
 * bennefit from SSL and proxy configuration options.
 */
package batchpost;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLEncoder;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author mc
 */
public class batchpost {

  /**
   * General output device
   */
  static private Logger log = Logger.getLogger(batchpost.class.getName());

  /**
   * main
   *
   * Main entry point.
   *
   * @param args the command line arguments
   *   args[0] - is the fully qualified name of the batch file to read
   *   args[1] - is the URL to post the transactions to
   */
  public static void main(String[] args) {

    /*
     * TODO:
     * I should validate arguments  and do other things but I am skipping doing
     * them because of time.
     */

    processFile(args[0], args[1]);
  }

  /**
   * processFile
   *
   * Takes a file apart one line at a time and hands processing off to a
   * message processing method.  Logs errors if the file is not found or there
   * is an IO error while reading the file.  Assumes that each line contains a
   * complete message.
   *
   * @param url - path to the web server to send the messages to
   * @param file - file to retrieve the message lines from
   */
  static private void processFile(String url, String file) {

    try {

      String line;
      BufferedReader br =
          new BufferedReader(
          new InputStreamReader(
          new DataInputStream(
          new FileInputStream(file))));

      try {

        while ((line = br.readLine()) != null) {
          processMessage(url, line);
        }

      } catch (UnsupportedEncodingException ex) {

        log.log(Level.SEVERE, "processFile - processing halted because it is " +
            "not possible to encode  the post string in UTF-8.", ex);
      } catch (IOException ex) {

        log.log(Level.SEVERE, "processFile - IO exception has halted " +
            "processing of the file \"" + file + "\".", ex);
      }

      try {

        br.close();

      } catch (IOException ex) {

        log.log(Level.SEVERE, "processFile - IO exception has interrupted " +
            "closing of the file \"" + file + "\".", ex);
      }
    } catch (FileNotFoundException ex) {

      log.log(Level.SEVERE, "processFile - unable to locate the file \"" +
          file + "\".", ex);
    }
  }

  /**
   * processMessage
   *
   * Takes a line of | delimited message fields and posts them to a web server.
   * Each line is composed of a list of field_name|field_value pairs such that
   * the line looks like:
   *
   *    name_1|value_1|name_2|value_2|...
   *
   *    or
   *
   *    name|bob charles|age|62|occupation|pro golfer
   *
   * The total number of | delimited fields must be a multiple of 2.  The
   * message fields must not contain a |.
   *
   * @param url - address of the web server to post this message to
   * @param line - string containing a | delimited set of fields
   * @throws java.io.UnsupportedEncodingException when the platform does not
   *    support utf-8
   */
  static private void processMessage(String url, String line)
      throws UnsupportedEncodingException {

    String[] fields = line.split("\\|");
    if (fields.length % 2 == 1) {
      log.log(Level.SEVERE, "processMessage - unable to process the following" +
          " message as it did not contain a multiple of 2 fields: message = " +
          "\"" + line + "\"");
      return;
    }
    String postData = createPostData(fields);

    log.log(Level.INFO, "START OF DATA TO BE POSTED");
    log.log(Level.INFO, postData);
    log.log(Level.INFO, "END OF DATA TO BE POSTED");

    String responseData;
    responseData = doHTTPPost(url, postData);

    log.log(Level.INFO, "START OF DATA RECEIVED FROM POST");
    log.log(Level.INFO, responseData);
    log.log(Level.INFO, "END OF DATA RECEIVED FROM POST");
  }

  /**
   * createPostData
   *
   * Takes an array of field names and their values such that each two
   * consecutive strings are a field name then value pair and prepares a POST
   * data string for sending to a web server.  Throws the encoding error as it
   * is pointless to continue processing as this error is going to reccur for
   * all post attempts if it takes place for one.
   *
   * @param fields - a string array of field name and value pairs.
   * @return string containing the post data.
   * @throws java.io.UnsupportedEncodingException
   */
  static private String createPostData(String[] fields)
      throws UnsupportedEncodingException {

    StringBuffer buf = new StringBuffer();
    String charEnc = "UTF-8";

    try {

      buf.append(URLEncoder.encode(fields[0], charEnc));
      buf.append('=');
      buf.append(URLEncoder.encode(fields[1], charEnc));

      for (int i = 2; i < fields.length; i = i + 2) {

        buf.append('&');
        buf.append(URLEncoder.encode(fields[i], charEnc));
        buf.append('=');
        buf.append(URLEncoder.encode(fields[i + 1], charEnc));
      }

      return buf.toString();
    } catch (UnsupportedEncodingException ex) {

      log.log(Level.SEVERE, "createPostData - unable to encode the post data " +
          "as " + charEnc + " is not available on this platform.", ex);
      throw ex;
    }

  }

  /**
   * readAll
   *
   * Reads all of the input from the given stream and returns it in a byte array
   * output stream, the stream contents can then be retrieved as a byte array or
   * a string using either toByteArray or toString respectively.
   *
   * @param is - an open input stream to read the data from
   *
   * @return a byte array output stream that contains the data read from the is
   * @throws IOException if there is an error reading from the input stream
   */
  static private ByteArrayOutputStream readAll(InputStream is)
      throws IOException {

    ByteArrayOutputStream result = new ByteArrayOutputStream();
    byte[] buf = new byte[1024];

    int len = is.read(buf);

    while (!(len < 0)) {

      result.write(buf, 0, len);
      len = is.read(buf);
    }

    return result;
  }

  /**
   * doHTTPPost
   *
   * performs the https post operation of the given data to the given url
   * returning the result in a byte array output stream, throws an exception if
   * an error takes place while performing io operations, does not deal with
   * proxy servers
   *
   * @param data - a post formatted data stream for sending to the url server
   * @param url - the target to send the post to
   *
   * @return a data stream of the response from the server at the url
   * @throws IOException on failure of any io operation
   */
  static private String doHTTPPost(String url, String data) {

    String result = "";
    HttpURLConnection conn = null;

    try {

      // set up the url connection
      conn = (HttpURLConnection) (new URL(url)).openConnection();
      try {

        // write out the data to the server
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        conn.getOutputStream().write(data.getBytes());
        System.out.println(conn.getResponseMessage());

        // disconnect and recycle the connection, return the response data
        result = readAll(conn.getInputStream()).toString();
      } catch (ProtocolException ex) {

        log.log(Level.SEVERE, "doHTTPPost - unable to marshal the required " +
            "protocol to establish a connection to \"" + url + "\"", ex);
      } catch (IOException ex) {

        log.log(Level.SEVERE, "doHTTPPost - IO error while attempting to " +
            "perform the data post operation.", ex);
      } finally {

        conn.disconnect();
      }

    } catch (MalformedURLException ex) {

      log.log(Level.SEVERE, "doHTTPPost - the URL currently being attempted " +
          "to connect with is malformed \"" + url + "\"", ex);
    } catch (IOException ex) {

      log.log(Level.SEVERE, "doHTTPPost - IO error while attempting to set up" +
          " the data post operation.", ex);
    } finally {

      conn = null;
    }

    return result;
  }

}

Do you have a Spring in your Wheel?

Spring is one of the frameworks of the moment but is it really a great framework or something entirely different? Most of the frameworks that I know of are fairly targeted and form a particular function. All of the good ones that I know of have a particular place in life; a frame work for doing some thing. Spring does not. But there’s gold in that there code…

Probably the most disappointing thing about Spring is its documentation. The entry barrier for integrating Spring with the rest of your tool set is quite high by its limited documentation. Yes there is a great volume of the stuff, but it appears to be limited to those who are already in ‘the know’. In other words if you really want to get a handle on Spring from scratch you have two choices: either buy a book or surf the web and hope.

But this is because we’ve been mislead. Struts is a framework, Spring is not. So a conclusive introduction to Struts is easy to write and easy to understand because it frames an idea. However as Spring does not frame a central idea and so writing an introduction to Spring is almost a lost cause from a framework point of view.

Spring is an SDK. A jolly brilliant SDK. When you look at the Spring development kit you find that it will work with what you have, doesn’t force a great monster of a framework on you and it riddled with simply brilliant concepts and patterns. As you start to delve into it you realise that the guys who put it together have brought together a great collection of conceptual gems. If you keep watching the SDK grow you will see more and more of them being added to the SDK as components for use in groups or by themselves.

Underlying all of these gems is a strong theme of patterns and approaches to design that pervades all corners of the SDK making it feel and look like a slick whole. These concepts include such things as the pervasive use of IOC accross the board to the modular adoption of specific patterns like MVC, which IS a framework, that are included in such a way as to let the designer include or exclude them in accordance with usefulness. In most ‘frameworks’ that I’ve seen its either all features or a difficult configuration to remove unwanted bloat.

So is Spring a case against bloat ware? No. Bloat ware is a term given to things that produce copious quantities of bulk which could easily be replaced by more stream lined solutions. When you see a product that makes you think ‘surely that could be done with less’ you’re probably looking at bloat ware. Spring is not there for that purpose. You see almost everything it does belongs to the school of computing that is termed ‘middle ware’. Middle ware is almost by definition bloat.

However tempting to label Spring as bloat ware it does perform two very critical tasks often overlooked by those bloat ware vigilantes out there; it makes your software manageable. Everything that Spring does could be pared back to make it faster more efficient etc but you could barely dent it at the cost of making your software less easy to design, implement, install and operate. Carefully add Spring to your project and you are adding real value in terms of future proofing your product and saving yourself a ton of grief.

So if this is a SDK how does it compare to other SDK’s? To answer this question you need to think about perspective. If you look at the JDK, the standard C/C++ libraries, X windows xt or even Microsoft’s extensive .Net SDK you will find products that are built bottom up. That is products that have been built from a wide array of small useful components into a general smorgasbord of fancy components and knick knacks. Spring is built the other way around, it has been built from concepts to components. So when you look at Spring you see a large number of cohesive modules rather than the gravel and rocks of most other SDK’s. Effectively Spring takes the concepts and makes them real relying on other foundational tool kits to get the simple things in life done. Top down.

So Spring is not a framework, it is not a way of protecting you from bloat ware, it is an implementation of concepts, patterns and design built on the basics for you to cherry pick as you please and improve your product and its operation. Its an SDK like so many others; hardly a reinvention of an old wheel, but a new sporty set of spokes to use in building your own.


Pattern: Web Application Security Filter

Pattern Name: Web Application Security Filter

Classification: Structural Filter

Intent:

Isolates authentication and authorisation from the application by filtering requests before they are received by the application so that authentication and authorisation may be easily applied to existing applications and managed seperately from other aplication concerns.

Motivation:

Incorporating authentication and authorisation security protocols into an Internet application is generally complex and when done improperly can lead to significant exposure to abuse and maluse. Due to the complex nature of implementing these security features significant risk is encountered when security code is combined with application code. This pattern is based on the generic filter and observer patterns allowing the seperation of security concerns from the development and management of the application and hopefully providing a better quality of service.

Filters provide an excellent opportunity for seperating security concerns from your web application. Because they intercept the incoming requests to your site before the site even sees them you can even apply the same filter pattern to existing sites without too much alteration. Combined with the power of directory services the pattern can be applied to both authentication and authorisation.

A filter is a special type of the decorator pattern because it allows the data being transmitted not only to be decorated but altered or even replaced altogether. Security functions naturall lend themselves to filter type implementations, perhaps the most well known type of filter implented today is the NetFilter or firewall. Network filters while suitable for addressing network traffic issues are not really suitable for application security, which after the network and operating system produce the most opportunities for security breaches.

Also Known As:

No alternate designs or implementations meeting the pattern are currently known

Applicability:

Any hosted application has the potential to bennefit from deployment of an implementation of this pattern. Also due to the generic nature of this pattern it would suit almost any web aplication container where the container supports filtered access to its hosted applications.

In addition to the basic objectives this security filter pattern can be used to address any olf the following requirements:

  • When security is required to be handled external to the application.
  • Where it is advantageous to have the same security implementation across multiple applications.
  • If security factors need to be isolated to demonstrate security processes for audit.

Structure: A graphical representation of the pattern. Class diagrams and Interaction diagrams can be used for this purpose.

security filter class diagram

Participants: A listing of the classes and objects used in this pattern and their roles in the design.

Collaboration: Describes how classes and objects used in the pattern interact with each other.

Consequences: This section describes the results, side effects, and trade offs caused by using this pattern.

Implementation: This section describes the implementation of the pattern, and represents the solution part of the pattern. It provides the techniques used in implementing this pattern, and suggests ways for this implementation.

Sample Code:

This section has a deliberately brief snip of a filter and its associated filter classes. This is an example of simplified function to higlight the general idea and not how it would be implemented for real. In reality the application container that you are using will already have something to base this on like javax.servlet.Filter so try and use that or something similar.


/*

 * Filter.java

 *

 * @author Michael Chester

 * @date 2007-03-09

 *

 * Filter interface used to chain filters, and eventually an 

 * application adapter.

 *

 * Filter class used to illustrate a simple interpretation on the 

 * securilty filter pattern, a factory should initialise the 

 * private attributes.

 */

public interface FilterInterface {

        public void doProcess(Session session, Request request,

            Response response);

}

public class EntryGate implements FilterInterface {

    /**

     * doProcess the filter action

     *

     * @param session for the current request

     * @param request the request that was sent through

     * @param response to fill out if authorisation fails

     *

     * @returns nothing

     */

    public void doProcess(Session session, Request request,

            Response response) {

        response.setResponse("performing filter");

        if(authorisor.isAuthorised(session, request, response))

            if(validator.isValidated(session, request, response))

                filter.doProcess(session, request, response);

    }

    /**

     * Holds value of property validator.

     */

    private Validator validator;

    /**

     * Holds value of property authority.

     */

    private Authorisor authorisor;

    /**

     * Holds value of property filter.

     */

    private FilterInterface filter;

}

/*

 * Authorisor.java

 *

 * @author Michael Chester

 * @date 2007-03-09

 *

 * Authorisor interface and class used to illustrate the role and

 * function of the authorisation concrete class.

 */

public interface Authorisor {

    public boolean isAuthorised(Session session, Request request,

            Response response);

}

public class AuthorisorExample implements Authorisor {

    /**

     * isAuthorised verifies the identity of the requestor

     *

     * @param session for the current request

     * @param request the request that was sent through

     * @param response to fill out if authorisation fails

     *

     * @returns true if authorised, false otherwise

     */

    public boolean isAuthorised(Session session, Request request,

            Response response) {

        /* authenticate on token */

        if(session.getAuthenticationToken() != null)

            if(session.getAuthenticationToken().equals("validToken"))

                return true;

        /* or authenticate on identity */

        if(request.getIdentity() != null)

            if(request.getIdentity().equals("validUser")) {

            /* and set a token to validate on next request */

            session.setAuthenticationToken("validToken");

            return true;

            }

        /* otherwise the identity is not authorised */

        response.setResponse("user not authorised");

        return false;

    }

}

/*

 * Validator.java

 *

 * @author Michael Chester

 * @date 2007-03-09

 *

 * Validator interface and class used to illustrate the role and

 * function of the validation concrete class.

 */

public interface Validator {

    public boolean isValidated(Session session, Request request,

            Response response);

}

public class ValidatorExample implements Validator {

    /**

     * example of a request validator, put your code here

     *

     * @param session for the current request

     * @param request the request that was sent through

     * @param response to fill out if authorisation fails

     *

     * @returns true if authorised, false otherwise

     */

    public boolean isValidated(Session session, Request request,

            Response response) {

        /* return true if the task matches */

        if(request.getTask() != null)

            if(request.getTask().equals("validTask")) return true;

        /* false otherwise */

        response.setResponse("request is not valid for user");

        return false;

    }

}

Known Uses:

Due to the nature of security applications and the way that this pattern is applied no implemented uses are mentioned here. However a number of applications are currently using this pattern hosted on the Apache Tomcat Servlet Container engine using implementations based on extending Tomcat’s own filter implementation.

Related Patterns:

This pattern is essentially an extension to or application of the already existing generic filter patterns.


Copyright © 1996-2010 Code Snips. All rights reserved.
iDream theme by Templates Next | Powered by WordPress