当问这个问题时,我正在寻找实现我自己的 AuthenticationProvider 的指导。我的意思是:
到目前为止,我已经了解到 Spring Security 会询问 AuthenticationProvider 对象是否用户已通过身份验证。目前我正在使用 DaoAuthenticationProvider 来处理我自己的客户 UserDetailService 返回的用户名和密码。一切都很好!Spring 支持许多不同的 AuthenticationProvider,例如有一个用于 LDAP、Jdbc、DAO(如上所述),我什至能够找到一个用于 Kerberos。但是 SRP 没有身份验证提供程序,因此需要编写一个。
我的问题如下:
当我们使用 DaoAuthenticationProvider 即用户/密码身份验证时,我们有一个 html 表单,其中输入了用户名和密码,然后一个按钮负责提交这两个参数。购买的参数通过某些传输通道传输到服务器,即只需单击一下,我们就可以在同一个 http 请求中发送所有数据,即身份验证所需的所有数据。这可以在 UsernamePasswordAuthenticationFilter 中看到。这里“attemptAuthentication”方法采用“HttpServletRequest request”,其中包括用户名和密码。到现在一切都好。
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
...
}
好吧,在简单的 SRP 中,我们还有一个包含用户名和密码的表单,除了密码!!!必须!!!不能通过网络传输。为了实现该约束,必须在客户端和服务器之间进行“讨论”,即必须交换以下参数。
1) 用户名 (I),
2) 一个名为“A”的值
3) 一个名为“B”的值
4) 一个名为“M1”的值
5) 一个名为“M2”的值
好吧,让我们假设有一个名为“SrpAuthenticationProcessingFilter”的过滤器,如果新的身份验证协议更像是来自 RFC 5054 的对话,那么过滤器应该是什么样子。
Client Server
Client Hello (I) -------->
Server Hello
Certificate*
Server Key Exchange (N, g, s, B)
<-------- Server Hello Done
Client Key Exchange (A) -------->
[Change cipher spec]
Finished -------->
[Change cipher spec]
<-------- Finished
Application Data <-------> Application Data
在这里,我们有一个客户需要
- a) 首先发送他的用户名 (I)
- b) 然后服务器需要以值 B 响应。(在这种情况下,N,g,s 并不是真正需要的)
- c)客户端发送它的“值A”
- d) 客户端使用来自服务器的值 B 并基于该值计算密钥。
- e) 服务器也根据值 A 计算密钥。
- f) 客户端向服务器发送值 M1。
- g) 服务器获取 M1 值并基于以 M1 值作为参数的公式,他能够验证密钥是否匹配,如果计算出的购买方的密钥匹配,则用户通过身份验证,并且产品即共享密钥可以进一步用于其他处理。
与用户名和密码验证相比,这些是 7 个步骤而不是一个步骤。其中 3 个需要在 SrpAuthenticationProcessingFilter 之前发生。现在我知道有可能将用户名与“值 A”一起发送,从而缩短步骤数,但我想严格遵守 RFC。永远不要走简单的路,对吧?
问题实际上是我在哪里放置负责客户端和服务器之间的乒乓(对话)的代码,即上面提到的前 3 个步骤 a、b 和 c。它应该将它们放在 SrpEntryPoint 对象中还是其他地方。if else 那么是在 SpringSecurity 的上下文中吗?
我可以解决这个问题的一种方法是使用 websockets,但我也想让该身份验证独立于任何第 5-7 层协议,例如 websockets、http、spdy 等。这意味着第一个实现应该是通过简单的 http 请求/响应,然后使用任何其他协议。
因此,目前实施 SRP 的正确结构是:
SRPAuthenticationEntryPoint 实现 org.springframework.security.web.AuthenticationEntryPoint - 这基本上说明了如果对受保护资源的请求进入但用户尚未经过身份验证应该做什么。在这里,我们可以在资源尚未经过身份验证的情况下进行重定向。也许这也是负责步骤 a、b、c 的地方,不确定这是否是正确的地方。请求指导和信息!
SrpAuthenticationProcessingFilter 扩展了 GenericFilterBean。SrpAuthenticationProcessingFilter 的存在是为了进行部分验证,例如检查 srp 参数是否接收到正确的并对应于服务器设置的 srp 参数。在这里重要的是要提到 SrpAuthenticationProcessingFilter 没有进行任何用户名验证,即需要在调用 SrpAuthenticationProcessingFilter 之前的一步中进行,可能是 SrpEntryPoint 或我不知道如何调用它的其他步骤。SrpAuthenticationProcessingFilter 有一个方法“doFilter”,其中正在创建第二个结构,即 SrpAuthenticationToken。
SrpAuthenticationToken 扩展 org.springframework.security.authentication.AbstractAuthenticationToken。在我的理解中,该令牌与 DAO 对象类似,该令牌映射成功身份验证所需的所有字段。当部分验证的参数被填充到 SrpAuthenticationToken 中时,SrpAuthenticationToken 被传递给 org.springframework.security.authentication.AuthenticationManager 接口的authenticat方法,即类似的东西
myAuthentication = authenticationManager.authenticate(SrpAuthenticationToken);
根据 Spring Security 配置中配置的身份验证提供程序,在我们的案例中调用 SrpAuthentication 提供程序,即:
@Autowired
public void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(sRPAuthenticationProvider);
}
SRPAuthenticationProvider - 实现 org.springframework.security.authentication.AuthenticationProvider。在这里,步骤 d、e、f 和 g 正在被验证和比较。如果发生错误,则抛出新的 BadCredentialsException("Invalid username/password/Verifiere") 异常。
SrpSessionValidator - 这个只负责验证 Srp 会话的特定参数,并且会从 SrpAuthenticationProcessingFilter 以及在 SrpAuthenticationProcessingFilter 之前的一步中调用,以验证用户名是否存在于数据库中。
我只知道如何实现 Srp 身份验证,因此如果这完全有意义并且 SRPAuthenticationEntryPoint 是步骤 a、b 和 c 的正确位置,我想要一些评论。我觉得这不是正确的地方。
非常感谢任何反馈。
问候,
铁托
Addition1(2014 年 11 月 21 日)-> 作为对“在哪里放置负责客户端和服务器之间的 ping pong(对话)的代码,即前 3 个步骤 a、b 和 c”的问题的回答这很可能是一个标准(我称之为协商)过滤器,它将承担这项工作。
现在我想重新表述这个问题,即在身份验证完成之前以及在接收到 M1 和 M2 消息之前,即步骤 1、2 和 3。我应该把那个对象放在哪里?即它应该是一个对象应该存在的地方,例如 60 秒,然后在没有收到 M1 和 M2 消息的情况下自动删除。我的意思是“SecurityContextHolder”对象之前的某个对象。我只是不知道与弹簧安全相关的对象/上下文的名称是什么,我也不知道这种结构是否存在?