有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我有一个Spring MVC REST端点,我成功地将其配置为由Kerberos as recommended保护。成功认证后,一切正常。问题是当涉及到自定义401错误页面时

我将其配置为(我是spring boot 1.3.5),如下所示:

@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
    return container -> container.addErrorPages(new ErrorPage(HttpStatus.UNAUTHORIZED, "/error/401.html"));
}

这很好地工作,我可以通过切换到基本身份验证并提供错误的凭据来确认

当使用Kerberos时-如果我使用kinit访问我的安全端点,一切正常,并且在curl中,我会看到详细的请求:

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

下面是我的两个问题:

    >P>当握手发生时,我如何返回401错误页面?

  1. 如果spring尝试进行协商,但客户机根本没有响应,它怎么可能回退到任何其他身份验证作为回退(form,basic)


共 (2) 个答案

  1. # 1 楼答案

    所以回到我的调查中

    我观察到的这种行为是意料之中的。如果客户端(浏览器、curl)无法进行身份验证,则不会继续进行身份验证。提供定制页面的关键是SpnegoEntrypoint。它允许在其中指定转发URL,它的javadoc说明:

    Instantiates a new spnego entry point. This constructor enables security configuration to use SPNEGO in combination with login form as fallback for clients that do not support this kind of authentication.

    重点是转发url任何资源,它将包含在第一个401响应中。您可以包括任何页面,而不仅仅是表单登录。在我的例子中,我包括自定义401错误页面,因为我不做任何身份验证回退

    @Bean
    public SpnegoEntryPoint spnegoEntryPoint() {
        return new SpnegoEntryPoint("/error/401.html");
    }
    

    然后,通信看起来就像客户端发送GET和get的返回401响应,并在主体中显示我的自定义错误页面。如果客户端能够协商,它将完全忽略响应主体,并使用适当的令牌重新提交请求。如果无法进行身份验证,它会显示返回的任何内容——自定义错误页面

  2. # 2 楼答案

    作为对第一个问题的回答:

    我有相同的用例,但选择了另一种解决方案,在该解决方案中,我扩展了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);
        }
    }