From 97ff4f76b1e44190b592c65fdf1096b18401f539 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Thu, 18 Aug 2016 14:23:17 +0200 Subject: [PATCH] Sync docs from v1.0.3.RELEASE to gh-pages --- .../1.0.3.RELEASE/ghpages.sh | 54 + .../1.0.3.RELEASE/index.html | 976 ++++++++++++++++++ 2 files changed, 1030 insertions(+) create mode 100644 spring-cloud-security/1.0.3.RELEASE/ghpages.sh create mode 100644 spring-cloud-security/1.0.3.RELEASE/index.html diff --git a/spring-cloud-security/1.0.3.RELEASE/ghpages.sh b/spring-cloud-security/1.0.3.RELEASE/ghpages.sh new file mode 100644 index 00000000..e1063ce3 --- /dev/null +++ b/spring-cloud-security/1.0.3.RELEASE/ghpages.sh @@ -0,0 +1,54 @@ +#!/bin/bash -x + +git remote set-url --push origin `git config remote.origin.url | sed -e 's/^git:/https:/'` + +if ! (git remote set-branches --add origin gh-pages && git fetch -q); then + echo "No gh-pages, so not syncing" + exit 0 +fi + +if ! [ -d docs/target/generated-docs ]; then + echo "No gh-pages sources in docs/target/generated-docs, so not syncing" + exit 0 +fi + +# Find name of current branch +################################################################### +branch=$TRAVIS_BRANCH +[ "$branch" == "" ] && branch=`git rev-parse --abbrev-ref HEAD` +target=. +if [ "$branch" != "master" ]; then target=./$branch; mkdir -p $target; fi + +# Stash any outstanding changes +################################################################### +git diff-index --quiet HEAD +dirty=$? +if [ "$dirty" != "0" ]; then git stash; fi + +# Switch to gh-pages branch to sync it with current branch +################################################################### +git checkout gh-pages + +for f in docs/target/generated-docs/*; do + file=${f#docs/target/generated-docs/*} + if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then + # Not ignored... + cp -rf $f $target + git add -A $target/$file + fi +done + +git add -A README.adoc || echo "No change to README.adoc" +git commit -a -m "Sync docs from $branch to gh-pages" || echo "Nothing committed" + +# Uncomment the following push if you want to auto push to +# the gh-pages branch whenever you commit to branch locally. +# This is a little extreme. Use with care! +################################################################### +git push origin gh-pages || echo "Cannot push gh-pages" + +# Finally, switch back to the current branch and exit block +git checkout $branch +if [ "$dirty" != "0" ]; then git stash pop; fi + +exit 0 diff --git a/spring-cloud-security/1.0.3.RELEASE/index.html b/spring-cloud-security/1.0.3.RELEASE/index.html new file mode 100644 index 00000000..1fd7ecbb --- /dev/null +++ b/spring-cloud-security/1.0.3.RELEASE/index.html @@ -0,0 +1,976 @@ + + + + + + + +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 +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 + +ProxyAuthenticationProperties for full details.

+
+
+
+
+ + + \ No newline at end of file