I am trying to implement an API along the lines of this guide
The basic flow is:
So I am trying to secure my webapp to allow normal login flow (with Spring Security) via login form, and then all requests to /api/** are authenticated based on a token passed in request header.
I had originally started implementing this by having two web configs - one for the normal webapp security:
@Override protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/sign-in").permitAll()
.antMatchers("/success").authenticated()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/loginprocess")
.failureUrl("/sign-in?loginFailure=true")
.permitAll();
}
Above just defines standard spring security authentication (custom userDetailsService to get userdetails from DB) and authenticating he login and success pages.
Then another (two files just for clarity/ease of reading) for the API authentication:
@Override protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.csrf()
.disable()
.authorizeRequests().anyRequest().authenticated().and()
.addFilterBefore(authenticationTokenFilter(), BasicAuthenticationFilter.class )
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint());
}
The above has a pre-auth filter that grabs the relevant HTTP headers from the request (token etc) and adds them to the security context - the custom authentication provider then validates the token/user details.
All good - however, it feels like I am re-inventing a bunch of stuff. Having looked at Spring Security's RememberMe functionality, it looks like they already handle a lot of this - on login it returns a cookie with a token that can be then used for auto login on future requests. From the java docs:
<bean id="rememberMeFilter" class=
"org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="theAuthenticationManager" />
</bean>
<bean id="rememberMeServices" class=
"org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="key" value="springRocks"/>
</bean>
<bean id="rememberMeAuthenticationProvider" class=
"org.springframework.security.authentication.rememberme.RememberMeAuthenticationProvider">
<property name="key" value="springRocks"/>
</bean>
The only problem is that I want to include the token in future requests as header params, not a cookie. I have looked at the source for the above classes and the TokenBasedRememberMeServices class autoLogin()
method explicitly examines the cookie. The code also uses MD5 as default for hashing.
My questions are:
I would prefer not to have to extend all those classes, as a bunch of the core stuff would be the same, and seems overkill to have to extend them just to change the source of the token and the hashing algorithm.
Ok, having looked around a little, there didnt seem to be core classes that implemented the RememberMe functionality for request headers - however, reading through the Spring Security remember me source code, it was actually quite simple to extend the above classes to look at the request header.
Details are all here: http://automateddeveloper.blogspot.co.uk/2014/03/securing-your-mobile-api-spring-security.html but basically just use RememberMe as normal, but then extend the TokenBasedRememberMeServices and override the extractCookie method to just grab the token from a header rather than a cookie (possibly a little bit hacky, extending a method called extractCookie to grab request headers, but it works)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With