Showing posts with label OAuth2. Show all posts
Showing posts with label OAuth2. Show all posts

Tuesday, March 6, 2018

Spring Boot 2 native approach to SSO with OAuth 2/OpenID Connect

This post is the final part of a 3 post series exploring ways to enable SSO with an OAuth2 provider for Spring Boot 2 based applications. The 3 posts are:

1. Ways to bootstrap an OpenID Connect compliant OAuth2 Authorization Server/OpenID Provider
2. Legacy Spring Boot/Spring 5 approach to integrating with an OAuth2 Authorization Server/OpenID Provider
3. Newer Spring Boot 2/Spring 5 approach to integrating with an OAuth2 Authorization Server/OpenID Connect Provider - this post

This post will explore the shiny new way to enable SSO for a Spring Boot 2 application using the native OAuth2 support in Spring Security.

The post again assumes that everything described in the first post is completed.


Spring Boot 2 Auto-configuration


Spring Boot 2 provides an auto-configuration for native OAuth2 support in Spring Security ( see class org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration).
The auto-configuration is activated by the presence of "spring-security-oauth2-client" library available via the following gradle coordinates:

compile "org.springframework.security:spring-security-oauth2-client"

This auto-configuration works off a set of properties, for the UAA Identity provider that has been started up, the set of properties are the following:

uaa-base-url: http://localhost:8080/uaa

spring:
  security:
    oauth2:
      client:
        registration:
          uaa:
            client-id: client1
            client-secret: client1
            authorizationGrantType: authorization_code
            redirect_uri_template: "{baseUrl}/login/oauth2/code/{registrationId}"
            scope: resource.read,resource.write,openid,profile
            clientName: oauth2-sample-client
        provider:
          uaa:
            token-uri: ${uaa-base-url}/oauth/token
            authorization-uri: ${uaa-base-url}/oauth/authorize
            user-info-uri: ${uaa-base-url}/userinfo
            jwk-set-uri: ${uaa-base-url}/token_keys
            userNameAttribute: user_name

If I were to depend on Spring Boot 2 auto-configuration support for native OAuth2 support to do its magic and were to start the application up, I would be presented with this page on accessing the application:


Note that this login page is a default page created by Spring Security OAuth2 and by default presents the list of registrations.

Clicking on "oauth2-sample-client" presents the login page of the Identity provider, UAA in this instance:

For an OpenID Connect based flow, applications are issued an ID Token along with an Access Token which I am decoding and presenting on a page:



Customizations

One of the quick customizations that I want to make is to redirect to UAA on access of any secured page specified via a "/secured" uri pattern, the following is a set of configuration that should enable this:

package sample.oauth2.config

import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.builders.WebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter

@Configuration
class OAuth2SecurityConfig : WebSecurityConfigurerAdapter() {
    override fun configure(web: WebSecurity) {
        super.configure(web)
        web.ignoring()
                .mvcMatchers(
                        "/favicon.ico",
                        "/webjars/**",
                        "/css/**"
                )
    }

    override fun configure(http: HttpSecurity) {
        http.csrf().disable()

        http.authorizeRequests()
                .antMatchers("/secured/**")
                    .authenticated()
                .antMatchers("/", "/custom_login")
                    .permitAll()
                .anyRequest()
                    .authenticated()
                .and()
                    .oauth2Login()
                    .loginPage("/custom_login")
    }
}

See the "/custom_login" being set as the URI above, which in turn simply hands over control to OAuth2 controlled endpoints which know to set the appropriate parameters and redirect to UAA:

@Controller
class LoginController {

    @RequestMapping("/custom_login")
    fun loginPage(): String {
        return "redirect:/oauth2/authorization/uaa"
    }
}



This concludes the exploration of native OAuth2 support in Spring Boo2 applications.

All of the samples are available in my github repo - https://github.com/bijukunjummen/oauth2-boot2


The following references were helpful in understanding the OAuth2 support:

1. Spring Security Documentation - https://docs.spring.io/spring-security/site/docs/current/reference/html/
2. Joe Grandja's Spring One Platform 2017 Presentation - https://www.youtube.com/watch?v=WhrOCurxFWU

Monday, February 26, 2018

Spring Boot 2 Applications and OAuth 2 - Legacy Approach

This post is the second part of a 3 post series exploring ways to enable SSO with an OAuth2 provider for Spring Boot 2 based applications. The 3 posts are:

1. Ways to bootstrap an OpenID Connect compliant OAuth2 Authorization Server/OpenID Provider
2. Legacy Spring Boot/Spring 5 approach to integrating with an OAuth2 Authorization Server/OpenID Provider - this post
3. Newer Spring Boot 2/Spring 5 approach to integrating with an OAuth2 Authorization Server/OpenID Connect Provider


The post will explore a legacy Spring Boot 2/Spring Security 5 approach to enabling OAuth2 based authentication mechanism for an application, this post assumes that all the steps in the previous blog post have been followed and UAA is up and running.

A question that probably comes to mind is why I am talking about legacy in the context of Spring Boot 2/Spring Security 5 when this should have been the new way of doing SSO! The reason is, as developers we have been using an approach with Spring Boot 1.5.x that is now considered deprecated, there are features in it however that has not been completely ported over to the new approach(ability to spin up an OAuth2 authorization server and ability to create an OAuth2 resource server are examples), in the interim, Spring Security developers(thanks Rob Winch & Joe Grandja) provided a bridge to the legacy approach in the form of a spring-security-oauth2-boot project.

Approach

So what does the legacy approach look like - I have detailed it once before here, to recap it works on the basis of an annotation called @EnableOAuth2SSO and a set of properties supporting this annotation, a sample security configuration looks like this -

import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableOAuth2Sso
@Configuration
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);

        web.ignoring()
           .mvcMatchers("/favicon.ico", "/webjars/**", "/css/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();

        http.authorizeRequests()
                .antMatchers("/secured/**")
                    .authenticated()
                .antMatchers("/")
                    .permitAll()
                .anyRequest()
                    .authenticated();
    }

}

and the set of supporting properties to point to the UAA is the following:

ssoServiceUrl: http://localhost:8080/uaa

security:
  oauth2:
    client:
      client-id: client1
      client-secret: client1
      access-token-uri: ${ssoServiceUrl}/oauth/token
      user-authorization-uri: ${ssoServiceUrl}/oauth/authorize
    resource:
      jwt:
        key-uri: ${ssoServiceUrl}/token_key
      user-info-uri: ${ssoServiceUrl}/userinfo


With the spring-security-oauth2-boot project pulled in as a dependency:

compile 'org.springframework.cloud:spring-cloud-starter-oauth2'
compile("org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.0.0.BUILD-SNAPSHOT")

these annotations just work for a Spring Boo2 application also. Note however Spring Boot 2 supports two distinct Web Frameworks - Spring Web and Spring Webflux, this approach pulls in Spring Web transitively which forces Spring Web as the default framework.

The sample in its entirety with ways to start it up is available in my github repo here - https://github.com/bijukunjummen/oauth2-boot2


Testing

Any uri starting with "/secured/**" is SSO enabled, if the index page is accessed it is displayed without needing any authentication:



Now, clicking through to a uri starting with "/secured/**" should trigger a OAuth2 Authorization Code flow:


and should present a login screen to the user via UAA:



Logging in with the credentials that were created before - user1/user1 should redirect the user back to the Spring Boot 2 legacy version of the app and should display the secured page:




This completes the legacy approach to SSO with Spring Boot 2. Note that this is just pseudo-authentication, OAuth2 is meant more for authorization to access a users resource than authentication the way it is used here. An article which clarifies this is available here. The next post with native Spring Security 5/Spring Boot2 will provide a cleaner authentication mechanism using OpenID Connect.

Sunday, February 11, 2018

Spring Boot 2 Applications and OAuth 2 - Setting up an Authorization Server

This will be a 3 post series exploring ways to enable SSO with an OAuth2 provider for Spring Boot 2 based applications. I will cover the following in these posts:

1. Ways to bootstrap an OpenID Connect compliant OAuth2 Authorization Server/OpenID Provider - this post
2. Legacy Spring Boot/Spring 5 approach to integrating with an OAuth2 Authorization Server/OpenID Provider
3. Newer Spring Boot 2/Spring 5 approach to integrating with an OAuth2 Authorization Server/OpenID Provider

This post will cover ways to bootstrap an OpenID Connect compliant OAuth2 Authorization Server running on a local machine.

The post is essentially a rehash of an earlier post which went into details of bootstrapping an OAuth2 authorization server using the excellent Cloud Foundry UAA project. There are a few changes since my previous post and I wanted to capture afresh the steps to bring up an Authorization server with a little more emphasis on changes to make it OpenID Connect compliant.

The best way to get a local version of a robust OAuth2 Authorization server running is to use the excellent Cloud Foundry UAA project.

Step 1: Clone the project:

git clone https://github.com/cloudfoundry/uaa

Step 2: Generate a keypair
UAA can make use of an asymmetric RSA keypair for signing and let clients verify the signature. I have a handy script available here which generates a keypair and generates a configuration file that can used for bootstrapping UAA:



When run this creates a UAA configuration which looks like this:

jwt:
   token:
      signing-key: |
       -----BEGIN RSA PRIVATE KEY-----
       MIIEpAIBAAKCAQEAuE5Ds...5Nka1vOTnjDgKIfsN
       NTAI25qNNCZOXXnGp71gMWsXcLFq4JDJTovL4/rzPIip/1xU0LjFSw==
       -----END RSA PRIVATE KEY-----
      verification-key: |
       -----BEGIN PUBLIC KEY-----
       MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuE5DsCmjfvWArlCIOL6n
       ZwIDAQAB
       -----END PUBLIC KEY-----

Step 3: Use the configuration to start up the UAA server:

UAA_CONFIG_URL=file://$PWD/uaa_config.yml ./gradlew run 

Step 4: Validate
A quick way to validate if the UAA has started up is to check the JWKS_URI, this is an endpoint which exposes the set of verification keys that a client can use to validate the token. For UAA, this is available at "/token_keys" endpoint, with either curl or httpie this endpoint can be validated:

http GET http://localhost:8080/uaa/token_keys

# OR

curl http://localhost:8080/uaa/token_keys

if things are configured okay, an output of the following form is expected from this endpoint:

{
    "keys": [
        {
            "alg": "RS256",
            "e": "AQAB",
            "kid": "legacy-token-key",
            "kty": "RSA",
            "n": "APLeBV3dcUrWuVEXRyFzNaOTeKOLwFjscxbWFGofCkxrp3r0nRbBBb4ElG4qYzmbStg5o-zXAPCOu7Pqy2j4PtC3OxLHWnKsflNOEWTeXhLkPE0IptHPbc6zgVPP3EoiG_umpm0BYeJPZZc-7tA11uU_3NqidY9wnpOgKBuwNmdoyUrjb4fBDoMr_Wk2_sn_mtHSG8HaX8eJ9SbC9xRCJySjJDApOYR_dKjuwpbcM2ITfbTzD9M2J7yOtoJRkFhd1Ug2t_6AA_z47BBws-x9BBfSNbYGsVlDAbe6NK_jUE",
            "use": "sig",
            "value": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8t4FXd1xSta5URdHIXM1\no5N4o4vAWOxzFtYUah8KTGunevSdFsEFvgSUbipjOZtK2Dmj7NcA8I67s+rLaPg+\n0Lc7Esdacqx+U04RZN5eEuQ8TQim0c9tzrOBU8/cSiIb+6ambQF62glGQWF3VSDa3/oAD/PjsEHCz7H0EF9I1tgaxWUMBt7o0r+N\nQQIDAQAB\n-----END PUBLIC KEY-----"
        }
    ]
}



Step 5: Populate Data
UAA has a companion CLI application called uaac, available here. Assuming that you have the uaac cli downloaded and UAA started up at its default port of 8080, let us start by pointing the uaac to the uaa application:

uaac target http://localhost:8080/uaa

and log into it using one of the canned client credentials(admin/adminsecret):

uaac token client get admin -s adminsecret

Now that a client has logged in, the token can be explored using :

uaac token decode

which should display the details of the logged in client:

jti: 4457847692b7464ca0320f08271a9e98
  sub: admin
  authorities: clients.read clients.secret clients.write uaa.admin clients.admin scim.write scim.read
  scope: clients.read clients.secret clients.write uaa.admin clients.admin scim.write scim.read
  client_id: admin
  cid: admin
  azp: admin
  grant_type: client_credentials
  rev_sig: 3c12911
  iat: 1518332992
  exp: 1518376192
  iss: http://localhost:8080/uaa/oauth/token
  zid: uaa

the raw jwt token can be obtained using the following command:

uaac context


with an output which looks like this:

[3]*[http://localhost:8080/uaa]
  skip_ssl_validation: true

  [2]*[admin]
      client_id: admin
      access_token: eyJhbGciOiJSUzI1NiIsImtpZCI6ImxlZ2FjeS10b2tlbi1rZXkiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiI0NDU3ODQ3NjkyYjc0NjRjYTAzMjBmMDgyNzFhOWU5OCIsInN1YiI6ImFkbWluIiwiYXV0aG9yaXRpZXMiOlsiY2xpZW50cy5yZWFkIiwiY2xpZW50cy5zZWNyZXQiLCJjbGllbnRzLndyaXRlIiwidWFhLmFkbWluIiwiY2xpZW50cy5hZG1pbiIsInNjaW0ud3JpdGUiLCJzY2ltLnJlYWQiXSwic2NvcGUiOlsiY2xpZW50cy5yZWFkIiwiY2xpZW50cy5zZWNyZXQiLCJjbGllbnRzLndyaXRlIiwidWFhLmFkbWluIiwiY2xpZW50cy5hZG1pbiIsInNjaW0ud3JpdGUiLCJzY2ltLnJlYWQiXSwiY2xpZW50X2lkIjoiYWRtaW4iLCJjaWQiOiJhZG1pbiIsImF6cCI6ImFkbWluIiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInJldl9zaWciOiIzYzEyOTExIiwiaWF0IjoxNTE4MzMyOTkyLCJleHAiOjE1MTgzNzYxOTIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC91YWEvb2F1dGgvdG9rZW4iLCJ6aWQiOiJ1YWEiLCJhdWQiOlsic2NpbSIsImNsaWVudHMiLCJ1YWEiLCJhZG1pbiJdfQ.ZEcUc4SvuwQYwdE0OeG5-l8Jh1HsP0JFI3aCob8A1zOcGOGjqso4j1-k_Lzm__pGZ702v4_CkoXOBXoqaaRbfVgJybBvOWbWsUZupMVMlEsyaR_j8DWY8utFAIiN2EsQgjG3qLrsf0K8lm0I3_UIEjaNZhSkWSLDLyY9wr_2SRanSf8LkcEJoSTTgDdO0aP8MvwNpDG7iQ2Om1HZEN08Bed1hHj6e1E277d9Kw7gutgCBht5GZDPFnI6Rjn0O5wimgrAa6FEDjdCpR7hy2P5RiOTcTvjj3rXtVJyVcQcxGKymZrY2WOx1mIEzEIAj8NYlw0TLuSVVOiNZ9fKlRiMpw
      token_type: bearer
      expires_in: 43199
      scope: clients.read clients.secret clients.write uaa.admin clients.admin scim.write scim.read
      jti: 4457847692b7464ca0320f08271a9e98

Finally to add a client with creds of client1/client1 and a user with a creds of user1/user1:

uaac client add client1 \
   --name client1 \
   --scope resource.read,resource.write,openid,profile,email,address,phone \
   -s client1 \
   --authorized_grant_types authorization_code,refresh_token,client_credentials,password \
   --authorities uaa.resource \
   --redirect_uri http://localhost:8888/**


# Add a user called user1/user1
uaac user add user1 -p user1 --emails user1@user1.com


# Add two scopes resource.read, resource.write
uaac group add resource.read
uaac group add resource.write

# Assign user1 both resource.read, resource.write scopes..
uaac member add resource.read user1
uaac member add resource.write user1


At this point we have a working Authorization Server with a sample client and a sample user available. The subsequent posts will make use of this data to enable authentication for a Sample Spring Boot2 application. I will update the links in this post as I complete the newer posts.


Correction

Previously I had defined only "openid" scope as the scope that a client requests on behalf of a user. OpenID Connect requires other scopes to be able to call the userinfo endpoint, the updated client definition looks like this:

uaac client add client1 \
   --name client1 \
   --scope resource.read,resource.write,openid,profile,email,address,phone \
   -s client1 \
   --authorized_grant_types authorization_code,refresh_token,client_credentials,password \
   --authorities uaa.resource \
   --redirect_uri http://localhost:8888/**