Search code examples
javaspringsoapspring-securitycxf

Apache CXF authentication + spring security


I want to use @RolesAllowed (or similar) annotation in my Apache-CXF-based SOAP application. But I don't understand how to configure Spring Security for this.

I want to authenticate from a XML header in SOAP messages.

Endpoint security configuration:

Map<String, Object> props = new HashMap<>();
props.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
props.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
endpoint.getInInterceptors().add(new WSS4JInInterceptor(props));

endpoint.getProperties().put("ws-security.validate.token", false);
endpoint.getProperties().put("ws-security.ut.no-callbacks", true);
endpoint.getProperties().put("ws-security.ut.validator", 
                             CredentialValidator.class.getName());

Also tried to use CallbackHandler. Same results.

Validator:

public class CredentialValidator extends UsernameTokenValidator {
    @Override
    public Credential validate(Credential credential, RequestData data)
                  throws WSSecurityException {
        String userName = credential.getUsernametoken().getName();
        String password = credential.getUsernametoken().getPassword();

        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority(Role.USER_ROLE));

        PreAuthenticatedAuthenticationToken token = new 
           PreAuthenticatedAuthenticationToken(
               userName, 
               password, 
               authorities);
        SecurityContextHolder.getContext().setAuthentication(token);
    }   
}

Spring Security configuration:

@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
          .antMatchers(HttpMethod.POST, "/services/**")
          .permitAll()
        ;
    }
}

If I use permitAll() in configuration then all requests pass, but annotations don't work. If I use authenticated() then I get "access denied" before my validator is working.

I use @AllowedRoles annotations in my @WebService interface.


Solution

  • Instead of using CredentialValidator you can try using TokenFilter. Your Spring Security configuration should look like this:

    @EnableWebSecurity
    @EnableGlobalMethodSecurity(jsr250Enabled = true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
          .antMatchers(HttpMethod.POST, "/services/**")
          .authenticated()
          .addFilterBefore(tokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
      }
    
    @Bean
    public TokenFilter tokenFilterBean() {
        return new TokenFilter();
      }    
    
    }    
    

    You can find full working project in my repo: repo