DEV Community

Cover image for Spring Boot and Multiple Authentication Profiles (None, Password & Okta)
Alex Yaroslavsky
Alex Yaroslavsky

Posted on • Edited on

Spring Boot and Multiple Authentication Profiles (None, Password & Okta)

Ahoy Spring user!

Recently, I added Okta login to my application to secure the admin section of the website. This is simple enough to accomplish but suddenly I felt the need to run my application locally without any authentication for testing purposes. As I couldn't find any good info on this on the web I decided to share the solution I came up with.

Full source code is here:

GitHub logo trexinc / spring-multi-web-security-config

Spring Boot and Multiple Authentication Profiles (None, Password & Okta)


A few quick words on setting up Okta authentication

  1. Register for a free developer account at https://developer.okta.com/
  2. Create a Spring Boot project with the following Spring Initialzer settings. Dependencies: Spring Web, Spring Security, Thymeleaf & OAuth2 Client. This solution works specifically with OAuth2 Client and not the native Okta library.
  3. In Okta application configuration change the Login redirect URIs to: http://localhost:8080/login/oauth2/code/okta Okta configuration
  4. In your application.properties configure the following:
    spring.security.oauth2.client.registration.okta.client-id=<client>
    spring.security.oauth2.client.registration.okta.client-secret=<client-secret>
    spring.security.oauth2.client.provider.okta.issuer-uri=https://<your-company>.okta.com/oauth2/default
  5. And you need to define a Web Security Config to enable Okta authentication:
    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
    @EnableWebSecurity
    public class SecurityOktaConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
    // require authenticated access to all resources
    .anyRequest().authenticated()
    // set logout URL
    .and().logout().logoutSuccessUrl("/")
    // enable OAuth2/OIDC
    .and().oauth2Client()
    .and().oauth2Login();
    }
    }

Back to the actual point

To enable several different security profiles I came up with the following solution. We define several Web Security Configurations each with its own @Profile("ProfileX) annotation, which enables this profile only when this profile is enabled in Spring.
The code looks likes this:

@Configuration
class WebSecurityConfig {
@Profile("local")
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@EnableWebSecurity
public static class SecurityDisabledConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// allow all requests
http.authorizeRequests().anyRequest().permitAll();
}
}
@Profile("password")
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@EnableWebSecurity
public static class SecurityPasswordConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// require authenticated access to /admin
.antMatchers("/admin", "/admin/**").authenticated()
// allow anonymous access to all other requests
.anyRequest().permitAll()
// set logout URL
.and().logout().logoutSuccessUrl("/")
// enable http basic authorization
.and().formLogin().and().httpBasic();
}
}
@Profile("okta")
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@EnableWebSecurity
public static class SecurityOktaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// require authenticated access to /admin
.antMatchers("/admin", "/admin/**").authenticated()
// allow anonymous access to all other requests
.anyRequest().permitAll()
// set logout URL
.and().logout().logoutSuccessUrl("/")
// enable OAuth2/OIDC
.and().oauth2Client()
.and().oauth2Login();
}
}
}

The relevant applications.properties sections look like this (of course only the one you want to use should be enabled, and it should be enabled only at runtime in your CI/CD pipeline):

#access open to all pages
spring.profiles.active=local
#require password for /admin
spring.profiles.active=password
spring.security.user.name=<user>
spring.security.user.password=<password>
#require Okta login for /admin
#in Okta dashboard, the web app login redirect URI must be set to (can be localhost if needed):
#<your-url>/login/oauth2/code/okta
spring.profiles.active=okta
spring.security.oauth2.client.registration.okta.client-id=<client>
spring.security.oauth2.client.registration.okta.client-secret=<client-secret>
spring.security.oauth2.client.provider.okta.issuer-uri=https://<your-company>.okta.com/oauth2/default

What is the best way to run the code locally?

Once we have the code and know how to make it work one issue remains, what is the best way to run it locally with authentication disabled without modifying the application.properties files and risking pushing those modifications to productions.

Two options that I like the most:

  1. Configure the relevant Spring profile in InteliJ, go to "Edit Configurations..." Edit Configurations... And set the profile as local Set profile
  2. Configure a bootRun task in build.gradle that will set the profile to local (unless defined otherwise in the environment):
    //Override profile when running locally
    bootRun {
    environment SPRING_PROFILES_ACTIVE: environment.SPRING_PROFILES_ACTIVE ?: "local"
    }
    view raw build.gradle hosted with ❤ by GitHub

That's it. Hope you found this useful. Leave comments and likes :)

Top comments (2)

Collapse
 
belgoros profile image
Serguei Cambour • Edited

Thank you for sharing. Do we need to set up an @Order when using different configurations by profile? For example, I have a configuration class in which I'd like just to change .antMatchers("/**").fullyAuthenticated() to .antMatchers("/**").permitAll() for local settings in the overridden configure(HttpSecurity http) method.

Collapse
 
trexinc profile image
Alex Yaroslavsky

No need to use @Order as long as all security adapters have a specific profile set on them.