There are some new features in Spring Boot 1.3 to do with OAuth2 clients and servers and Spring Security OAuth2. Some of those features were ported from Spring Cloud Security and hence were in the Angel release train of Spring Cloud, but are not in the Brixton release train. This article helps you navigate the changes and update any existing apps to use the new features confidently.
If you are not using Spring Cloud you should be able to just change the version number of your Spring Boot dependency. Since some of the OAuth2 features migrated from Spring Cloud Security to Spring Boot in 1.3, it is likely that things are slightly more complicated than that. A separate article deals with upgrading Spring Cloud apps from Spring Boot 1.2 to 1.3. If you are using the Spring Cloud Angel release train then you should consult that article for details of how to manage the dependencies (independent of any specific features).
An OAuth2 Authorization Server is responsible first and foremost for issuing access tokens. To do this it must be able to authenticate client apps and (optionally) users.
A very simple OAuth2 Authorization Server with a single client can be implemented by convention and some configuration properties in Spring Boot 1.3. So a really basic example like the vanilla auth server from the Angular JS Spring Securrity Tutorial from spring.io can be simplified quite a bit. In Spring Boot 1.2 we have:
@SpringBootApplication
@RestController
@EnableResourceServer
public class AuthserverApplication {
@Configuration
@EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Excep
endpoints.authenticationManager(authenticationManager);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("acme")
.secret("acmesecret")
.authorizedGrantTypes("authorization_code", "refresh_token",
"password")
.scopes("openid").autoApprove(true);
}
}
...
}
In Spring Boot 1.3 we have just:
@SpringBootApplication
@RestController
@EnableResourceServer
@EnableAuthorizationServer
public class AuthserverApplication {
...
}
and in application.properties
:
security.oauth2.client.clientId: acme
security.oauth2.client.clientSecret: acmesecret
security.oauth2.client.authorized-grant-types: authorization_code,refresh_token,password
security.oauth2.client.scope: openid
This is a general purpose Authorization Server, great for demos, but not very realistic in practice because it only has one client ("acme"). Nevertheless, as a way to get started quickly with OAuth2 it's nice to be able to do so much with so little.
To extend the basic sample and take control of the Authorization Server features you only have to go back to the old Spring Boot 1.2 version (any app with its own AuthorizationServerConfigurer
switches off the autoconfigured features).
A Resource Server protects its endpoints by requiring a valid access token (as created by the Authorization Server).
Similarly to the Authorization Server, a Resource Server can be implemented by convention and some configuration properties in Spring Boot 1.3, and also with Spring Boot 1.2 in conjunction with Spring Cloud Security. As an example consider the vanilla resource server Angular JS Spring Security Tutorial from spring.io.
With Spring Boot 1.2 we had to use Spring Cloud Security for the @EnableOAuth2Resource
annotation:
@SpringBootApplication
@RestController
@EnableOAuth2Resource
class ResourceApplication {
...
}
and some configuration to help decode the access tokens in application.properties
spring.oauth2.resource.userInfoUri: http://localhost:9999/uaa/user
With Spring Boot 1.3 the Spring Cloud dependency can be removed and the annotation replaced with a vanilla @EnableResourceServer
annotation from Spring Security OAuth2:
@SpringBootApplication
@RestController
@EnableResourceServer
class ResourceApplication {
...
}
To finish the app there is a slightly different configuration (note the key prefix change from spring.oauth2
to security.oauth2
):
security.oauth2.resource.userInfoUri: http://localhost:9999/uaa/user
In OAuth2 a client is an agent (usually an application) that acquires a token, often on behalf of a user. Single Sign On can be implemented by having a single Authorization Server and dependent authenticating apps that are OAuth2 clients.
On the client side in Spring Boot 1.3 you can implement the Single Sign On pattern with an annotation and some configuration properties. You can do the same with Spring Boot 1.2 is you use Spring Cloud Security as well.
A really generic example with Spring Boot 1.2 and Spring Cloud Angel would use a single @EnableOAuth2Sso
annotation:
@SpringBootApplication
@EnableOAuth2Sso
public class SsoApplication {
...
}
and some configuration for the client in application.yml
(or equivalently application.properties
). Here's an example for authentication with Facebook for an app running on localhost:8080:
spring:
oauth2:
client:
clientId: 233668646673605
clientSecret: 33b17e044ee6a4fa383f46ec6e28ea1d
accessTokenUri: https://graph.facebook.com/oauth/access_token
userAuthorizationUri: https://www.facebook.com/dialog/oauth
tokenName: oauth_token
authenticationScheme: query
clientAuthenticationScheme: form
resource:
userInfoUri: https://graph.facebook.com/me
The same app looks almost identical in Spring Boot 1.3 but there is no need for Spring Cloud Security. Also the annotation moved to a different package, and the configuration prefix changed. So removing the Cloud dependency, changing the import for the annotation and switching the prefix in application.yml
from spring
to security
is all that is needed to migrate this app.
In Spring Cloud Security 1.0 (from the Angel release train) users can customize the request matching and access rules using a combination of a special callback OAuth2ClientConfigurer
and some configuration properties in spring.oauth2.sso.*
. So for example, the vanilla client app in the Angular JS Spring Security Tutorial from spring.io has this general pattern of implementation in Spring Boot 1.2:
@SpringBootApplication
@EnableOAuth2Sso
public class UiApplication {
@Configuration
protected static class SecurityConfiguration extends OAuth2SsoConfigurerAdapter {
@Override
public void match(RequestMatchers matchers) {
matchers.anyRequest();
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/index.html", "/home.html", "/").permitAll()
.anyRequest().authenticated()
.and().csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
}
}
...
}
and a similar application.yml
to the vanilla sample:
spring:
oauth2:
sso:
home:
secure: false
path: /,/**/*.html
client:
accessTokenUri: http://localhost:9999/uaa/oauth/token
userAuthorizationUri: http://localhost:9999/uaa/oauth/authorize
resource:
userInfoUri: http://localhost:9999/uaa/user
With Spring Boot 1.3 there is no need for Spring Cloud Security, and the customizations don't need the obsolete OAuth2SsoConfigurerAdapter
. Instead they just need all of the same code, plus a request matcher, in a regular WebSecurityConfigurerAdapter
carrying the @EnableOAuth2Sso
annotation:
@SpringBootApplication
@EnableZuulProxy
@EnableOAuth2Sso
public class UiApplication extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/index.html", "/home.html", "/").permitAll()
.anyRequest().authenticated()
.and().csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
}
...
}
The configuration properties in the updated version are mostly the same: there is a prefix change from spring.oauth2
to security.oauth2
and there is no need for the *.oauth2.sso.*
properties because they are explicitly configured by the user in the WebSecurityConfigurerAdapter
.
The actual client app in the Angular JS Spring Security Tutorial from spring.io is similar to the customized one above, but it is also a Zuul proxy, responsible for forwarding requests from the browser client to back-end services. In Spring Boot 1.3, this app still needs Spring Cloud Security for the token relay (it wants to send the access tokens used for authentication to the back end resources), but it doesn't need it for the basic SSO features, so the implementation is identical to the previous sample with the addition of an @EnableZuulProxy
annotation.
NOTE: a bug in Spring Boot 1.3.0 leads to a workaround in the current implementation (at time of writing) of the client app in the Angular JS Spring Security Tutorial. The workaround is only needed because it is using Spring Cloud Security, and will also be redundant in Spring Boot 1.3.1:
@Component @Order(Ordered.HIGHEST_PRECEDENCE) class WorkaroundRestTemplateCustomizer implements UserInfoRestTemplateCustomizer { public void customize(OAuth2RestTemplate template) { template.setInterceptors(new ArrayList<>(template.getInterceptors())); } }
The sample apps in the Spring Guides have all been updated to Spring Boot 1.3 now, even if that means they depend on a milestone of Spring Cloud (this only applies to the Zuul proxy sample). Many do not need Spring Cloud any more. If you need a GA version of Spring Cloud you need to stay with Spring Boot 1.2 right now. The samples for that combination can be lifted from git history.
Do you know how the userInfoUri can be set programatically?