Add CORS management with Tomcat and Angular-Js

In one of my projects, I decided to setup a SOA architecture using Angular-Js as the UI layer. My main focus is to have a clear separation between the business and the presentation. Another benefit of this is that it is possible the use different servers to these 2 parts.
But doing this causes an issue, because of security, an Ajax request cannot connect to a server which is in another domain from where it is originated. It is done like that to avoid some malicious code executed in a page sends information to another server but in my case, it’s a problem. This behavior is called the Cross-origin Resource Sharing and fortunately, most modern browsers (it excludes IE) can deal with this but the server needs more configuration.
On the server side (Tomcat), there is a provided filter that we need to add to our web configuration (CorsFilter).
In the web.xml, we add:

<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
    <init-param>
        <param-name>cors.allowed.origins</param-name>
        <param-value>*</param-value>
    </init-param>
    <init-param>
        <param-name>cors.allowed.methods</param-name>
        <param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE</param-value>
    </init-param>
</filter>

I added also some parameters but the default values should be enough.

Now, the server can manage the headers sent by the browser and with this configuration, the filter will automatically allow the request, it is also possible to configure the filter to restrict access to certain domains, but in my case, as I am already in a restricted network, it is not needed.

Another issue I encountered was with the web session. My services need an authenticated user, it is done using an authentication page and a web session. But when the CORS principle is used, by default, the browser does not send the session cookie, to enable it, I added in my Angular app:

var classNotFound = angular.module('classNotFound', ['ngRoute', 'ui.bootstrap', ...])
	.config(['$httpProvider', function($httpProvider) {//mandatory to enable cors feature (http://en.wikipedia.org/wiki/Cross-origin_resource_sharing)
		$httpProvider.defaults.withCredentials = true;
	}])

Now it works!

Multithreading and Spring Security

I manage a Spring project where I need to create a new thread to launch an asynchronous task. This project uses Spring Security and an Oracle proxy user (I will describe it in a future post), which means that, for each starting transaction, a call is made to the security context to get the current user.
The problem is that the new thread must access the database, then it tries to access the security context managed by Spring. But as Spring Security uses a ThreadLocal to store the security context, I receive the usual NullPointerException.
But fortunately, Spring is a well designed API and I can solve this issue by simply adding the security context to the thread:

public class CalculatorTask{
    public CalculatorTask(final Data data, final MyDao dao, final SecurityContext context) {
        super();
        this.data = data;
        this.myDao = dao;
        this.context = context;
    }

    @Override
    @Transactional
    public void run() {
        LOG.info("Starting asynchronous calculation");
        SecurityContextHolder.setContext(context);
        myDao.doStuff(data);
        //Make here some amazing action
        ...
        LOG.info("Finishing asynchronous calculation");
    }
}

Note that the context is only set in the run() method.

And how I call it:

public class MyClass {
    private static final Logger LOG = LoggerFactory.getLogger(BsBillSetServiceImpl.class);

    @Autowired
    private TaskExecutor executor;

    @Autowired
    private MyDao myDao;

    @Override
    public void calcul(final  Object data) {
        
        SecurityContext context = SecurityContextHolder.getContext();

        CalculatorTask CalculatorTask = new CalculatorTask(data, myDao, context);
        executor.execute(CalculatorTask);
        LOG.info("The calculation has been launched");
    }
}

So simple even if at the first beginning, it was more like “What the f…!!!” 😀