Spring Cloud Security offers a set of primitives for building secure +applications and services with minimum fuss. A declarative model which +can be heavily configured externally (or centrally) lends itself to +the implementation of large systems of co-operating, remote components, +usually with a central indentity management service. It is also extremely +easy to use in a service platform like Cloud Foundry. Building on +Spring Boot and Spring Security OAuth2 we can quickly create systems that +implement common patterns like single sign on, token relay and token +exchange.
+|
+ Note
+ |
++Spring Cloud is released under the non-restrictive Apache 2.0 license. If you would like to contribute to this section of the documentation or if you find an error, please find the source code and issue trackers in the project at github. + | +
Quickstart
+OAuth2 Single Sign On
+Here’s a Spring Cloud "Hello World" app with HTTP Basic +authentication and a single user account:
+@Grab('spring-boot-starter-security')
+@Controller
+class Application {
+
+ @RequestMapping('/')
+ String home() {
+ 'Hello World'
+ }
+
+}
+You can run it with spring run app.groovy and watch the logs for the password (username is "user"). So far this is just the default for a Spring Boot app.
Here’s a Spring Cloud app with OAuth2 SSO:
+@Controller
+@EnableOAuth2Sso
+class Application {
+
+ @RequestMapping('/')
+ String home() {
+ 'Hello World'
+ }
+
+}
+Spot the difference? This app will actually behave exactly the same as +the previous one, because it doesn’t know it’s OAuth2 credentals +yet.
+You can register an app in github quite easily, so try that if you +want a production app on your own domain. If you are happy to test on +localhost:8080, then set up these properties in your application +configuration:
+spring:
+ oauth2:
+ client:
+ clientId: bd1c0a783ccdd1c9b9e4
+ clientSecret: 1a9030fbca47a5b2c28e92f19050bb77824b5ad1
+ accessTokenUri: https://github.com/login/oauth/access_token
+ userAuthorizationUri: https://github.com/login/oauth/authorize
+ clientAuthenticationScheme: form
+ resource:
+ userInfoUri: https://api.github.com/user
+ preferTokenInfo: false
+run the app above and it will redirect to github for authorization. If +you are already signed into github you won’t even notice that it has +authenticated. These credentials will only work if your app is +running on port 8080.
+To limit the scope that the client asks for when it obtains an access token
+you can set spring.oauth2.client.scope (comma separated or an array in YAML). By
+default the scope is empty and it is up to to Authorization Server to
+decide what the defaults should be, usually depending on the settings in
+the client registration that it holds.
|
+ Note
+ |
++The examples above are all Groovy scripts. If you want to write the +same code in Java (or Groovy) you need to add Spring Security OAuth2 +to the classpath (e.g. see the +sample here). + | +
OAuth2 Protected Resource
+You want to protect an API resource with an OAuth2 token? Here’s a +simple example (paired with the client above):
+@Grab('spring-cloud-starter-security')
+@RestController
+@EnableResourceServer
+class Application {
+
+ @RequestMapping('/')
+ def home() {
+ [message: 'Hello World']
+ }
+
+}
+and
+spring:
+ oauth2:
+ resource:
+ userInfoUri: https://api.github.com/user
+ preferTokenInfo: false
+More Detail
+Single Sign On
+|
+ Note
+ |
++All of the OAuth2 SSO and resource server features moved to Spring Boot +in version 1.3. You can find documentation in the +Spring Boot user guide. + | +
Token Relay
+A Token Relay is where an OAuth2 consumer acts as a Client and +forwards the incoming token to outgoing resource requests. The +consumer can be a pure Client (like an SSO application) or a Resource +Server.
+Client Token Relay
+If your app has a
+Spring
+Cloud Zuul embedded reverse proxy (using @EnableZuulProxy) then you
+can ask it to forward OAuth2 access tokens downstream to the services
+it is proxying. Thus the SSO app above can be enhanced simply like this:
@Controller
+@EnableOAuth2Sso
+@EnableZuulProxy
+class Application {
+
+}
+and it will (in addition to loggin the user in and grabbing a token)
+pass the authentication token downstream to the /proxy/*
+services. If those services are implemented with
+@EnableOAuth2Resource then they will get a valid token in the
+correct header.
How does it work? The @EnableOAuth2Sso annotation pulls in
+spring-cloud-starter-security (which you could do manually in a
+traditional app), and that in turn triggers some autoconfiguration for
+a ZuulFilter, which itself is activated because Zuul is on the
+classpath (via @EnableZuulProxy). The
+filter
+just extracts an access token from the currently authenticated user,
+and puts it in a request header for the downstream requests.
Resource Server Token Relay
+If your app has @EnableOAuth2Resource and also is a Client (i.e. it
+has a spring.oauth2.client.clientId, even if it doesn’t use it),
+then the OAuth2RestOperations that is provided for @Autowired
+users by Spring Cloud (it is declared as @Primary) will also forward
+tokens. If you don’t want to forward tokens (and that is a valid
+choice, since you might want to act as yourself, rather than the
+client that sent you the token), then you only need to create your own
+OAuth2RestOperations instead of autowiring the default one. Here’s
+a basic example showing the use of the autowired rest template ("foo.com"
+is a Resource Server accepting the same tokens as the surrounding app):
@Autowired
+private OAuth2RestOperations restTemplate;
+
+@RequestMapping("/relay")
+public String relay() {
+ ResponseEntity<String> response =
+ restTemplate.getForEntity("https://foo.com/bar", String.class);
+ return "Success! (" + response.getBody() + ")";
+}
+Configuring Authentication Downstream of a Zuul Proxy
+You can control the authorization behaviour downstream of an
+@EnableZuulProxy through the proxy.auth.* settings. Example:
proxy:
+ auth:
+ routes:
+ customers: oauth2
+ stores: passthru
+ recommendations: none
+In this example the "customers" service gets an OAuth2 token relay, +the "stores" service gets a passthrough (the authorization header is +just passed downstream), and the "recommendations" service has its +authorization header removed. The default behaviour is to do a token +relay if there is a token available, and passthru otherwise.
+See + +ProxyAuthenticationProperties for full details.
+