Showing posts with label code configuration. 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 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.