From c9833720e64f0d1034488416f4195491aeda3911 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Thu, 25 Jun 2015 11:41:49 +0000 Subject: [PATCH] Sync docs from master to gh-pages --- spring-cloud.html | 574 +--------------------------------------------- 1 file changed, 2 insertions(+), 572 deletions(-) diff --git a/spring-cloud.html b/spring-cloud.html index dacfefc..8ac0918 100644 --- a/spring-cloud.html +++ b/spring-cloud.html @@ -541,26 +541,6 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
  • Encryption and Decryption
  • -
  • Spring Cloud Security - -
  • @@ -3485,565 +3465,15 @@ the key value with "@" and provide the file path, e.g.

    AQAjPgt3eFZQXwt8tsHAVv/QHiY5sI2dRcR+... - - -

    Spring Cloud Security

    -
    -
    -

    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.

    -
    - -
    -
    -
    -

    Quickstart

    -
    -
    -

    OAuth2 Single Sign On

    -
    -

    Here’s a Spring Cloud "Hello World" app with HTTP Basic -authentication and a single user account:

    -
    -
    -
    app.groovy
    -
    -
    @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:

    -
    -
    -
    app.groovy
    -
    -
    @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:

    -
    -
    -
    application.yml
    -
    -
    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):

    -
    -
    -
    app.groovy
    -
    -
    @Grab('spring-cloud-starter-security')
    -@RestController
    -@EnableOAuth2Resource
    -class Application {
    -
    -  @RequestMapping('/')
    -  def home() {
    -    [message: 'Hello World']
    -  }
    -
    -}
    -
    -
    -
    -

    and

    -
    -
    -
    application.yml
    -
    -
    spring:
    -  oauth2:
    -    resource:
    -      userInfoUri: https://api.github.com/user
    -      preferTokenInfo: false
    -
    -
    -
    -
    -
    -
    -

    More Detail

    -
    -
    -

    Single Sign On

    -
    -

    An app will activate @EnableOAuth2Sso if you bind provide the -following properties in the Environment:

    -
    -
    -
      -
    • -

      spring.oauth2.client.* with * equal to clientId, clientSecret, -accessTokenUri, userAuthorizationUri and one of:

      -
      -
        -
      • -

        spring.oauth2.resource.userInfoUri to use the "/me" resource -(e.g. "https://uaa.run.pivotal.io/userinfo" on PWS), or

        -
      • -
      • -

        spring.oauth2.resource.tokenInfoUri to use the token decoding endpoint -(e.g. "https://uaa.run.pivotal.io/check_token" on PWS).

        -
      • -
      -
      -
      -

      If you specify both the userInfoUri and the tokenInfoUri then -you can set a flag to say that one is preferred over the other -(preferTokenInfo=true is the default). Or

      -
      -
    • -
    • -

      spring.oauth2.resource.jwt.keyValue to -decode a JWT token locally, where the key is a verification key. The -verification key value is either a symmetric secret or PEM-encoded -RSA public key. If you don’t have the key and it’s public you can -provide a URI where it can be downloaded (as a JSON object with a -"value" field) with spring.oauth2.resource.jwt.keyUri. E.g. on PWS:

      -
      -
      -
      $ curl https://uaa.run.pivotal.io/token_key
      -{"alg":"SHA256withRSA","value":"-----BEGIN PUBLIC KEY-----\nMIIBI...\n-----END PUBLIC KEY-----\n"}
      -
      -
      -
    • -
    -
    -
    - - - - - -
    -
    Warning
    -
    -If you use the spring.oauth2.resource.jwt.keyUri the authorization -server needs to be running when your application starts up. It will -log a warning if it can’t find the key, and tell you what to do to fix -it. -
    -
    -
    -

    You can set the preferred scope (as a comma-separated list or YAML -array) in spring.oauth2.client.scope. It defaults to empty, in which case -most Authorization Servers will ask the user for approval for the -maximum allowed scope for the client.

    -
    -
    -

    There is also a setting for spring.oauth2.client.clientAuthenticationScheme which -defaults to "header" (but you might need to set it to "form" if, like -Github for instance, your OAuth2 provider doesn’t like header -authentication). The spring.oauth2.client.* properties are bound to an instance -of AuthorizationCodeResourceDetails so all its properties can be specified.

    -
    -
    -
    -

    Token Type in User Info

    -
    -

    Google (and certain other 3rd party identity providers) is more strict -about the token type name that is sent in the headers to the user info -endpoint. The default is "Bearer" which suits most providers and -matches the spec, but if you need to change it you can set -spring.oauth2.resource.tokenType.

    -
    -
    -
    -

    Customizing the RestTemplate

    -
    -

    The SSO (and Resource Server) features use an OAuth2RestTemplate -internally to fetch user details for authentication. This is provided -as a qualified @Bean with id "userInfoRestTemplate", but you -shouldn’t need to know that to just use it. The default should be fine -for most providers, but occasionally you might need to add additional -interceptors, or change the request authenticator (which is how the -token gets attached to outgoing requests). To add a customization just -create a bean of type UserInfoRestTemplateCustomizer - it has a -single method that will be called after the bean is created but before -it is initialized. The rest template that is being customized here is -only used internally to carry out authentication (in the SSO or -Resource Server use cases).

    -
    -
    -

    A second {@link OAuth2RestTemplate} is available for autowiring if you -want to use it for back channel calls, and if there is a -token-authenticated user (in a web application) it will have the token -injected for you.

    -
    -
    - - - - - -
    -
    Tip
    -
    -
    -

    To set an RSA key value in YAML use the "pipe" continuation -marker to split it over multiple lines ("|") and remember to indent -the key value (it’s a standard YAML language feature). Example:

    -
    -
    -
    -
    oauth2:
    -  resource:
    -    jwt:
    -      keyValue: |
    -        -----BEGIN PUBLIC KEY-----
    -        MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC...
    -        -----END PUBLIC KEY-----
    -
    -
    -
    -
    -
    -

    Access Decision Rules

    -
    -

    By default the whole application will be secured with OAuth2 with the -same access rule ("authenticated"). This includes the Actuator -endpoints, which you might prefer to be secured differently, so Spring -Cloud Security provides a configurer callback that lets you change the -matching and access rules for OAuth2 authentication. Any bean of type -OAuth2SsoConfigurer (there is a convenient empty base class) will -get 2 callbacks, one to set the request matchers for the OAuth2 -filter, and one with the full HttpSecurity builder (so you can set -up all sorts of behaviour, but the main application is to control -access rules).

    -
    -
    -

    The default login path, i.e. the one that triggers the redirect to the -OAuth2 Authorization Server, is "/login". It will always be added to -the matching patterns for the OAuth2 SSO, even if you have -OAuth2SsoConfigurer beans as well. The default logout path is -"/logout" and it gets similar treatment, as does the "home" page -(which is the logout success page, defaults to "/"). Those paths can -be overriden by setting spring.oauth2.sso.*' (`loginPath, logoutPath and -home.path).

    -
    -
    -

    For example if you want the resources under "/ui/**" to be protected with OAuth2:

    -
    -
    -
    -
    @Configuration
    -@EnableOAuth2Sso
    -@EnableAutoConfiguration
    -protected static class TestConfiguration extends OAuth2SsoConfigurerAdapter {
    -    @Override
    -    public void match(RequestMatchers matchers) {
    -        matchers.antMatchers("/ui/**");
    -    }
    -}
    -
    -
    -
    -

    In this case the rest of the application will default to the normal -Spring Boot access control (Basic authentication, or whatever custom -filters you put in place).

    -
    -
    -
    -

    Integrating with the Actuator Endpoints

    -
    -

    The Spring Boot Actuator endpoints ("/env", "/metrics", etc.) if -present will, by default, be protected by the standard Spring Boot -basic authentication. The SSO authentication filter is added in a -position directly behind the filter that intercepts requests to the -Actuator endpoints by default (i.e. -ManagementProperties.BASIC_AUTH_ORDER + 1 which is -Ordered.LOWEST_PRECEDENCE-9 or 2147483636). If you want to change -the order you can set spring.oauth2.sso.filterOrder. If you do that -and the value is less than the default, then you will need to consider -setting the access rules for the Actuator, since they will become -accessible to all authenticated users who sign on with the external -provider. One way to do that would be to set -management.contextPath=/admin (for instance) and use an -OAuth2SsoConfigurer to set the access rules, e.g.

    -
    -
    -
    -
    	@Configuration
    -	@EnableOAuth2Sso
    -	@EnableAutoConfiguration
    -	protected static class TestConfiguration extends OAuth2SsoConfigurerAdapter {
    -		@Override
    -		public void configure(HttpSecurity http) {
    -	         http.authorizeRequests()
    -                 .antMatchers("/admin/**").role("ADMIN")
    -                 .anyRequest().authenticated();
    -		}
    -	}
    -
    -
    -
    -
    -
    -

    Resource Server

    -
    -

    The @EnableOAuth2Resource annotation will protect your API endpoints -if you have the same environment settings as the SSO client, except -that it doesn’t need a tokenUri or authorizationUri, and it also -doesn’t need a clientId and clientSecret if it isn’t using the -tokenInfoUri (i.e. if it has jwt.* or userInfoUri).

    -
    -
    -

    By default all your endpoints are protected (i.e. "/**") but you can -pick and choose by adding a ResourceServerConfigurerAdapter (standard -Spring OAuth feature), e.g. to protect only the "/api/**" resources

    -
    -
    -
    Application.java
    -
    -
    @RestController
    -@EnableOAuth2Resource
    -class Application extends ResourceServerConfigurerAdapter {
    -
    -  @Override
    -  public void configure(HttpSecurity http) throws Exception {
    -    http.requestMatchers()
    -      .antMatchers("/api/**")
    -   .and()
    -     .authorizeRequests()
    -       .anyRequest().authenticated();
    -  }
    -
    -  @RequestMapping("/api")
    -  public String home() {
    -    return "Hello World";
    -  }
    -
    -}
    -
    -
    -
    -

    Customizing the JWT Token Converter

    -
    -

    When a resource server accepts an access token as a JWT, it has to -convert it to an Authentication so that Spring Security can do its -access decisions. Different token providers might support JWT tokens -with different contents, so Spring OAuth2 has an abstraction for -converting the token into security domain objects -(AccessTokenConverter). You can modify the default behaviour easily -by providing a @Bean of type JwtAccessTokenConverterConfigurer, -e.g.

    -
    -
    -
    -
    @Component
    -public class JwtCustomization extends DefaultAccessTokenConverter implements
    -        JwtAccessTokenConverterConfigurer {
    -
    -    @Override
    -    public void configure(JwtAccessTokenConverter converter) {
    -        converter.setAccessTokenConverter(this);
    -    }
    -
    -    ... // implement custom AccessTokenConverter here
    -
    -}
    -
    -
    -
    -
    -
    -

    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:

    -
    -
    -
    app.groovy
    -
    -
    @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 -{github}/tree/master/src/main/java/org/springframework/cloud/security/oauth2/proxy/OAuth2TokenRelayFilter.java[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):

    -
    -
    -
    MyController.java
    -
    -
    @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:

    -
    -
    -
    application.yml
    -
    -
    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 -{github}/tree/master/src/main/java/org/springframework/cloud/security/oauth2/proxy/ProxyAuthenticationProperties[ -ProxyAuthenticationProperties] for full details.

    +

    Unresolved directive in spring-cloud.adoc - include::../../../security/src/main/asciidoc/spring-cloud-security.adoc[]