October 22, 2024
Chicago 12, Melborne City, USA
java

Spring security issue related to SpEL expressions after migrating from Spring boot 2 to spring boot 3


I had to migrate my spring boot application from spring boot 2 to spring boot 3. Along with that change I had to migrate from javax to jakarta. One main change was migrating security functionality from WebSecurityConfigurerAdapter to SecurityFilterChain. During this migration process, I faced several difficulties and among those difficulties, I still couldn’t solve one case related to SpEL.

The way it was handled in spring boot 2:
(The access API expects a String argument)

  private ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry mvcMatchers(
          ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
    final List<SecurityProperties.RequestMatcher> securedUrls = securityProperties.getSecured();
    
    securedUrls.forEach(entry -> {
      if (entry.getMethods() != null && !entry.getMethods().isEmpty()) {
        entry.getMethods().stream().forEach(httpMethod -> {
          ExpressionUrlAuthorizationConfigurer.AuthorizedUrl authorizedUrl = registry
                  .mvcMatchers(httpMethod, entry.getPatterns().toArray(new String[]{}));
          authorizedUrl.fullyAuthenticated();
          Optional.ofNullable(entry.getAccess()).ifPresent(spEL -> authorizedUrl.access(spEL));
        });
      }
    });
    return registry;
  }

The access API has been changed with spring boot 3. Now it requires AuthorizationManager<RequestAuthorizationContext> manager argument. I did attempt to convert my String SpEL expression into required argument type and continue yet it didn’t work as expected.

My spring boot 3 attempt to solve the issue:

  private void configureRequests(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry requests) {
    final List<SecurityProperties.RequestMatcher> securedUrls = securityProperties.getSecured();
    if (securedUrls != null) {
      securedUrls.forEach(entry -> {
        if (entry.getMethods() != null && !entry.getMethods().isEmpty()) {
          entry.getMethods().forEach(httpMethod -> {
            var authorizedUrl = requests.requestMatchers(httpMethod, entry.getPatterns().toArray(new String[]{}));
            authorizedUrl.fullyAuthenticated();
            Optional.ofNullable(entry.getAccess()).ifPresent(spEL -> {
              var manager = new WebExpressionAuthorizationManager(spEL);
              authorizedUrl.access(manager);
            });
          });
        } 
      });
    }
    requests.anyRequest().permitAll();
  }

With spring boot 2 it was very easy to provide the String SpEL expression and it did handle itself very well. Below is one example of such:

hasAuthority('role1') || hasAuthority('role2') || hasAuthority('role3') || request.getHeader('header_name') == 'header_value')

I am missing this easy configuration with spring boot 3 and I had to find a workaround solution. My solution was to manually go through the SpEL expression configuration and enable security as shown below:

  requests.requestMatchers(httpMethod, entry.getPatterns().toArray(new String[]{}))
          .hasAuthority(authority);

This is lot of work and very hard to tackle complex SpEL expressions. My concern is if it was so easy to provide the SpEL expression in spring boot 2, it can’t be that difficult to do the same in spring boot 3. I think I am missing something and really appreciate if anyone could help me to solve this. Thank you!



You need to sign in to view this answers

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video