我有一个Spring MVC REST端点,我成功配置为由Kerberos as recommended保护。成功验证后一切正常。问题在于自定义401
错误页面。
我将它配置为(我的弹跳启动1.3.5),如下所示:
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return container -> container.addErrorPages(new ErrorPage(HttpStatus.UNAUTHORIZED, "/error/401.html"));
}
这很好用,我可以通过切换到例如基本身份验证并提供错误的凭据。
当使用Kerberos返回时 - 如果我使用 kinit 访问我的安全端点,一切正常并且卷曲,我会看到详细的请求:
curl -v -u : --negotiate http://my-enpoint:8080/
> GET / HTTP/1.1
> Host: ...:8080
> User-Agent: curl/7.43.0
> Accept: */*
< HTTP/1.1 401 Unauthorized
< ...
< WWW-Authenticate: Negotiate
> GET / HTTP/1.1
> Host: ...:8080
> Authorization: Negotiate YIIH7 ...
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< ...
现在,如果我做 kdestroy 并再次进行卷曲:
curl -v -u : --negotiate http://my-enpoint:8080/
> GET / HTTP/1.1
> Host:...8080
> User-Agent: curl/7.43.0
> Accept: */*
< HTTP/1.1 401 Unauthorized
< ...
< WWW-Authenticate: Negotiate
......那就是它。在这种情况下,spring返回401
作为期望的响应,这是握手的一部分,因此不会发送错误页面。
这是我的两个问题:
如果在握手过程中物品死亡,我该如何返回401错误页面?
如果尝试进行协商但是客户端根本没有响应,那么Spring怎么可能回退到任何其他身份验证作为回退(表单,基本)?
< / LI> 醇>答案 0 :(得分:0)
回到我的调查......
我观察到的这种行为是预料之中的。客户端(浏览器,curl)如果无法进行身份验证,则不会继续进行身份验证。提供自定义页面的关键是SpnegoEntrypoint
。它允许在其中指定 forwardUrl ,它的javadoc说:
实例化一个新的spnego入口点。这个构造函数启用 安全配置将SPNEGO与登录表单结合使用 对于不支持此类身份验证的客户端的回退。
要点是转发网址任何资源,它将包含在第一个401
响应中。您可以包含任何页面,而不仅仅是表单登录。在我的情况下,我包括自定义401错误页面,因为我没有做任何身份验证后备。
@Bean
public SpnegoEntryPoint spnegoEntryPoint() {
return new SpnegoEntryPoint("/error/401.html");
}
然后通信看起来像客户端发送GET
并返回401
响应,并在我的自定义错误页面中显示。如果客户端能够进行协商,则完全忽略响应主体,并使用适当的令牌重新提交请求。如果它无法进行身份验证,则会显示它返回的内容 - 自定义错误页面。
答案 1 :(得分:0)
作为对第一个问题的回答:
我有相同的用例,但选择了另一种解决方案,我在其中扩展了SpnegoEntryPoint,并将一个小JSON主体添加到REST客户端使用的响应中:
public class JsonSpnegoEntryPoint extends SpnegoEntryPoint {
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex)
throws IOException, ServletException {
response.getWriter().write("{\"message\": \"Spnego negotiate, expecting to be called with negotiate-flags set\"}");
super.commence(request, response, ex);
}
}