Tag Archives: Angular

Implementing CSRF protection with Angular-js

After 2 articles on the security, I continue with the set up of the CSRF protection using Spring security.

The main idea behind is to prevent some one else to create (forge) a request without our authorization. Imagine that a page uses JavaScript to send something like http://my.bank.com/pay/15000/cayman_account, if you are connected to your bank in another tab browser, the request could be successful…
To avoid that, for each request, the server sends a unique identifier (Spring uses a UUID) and it must be part of the request you send back to the server.

Fortunately, Angular provides a support for CSRF protection. Following the documentation, the server needs to provide a cookie named XSRF-TOKEN and Angular will send its value in a header named X-XSRF-TOKEN. On the server side, Spring then verifies that the value from the header is the expected one and continue the process, otherwise, it sends an error.

But to make them working together, we need to make some adjustments.
I use the same pet store application I used in my previous article and it is still available on github.

Let’s go to the code!
First of all, on the server side, Spring provides the identifier as a request attribute, because in a standard Spring-MVC application, it is very simple to add it in an HTML form using expression language. But with our SOA approach, we are just sending data, therefore we need to put it in the cookie we send to the browser. To do that, I defined a filter which just take the CSRF token and set a cookie:

@Component
public class CsrfInjectorFilter extends OncePerRequestFilter {

	private static final String XSRF_TOKEN = "XSRF-TOKEN";
	private static final Logger LOG = LoggerFactory.getLogger(CsrfInjectorFilter.class);

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
			throws ServletException, IOException {

		CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
		if (csrfToken != null) {
			Cookie cookie = new Cookie(XSRF_TOKEN, csrfToken.getToken());
			//mandatory to avoid duplicate cookies in browser
			cookie.setPath("/");
			response.addCookie(cookie);
		}else {
			LOG.debug("No csrf token found!!");
		}
		chain.doFilter(request, response);
	}
}

Note: I choose to define the cookie name as Angular expects it, but it also possible to define its name on the client side (using $httpProvider.defaults.xsrfCookieName) and keeping the web service ignore who is the client.

There is also one important thing you must absolutely do (I spent half of a day with that!), you have to set a path to your cookie! Otherwise, for some reasons, the browser does not replace the cookie when it is changed, and it simply manage several cookies with the same name, resulting in CSRF errors on the server side. I tested this issue with Firefox and Chrome.
On the other side, I need to configure Angular to return the header as expected by Spring, this is done in the app.js file:

petstoreApp.config(['$httpProvider', function($httpProvider){
    $httpProvider.defaults.xsrfHeaderName = 'X-CSRF-TOKEN';
}]);

We can see that the code is very straightforward.

Angular-js and Restful web services access

Following my previous article about the integration of Spring Security with web services, I will now explain how I integrate it with an Angular-js project.
For that purpose, I am a little bit lazy and I use a project I already written instead of building a completely new one.

The project is a “funny” pet-store based on Spring boot (I like it definitely!), using an H2 database and Flyway to restore its content at each start.
The full project is available on Github.

The web services are defined with Spring MVC in the net.classnotfound.pet.web.PetController:

package net.classnotfound.pet.web;
...
@RestController
public class PetController {
	
	@Autowired
	private PetService petService;
	
	@RequestMapping(value = "/pet/all", method = RequestMethod.GET)
	@ResponseBody
	public Collection<JsonPet> findAll() {
		...
	}
	
	@Transactional(propagation= Propagation.SUPPORTS)
	@RequestMapping(value = "/pet/{id}", method = RequestMethod.GET)
	@ResponseBody
	public JsonPet find(@PathVariable("id") final Integer id) {
		...
	}

	@Transactional(propagation= Propagation.REQUIRED)
	@RequestMapping(value = "/pet", method = RequestMethod.POST, consumes = {"application/json" })
	@ResponseStatus(HttpStatus.CREATED)
	public @ResponseBody JsonPet save(@RequestBody final JsonPet jsonPet) {
		...
	}
}

The PetService is the class responsible of business processes (mainly access data here).

We can see that there are 3 actions available to:

  • display the list of pets in the store
  • display the detail of a pet
  • create a “new” pet in the store

The attributes of the requestMapping annotation seem explicit, for example, with @RequestMapping(value = “/pet”, method = RequestMethod.POST, consumes = {“application/json” }), I express that the method can be reach with /pet URL, by using the POST method and it needs json.
Based on Spring, the conversion from Json to Java Object (and the opposite) is totally hidden (it relies on Jackson API) and it avoid this burden to the developer (meaning me, here!).

Now that the landscape is set, let’s have a look at the security configuration (it should be familiar to whose who read my previous article):

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
	auth.inMemoryAuthentication().
	  withUser("admin").password("password").roles("ADMIN", "USER").and().
	  withUser("user").password("password").roles("USER");
}

@Override
protected void configure(HttpSecurity http) throws Exception { 
	
	http
	.csrf().disable()
	.authorizeRequests()
	.antMatchers("/login").anonymous()
	.antMatchers(HttpMethod.GET, "/pet/**").access("hasRole('USER')")
	.antMatchers(HttpMethod.POST, "/pet/**").access("hasRole('ADMIN')");
	
	http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
	FormLoginConfigurer formLogin = http.formLogin();
	formLogin.loginProcessingUrl("/login");
	formLogin.usernameParameter("username");
	formLogin.passwordParameter("password");
	formLogin.successHandler(authenticationSuccessHandler);
	formLogin.failureHandler(authenticationFailureHandler);
	
}

I started with the users definition with their roles.
And after that, Y can see how I restricted access to the features, as previously, I disabled the CSRF protection but I will come back to it in a next article.

Now, if a unauthenticated user tries to access the protected resources, he will receive an HTTP 401 error. Let’s see how I deal with it on the client side (Angular-js).
The web pages are located in

The idea is to have the generic process to intercept the right HTTP code when the user needs to be authenticated, and redirect him automatically to the login page .
The application is based on the single page principle, for that purpose, I use the ngRoute module, it is configured in the app.js file:

petstoreApp.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.
      when('/pets', {
	      templateUrl: 'partials/pet-list.html',
	      controller: 'PetListCtrl'
      }).
      when('/pets/new', {
    	  templateUrl: 'partials/pet-new.html',
    	  controller: 'PetNewCtrl'
      }).
      when('/pets/:petId', {
          templateUrl: 'partials/pet-detail.html',
          controller: 'PetDetailCtrl'
      }).
      when('/login', {
          templateUrl: 'partials/login.html',
          controller: 'LoginCtrl'
        }).
      otherwise({
        redirectTo: '/pets'
      });
  }]);

As expected, we can find our 3 pages related to the web services features and another one to ask credentials to users. This one will be used when redirecting unauthenticated users.
For that purpose, the application is configured with an Angular-js interceptor. All the requests sent or received can be manipulated by interceptor, this is very useful for common purposes like error management or authentication, and it is exactly the way I use it (still in the app.js file):

petstoreApp.factory('errorInterceptor', ['$q', '$location', '$window', '$injector', function($q, $location, $window, $injector) {
	var authSrv;
	var popupSrv;
	var errorInterceptor = {
			'responseError' : function(rejection) {
				var status = rejection.status;
				if (rejection.data){
					if (status == 401) {//Unauthenticated, redirect to login page
						$window.location.href="/#/login";
						return;
					} else if (status == 418) {//undefined error->HTTP code 418 ( I'm a teapot) is responsibility of the caller
						return $q.reject(rejection);
					} else{
						popupSrv = popupSrv || $injector.get('popUpSrv');
						popupSrv.alert("Erreur: "+rejection.data.message+ (rejection.data.stackTrace?"\r\n___________________________________\r\n\r\nErreur complète:\r\n" + rejection.data.stackTrace:''));
						return;
					} 
				} else {
					popupSrv = popupSrv || $injector.get('popUpSrv');
					popupSrv.alert("Erreur inconnue( http status: "+status+")");
					return;
				}
				return $q.reject(rejection);
			}};
	return errorInterceptor;
}]);
petstoreApp.config(['$httpProvider', function($httpProvider) {  
    $httpProvider.interceptors.push('errorInterceptor');
}]);

The interceptor is in charge of managing the HTTP 401 code by redirecting to the login form, and also of the display of a generic message error.
For more information about interceptors and their usage, you can directly have a look at the official site.

And now, it works! The web site can access resources protected with Spring security. In the real world, I should display the new pet button only for admin users, it means that I should also provide a service indicate which actions are available for a user.

For those who missed the point, the sources of the project are available here.

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!

Define Restful web services using Spring

In one of my project, I had the difficult decision to switch to another technology: I replaced JSF with Angular-JS.
Our goal was to speed up the development by removing the painful part implied with JSF, as a lot of server requests to manage, some view state issues, the refresh management, the need to implement the view on the Java part with its managed beans, etc…

But the big impact on the architectural point of view was that we have to move the GUI (and its logic) on the client side and give access to the data. Fortunately, this part was ease by the layered structure of the application, I just need to replace the old JSF part with a REST interface which is accessed by the Angular-JS components using Ajax requests.
As the project used already Spring, I decided to use it also to set up the restful part, I describe hereafter what I did.

First of all, we need to add the corresponding dependencies in our POM:

<properties>
    <spring.framework.version>4.0.5.RELEASE</spring.framework.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${spring.framework.version}</version>
    </dependency>
            <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.framework.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.3.4</version>
    </dependency>
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.9.12</version>
    </dependency>
</dependencies>

We need also to activate the configuration using annotation, for that we have to add in our Spring configuration file:

    <context:component-scan base-package="net.classnotfound.ws"/>
    <mvc:annotation-driven />

Even if I do not like to use the annotations to configure the application, I decided to make an exception for the web services, as they are not intended to have some intelligence and are just a bridge to the business layer, I consider it as acceptable.

A web service is declared using the @RestController Spring annotation:

package net.classnotfound.ws.controller;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {
	//Web service implementation here
    
}

When we define an endpoint for the web service, we need to indicates which HTTP method we use, the type of data we expect (JSON is the usual case), etc…
This can be done easily by using the Spring annotation:

    @RequestMapping(value = "/service/print", method = RequestMethod.POST, consumes = {"application/json" })
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void print(@RequestBody final Data data) {
        System.out.println(data);
    }

Here, we defined a method print, which is reachable using “/service/print” URL, using a POST request with data in JSON format.
The @ResponseStatus is used to define the HTTP return code to be used.

Another option is to use a GET method, but doing this, the parameters are now directly provided with the requested URL:

    @Autowired
    private DataService dataService;

    @Transactional
    @Globals
    @RequestMapping(value = "/service/data/{id}", method = RequestMethod.GET)
    @ResponseBody
    public Data find(@PathVariable("id") final String id) {
        Data data = dataService.find(id);
        if (data==null) {
            throw new ObjectNotFoundException(id);
        }
        return data;
    }

We can see the parameter defined in the URL using a EL syntax and this parameter is also mentioned in the signature of the method using @PathVariable annotation.

Too easy, isn’t it? 😀