简体   繁体   中英

Spring Security SAML with roles from database

I'm trying to integrate SAML SSO into an existing application that uses Spring Security with users, groups, and roles/permissions stored in a MySQL database. The application currently uses <security:jdbc-user-service> to get users and roles from the DB. The IDP in question offers only a unique username and an email address as attributes, so the application still has to store groups and roles associated with each user itself (as far as I understand).

So, I trying using both SAML and the DB by hooking the jdbc-user-service up with the samlAuthenticationProvider through the context configuration and a custom SAMLUserDetailsService .

Here's the relevant part of my applicationContext.xml :

<bean id="samlAuthenticationProvider" class="org.springframework.security.saml.SAMLAuthenticationProvider">
    <property name="userDetails" ref="customUserDetailService" />
</bean>
<bean id="customUserDetailService" class="org.myapp.CustomUserDetailsService">
    <property name="jdbcUserService" ref="jdbcUserDetailService" />
</bean>

<bean id="jdbcUserDetailService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
    <property name="dataSource" ref="dataSource" />
    <property name="usersByUsernameQuery" value="select username,username as password,enabled from person where username=?" />
    <property name="authoritiesByUsernameQuery" value="select u.username, p.name as authorities 
                from person u, group g, group_permissions up, permission p 
                where u.group = g.id and g.id = up.group and up.permissions = p.id and  
                u.username=?" />
</bean>

And this is the relevant part of CustomUserDetailsService :

public class CustomUserDetailsService implements SAMLUserDetailsService {

    private JdbcDaoImpl jdbcUserService;

    @Override
    public Object loadUserBySAML(SAMLCredential credential) throws UsernameNotFoundException {

        UserDetails user = null;
        String username = credential.getAttributeAsString("urn:mace:dir:attribute-def:cn");

        try {
            user = jdbcUserService.loadUserByUsername(username);
        } catch (UsernameNotFoundException e) {
            System.out.println("User not found in DB");
            // TODO
        }

        return user;
    }

    @Autowired
    public void setJdbcUserService(JdbcDaoImpl jdbcUserService) {
        this.jdbcUserService = jdbcUserService;
    }

    public JdbcDaoImpl getJdbcUserService() {
        return jdbcUserService;
    }
}

My question is: Is this a good idea to use org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl in this way?

I figured that the official Spring Security implementation (JdbcDaoImpl) of role retrieval from a DB is much more well-maintained, flexible, and bug-free than what I would come up with myself.

My second question is: Will using select username, username as password create a security problem in the app somehow?

Since my app never gets to see the password (because the user only enters it at the IDP), I have to replace it with something in the query. Should I take care to make this something hard to guess or is the password in the UserDetails not re-used anyway?

1. Is this a good idea and/or the way it's meant to be used?

Yes, You can have custom user object in spring and populate the user details.

2.Will using select username, username as password create a security problem in the app somehow?

No , Spring SAML doesnt expect user password to be stored in user object (rather saml response will be validted by spring). spring will validate username and authority alone. I advise you to just set username and Granted Authorities in user object.

Consider the diagram as follows:

基于 SAML 的 AuthN

It describes all the typical steps for SAML-based Authentication process.

  • An user asking for a protected resource is going to be redirected from the service provider (relying party) to a third-party Identity Provider.
  • The user performs the authentication on the Identity Provider (ie while providing username/password, OTP, PIN codes, etc.).
  • In case of successful authentication, the Identity Provider sends back to the Service Provider a SAML envelope. It contains user's profile information (first name, last name, email, telephone number, organisation, ect.) stored in SAML assertions, according to the agreement between the two parties for the attribute releasing. The user is as well redirected back to the Service Provider.

At this point, the IdP is guarantying for the user identity due to the trust relationship between the two parties. You don't need anymore to ask for a password because the AuthN process is completed. What you typically need at this point are the information to manage the resource access control, hence the Authorization (AuthZ). Generally the AuthZ is performed using a role model (RBAC):

The user "jdoe" is authenticated.
The user "jdoe" has "StandardUser" as role.
The resource A is available only for "Administrator".
The user "jdoe" is not authorised to access to the resource A.

As well:

The user "jdoe" is authenticated.
The user "jdoe" has "StandardUser" as role.
The resource B is available only for "StandardUser".
The user "jdoe" is authorised to access to the resource B.

Considering that all the users' roles are stored in a local DB, you have to retrieve those information performing a data-access in order to match identities and roles.

So:

Is this a good idea and/or the way it's meant to be used?

The method loadUserBySAML is supposed to identify local account of user referenced by data in the SAML assertion and return UserDetails object describing the user. At this point, you should also grant the proper authorities to a certain user, according to his role inside your application domain. The local data retrieval implementation is up to you. You could use a standard access, performing a direct query on your database, or implement a modern data access model according to the JPA specifications (see Spring Data ), by using as well an ORM.

Will using select username, username as password create a security problem in the app somehow?

As already said, you don't need to perform user credential verification on you application since you're using a SAML-based Authentication. The SSO is actually designed to not share critical information such as a password.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM