具有数据库角色的 Spring Security SAML

Posted

技术标签:

【中文标题】具有数据库角色的 Spring Security SAML【英文标题】:Spring Security SAML with roles from database 【发布时间】:2016-07-09 18:25:06 【问题描述】:

我正在尝试将 SAML SSO 集成到现有应用程序中,该应用程序使用 Spring Security 以及存储在 mysql 数据库中的用户、组和角色/权限。该应用程序当前使用<security:jdbc-user-service> 从数据库中获取用户和角色。有问题的 IDP 仅提供唯一的用户名和电子邮件地址作为属性,因此应用程序仍然必须存储与每个用户本身相关的组和角色(据我所知)。

因此,我尝试通过上下文配置和自定义 SAMLUserDetailsServicejdbc-user-servicesamlAuthenticationProvider 挂钩,从而同时使用 SAML 和 DB。

这是我的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>

这是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;
    

我的问题是:以这种方式使用 org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl 是个好主意吗?

我认为从数据库中检索角色的官方 Spring Security 实现 (JdbcDaoImpl) 比我自己想出的要维护得好、灵活且无错误。

我的第二个问题是:使用select username, username as password 会以某种方式在应用中产生安全问题吗?

由于我的应用程序永远无法看到密码(因为用户只能在 IDP 中输入密码),所以我必须用查询中的内容替换它。我应该注意让这件事变得难以猜测,还是 UserDetails 中的密码无论如何都不会重复使用?

【问题讨论】:

【参考方案1】:

1.这是一个好主意和/或它的使用方式吗?

是的,您可以在 spring 中拥有自定义用户对象并填充用户详细信息。

2. 使用选择用户名、用户名作为密码是否会在应用程序中产生某种安全问题?

不,Spring SAML 不希望用户密码存储在用户对象中(而是 saml 响应将由 spring 验证)。 spring 将单独验证用户名和权限。我建议您只在用户对象中设置用户名和授予权限。

【讨论】:

与以下相同:这不能回答我想问的问题。我已经稍微编辑了这个问题 - 我希望它更清楚我所追求的。我主要关心的是:我是否应该以这种方式连接 JdbcDaoImpl 和 SAMLAuthenticationProvider,重用 JdbcDaoImpl 的数据库访问功能,而不是自己实现它。一旦你使用了 JdbcDaoImpl,你必须为密码提供一些东西,但这并不重要。 @Ginkobonsai spring 永远不会使用 userdetails 对象中的密码...(它使用用户名和授予权限)您可以将其存储为空/带有垃圾值.. 对于每个请求,spring 将进一步只检查 saml 断言令牌和用户的角色。【参考方案2】:

考虑如下图:

它描述了基于 SAML 的身份验证过程的所有典型步骤。

请求受保护资源的用户将从服务提供商(依赖方)重定向到第三方身份提供商。 用户在身份提供者上执行身份验证(即同时提供用户名/密码、OTP、PIN 码等)。 如果身份验证成功,身份提供者会向服务提供者发回一个 SAML 信封。它包含存储在 SAML 断言中的用户的个人资料信息(名字、姓氏、电子邮件、电话号码、组织等),根据双方之间的属性释放协议。用户也会被重定向回服务提供商。

此时,由于双方之间的信任关系,IdP正在为用户身份做担保。您不再需要询问密码,因为 AuthN 过程已完成。 此时您通常需要的是管理资源访问控制的信息,即授权 (AuthZ)。通常使用角色模型 (RBAC) 执行 AuthZ:

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.

还有:

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.

考虑到所有用户的角色都存储在本地数据库中,您必须检索执行数据访问的那些信息才能匹配身份和角色。

所以:

这是一个好主意和/或它的使用方式吗?

loadUserBySAML 方法应该识别 SAML 断言中的数据引用的用户的本地帐户,并返回描述用户的 UserDetails 对象。此时,您还应该根据某个用户在您的应用程序域中的角色授予适当的权限。 本地数据检索实现由您决定。您可以使用标准访问,对数据库执行直接查询,或者根据 JPA 规范(参见 Spring Data)实现现代数据访问模型,同时使用 ORM。 p>

使用选择用户名、用户名作为密码会以某种方式在应用中造成安全问题吗?

如前所述,您无需对应用程序执行用户凭据验证,因为您使用的是基于 SAML 的身份验证。 SSO 实际上旨在不共享密码等关键信息。

【讨论】:

嗯,这并不能回答我想问的问题。我已经稍微编辑了这个问题 - 我希望它更清楚我所追求的。我主要关心的是:我是否应该以这种方式连接 JdbcDaoImpl 和 SAMLAuthenticationProvider,重用 JdbcDaoImpl 的数据库访问功能,而不是自己实现它。一旦你使用了 JdbcDaoImpl,你必须为密码提供 something 但这并不重要。

以上是关于具有数据库角色的 Spring Security SAML的主要内容,如果未能解决你的问题,请参考以下文章

具有 Active Directory 和数据库角色的 Spring Security

Spring Security:检查用户是不是具有分层角色的方法

拒绝Spring Security中具有相同角色的多个用户的访问

具有角色的经过身份验证的用户的 Spring Security Java 配置

Spring Security 推荐的设计以请求用户登录到具有不同角色的不同用户

使用 Spring Security 更新角色时如何注销用户