Spring 具有来自数据库的角色的安全 SAML

Spring Security SAML with roles from database

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

因此,我尝试通过上下文配置和自定义 SAMLUserDetailsService.

jdbc-user-servicesamlAuthenticationProvider 挂钩,从而同时使用 SAML 和数据库

这是我的 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 安全实现 (JdbcDaoImpl) 比我自己想出的要维护得好、灵活且无错误。

我的第二个问题是:使用 select username, username as password 会不会以某种方式在应用程序中造成安全问题?

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

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

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

2.Will 使用 select 用户名,用户名作为密码以某种方式在应用程序中创建安全问题?

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

考虑下图:

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

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

此时,由于双方之间的信任关系,IdP正在为用户身份提供担保。您不再需要询问密码,因为 AuthN 过程已完成。 此时您通常需要的是管理资源访问控制的信息,因此是授权 (AuthZ)。通常,AuthZ 是使用角色模型 (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.

还有:

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.

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

所以:

这是个好主意吗and/or它的使用方式?

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

使用 select 用户名,用户名作为密码会不会在应用程序中产生安全问题?

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