Archive for the ‘Spring’ Category

Customizing Spring Security with Legacy Transactions and Authorization

A few months ago at work I got stuck with a rather daunting assignment: to make Spring Security work alongside our legacy security model.

The rationale was sound. We have a legacy UI and we want a smooth transition to the new one. Which means that as much of their information, including their credentials need to carry over. Furthermore, our application runs load-balanced in the production environment and we can’t make use of sticky sessions. Which means that the solution needs to integrate with our database-backed sessions. If that was not complicated enough, there was also a lot of hidden authorization code that relied on specific properties being set in ThreadLocal.

After a few months of trial and error, I think I finally have a solution that both works and doesn’t lock the database. There are quite a few steps and the process is somewhat lengthy. For that reason, the rest of this tutorial is under the fold.
Read more

  • Share/Bookmark

Spring like Validation in DWR

One challenge of a hybrid AJAX and Spring MVC approach is consistent error handling. Since DWR does not have standard validation support, ad-hoc solutions tend to proliferate throughout the source code, leaving both the developer and the end-user confused. This is in contrast to Spring, which includes a validation as part of it’s form processing workflow. Our solution was to graft Spring-like validation on top of our DWR controllers. We’ve implemented this approach on DWR 2.0.

Our methods, exposed via DWR now look like this:

    @RemoteMethod
    @AjaxValidators(PersonalInfoValidator.class)
    public void updatePersonalInfo(PersonalInfo pi) {

Now lets look at the magic that makes this possible.

The first step is to add a filter in the allow section of the dwr.xml configuration file.

    

This line allows you to intercept a call on a dwr method and process any annotations that you might have added on the method (such as @AjaxValidators). The next step is to implement an AjaxFilter. This class has to process the annotations, find the appropriate bean, then preform the validation.

public class AjaxValidationFilter implements AjaxFilter {

    private ApplicationContext applicationContext;

    public AjaxValidationFilter() {
        applicationContext = (WebApplicationContext) ThreadContext.get(ThreadLocalSpringCreator.BEAN_FACTORY_KEY);
    }

    public Object doFilter(Object obj, Method method, Object[] params, AjaxFilterChain chain) throws Exception {
        AjaxValidators ann = method.getAnnotation(AjaxValidators.class);
        boolean throwErrors = false;
        if(ann != null) {

            int lastParamToValidate = Math.min(params.length, ann.value().length);
            BindException[] errors = new BindException[lastParamToValidate];

            for(int i = 0; i < lastParamToValidate; i++) {
                Validator validator = getValidator(ann.value()[i]);

                // allow skipping un-validated arguments by passing null
                if(null != validator) {
                    Object param = params[i];
                    errors[i] = new BindException(param, "");
                    ValidationUtils.invokeValidator(validator, param, errors[i]);

                    if(!throwErrors && errors[i].hasErrors()) {
                        throwErrors = true;
                    }
                }
            }
            if(throwErrors) {
                throw new net.vijedi.ajax.validation.AjaxValidationException(errors);
            }
        }

        // if everything went well no exceptions have been thrown,
        // and we can call the actual method
        return chain.doFilter(obj, method, params);

    }

    private Validator getValidator(Class validatorClass ) throws Exception {
        if(validatorClass == null) return null;
        String[] possibleValidators = applicationContext.getBeanNamesForType(validatorClass);
        return (Validator) applicationContext.getBean(possibleValidators[0]);
    }
}

There’s a few things of note. First is that the value of the annotation is an array. Therefore, you can have one validator per argument to your DWR method. Secondly, we need access to the context where the DWR beans are defined, so that we can find the correct instance of the validator. We use an instantiated bean so that we can inject Managers and other properties into the validator to validate business layer requirements (such as searching the database for name conflicts).

The AjaxValidationException class is a normal runtime-exception class that contains an array of org.springframework.validation.Errors objects for errors. It then internally translates this information into a list of NameValue pairs for easy access in javascript. This is our approach, but there are other ways to do this.

Now all errors will be marshaled into a class that has the property javaClassName set to net.vijedi.ajax.validation.AjaxValidationException. This allows you to do whatever you need in your error handler. The simplest thing to do is update the contents of a placeholder div by looping through the errors array. However, if your exception can give you name-value pairs, then it’s entirely possible to highlight specific form fields.

  • Share/Bookmark

Business Logic Layer Security and Transactions with Annotations

Not too long again, my place of employment switched to using the Acegi framework for security. The major reasons for this switch were the large user community using Acegi and it’s officially the “Security System for Spring.” One of the loose ends that we didn’t tie up as part of the initial migration was method level security declared with Java 1.5 Annotations. Our old security system had it, but it was practically unused (since the web layer performed the same checks), so we just chucked it. Unfortunately, adding the functionality back it was not as easy as we would have liked. This post is basically an overview of how we got Acegi to use Spring AOP for method level security and still play nice with our transactional support.

We already had our transactional support configured before we started implementing method level security. Like our security, we had this configured with annotations. Our pattern is to annotate our business logic interfaces. The corresponding implementation remains un-marked. This is an example of how our business interface looked before security.

@Transactional
public interface UserManager {

    User createUser(String login, String password);

    @Transactional(readOnly=true)
    User getUser(String userId);

    User deleteUser(String userId);
}

Spring’s AOP support reads the @Transactional annotation on these interfaces and intercepts the method invocation to add a transaction around it. Getting Spring to perform this dark magic is as simple as adding a few lines to your spring context xml file.

First, you need to tell Spring to do it’s AOP magic.

    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

This bean definition tells Spring to check for potential AOP advice (ie, method interceptors) to run on a classes method at bean creation time. Anytime your bean is injected into another class, you will get a aop-aware, proxied version, instead of your vanilla concrete implementation. In order to add transactional “advice” to your proxied version, the following lines need to go into your spring context configuration.

    <bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
        <property name="transactionInterceptor" ref="txInterceptor"/>
    </bean>

    <bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionManager" ref="transactionManager"/>
        <property name="transactionAttributeSource">
            <bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"/>
        </property>

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

Since we use Hibernate, we use the HibernateTransactionManager. If you don’t use hibernate, you have a smorgasbord to choose from.

This is what we had before we tried to add method level security. To add method level security, the first step is to realize that you can only have one AOP Proxy Creator. Therefore, blindly following the tutorials on the Spring website won’t help too much. I’m also assuming that you have a working Acegi setup that does authentication at a URL level and that you have an authentication manager bean configured. Configuring that aspect of Acegi is outside the scope of this post.

We decided to use role-based authorization for our methods, so we configured a RoleVoter and an AccessDecisionManager to make decisions based on the users GrantedAuthorities. How users get granted authorities is covered in the Acegi documentation.

    <bean id='accessDecisionManager' class='org.acegisecurity.vote.AffirmativeBased'>
        <property name='decisionVoters'>
            <list><ref bean='roleVoter'/>
        </property>
    </bean>

    <bean id='roleVoter' class='org.acegisecurity.vote.RoleVoter'>
        <property name="rolePrefix" value="PERMISSION_" />
    </bean>

The standard rolePrefix is ‘ROLE_’. We just used ‘PERMISSION_’ since it maps to our egacy model more appropriately. Next, we need to configure something to read the Security annotations:

    <bean id="objectDefinitionSource" class="org.acegisecurity.intercept.method.MethodDefinitionAttributes">
      <property name="attributes">
        <bean class="org.acegisecurity.annotation.SecurityAnnotationAttributes" />
      </property>
    </bean>

Then we put it all together by creating a security interceptor and adding it to the chain of advisors that the proxy will call before the method invocation.

    <bean class="org.acegisecurity.intercept.method.aopalliance.MethodDefinitionSourceAdvisor">
        <constructor -arg>
            <ref bean="methodSecurityInterceptor" />
        </constructor>
    </bean>

    <bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
        <property name="validateConfigAttributes"><value>true</value>
        <property name="authenticationManager"><ref bean="authenticationManager"/>
        <property name="accessDecisionManager"><ref bean="accessDecisionManager"/>
        <property name="objectDefinitionSource"><ref bean="objectDefinitionSource"/>
    </bean>

Finally, we can annotate our classes. If we wanted to ensure that only users with the permission to create a user (PERMISSION_UserCreate) then we need to add ‘@Secured({“PERMISSION_UserCreate”})’ to the correct method on the interface. Our final interface looks like:

@Transactional
public interface UserManager {

    @Secured({"PERMISSION_UserCreate"})
    User createUser(String login, String password);

    @Transactional(readOnly=true)
    User getUser(String userId);

    User deleteUser(String userId);
}

Viola! Users without the correct permissions will no longer be allowed to create new users.

Unfortunately, things aren’t ever that simple, and we ran into one pretty major issue. A good chunk of our beans in the business logic layer didn’t get proxied. Therefore, we got neither transactions nor security on these beans. To add the confusion, the business-logic calls failed in a very odd way. Whenever we did an update or create on a persisted model object, we got a:

org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove ‘readOnly’ marker from transaction definition.

This, of course, was totally unhelpful, since we didn’t have a readOnly marker on our transaction definition, and we were pretty sure that we were setting our FlushMode in our transaction interceptor. Removing the security annotations stuff made the problem go away again. Eventually we, realized the problem was that instead of a proxy with transaction advice and security advice, we received the configured implementation of the interface. Our interceptors hadn’t finished initializing by the time some beans were creating. The culprit turn out to be the manner in which we created our spring context files. The structure of our files was:

   <!--Transaction Stuff -->
   <!-- a lot of bean defs -->
   <!-- Security stuff -->
   <!-- Some more beans -->

Changing that to:

   <!-- Security stuff -->
   <!--Transaction Stuff -->
   <!-- a lot of bean defs -->
   <!-- Some more beans -->

made the problem go away for good. If you’re having weird issues with transactional annotations and security annotations, this would probably be a good place to look.

  • Share/Bookmark
Return top

About

This is my blog about programming. For random stuff, checkout my Twitter or Tumblr