4

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.

Community
  • 1
  • 1
user2601995
  • 6,463
  • 8
  • 37
  • 41
  • 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: http://docs.spring.io/spring-security/site/docs/3.0.x/reference/preauth.html – CodeChimp Apr 09 '14 at 16:47
  • Yes, my idea is to modify the UserDetailsService to take the SM_USER and place the value into the authorities. – user2601995 Apr 10 '14 at 01:06
  • 1
    `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: http://forum.spring.io/forum/spring-projects/security/44678-spring-security-and-siteminder – CodeChimp Apr 10 '14 at 11:07

1 Answers1

4

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
}
user2601995
  • 6,463
  • 8
  • 37
  • 41
  • The loadUserByUserName, I think there is a mistake, because SiteMinderUserDetails userDetails = new SiteMinderUserDetails(); userDetails.setUsername(arg0); is not possible. There is no setUsername method in SiteMinderUserDetails class . I know it implements UserDetails, but UserDetails doesnt have any setters.Can you please elaborate and update this. This is a very useful answer and I just want it to be perfect, so that it will be useful to lot of ppl like myself :) Thanks ! – PavanSandeep Oct 31 '14 at 19:55
  • I dumped a bunch of code online a while back about this. http://www.learningthegoodstuff.com/2014/12/spring-security-pre-authentication-and.html – dseibert Feb 10 '16 at 01:54
  • I have to implement the Authorization completely using Java config (No XML), can you please provide solution for that. – Aditya Khajuria May 23 '16 at 11:29