Search code examples
javaspringspring-mvcspring-securitysiteminder

Integrating Spring Security with SiteMinder


How do you integrate Spring Security with SiteMinder to receive a User and Role?

I have a project setup with Spring Security 'in-memory' and I want to use convert it to accept SiteMinder header with User and Roles. If SiteMinder will send the role of the user (ROLE_READ,ROLE_WRITE) and have the Service layer grant access. How do you convert the in-memory to use SiteMinder?

In-Memory User Roles

List of users and roles for in-memory

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="test" password="test" authorities="ROLE_READ" />
            <user name="admin" password="admin" authorities="ROLE_READ,ROLE_WRITE" />
        </user-service>
    </authentication-provider>
</authentication-manager>

Service Layer Protection

Here the service methods are protected with specific roles

<beans:bean id="testService" class="com.stackoverflow.test" scope="request">
    <security:intercept-methods>
        <security:protect access="ROLE_WRITE" method="do*"/>
        <security:protect access="ROLE_READ" method="find*"/>
    </security:intercept-methods>
</beans:bean>

This source (Spring Security Java Config for Siteminder) looks promising but its always assigned role RoleEmployee.


Solution

  • There is Spring Security for SiteMinder that exists to receive a User only. However, to receive a Role you'll need to create an extended authentication process. This will authenticate a user using a role.

    Within the root-security.xml

    <beans:bean id="userDetailsService" class="test.sm.SiteMinderUserDetailsService"/>
    
    <beans:bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
        <beans:property name="preAuthenticatedUserDetailsService">
            <beans:bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
                <beans:property name="userDetailsService" ref="userDetailsService" />
            </beans:bean>
        </beans:property>
    </beans:bean>
    
    <beans:bean id="siteminderFilter" class="test.sm.SiteMinderFilter">
        <beans:property name="principalRequestHeader" value="SM_USER" />
        <beans:property name="rolesRequestHeader" value="SM_ROLE" />
        <beans:property name="rolesDelimiter" value="," />
        <beans:property name="authenticationManager" ref="authenticationManager" />
    </beans:bean>
    
    <authentication-manager alias="authenticationManager">
        <authentication-provider ref="preauthAuthProvider" />
    </authentication-manager>
    

    SiteMinderUserDetailsService

    public class SiteMinderUserDetailsService extends PreAuthenticatedGrantedAuthoritiesUserDetailsService implements
            UserDetailsService {
    
        @Override
        public UserDetails loadUserByUsername(String arg0) throws UsernameNotFoundException {
            SiteMinderUserDetails userDetails = new SiteMinderUserDetails();
            userDetails.setUsername(arg0);      
            return userDetails;
        }
    
        @Override
        protected UserDetails createuserDetails(Authentication token, Collection<? extends GrantedAuthority> authorities) {
            return super.createuserDetails(token, authorities);
        }
    }
    

    SiteMinderUserDetails

    public class SiteMinderUserDetails implements UserDetails {
        // implement all methods
    }
    

    SiteMinderFilter

    public class SiteMinderFilter extends RequestHeaderAuthenticationFilter {
    
        private String rolesRequestHeader;
        private String rolesDelimiter;
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException, NullPointerException {
    
            String roles = (String)  ((HttpServletRequest)request).getHeader(getRolesRequestHeader());
            String[] rolesArray = roles.split(rolesDelimiter);
    
            Collection<SimpleGrantedAuthority> auth = new ArrayList<SimpleGrantedAuthority>();
            for (String s : rolesArray) {               
                auth.add(new SimpleGrantedAuthority(s));
            }
    
            SiteMinderUserDetails userDetails = new SiteMinderUserDetails();
            userDetails.setUsername((String) super.getPreAuthenticatedPrincipal(((HttpServletRequest)request)));
            userDetails.setAuthorities(auth);
    
            AuthenticationImpl authentication = new AuthenticationImpl();
            authentication.setAuthenticated(true);
            authentication.setAuthorities(auth);
            authentication.setPrincipal(userDetails);
            authentication.setCredentials(super.getPreAuthenticatedCredentials(((HttpServletRequest)request)));
            SecurityContextHolder.getContext().setAuthentication(authentication);
    
            super.doFilter(request, response, chain);
        }
    
        public SiteMinderFilter() {
            super();        
        }
    
        @Override
        public void setPrincipalRequestHeader(String principalRequestHeader) {
            super.setPrincipalRequestHeader(principalRequestHeader);
        }
    
        public void setRolesRequestHeader(String rolesRequestHeader) {
            this.rolesRequestHeader = rolesRequestHeader;
        }
    
        public String getRolesRequestHeader() {
            return rolesRequestHeader;
        }
    
    
        public void setRolesDelimiter(String rolesDelimiter) {
            this.rolesDelimiter = rolesDelimiter;
        }
    
        public String getRolesDelimiter() {
            return rolesDelimiter;
        }
    }
    

    AuthenticationImpl

    public class AuthenticationImpl implements Authentication {
        // implement all methods
    }