0

My spring boot (2.2.4) application is using siteminder as authentication provider. Upon successful authentication siteminder sends user details (Roles) in Http header. Inside the application I need to use spring security for role based authorization. Here is reference documentation I am following - https://docs.spring.io/spring-security/site/docs/5.0.x/reference/html/preauth.html

My spring-security.xml will look this.

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/security
        https://www.springframework.org/schema/security/spring-security.xsd">

    <security:http>
        <!-- Additional http configuration omitted -->
        <security:csrf disabled="true"/>
        <security:intercept-url pattern="/**" access="hasRole('ROLE_ABC')"/>
        <security:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter" />
    </security:http>

    <bean id="siteminderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
        <property name="principalRequestHeader" value="SM_USER"/>
        <property name="authenticationManager" ref="authenticationManager" />
    </bean>

    <bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
        <property name="preAuthenticatedUserDetailsService">
            <bean id="userDetailsServiceWrapper"
                  class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
                <property name="userDetailsService" ref="userDetailsService"/>
            </bean>
        </property>
    </bean>

    <bean id="userDetailsService" class="com.mycode.service.SCPMUserDetailsService"/>

    <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider ref="preauthAuthProvider" />
    </security:authentication-manager>
</beans>

How do I create a Java config file which will incorporate above security for Spring boot application.

I started something like this and need to inject all the pieces in above xml file.

@EnableWebSecurity
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService myUserDetailsService;


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()// Disable for GraphIQL to work locally
                .antMatcher("/**")
                .authorizeRequests()
                .antMatchers("/healthcheck/**").permitAll()
                .antMatchers("/scpm/**").permitAll()
                .antMatchers("/approvers/**").hasRole("APPROVER")
                .antMatchers("/departments/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and().httpBasic();
    }
}
Bikram Das
  • 21
  • 2

1 Answers1

2

Spring Security reference document does not provide Java Code for SiteMinder integration. It just provides xml configuration for non-spring boot applications. Here is the Java code which can be used in any Spring Boot Application.

@EnableWebSecurity
@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
        auth.authenticationProvider(preAuthenticatedAuthenticationProvider());
    }

    @Bean
    public RequestHeaderAuthenticationFilter siteminderFilter() throws Exception {
        RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
        filter.setPrincipalRequestHeader("SM_USER");
        filter.setAuthenticationManager(this.authenticationManager());
        return filter;
    }

    @Bean
    public PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider() {
        PreAuthenticatedAuthenticationProvider preauthAuthProvider = new PreAuthenticatedAuthenticationProvider();
        preauthAuthProvider.setPreAuthenticatedUserDetailsService(userDetailsByNameServiceWrapper());
        return preauthAuthProvider;
    }

    @Bean
    public UserDetailsByNameServiceWrapper userDetailsByNameServiceWrapper() {
        UserDetailsByNameServiceWrapper userDetailsServiceWrapper = new UserDetailsByNameServiceWrapper();
        userDetailsServiceWrapper.setUserDetailsService(userDetailsService);
        return userDetailsServiceWrapper;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .addFilter(siteminderFilter())
                .csrf().disable()// Disable for GraphIQL to work locally
                .antMatcher("/**")
                .authorizeRequests()
                .antMatchers("/healthcheck/**").permitAll()
                .antMatchers("/approvers/**").hasRole("APPROVER")
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and().httpBasic();
    }
}

Here is custom UserDetailsService.

@Service
public class MyUserDetailsService implements UserDetailsService {

    private Logger logger = LoggerFactory.getLogger(SCPMUserDetailsService.class);

    @Autowired
    private HttpServletRequest request;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException{
        HttpServletRequest request  =
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                        .getRequest();
        String csgroups = "";
        Collection<GrantedAuthority> auth = new ArrayList<>();

        try {
            username = request.getHeader("SM_USER");
        } catch (Exception ex){
            logger.trace("SM_USER not found in Request Http Headers");
            ex.printStackTrace();
        }

        try {
            csgroups = request.getHeader("ROLES");;
        } catch (Exception ex){
            logger.trace("CSGROUPS not found in Request Http Headers");
            ex.printStackTrace();
        }

        //Roles
        if(csgroups != null) {
            StringTokenizer st = new StringTokenizer(csgroups, "^");

            while (st.hasMoreElements()) {
                GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + st.nextToken());
            }
        }
        return new User(username, "", true, true, true, true,auth);
    }


    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }
}
Bikram Das
  • 21
  • 2