Securing Microservices with OpenID Connect and Spring Security 5.1 [Workshop]

Andreas Falk

@andifalk

Slides: https://andifalk.github.io/oidc-workshop-spring-io-2019
Source-Code: https://github.com/andifalk/oidc-workshop-spring-io-2019.git

Andreas Falk

Novatec Consulting GmbH

https://www.novatec-gmbh.de
andreas.falk@novatec-gmbh.de / @andifalk

Novatec Offices

Session tomorrow at 18:00

Agenda

Intro to OAuth 2.0

Intro to OpenID Connect 1.0

Hands-On Part with Spring Security 5.1

What's new in Spring Security 5.2 and 5.3

In the meantime...

git clone https://tinyurl.com/yylensdd oidc_workshop

import as gradle project into your Java IDE

AND

copy/extract keycloak.zip from provided USB sticks

OR follow setup instructions at https://tinyurl.com/y3rgohqo

OAuth 2.0

101

RFC 6749: The OAuth 2.0 Authorization Framework
RFC 6750: OAuth 2.0 Bearer Token Usage
RFC 6819: OAuth 2.0 Threat Model and Security Considerations

What is OAuth 2.0?

OAuth 2.0 is an authorization delegation framework

OAuth 2.0 Model

OAuth 2.0 Grant Flows

Client Type Flow Refresh Tokens
Confidential Authorization Code X
Public (Native) Authorization Code (PKCE) X
Public (SPA) Implicit --
Trusted RO Password Creds X
No Resource Owner Client Credentials --

Authorization Code Grant Flow

We'll see

Authorization Code Grant Flow

in action as part of Intro Lab

Implicit Flow Attacks


Source: Torsten Lodderstedt and Daniel Fett

OAuth 2.0 Security Best Current Practice

“OAuth 2.1” Grant Flows

Client Type Flow Refresh Tokens
Confidential Authorization Code (PKCE) X
Public (Native) Authorization Code (PKCE) X
Public (SPA) Authorization Code (PKCE) --
Trusted RO Password Creds X
No Resource Owner Client Credentials --

Proof Key for Code Exchange by OAuth Public Clients (PKCE)

(“Pixy”)

Mitigates authorization code attacks

Mitigates token leakage in SPAs

Proof Key for Code Exchange by OAuth Public Clients

PKCE - Authorization Request

GET https://authserver.example.com/authorize

?response_type=code

&client_id=abcdefg

&redirect_uri=https://client.abc.com/callback

&scope=api.read api.write

&state=xyz

&code_challenge=xyz...

&code_challenge_method=S256

PKCE - Token Request

POST https://authserver.example.com/token

Content-Type:
application/x-www-form-urlencoded

grant_type=authorization_code&code=ab23bhW56Xb

&redirect_uri=https://client.abc.com/callback

&client_id=123&client_secret=456

&code_verifier=4gth4jn78k_8

OAuth 2 Access Token JWT Profile

Required claims: iss, exp, aud, sub, client_id

Consider privacy restrictions for identity claims

Authorization claims according to SCIM Core (RFC7643):

  • Groups
  • Entitlements
  • Roles

System for Cross-domain Identity Management (SCIM)
JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens

OpenID Connect 1.0

101

OpenID Connect Core 1.0
OpenID Connect Dynamic Client Registration 1.0
OpenID Connect Discovery 1.0

OpenID Connect 1.0 is for Authentication

OAuth 2.0 is not an authentication protocol

OIDC Model

Additions to OAuth 2.0

Id Token (JWT format)

User Info Endpoint

OpenID Provider Configuration Information

ID Token

JSON Web token (JWT)

Base 64 Encoded JSON Formatted Value of...

...Header

...Payload

...Signature


                            GET / HTTP/1.1
                            Host: localhost:8080
                            Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1N...
                        

JSON Web Token (JWT)

Header


                            {
                              typ: "JWT",
                              alg: "RS256"
                            }
                        

Payload


                            {
                              iss: "https://identity.example.com",
                              aud: "my-client-id",
                              exp: 1495782385,
                              nonce: "N0.46824857243233511495739124749",
                              iat: 1495739185,
                              at_hash: "hC1NDSB8WZ9SnjXTid175A",
                              sub: "mysubject",
                              auth_time: 1495739185,
                              email: "test@gmail.com"
                            }
                        

ID Token Claims

Scope Required Description
iss X Issuer Identifier
sub X Subject Identifier
aud X Audience(s) of this ID Token
exp X Expiration time
iat X Time at which the JWT was issued
auth_time (X) Time of End-User authentication
nonce -- Associate a client with an ID Token

Token Validation

User Info Endpoint


                            GET /userinfo HTTP/1.1
                            Host: identityserver.example.com
                            Authorization: Bearer SlAV32hkKG
                        

                            HTTP/1.1 200 OK
                            Content-Type: application/json

                            {
                             "sub": "248289761001",
                             "name": "Jane Doe",
                             "given_name": "Jane",
                             "family_name": "Doe",
                             "preferred_username": "j.doe",
                             "email": "janedoe@example.com",
                             "picture": "http://example.com/janedoe/me.jpg"
                            }
                        

OpenID Connect 1.0 Configuration

https://example.com/.well-known/openid-configuration


                            {
                              "authorization_endpoint": "https://idp.example.com/auth",
                              "grant_types_supported": [
                                  "authorization_code",
                                  "implicit",
                                  "refresh_token"
                              ],
                              "issuer": "https://idp.example.com",
                              "jwks_uri": "https://idp.example.com/keys",
                              "token_endpoint": "https://idp.example.com/token",
                              "userinfo_endpoint": "https://idp.example.com/userinfo",
                              ...
                            }
                        

OpenID Connect Discovery 1.0

Hands-On Part

OAuth 2.0 & OpenID Connect 1.0

With Spring Security 5

“Legacy” Spring Security OAuth 2 Stack

“New” Spring Security
OAuth 2 Stack

“New” Spring Security
OAuth 2 Stack

We will use THIS stack !!!

Let's Code!!

git clone https://tinyurl.com/yylensdd oidc_workshop

import as gradle project into your Java IDE

AND

copy/extract keycloak.zip from provided USB sticks

Setup Keycloak

Follow setup instructions at: https://tinyurl.com/y3rgohqo

  1. Download the binary distribution: https://tinyurl.com/y2dcuu2o
  2. Extract the downloaded keycloak-6.0.1.zip file
  3. Download the prepared keycloak configuration: https://tinyurl.com/y3gpuwkj
  4. Extract the downloaded file keycloak_data.zip into the sub directory standalone of extracted keycloak

Start Keycloak

Start keycloak on Linux/Mac OS


                            [keycloak_install_dir]/bin/standalone.sh
                        
or on Windows

                            [keycloak_install_dir]\bin\standalone.bat
                        

Session tomorrow at 12:30

Intro-Lab

Authorization Code Grant Flow

In Action

See intro-labs/auth-code-demo for instructions

Hands-On application

An online book library

Administer Books

List available Books

Borrow a Book

Return a borrowed Book

Administer Library Users

Hands-On application

Hands-On Labs

  • Lab 1: OAuth2/OIDC Resource Server
  • Lab 2: OAuth2/OIDC Client (Auth Code Flow)
  • Lab 3: OAuth2/OIDC Client (Client-Credentials Flow)
  • Lab 4: OAuth2/OIDC Testing Environment

Please follow lab tutorials in GitHub Repo

What's new in

Spring Security

5.2 & 5.3

Spring Security 5.2 (08/2019)

Spring Security 5.2.0 M2 GitHub Issues
Spring Security 5.2.0 M3 GitHub Issues
Spring Security 5.2.0 RC1 GitHub Issues

OAuth 2.0 Token Introspection

Opaque Tokens


                            class ResSrvConfig extends WebSecurityConfigurerAdapter {

                                @Override
                                protected void configure(HttpSecurity http)
                                        throws Exception {
                                    http.oauth2ResourceServer()
                                            .opaqueToken()
                                                .introspectionUri(this.introspectionUri)
                                                .introspectionClientCredentials(
                                                    this.clientId, this.clientSecret);
                                }
                            }
                        
https://github.com/spring-projects/spring-security/issues/5200

Resource Server Multi-tenancy


                            class ResSrvConfig extends WebSecurityConfigurerAdapter {

                                @Override protected void configure(HttpSecurity http) {
                                    http.oauth2ResourceServer()
                                        .authenticationManagerResolver(
                                            multitenantAuthenticationManager());
                                }

                                @Bean AuthenticationManagerResolver<HttpServletRequest>
                                    multiTenantAuthMgr() {...}

                                AuthenticationManager jwt() {...}
                                AuthenticationManager opaque() {...}
                            }
                        
https://github.com/spring-projects/spring-security/issues/5351
https://github.com/spring-projects/spring-security/issues/6727

Use symmetric keys with JwtDecoder


                            class ResSrvConfig extends WebSecurityConfigurerAdapter {

                              @Value("${spring.security.oauth2.resourceserver.
                                            jwt.key-value}") RSAPublicKey key;

                              @Override protected void configure(HttpSecurity http) {
                                http.oauth2ResourceServer().jwt().decoder(jwtDecoder());
                              }

                              @Bean JwtDecoder jwtDecoder() throws Exception {
                                  return NimbusJwtDecoder.
                                          withPublicKey(this.key).build();
                              }
                            }
                        
https://github.com/spring-projects/spring-security/issues/5465

JWT Flow API in Test Support


                            public class OAuth2ResourceServerTest {

                                @Test
                                public void testRequestPostProcessor() {
                                  mockMvc.perform(get("/message")
                                  .with(mockAccessToken().scope("message:read")))
                                  .andExpect(status().isOk())

                                  mockMvc.perform(get("/")
                                  .with(jwt().claim(SUB, "the-subject")))
                                  .andExpect(status().isOk())
                                }
                            }
                        
https://github.com/spring-projects/spring-security/issues/6634

Spring Security 5.3

Support OAuth 2.0 Authorization Server:

  • OAuth 2.0 Authorization Code Grant
  • OpenID Connect 1.0 (Authorization Code Flow)
  • PKCE
  • OAuth 2.0 Client Credentials Grant
  • JWT Access Token format
  • JWK Set Endpoint
  • Opaque Access Token format
  • OAuth 2.0 Token Revocation

Spring Security 5.3.0 GitHub Issues

Session tomorrow at 14:30

Book References

Q&A

https://www.novatec-gmbh.de
https://blog.novatec-gmbh.de

andreas.falk@novatec-gmbh.de
Twitter: @andifalk

Online References

All images used are from Pixabay and are published under Creative Commons CC0 license.

All used logos are trademarks of respective companies