AngularJS web apps for Spring-based REST services security: the server side part 1

First of all, I owe an apology to the readers who have been asking a full security example for some time. I could list all the usual excuses or describe what a week of my life looks like… but I’d rather not underestimate their intelligence. You are all probably living a busy and hectic life, so I’d rather plead for your understanding!

I also want to point out that you should not consider this solution a security “silver bullet“. I am satisfyingly applying this solution for a project I’m working on, and I believe it is secure enough for that specific context. However you will probably want to examine the code and adapt it to your needs (is it secure enough for your needs? Do you actually need to handle CORS or CSRF? Do you need OAuth2 for scalability? Etc.). There’s also the matter of the human factor (me!) and the mistakes that come with that! So keep an eye open and feel free to send me your feedback if you spot anything. That’s how we’re all supposed to learn, right?

The full code for this tutorial is available on GitHub here:

In this series of posts I will examine and explain the code found on the repositories here above.

So let’s start with the server-side then!

Setting up the project

I’ve used Spring IO 1.1.2 (current stable version at the time of writing the code) with Spring Boot on top to set up the project. The pom.xml written for that purpose is quite straightforward, except maybe for the exclusion of that spring-boot-starter-tomcat artifact: I decided I’d use Jetty instead 🙂

One important thing should be noted regarding the application.properties file, which is used by Spring Boot for its initial configuration:

logging.level.org.springframework=INFO
logging.level.org.springframework.security=INFO

server.port=8081

I have changed the server port to 8081. This is to avoid later conflict with the other server that I’ll be using to run the web client. Running the server and the client on two different servers with two different ports will allow us to verify our handling of CORS.

Entry point and context configuration

The application’s entry point class, unsurprisingly named Application, is quite uneventful:

@ComponentScan
@Configuration
@EnableAutoConfiguration
public class Application {

  @Bean
  public WebSecurityConfigurerAdapter webSecurityConfigurerAdapter() {
    return new ApplicationSecurity();
  }

  public static void main(String[] args) {
    SpringApplication application = new SpringApplication(Application.class);
    application.run(args);
  }
}

We enable component scanning and auto configuration through annotations, and we define the main method which will be executed when the Spring Boot application is started. Since I have decided that this will also serve as the very root of my configuration structure, I have also annotated the class with the @Configuration annotation so that any @Bean-annotated method declared here will be registered.

And indeed, this is also where I have decided to provide my own version of the WebSecurityConfigurer bean, which we will use to provide our custom security configuration for this application. I do that by implementing an ApplicationSecurity class which extends the WebSecurityConfigurerAdapter class to override Spring Boot’s default security configuration.

To avoid defining all my beans in Application, I have also set up a SecurityConfiguration class which is responsible of defining beans related to… yep, security!

Providing our own WebSecurityConfigurer implementation

Much of what you will see in our ApplicationSecurity class has been discussed already in one of my previous posts.

In essence, we override Spring Security’s configured AuthenticationEntryPoint, AuthenticationFailureHandler, AuthenticationSuccessHandler and LogoutSuccessHandler in order to provide a behavior that is more REST-friendly than what is proposed by Spring Security out-of-the-box: sending back a 401 when user is not authenticated, or removing the redirections after successfully authenticating or after logging out. I invite you to check these classes in the GitHub repository: they are quite self-explanatory.

http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
http.formLogin().successHandler(authenticationSuccessHandler);
http.formLogin().failureHandler(authenticationFailureHandler);
http.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);

Since we need some basic profiles to test the authentication, we simply override the configure(AuthenticationManagerBuilder) method from WebSecurityConfigurerAdapter in order to set up a couple of in-memory users:

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

Finally, we define in the configure(HttpSecurity) method override what is protected by authentication and what is not. Following good practices what we really define is what we exempt from authentication:

http.authorizeRequests()
  .antMatchers(HttpMethod.OPTIONS, "/*/**").permitAll()
  .antMatchers("/login", "/rest/open/**").permitAll()
  .antMatchers("/logout", "/rest/**").authenticated();

What the above says is:

  • Requests of the OPTIONS type are always permitted (otherwise preflights cannot be done… more about that further below).
  • Requests whose URL is “/login” or beginning with “/rest/open/” are always permitted. This covers the URLs which we want to make accessible to all (the “open” ones) as well as the login POST request (otherwise, it’s kind of a catch-22 situation: needing to be logged in order to… login!).
  • All other requests under “/rest/“, as well as the “/logout” URL, are only accessible to authenticated users. This excludes however those URLs starting with “/rest/open/“, because they have been previously been specified as not needing authentication.

There are two more security aspects defined in ApplicationSecurity: CORS and CSRF.

CORS

CORS (cross-origin resource sharing) is the mechanism that secures the sharing of resources with domains that are not the domain of origin of those resources. This helps preventing malevolent persons, under certain circumstances, from adding scripts that are NOT from your site to your web page. The users, feeling safe while using your web application, could otherwise be lured into running some malicious code.

AJAX requests, with their ability to perform POSTs, PUTs or DELETEs, are logically forbidden by default in order to avoid those situations. However that’s kind of a bummer for us, since we actually want our web client on a domain perform AJAX requests on our server, which is on a different domain! So how can we do that in a safe way?

In a nutshell: the browser, who makes a resource request using AJAX, makes a deal with the server. The browser first asks permission to the server for accessing the resource (the preflight), and once the permission is obtained the browser can then perform the actual request to obtain that resource. It might go a little like this:

  • (browser) Err… hi there! I’m http://mywebclient.com. Nice meeting you!
    So… I’d like to perform a POST request with this and that header…
  • (server) Yeah yeah, hi. Let me check if I can accept that… Hmm… Yep, sounds legit! Ok then, bring it on.
  • (browser) Alright mate! Here’s my actual request! …
  • (server) Yep, that matches what you said you would request. So here goes the response. Have a nice day!

That’s basically it. If you want the details of what actually happens during that process, check this excellent post on how CORS work. You will have all the dirt, client and server-side.

Do note however that this preflight request is performed automatically by the browser before the actual request. This is not something that has to be programmed in the client.

Setting up CORS

So how do we actually implement that on the server side with Spring Security?

Well, we know we need to define the “rules” by which a resource sharing will be accepted or not. These rules are specified in the header of the response to be sent back to the browser when it preflights.

In practice we set up a filter that does that. In the tutorial code, this is the CORSFilter class. What headers should we specify in there? The available options for the response headers are described quite nicely in this MDN page. For this tutorial I have set up the following ones:

// Access-Control-Allow-Origin
String origin = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", allowedOrigins.contains(origin) ? origin : "");
response.setHeader("Vary", "Origin");

// Access-Control-Max-Age
response.setHeader("Access-Control-Max-Age", "3600");

// Access-Control-Allow-Credentials
response.setHeader("Access-Control-Allow-Credentials", "true");

// Access-Control-Allow-Methods
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");

// Access-Control-Allow-Headers
response.setHeader("Access-Control-Allow-Headers",
  "Origin, X-Requested-With, Content-Type, Accept, " + CSRF.REQUEST_HEADER_NAME);
  • Access-Control-Allow-Origin specifies the origin URL from which requests will be accepted. A request received from a different origin will be rejected. In this code I compare the origin I get against a list of accepted origins that I have defined. If it is in the list, I specify that origin as being accepted.
  • Access-Control-Max-Age defines how long the preflight will be cached, that is, how much time the browser has between what he announced it would request and the actual request.
  • Access-Control-Allow-Credentials indicates whether the actual request can contain credentials or not.
  • Access-Control-Allow-Methods indicates which methods are allowed to access the resource.
  • Access-Control-Allow-Headers lists the headers that can be used by the browser when making the actual request. Notice how in my code I allow a custom header to send CSRF tokens? If that CSRF header is not specified, the tokens will never be accepted by the browser. For requests needing to return CSRF tokens this would obviously be problematic… But I get ahead of myself. More on that later!

There’s one more possible header which we do not use in our tutorial: Access-Control-Expose-Headers. This tells the browser what headers he can access.

We then register that CORS filter in ApplicationSecurity:

http.addFilterBefore(corsFilter, ChannelProcessingFilter.class);

And that’s it!

Let’s go over that sequence again. When the client wants to access a resource:

  1. The browser preflights a CORS-triggering request. In practice, it sends an OPTIONS request for that purpose. (always authorize OPTIONS requests in your configuration!).
  2. The server replies with the set of conditions by which the actual request is accepted.
  3. The browser sends the actual request.
  4. The server provides the requested resource.

As we said before, the browser takes care of the preflight. So all the client needs to do, from a code point of view, is send the actual request.

In a forthcoming post I will discuss how CSRF is configured. Later on we’ll also examine how the AngularJS client performs these requests securely. Until then , feel free to play around with the code. This is a Spring Boot application, so running the server is just a matter of running the Application class’ main method.

Cheers!

 

12 comments

  1. Ansuraj Reply
    19/07/2015 at 14:46

    Nice tutorial to begin with CORS.
    Thanks! 🙂

  2. […] AngularJS web apps for Spring-based REST services security: the server side part 1 […]

  3. Greg Reply
    19/09/2015 at 22:19

    Thanks for the nice tutorial on spring security. But i have some trouble to get the web client working. I pasted the webclient stuff into the resource folder of the server application. But i still get an Whitelabel Error Page. Then i created a static folder and pasted the webclient stuff there. but i can’t get it working with the server application.

    Do you have a suggestion what i’m doing wrong ?

    • codesandnotes Reply
      21/09/2015 at 08:47

      Hello Greg!
      The web-client code is meant to be checked out as a separate project.
      On one hand you should checkout the server code as one project in the IDE and run its Application class to have Spring Boot start a Jetty on port 8081 and deploy the project on it.
      On the other hand you should checkout the web client project as a separate project on the IDE, and configure your IDE to run another app server on 8080 (Jetty, Tomcat, whatever you like most) and deploy the application “as-is” on it. For example, on IntelliJ you would create a “Jetty Server” configuration, and in the “Deployment” tab of the Run/Debug Configurations you would add the project as a “Web Application: Exploded” artifact to the list of stuff to deploy at server startup. When running that configuration, the IDE would start the server and deploy the web application on it. Of course, you should be able to do something similar on Eclipse or Netbeans.

      I will soon update the README.md file to add a few instructions on how to deploy the web code. If you are still stuck, feel free to let me know!

      • Greg Reply
        21/09/2015 at 15:56

        Thanks for the reply and the awesome post. I got it working now.

  4. Francisco Reply
    05/11/2015 at 11:05

    Hi, so much useful the tutorial, thk you very much.
    I have one question, in the ApplicationSecurity.java, how can we change the inMemoryAuthentication from:

    @Override
    protected void configure(AuthenticationManagerBuilder builder) throws Exception {
    builder.inMemoryAuthentication().withUser(“user”).password(“user”).roles(“USER”).and().withUser(“admin”)
    .password(“admin”).roles(“ADMIN”);
    }

    to a dinamically method? So if some one want register and get auth, how can we update this builder without restart?

    • codesandnotes Reply
      05/11/2015 at 13:25

      Hello Francisco,

      I’m not sure the “in-memory” authentication is meant for more than testing or simple situations.

      If you want to be able to register new users dynamically, you will have to register an LDAP-based authentication service or a JDBC-based authentication service, which respectively rely on an LDAP or a JDBC datasource to check if the user’s username exists and if the password matches. So in the case of a JDBC authenticator, registering new users amounts to adding rows in the database! (and you don’t need to reboot the application to authenticate the new users)

      Check this DZone article for tips on how to proceed: https://dzone.com/articles/spring-security-4-authenticate-and-authorize-users

      Of course, you might need to use something else to authenticate your users. For example, I recently had to authenticate users against a NoSQL database…
      In that case you will have to implement your own UserDetailsService class, whose job will be to fetch the user from where you store your list of users (a NoSQL table, a text file, etc.). That custom implementation will be in charge of informing Spring Security (through a UserDetail instance) so that it can determine whether a given user is authenticated or not.

      Check this part of Spring Security’s documentation to learn more about this: http://docs.spring.io/spring-security/site/docs/4.0.3.RELEASE/reference/htmlsingle/#tech-userdetailsservice
      In a Java Configuration, you can then configure your authentication manager like this: builder.userDetailsService(myOwnUserDetailsService).passwordEncoder(passwordEncoder);

      Hope this helps!

  5. pramod Reply
    01/01/2016 at 06:20

    Thanks this the nice tutorial for beginning. Its working well chrome and sometimes automatically logout on fire fox, is it dependent on angular version. Also i want to do login by custom user details service instead of in memory authentication. Please help me if you have done it already, i ma now finding resources about it.

    • codesandnotes Reply
      01/01/2016 at 11:42

      Hi Pramod!
      Not sure why Firefox logs out automatically? I can’t see why it would do that… unless it has been configured to block cookies, or if you have a cookie manager add-on or similar installed? The login relies on storing your session ID in a cookie, which is why they must be allowed.
      As for the custom user details service, it is done by replacing the configure() override with one that calls our own implementation of the UserDetailsService interface:

      
      @Override
      protected void configure(AuthenticationManagerBuilder builder) throws Exception {
        builder.userDetailsService(myCustomUserDetailsService).passwordEncoder(passwordEncoder);
      } 
      

      You then write your “MyCustomUserDetailsService” bean that implements UserDetailsService. It has only one method to implement, which is loadUserByUsername(username). Inside that method you retrieve your user from your database (or from any place you want, really!) and you make it return an object of type org.springframework.security.core.userdetails.User, or eventually throw a UsernameNotFoundException if the user does not exist. The rest of the Security framework will take it from there and check the typed password against the password stored for that user.

      Hope that will set you on the right track to implement your custom user details service. If not, I’ll try to write a post soon on how to do that, with code and everything 😉

      Cheers!

  6. akram Reply
    27/01/2016 at 16:34

    Hi
    first of all i want to thank you for this great tutorial it was very helpful for me.
    i have a question :
    i see that you are using in memory authentication to define your users
    builder.inMemoryAuthentication().withUser(“user”).password(“user”).roles(“USER”).and().withUser(“admin”)
    .password(“admin”).roles(“ADMIN”);
    i’m using an xml config and i’m using a properties file as user provider :

    My question is how can i translate this xml config to a java class config to use a properties file

    Thanks

    • codesandnotes Reply
      27/01/2016 at 17:58

      Hi Akram,

      I can’t seem to find anything equivalent to the tag.
      The fastest way to go around that would be to load the properties using @PropertySource(value = {"classpath:users.properties"}) and iterate over the list of users to append them to the inMemoryAuthentication instance.
      The cleanest way would be to implement your own UserDetailsService that would fetch the users’ details from your properties file and return them as a org.springframework.security.core.userdetails.User object. The UserDetailsService interface is very easy to implement, so it’s just a matter of writing the bit of logic that extracts the username, password and roles from the properties’ values.
      Then again, I’m wondering: if your properties file has more than three or four users, wouldn’t it be time to go JBDC or similar? I’m not sure keeping the credentials as an .xml file is the safest, most secure option. But then again, that might be me 😉

      Cheers!

Leave A Comment

Please be polite. We appreciate that. Your email address will not be published and required fields are marked

This site uses Akismet to reduce spam. Learn how your comment data is processed.