Mocking ResourceBundle

If you want to unit test a method that depends java.util.ResourceBundle, and want to isolate bundle access code with mocking ResourceBundle, using for example, JMock Dynamic Mocking Library, you will face with a restriction, that commonly used methods, such as getString(key) are defined as final in ResourceBundle class. There is no way to extend and override final method declarations.

Luckily, there is an abstract subclass called ListResourceBundle, which can be used during unit test setups to mock ResourceBundle usage. The following is an excerpt from a unit test, that a JSF backing bean which fetches application messages from a ResourceBundle during runtime;

 

public class ApprovalPageCode {
    private ResourceBundle resourceBundle;
    public ResourceBundle getResourceBundle() {
        if(resourceBundle == null) {
            resourceBundle = ResourceBundle.getBundle("msgResources");
        }
        return resourceBundle;
    }
    public void setResourceBundle(ResourceBundle resourceBundle) {
        this.resourceBundle = resourceBundle;
    }
    public String doSuccessOperation() {
        String outcome = getResourceBundle().getString("msgSuccess");
        return outcome;
    }
}

public class TestApprovalPageCode extends TestCase {
    class MsgResourceBundle extends ListResourceBundle {
        private Object[][] contents = new Object[][]{
            {"msgSuccess","success message"},
            {"msgError","error message"}
        };
        protected Object[][] getContents() {
            return contents;
        }
   };
   public void testSuccess() {
       ApprovalPageCode pageCode = new ApprovalPageCode();
       pageCode.setResourceBundle(new MsgResourceBundle());
       String outcome = pageCode.doSuccessOperation();
       assertEquals(outcome,"success message");
   }
}

As you can see above, ApprovalPageCode needs a ResourceBundle, and creates one using property file if there is no resource bundle provided with it using its setter method. During unit test we created an inner class named MsgResourceBundle, which extends from ListResourceBundle to provide required messages, and set an instance of it into ApprovalPageCode instance before running test method. As a result, our test gets isolated from accessing file system to create resource bundle during our unit tests.

Enabling Acegi (1)

We have decided to use Acegi Security Framework in order to implement security requirements in our web based project, but might possibly have diverse security requirements, in addition to form based authentication and role based authorization, such as remoting support, domain object security, run-as capability, SSO, after invocation security, certificate based authentication which is integrated with Active Directory Services and so on.

We will most probably have to customize and modify some of its features, but Acegi definitely form a good basis for security architecture of our system. First step in making a system secure is to decide which authentication mechanism to use and characteristics of authorization process. One of our requirements is to provide users to authenticate themselves via X509 based client certificates which will be through enabling of SSL communication. Those certificates will hold distinguished name information which will further be used to validate their owners against Active Directory information. In summary, users first provide their client certificates and second their windows domain passwords to get authenticated.

Acegi provides a mechanism to implement form based authentication and allows us to obtain user credentials from any source, in our case X509 client certificates and Active Directory Server. Acegi uses Filters extensively to get its authentication and authorization services work, and each filter has its own particular role in the framework. It employs AuthenticationProcessingFilter in order to implement HTTP form based authentication. AuthenticationProcessingFilter come into process, if request url is: /j_acegi_security_check. Then it obtains username and password from request and further asks AuthenticationManager to authenticate against that information. AuthenticationProcessingFilter, as provided by Acegi, is not doing exactly what we want, it wants to extract username information itself from request, however, we want to provide this from our client certificate’s distinguished name. As a result, we extended AuthenticationProcessingFilter and modified the part in which it obtains username. Below is the modified filter;

public class TbsAuthenticationProcessingFilter extends AuthenticationProcessingFilter {
    protected String obtainUsername(HttpServletRequest request) {
        String username = null;
        X509Certificate cert = getUserCertificate(request);
        if(cert != null) {
            username = cert.getSubjectDN().getName();
        }
        return username;
    }
    private X509Certificate getUserCertificate(HttpServletRequest request) {
        if(request.isSecure()) {
            X509Certificate[] certs = (X509Certificate[]) request.
                getAttribute("javax.servlet.request.X509Certificate");
            if(certs != null) {
                return certs[0];
            }
        }
        return null;
    }
}

AuthenticationManager, then tries to authenticate user, but how? It consults its providers, for example PasswordDaoAuthenticationProvider, whether they can validate given authentication information. Unfortunately, Acegi, in its current distribution, does not provide a convenient PasswordAuthenticationDao to connect Active Directory Server and check if given username, password information is correct, but thanks God, there exists an LdapPasswordAuthenticationDao in Acegi;’s CVS repository, and we currently use it to connect Active Directory Server and perform authentication.