Skip to content
This repository has been archived by the owner on Aug 28, 2024. It is now read-only.

Spring Security 5.0.x OIDC integration (for spring boot 2.0.x)

Pan Li edited this page Feb 11, 2019 · 1 revision

Integrate AAD B2C OpenId Connect with Spring Security.

Overview

Almost all web applications are sensitive to security, they may leverage spring security framework to customizable authentication and access-control. Assume there is one web application with spring security. One use sign-in process may take the process in steps:

  • A user is prompted to log in with a username and password.
  • The web application (successfully) verifies that the password is correct for the username.
  • The context information for that user is obtained.
  • A security context is established for the user.
  • The user proceeds, potentially to perform some operation which is potentially protected by an access control mechanism which checks the required permissions for the operation against the current security context information.
  • The web application can leverage AAD B2C as the Id management service and delegate the authentication to AAD B2C. Then the web application can get rid of the Id/User management like DB based authentication and focus on its own logic.

Spring Security Integration

Typically web security WebSecurityConfigurerAdapter configuration may looks like below code. Assume that you have one web application deployed in Azure. It may be one simple web site like Photo gallery. The web site may allow users to upload photos, as well as something like CRUD. Like most web site, there is one home page for everyone from internet, as well as one button named Sign up or in.

@Slf4j
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    private AADB2CEntryPoint aadb2CEntryPoint;

    private AADB2CLogoutSuccessHandler aadb2CLogoutSuccessHandler;

    private AADB2CFilter filter;

    public WebSecurityConfiguration(AADB2CEntryPoint entryPoint, AADB2CLogoutSuccessHandler successHandler,
                                    AADB2CFilter filter) {
        this.aadb2CEntryPoint = entryPoint;
        this.aadb2CLogoutSuccessHandler = successHandler;
        this.filter = filter;
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/", "/favicon.ico")
                .permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic()
                .authenticationEntryPoint(aadb2CEntryPoint)
                .and()
                .logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .logoutSuccessHandler(aadb2CLogoutSuccessHandler).deleteCookies("JSESSIONID")
                .and()
                .csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and()
                .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);
    }
}

Leveraging AAD B2C as identify management service is simplify configured by the application.yml. Only tenan, client-id, sign-up-or-sign-in and logout-success-url are required to configure.

server:
  port: 8080
azure:
  activedirectory:
    b2c:
      tenant: ${your-tenant-id}
      client-id: ${your-client-id}
      policies:
        sign-up-or-sign-in: # Required
          name: ${your-policy-name}
          reply-url: http://localhost:8080/     
        password-reset: # Optional
          name: ${your-policy-name}
          reply-url: http://localhost:8080/
        profile-edit: # Optional
          name: ${your-policy-name}
          reply-url: http://localhost:8080/
      # Required
      logout-success-url: http://localhost:8080/ # Only absolute URL is supported
      # Optional
      password-reset-url: http://localhost:8080/password-reset # Only absolute URL is supported
      # Optional
      profile-edit-url: http://localhost:8080/profile-edit # Only absolute URL is supported

How it works

Direct workflow of customer application leverage AAD B2C.

Before we start to learn how above code works, we would like to introduce the basic workflow of AAD B2C directly.

AAD B2C openId native work flow

  • First the user try to access protected resource from customer application.
  • Then the customer application will redirect to AAD B2C login page.
  • After login success, AAD B2C will redirect to reply URL (registry in AAD application) with id_token and code.
  • Customer application get the id_token and(or) code and mark the user authenticated.

Spring security workflow of customer application leverage AAD B2C.

Integration AAD B2C will involve one more layer between web application and AAD B2C service. It will accept the request from web site, do some filter work and redirect to AAD B2C endpoint which is transparent to web applications.

AAD-B2C-openId-spring-security

AAD B2C filter workflow

The filter of AAD B2C contains many different kinds of scenarios, for now we support Policy reply, Password reset, Profile edit and Default sceaniro in filter.

AAD-B2C-openId-filter

Polices

Sign up/in/out

AAD B2C provides the Policy for such kind of Sign up or in scenario for web site. Fortunately our package make the things easier when redirecting users to AAD B2C Sign in endpoint, as well as the scenario that accessing resource from web site without login. We provide one bean of authenticationEntryPoint for security configuration. According to the concept of spring security, it works with httpBasic as web site entry point, and redirect to AAD B2C endpoint for Sign in process. After success, the AAD B2C will redirect the users back to one registered Reply URL. Only need to provide the AAD B2C policy name and Reply URL from your application.yml.

The Sign up almost the same process as Sign In, we can skip this here.

For Sign out scenario with security consideration, there is one extra thing we would like to do beside spring security standard logout process. We should tell the AAD B2C that the token of the logout user is invalid after logout from web site successfully. One LogoutSuccessHandler bean is also provided to archive this. It will redirect to AAD B2C endpoint for invalidating current user token transparently, and then redirect user to the Reply URL like Sign in process.

The most important part is about how we obtain JWT from AAD B2C endpoint. Actually it may contains 2 steps. First the AAD B2C redirect to the Reply URL with query state, code and id_token. Second it redirects users to the Referer url before redirect to AAD B2C Sign in endpoint. Following the convention of spring security, we provide one Filter to archive this. It will process some important processes include but not limit to:

  • Validate the result from AAD B2C.
  • Obtain the query from Reply URL.
  • Parse and validate the id_token.
  • Create UserPrincipal from JWTClaim and code.
  • Create PreAuthenticatedAuthenticationToken with UserPrincipal and update SecurityContext.

Password reset

For security consideration, we recommend users to reset your password every 3-6 months. In previous section, the filter only take care of the Reply URL scenario from AAD B2C. It is simple to support the Password Reset scenario within that filter.

Straightforwardly, Reply URL is the redirect URL after password reset success. As Password reset is not the standard scenario of spring security, the web site need to specify the URL for Password reset. That means if there is one request to the URL of Password reset url, the filter will consider that the authenticated users would like to change password, and then redirect to AAD B2C endpoint to start the Password reset process. After the process end successfully, the AAD B2C will redirect to the Reply URL, just like what we do from Sign in scenario.

Profile edit

The scenario of Profile edit is the same as Password reset. The web site need to specify the URL for Profile edit, and then start the Profile reeset process.

Filter scenarios

Filter policy reply scenario

This scenario take care of the Reply URL redirecting from AAD B2C endpoint, includes but not limits to policies Sign up or in, Password rest and Profile edit. The Reply URL will contains query code, state and id_token when success, or error and error_description. The scenario handler will parse these information and start the process respectively.

Filter password reset scenario

This scenario only acts when users request Password reset with the Password reset url configured by web site. It will filter out the request to Password reset url and redirect users to AAD B2C endpoint to start the process. After the AAD B2C redirect users to Reply URL, it will start the policy reply scenario and update the authentication.

Filter profile edit scenario

This scenario interests Profile edit requests from users. Like password reset scenario, the web site need to configure Profile edit url. Then it will filter out the request to Profile edit url and redirect users to AAD B2C endpoint to start the process. The same as password reset scenario, it will start the policy reply scenario and update authentication after redirecting users to Reply URL from AAD B2C endpoint.

Filter default scenario

This is the default scenario in most cases for authenticated users. No surprise here and just update the users authentication as time passing.

Default security filter Chain break down

Creating filter chain: any request, [
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@14e2e1c3,
    org.springframework.security.web.context.SecurityContextPersistenceFilter@109d724c,
    org.springframework.security.web.header.HeaderWriterFilter@51b1a8f6,
    org.springframework.security.web.csrf.CsrfFilter@7103ab0, 
    org.springframework.security.web.authentication.logout.LogoutFilter@48c3205a, 
    com.microsoft.azure.spring.autoconfigure.b2c.AADB2CFilter@e93f3d5, 
    org.springframework.security.web.savedrequest.RequestCacheAwareFilter@e4d2696, 
    org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@70242f38, 
    org.springframework.security.web.authentication.AnonymousAuthenticationFilter@2b4786dd, 
    org.springframework.security.web.session.SessionManagementFilter@1b005a0b, 
    org.springframework.security.web.access.ExceptionTranslationFilter@cb0f763, 
    org.springframework.security.web.access.intercept.FilterSecurityInterceptor@562457e1
]