4
votes

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.

1
I would suggest reading the chapter in the Spring Security docs about Pre-Authentication filters. It speaks directly about SiteMinder, and I believe gives working examples. The chapter in questions can be found here: docs.spring.io/spring-security/site/docs/3.0.x/reference/… - CodeChimp
Yes, my idea is to modify the UserDetailsService to take the SM_USER and place the value into the authorities. - user2601995
UserDetailsService is an interface. Simply make one and add it to your configuration. I believe that SiteMinder can be configured to include the user's roles as part of the headers passed in. Your custom UserDetailsService would have to get the value of that header (I think I remember it being 'SM_ROLES' or something like that) and parse the roles out. This posting on the Spring Forums provides one solution to that: forum.spring.io/forum/spring-projects/security/… - CodeChimp

1 Answers

4
votes

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
}