[spring-projects/spring-boot]为 OAuth2 资源服务器自动配置 RequestAttributeSecurityContextRepository

2024-07-08 509 views
6

这似乎已经破坏了2.6.X旧版本(我试过2.5.X)没有表现出下面描述的行为。

步骤 1: 提供WebSecurityConfigurerAdapter并为其配置STATELESS会话创建策略:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().authorizeRequests()
                .antMatchers("/test-user").hasRole("USER")
                .antMatchers("/test-admin").hasRole("ADMIN")
                .antMatchers("/error").authenticated()
                .and().httpBasic();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user").password("{noop}password").roles("USER").and()
                .withUser("admin").password("{noop}password").roles("ADMIN", "USER");
    }
}

第 2 步:设置一个简单的控制器

@Controller
public class ExampleController {

    @GetMapping(path = {"test-user", "test-admin"})
    public void test(HttpServletResponse response) {
        response.setStatus(HttpServletResponse.SC_OK);
    }
}

步骤 3:运行应用程序并向用户无权查看的资源发送请求

curl -v -u user:password http://localhost:8080/test-admin

预期行为:用户收到HTTP 403 Forbidden响应状态代码和响应主体(如下所示):

{
   "timestamp":"2022-02-04T23:42:41.621+00:00",
   "status":403,
   "error":"Forbidden",
   "path":"/test-admin"
}

实际行为:用户收到HTTP 403 Forbidden没有响应主体的响应状态代码

注意:如果STATELESS从上述配置中删除会话创建策略,它将按预期工作。

回答

8

@datagitlies 感谢您的报告。我们所说的示例是指我们可以自己运行的东西,而不是我们必须复制粘贴的文本代码,而且可能会遗漏一些未描述的内容。您能把它移到实际项目中吗?您可以通过将 zip 附加到此问题或共享 GitHub 存储库的链接来实现。

2

当然可以。error -response- body.zip文件包含一个完整的示例,您可以运行 @snicoll

spring-boot-starter-parent还有一点需要注意。通过将pom.xml 文件中的版本从 更改2.6.32.5.9...,它又可以按预期工作了。因此,我相信这是 2.6.X 中引入的一个问题

7

感谢@datagitlies提供的示例。此提交是为了支持先前授权的用户访问错误页面而添加的。此修复涵盖了所有情况,除了错误页面安全规则与原始请求不同的情况(这里就是这种情况)。我们讨论了这种情况,但并不认为这种情况会经常发生,并且认为当我们没有Authentication(在无状态会话策略的情况下)访问时限制访问比允许访问更好。

您能否更详细地描述为什么您希望未经授权的用户查看错误详细信息?在此示例中,似乎不应允许普通用户在尝试访问管理页面时查看错误详细信息。

对于想要恢复到 2.5.x 行为的用户,我们可以更轻松地排除错误安全过滤器。但是,这将允许未经身份验证的用户访问错误页面。您可以看到,在 2.5.9 的示例应用程序中,没有凭据的请求可以查看错误详细信息。在 2.6.3 上,可以使用permitAll()错误页面的 实现相同的行为。标记团队会议,看看我们是否可以在这里做些什么。

7

您能否更详细地描述一下为什么您希望未经授权的用户查看错误详细信息?

我是这样想的。如果你已经用有效的凭证验证了自己的身份,并且你是我的应用程序的用户……我有责任向你清楚地传达错误信息。

此外,在我的示例中只有一个/error,它适用于所有用户和所有场景。因此,我的示例使用.antMatchers("/error").authenticated()“经过身份验证”包括“用户”和“管理员”角色。即使我将其更改为, .antMatchers("/error").hasAnyRole("USER", "ADMIN")这个问题仍然存在。您是否认为最好为管理员用户提供一个错误页面,该页面与普通用户用户的错误页面@mbhave 单独定义并以不同的方式保护?如果是,两者之间的错误逻辑有多大可能不同?我认为应用程序只有一个共享的,/error这通常只是 spring boot 提供的默认错误逻辑,这可能是很常见的。

无论如何,我相信这里真正的问题是STATELESS会话的安全上下文丢失。似乎这个新的错误安全过滤器将单个请求视为两个单独的请求,如果您不能Authentication从“第一个”请求一致地访问并将其适当地应用于“第二个”请求,这似乎是错误的。除此之外,框架必须做出假设或对其如何工作持主观看法。此外,它设置了功能不一致的场景。有状态或无状态,我认为行为应该在两者之间保持一致。

8

我也受到这个问题的影响:这个STATELESS要求来自于我使用 JWT 进行身份验证,这使得这成为一个常见的用例。

2

@svilen-ivanov-kubit,正如 @mbhave上面所述,您应该能够permitAll()在配置访问权限时使用 来恢复 Boot 2.5 的行为/error。您可以尝试一下吗?

4

我的想法没有改变,但是我所说的并不是在无状态会话创建策略的背景下的。

不幸的是,当 Spring Security 配置为不使用会话时,它不会在针对同一原始请求的多个调度中保留用户的身份验证。我不完全理解为什么当客户端只发出一个请求时,即使没有会话也无法保留身份验证。我们将与安全团队讨论此事。

鉴于 Spring Security 的当前行为,我们可以允许任何人访问错误页面(如 Boot 2.5 所做的那样),或者我们可以保护它但需要有状态会话策略(如 Boot 2.6 现在所做的那样)。如果您使用的是具有无状态会话策略的 2.6,则可以使用 选择重新采用 Boot 2.5 的行为permitAll()。我并不认为这是一种解决方法,而是一种对 Spring Security 当前如何管理身份验证以及 servlet 容器错误页面如何工作的准确反映。

9

我尝试了这个.permitAll()建议,但没有任何效果。我看到的是 Jetty 默认的 401 HTML 页面,而不是 2.6.x 中的 401 JSON 响应:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/>
<title>Error 401 Unauthorized</title>
</head>
<body><h2>HTTP ERROR 401 Unauthorized</h2>
<table>
<tr><th>URI:</th><td>/....the path I request....</td></tr>
<tr><th>STATUS:</th><td>401</td></tr>
<tr><th>MESSAGE:</th><td>Unauthorized</td></tr>
<tr><th>SERVLET:</th><td>dispatcherServlet</td></tr>
</table>

</body>
</html>

我将尝试找出我的设置与最小可重现项目有何不同(除了我使用 JWT 进行身份验证)。

1

@svilen-ivanov-kubit 一个样本将会非常有帮助,谢谢。

5

@svilen-ivanov-kubit 一个样本将会非常有帮助,谢谢。

我更新了我们的版本WebSecurityConfigurerAdapter,删除了一些垃圾,问题不再重现。谢谢。

8

对于 2.6,我们建议.permitAll()使用。对于 2.7,我们将自动配置RequestAttributeSecurityContextRepositoryOAuth2 资源服务器,并记录用户可以自行配置。

2

@philwebb 是的,我看到

引入SecurityContextHolderFilter - 能够要求明确保存 SecurityContext

假设这意味着 spring-boot 2.6.x将不会使用 spring-security 5.7.x

2

@datagitlies Spring Boot 2.6.x 使用 Spring security 5.6.x,因此它不会使用 spring security 5.7.x

5

我们认为RequestAttributeSecurityContextRepositoryOAuth2 自动配置不需要自动配置,因为只有当有多个具有不同权限的用户并且需要访问最初登录的用户时才会发生此问题。我将关闭此问题以支持文档问题