SPNEGO身份验证失败的自定义错误页面

时间:2016-09-05 20:40:00

标签: java spring spring-mvc spring-security spring-boot

我有一个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作为期望的响应,这是握手的一部分,因此不会发送错误页面。

这是我的两个问题:

  1. 如果在握手过程中物品死亡,我该如何返回401错误页面?

  2. 如果尝试进行协商但是客户端根本没有响应,那么Spring怎么可能回退到任何其他身份验证作为回退(表单,基本)?

    < / LI>

2 个答案:

答案 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);
    }
}