Showing posts with label spring-security. Show all posts

Spring-Security: Different AuthenticationEntryPoint for API vs webpage

This is just a real quick post, on a little bit of Spring that I came across today. It's a very simple thing, but, in my opinion, beautiful in it's simplicity.

I found myself working on some Spring-Security stuff, and an app where I needed to define my AuthenticationEntryPoint (I am in the process of adding the security stuff, so this is not done yet).  Simple enough - normally in config you can just add it to the exception handling setup. However, this time I wanted to define two different entry points: one for when a user attempts to access an API (JSON) and one for normal site pages.

It's not unusual to have an API baked into an app (maybe under /api/** etc), and the ideal behaviour would be to return an appropriate HTTP Status code for the API (401) plus a JSON payload, and for a logged in web page the user would be bounced to the login page before continuing.


Having dealt with this split for error handling, controller routing and security elsewhere, I assumed I would have to implement a custom AuthenticationEntryPoint, chuck in a fer IF statements checking the logged in user and requested URL and either redirect or respond with the status appropriately. However, Spring has us covered with its DelegatingAuthenticationEntryPoint - which is what it sounds like, and super simple to use.  Probably best demonstrated with the code (because it's just that simple!)

In our normal configure method we just set the entrypoint as usual. But in the DelegatingAuthenticationEntryPoint we simply initialise it with a map of RequestMatcher: AuthenticationEntryPoint (defined in Groovy above, so we have nice Map definition etc - would be slightly more verbose in Java)  - The RequestMatcher can be any implementation you like, but of course simple path matchers will probably work fine; For the AuthenticationEntryPoint there are also lots of really nice Spring implementations - including the two used in the example above, which perfectly provide what I need.


This genuinely elicited an "awww yeah" from me.

Spring security & subdomains

As previously mentioned, I have been working with a Spring MVC app that has had to deal with multiple subdomains for the one app (in other words, the subdomain really needs to just be considered as part of the normal URL path in all routing/security configuration and concerns).

Having gone through the details on how to make the @Controller and @RequestMapping routing to play nicely with subdomains, here is a quick overview of how to handle subdomains in Spring security.


A custom matcher

The main thing we really need to handle with security, is how to configure Spring-security so we can define permissions for URLs that include the subdomain.

Normally, Spring MVC permissions looks something like this:

As you can see, this just specifies a URL path to authenticate.


The specific details of how you implement the matcher exactly will be dependent on your applications approach to identifying and extracting the subdomain (maybe from http request, maybe just use a regex on the request etc)

As you can see above, the matcher we have created is just a convenient wrapper around another two spring matchers to let you match easily on both the full URL and subdomain.

Now, with a little convenience method, we can make some pretty nice Spring security configuration:

As you can see, the subdomain makes a difference to the permissions and who should access the two /dashboard/ URLs in the different contexts, but with the above simple code, we can make some pretty convenient & readable configuration to take subdomains into account.

Securing your mobile API - Spring Security

Having recently posted an article on an approach to securing an API for a mobile app to use, here are the details of how something similar can be configured using Spring-MVC and Spring-Security (this post uses Java config - if you are un-familiar with Java config rather than XML then check out my previous post on the topic).


Basic webapp registration and authentication

The first thing we need is a basic web app that supports user registration and authentication.  I am not going to go into the details of how to build a Spring MVC app with basic security and users etc, so will assume you are familiar with basic Spring MVC architectures. For an example Spring webapp that supports user security and registration, you can check out one of my several random webprojects on GitHub.


As I am only looking at an API application - no web client right now - All I need to start with is to set up the security for registration and login:



Ok, so the above is my web security config - the configure() method is what is defining my URLs and the security - it's pretty basic, I state that anyone can access the resources (for css etc), the log-in and the sign-up and everything else should be authenticated.

The only parts of interest are:
  1. In the registerAuthentication() method, as well as the normal setting of UserServices and password encryptor, I am also adding a Remember Me Authentication provider
  2. In the configure() method on the formLogin component we are also setting a RemeberMeService
  3. We are setting @Order annotation on the class with value 2

This class basically just sets up the web part of the security, so all pretty straight forward.


API security configuration

For clarity and readability of code, I like to create separate configuration classes for the different aspects of security - Below is the security config for the API endpoints:



This file is a little more interesting, let's have a look at what is going on:
  1. First of all, we define @Order with value 1 - as you have probably guessed, this defines the order in which the security config is loaded/considered - we want the API security to kick in first
  2. In our configure() method, we first specify an ant matcher so the rules in this config only apply to URLs that start /api/
  3. We state that all requests to this pattern must be authenticated and apply a RememberMeAuthenticationFilter to run before the Basic authentication chain runs
  4. We also set the session management to be stateless - this refers to serverside sessions, as we don't want to retain server session state
  5. We then configure the Remember Me beans - this is all standard and as per the Spring guidelines here.  The only difference is that we have a custom TokenBasedRememberMeService - that we will look at later.


Security flow

Below is the basic security chain that we get as a result of the above confirmation
  1. Request comes in - we check if it matches /api/**
  2. If it does match, then all requests must be authenticated - and run the RememberMeAuthenticationFilter 
  3. The filter simply uses the RememberMeService and AuthenticationProvider to check the token/cookie value to see if it can pre-authenticate the request.
  4. If it has matched the URL but doesn't authenticate on the filter, then it will 403
  5. If the URL does not match /api/** then the request starts the second security config
  6. If the url matches the resources, sign-up, sign-in then allow the request to complete, otherwise require authentication, so (default spring behaviour) direct all other requests to the registered login page ("/")


Customising remember me

 So the good news is we have been able to re-use core Spring Security functionality so far, so no dubious hand-rolled solutions - We use the standard security chain, username/password authentication provider and Remember Me filter/provider. The only thing that we have to modify slightly is the RememberMeTokenService - the default behaviour for Remember Me assumes that the token will always be provided in a cookie (designed for auto-login websites if you tick "remember me"), and as we are extracting the token from the cookie and passing it in the request header instead, we need to modify the service class to grab it from the header.

As you can see, it's pretty simple - all we are doing is overriding the default extract cookie method so it looks in the request header instead.  I would really recommend you read through the source code for the RememberMe classes - starting with the filter - and seeing what is actually happening between the Filter, token service and auth provider, it's pretty clear to read and will help get a good understanding of what is going on.


Caveats

There are a few things to consider here:
  • This is fairly basic security - requests should be made over https to prevent man-in-the-middle attacks, alternatively look at a solution like Amazon use whereby the token isn't passed, rather it is used to hash the request body which is then checked on the server side (prevent the need for sending the user token every request)
  • This is currently open to anyone to use/build against - there aren't any checks for app key/secret etc - so you would probably want to build that in to prevent other parties building apps against the api and getting a user token in the same way.
  • I'm not a security expert - this is just my interpretation of the Google guidelines using Spring Securities RememberMe classes. This is really just a thought experiment, getting up to speed with how Spring Security works in more details and experimenting with mobile app fun. Use at your own risk..

Securing your API for mobile access

So I have been thinking about potential options regarding securing a server side API for use by mobile apps. No matter what question you ask on the stack exchange network, the answer will always come back as "you should really use oauth", which I guess we should consider as a half truth.

Having used OAuth on several occasions as a client (accessing Facebook/Twitter/LinkedIn/GitHub etc), it was naturally the first option that came to mind for securing my API.


My requirements right now are simple:
  • I am experimenting building an Android mobile app that will use a server API (webapp & API will be built using Java & Spring stack)
  • The app I am experimenting is mobile-only (no web client)
  • It is not going to become a public API (e.g. won't be supporting other apps/sites)


I guess the key point is that I only intend to expose the API to my mobile app, and not have lots of comsumers of the API - and given the complexity of implementing OAuth, it seemed like it would be overkill as a solution.  A big benefit of OAuth is that it supports client/application keys.


So I started looking around for other ideas as to how to do this - I was (and still am) curious as to how Twitter/Instagram secure their APIs for their own applications - I know that the Twitter API is secured for public use using OAuth, but the interesting question is how they secure their own application key/secret. The problem with mobile apps is that an application key needs to be stored on the device - and whilst Twitter offers severely throttled API access using OAuth (register an application, get a secret app key etc), their own apps are obviously not throttled, so it seems like it would be a challenge to keep their application key secured, as if its in the app code, then its subject to de-compilation.

Anyway, getting close to resigning to the fact that I was going to have to use OAuth I came across this one-pager from Google. The guide suggests a much simplified approach with the following basic steps:

  • Build an webapp on your server that has a login page 
  • From your mobile app, embed a WebView of the login page
  • Upon login to your app, return a cookie with a token value that can be used to log in your user on future requests - ideally re-using your frameworks Remember-Me type services so not to have to hand-roll your own
  • On every API request include the token in your request header to authenticate (again using the Remember Me services)

The fact that it was a suggested approach from Google is pretty good, and it's a tonne simpler than negotiating the OAuth dance, so I thought I would have a look at getting this setup.


This is all good - but really, the advice to use OAuth is a half-truth, as if you ever have to scale your application, and think you might one day have/want to open it up do other developers/clients then OAuth is the way to go - You won't get much love from third-party developers with a non-standard approach to securing your API.


So.. how can it be done with Spring? I will cover that in my next post later this/next week!

Spring 4: XML to @Annotation Configuration

I got 99 problems, but an XML based security configuration aint one..

I have for a long time preferred to use Spring (or generally Java) annotations over XML config for my development (I concede the point on XML configuration allowing a central place to understand all Controllers etc, but with modern decent IDEs this info can still be viewed centrally even if using annotations).

A while ago I made the switch to pure code configuration for my Spring webapps, with the exception of the web.xml (dependency on using Tomcat7 that I didn't want to enforce just yet) and the security config - which Spring didn't support.  Along with Spring 4, Spring have announced that they will now support security config as code, which is great news!


XML Configuration

Below is an example of a typical XML based configuration.

This basically turns on security for the webapp, it:
  • Adds a single intercept URL rule (in this case, our rule says all URLs are open to everyone - so not that secure! We would likely add more URL intercept rules above this as we have more URLs we want to secure - these rules are read top to bottom and fall through until a match is found, so permitAll must be the lowest rule found)
  • Defines a login form - including location of the form, the submission target URL, login failure redirect URL and the logout URL. Spring will automatically handle all these. If you submit a form to the login-processing-url then Spring will intercept it and attempt to authenticate - you don't need a specific controller handler defined.
  • Defines an authentication manager - this will be used to authenticate submitted requests. In this case, I have overriden the standard Spring User Service with my own implementation (this will be a common requirement as you will want to authenticate against users in your DB etc)


The config is all pretty simple really - the only unpleasantness is the requirement to have XML!


Code Configuration

And here is the config in code using the latest and greatest Spring dependencies.

Let's have a lookat what is going on here.
  • I am @Autowiring in my custom User Service class - this will be used in the Authentication manager later.
  • The configure() method is where we set the URL intercept rules and login form - it should be pretty self explanatory reading it through if you are familiar with old fashioned xml config (will come back to CSRF config shortly - but it is NOT recommended that you disable this! this is just in development)
  • The registerAuthentication() method sets up the Authentication Manager using our User Service implementation. Whilst setting up the Authentication Manager, we also define a password encryptor - you will note in the code config I am using the BCrypt password encoder, and in XML using a base64 MD5 hash - but whichever encoder you want to use you can configure it in the same fashion using the secondary method to instantiate and return the encoder desired (although you probably shouldn't be using MD5 over BCrypt.. really, you shouldn't ).



Observations and Gotchas

As you can see in the above code example, I am explicitly disabling CSRF. As of Spring 3.2 onwards, the security layer provides CSRF protection by default - so if this is not disabled then you have to provide a CSRF token to prove your request is legit. Should you need to disable it, you can using the above syntax, but obviously CSRF protection is built in to help you out, so probs best not to disable it on a prod system!

The link above details how to include tokens in requests for your webapp. It's really pretty easy to do.


The second point to note is one that caught me out.  Previously in Spring, when submitting a form to authenticate, the default field names had to be j_username and j_password. If you are hoping to switch the config out on an existing webapp then you have to make sure you update your login form with the correct field names (Spring 3.2 with XML config you still need j_*, its only Spring 3.2 & Java config..)



As always, the code is on GitHub - feel free to check it out.