首页 > 解决方案 > Kerberos POST 请求使用 Java 返回 401 错误

问题描述

我正在使用 KerberosTemplate 向经过 kerberos 身份验证的 rest API 发出 POST 请求。

我可以在命令行上成功运行不安全的请求,但是当我尝试使用 HTTP 客户端进行安全调用时,它返回 401 未经授权的错误。

我尝试关闭证书检查,因为我们不使用它,并且我还尝试了没有域的用户名,但这也没有影响。

我也尝试过 kerb4j 休息模板,但我遇到了同样的问题。从代码中您还可以看到我正在检查 keytab 文件是否存在。

感谢一些帮助,谢谢。

import ErrorHandlers.KerberosRestTemplateResponseErrorHandler;
import POJOs.PostBody;
import POJOs.PostResponse;
import com.fasterxml.jackson.databind.SerializationFeature;
//import com.kerb4j.client.spring.KerberosRestTemplate;
import org.springframework.security.kerberos.client.KerberosRestTemplate;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;

public class KerbTemplate {
    public static void main(String[] args) throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {

        PostBody postRequestBody = new PostBody();
        postRequestBody.setAggregation("data");
        postRequestBody.setEndDate("2119-03-30");
        postRequestBody.setStartDate("1900-03-30");
        postRequestBody.setMetadata(new String[] {"PARTIAL"});
        postRequestBody.setSymbols(new String[] {"requestdata"});
        postRequestBody.setModifiedDate("2019-07-20");
        postRequestBody.setFirstWeekday("0");

        TrustStrategy acceptingTrustStrategy = ((X509Certificate[] chain, String authType) -> true);
        SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);

        String base = System.getProperty("user.dir");
        String keytab = base+ File.separator+"src"+File.separator+"main"+File.separator+"resources"+File.separator+"username.keytab";
        System.out.println(keytab);
        File f = new File(keytab);
        if(f.exists() && !f.isDirectory()) {
            System.out.println("File exists");
        }

        KerberosRestTemplate kerberosRestTemplate = new KerberosRestTemplate( keytab,"'username@domain",requestFactory.getHttpClient());
        kerberosRestTemplate.setErrorHandler(new KerberosRestTemplateResponseErrorHandler());

        MappingJackson2HttpMessageConverter jsonHttpMessageConverter = new MappingJackson2HttpMessageConverter();
        jsonHttpMessageConverter.getObjectMapper().configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        kerberosRestTemplate.getMessageConverters().add(jsonHttpMessageConverter);
// Add CSRF header if required:
        HttpHeaders headers = new HttpHeaders();
        headers.set("X-Requested-By", "'username@domain");
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Client-Type","Web");
        headers.set("Client-UI-Component","Jim");


        HttpEntity<PostBody> postRequest = new HttpEntity<PostBody>(postRequestBody, headers);
        PostResponse pr = kerberosRestTemplate.postForObject("https://url.com/1/data/loadList", postRequest, PostResponse.class);

    }
}

package ErrorHandlers;

import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.ResponseErrorHandler;

import java.io.IOException;

public class KerberosRestTemplateResponseErrorHandler implements ResponseErrorHandler {
    @Override
    public boolean hasError(ClientHttpResponse httpResponse) throws IOException {
        return (
                httpResponse.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR
                        || httpResponse.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR);
    }

    @Override
    public void handleError(ClientHttpResponse httpResponse) throws IOException {

        System.out.println("Error Response code " + httpResponse.getRawStatusCode());
        System.out.println(httpResponse.getStatusText());
        System.out.println(httpResponse.getBody().toString());
    }
}

更新了部分日志

540 [main] DEBUG org.apache.http.client.protocol.RequestAddCookies - 已选择 CookieSpec:默认 21:58:30.561 [main] DEBUG org.apache.http.client.protocol.RequestAuthCache - 未在上下文中设置身份验证缓存 21 :58:30.565 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - 连接请求:[路由:{s}->myendpoint.com:443][总存活:0;分配的路线:2 条中的 0 条;总分配:0 of 20] 21:58:30.587 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - 连接租用:[id: 0][route: {s}->myendpoint.com:443] [存活总数:0;分配的路线:2 条中的 1 条;总分配:1 of 20] 21:58:30.591 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - 打开连接 {s}->myendpoint.com:443 21:58:30.617 [main] DEBUG org .apache.http.impl.conn。

21:58:30.962 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - 执行请求 POST /1/data/loadList HTTP/1.1 21:58:30.963 [main] DEBUG org.apache.http.impl。 execchain.MainClientExec - 目标身份验证状态: UNCHALLENGED 21:58:30.968 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - 代理身份验证状态: UNCHALLENGED 21:58:30.976 [main] DEBUG org.apache.http。 headers - http-outgoing-0 >> POST /1/data/loadList HTTP/1.1 21:58:30.979 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Accept: application/json, application /+json 21:58:30.979 [main] 调试 org.apache.http.headers - http-outgoing-0 >> 客户端类型:Fred 21:58:30.980 [main] 调试 org.apache.http.headers - http-传出-0 >> 内容类型:application/json 21:58:30.981 [main] 调试 org.apache.http.headers - http-outgoing-0 >> Client-UI-Component:Jim 21:58:30.981 [main ] 调试 org.apache.http.headers - http-outgoing-0 >> 内容长度:220 21:58:30.982 [main] 调试 org.apache.http.headers - http-outgoing-0 >> 主机:myendpoint。 com 21:58:30.983 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> 连接:Keep-Alive 21:58:30.983 [main] DEBUG org.apache.http.headers - http-outgoing -0 >> 用户代理:Apache-HttpClient/4.5.9 (Java/1.8.0_212-3-redhat) 21:58:30.983 [main] DEBUG org.apache.http.headers - http-outgoing-0 >>接受编码:gzip,放气 21:58:30.984 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "POST /1/data/loadList HTTP/1.1[\r][\n]" 21:58:30.984 [main] DEBUG org .apache.http.wire - http-outgoing-0 >> “接受:应用程序/json,应用程序/+json[\r][\n]" 21:58:30.984 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "客户端类型:Fred[\r][\n]" 21:58:30.985 [main] 调试 org.apache.http.wire - http-outgoing-0 >> “Content-Type: application/json[\r][\n]” 21:58:30.986 [main] 调试org.apache.http.wire - http-outgoing-0 >> "Client-UI-Component: Jim[\r][\n]" 21:58:30.986 [main] 调试 org.apache.http.wire - http -outgoing-0 >> "Content-Length: 220[\r][\n]" 21:58:30.986 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "Host: myendpoint. com[\r][\n]" 21:58:30.988 [main] 调试 org.apache.http.wire - http-outgoing-0 >> "连接:保持活动 [\r][\n]" 21 :58:30.990 [main] 调试 org.apache.http.wire - http-outgoing-0 >> "用户代理:Apache-HttpClient/4.5.9 (Java/1.8.0_212-3-redhat)[\r][\n]" 21:58:30.990 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "接受编码:gzip,deflate[\r ][\n]" 21:58:30.991 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "[\r][\n]" 21:58:30.992 [main] DEBUG org .apache.http.wire - http-outgoing-0 >> "{"firstWeekday":"0","metadata":["All"],"endDate":"2119-03-30","modifiedDate": "2019-07-20","聚合":"DAILY","symbols":["symbol1","symbol2"],"startDate":"1900-03-30"}" 21:58:31.043 [main ] 调试 org.apache.http.wire - http-outgoing-0 << "HTTP/1.1 401 [\r][\n]"接受编码:gzip,deflate[\r][\n]" 21:58:30.991 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "[\r][\n]" 21:58:30.992 [main] 调试 org.apache.http.wire - http-outgoing-0 >> "{"firstWeekday":"0","metadata":["All"],"endDate":"2119 -03-30","modifiedDate":"2019-07-20","聚合":"DAILY","symbols":["symbol1","symbol2"],"startDate":"1900-03-30 "}" 21:58:31.043 [main] 调试 org.apache.http.wire - http-outgoing-0 << "HTTP/1.1 401 [\r][\n]"接受编码:gzip,deflate[\r][\n]" 21:58:30.991 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "[\r][\n]" 21:58:30.992 [main] 调试 org.apache.http.wire - http-outgoing-0 >> "{"firstWeekday":"0","metadata":["All"],"endDate":"2119 -03-30","modifiedDate":"2019-07-20","聚合":"DAILY","symbols":["symbol1","symbol2"],"startDate":"1900-03-30 "}" 21:58:31.043 [main] 调试 org.apache.http.wire - http-outgoing-0 << "HTTP/1.1 401 [\r][\n]"> "{"firstWeekday":"0","元数据":["All"],"endDate":"2119-03-30","modifiedDate":"2019-07-20","聚合":" DAILY","symbols":["symbol1","symbol2"],"startDate":"1900-03-30"}" 21:58:31.043 [main] 调试 org.apache.http.wire - http-outgoing -0 << "HTTP/1.1 401 [\r][\n]"> "{"firstWeekday":"0","元数据":["All"],"endDate":"2119-03-30","modifiedDate":"2019-07-20","聚合":" DAILY","symbols":["symbol1","symbol2"],"startDate":"1900-03-30"}" 21:58:31.043 [main] 调试 org.apache.http.wire - http-outgoing -0 << "HTTP/1.1 401 [\r][\n]"“HTTP/1.1 401 [\r][\n]”“HTTP/1.1 401 [\r][\n]”

nosniff[\r][\n]" 21:58:31.044 [main] 调试 org.apache.http.wire - http-outgoing-0 << "X-XSS-Protection: 1; mode=block[\r][\n]" 21:58:31.044 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Cache-Control: no-cache, no-store, max -age=0, must-revalidate[\r][\n]" 21:58:31.044 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Pragma: no-cache[\r ][\n]" 21:58:31.044 [main] 调试 org.apache.http.wire - http-outgoing-0 << "Expires: 0[\r][\n]" 21:58:31.044 [main ] DEBUG org.apache.http.wire - http-outgoing-0 << "Strict-Transport-Security: max-age=31536000 ; includeSubDomains[\r][\n]" 21:58:31.044 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "X-Frame-Options: DENY[\r][\n] " 21:58:31.044 [主要] 调试 org.apache.http。

1个;mode=block 21:58:31.051 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Cache-Control: no-cache, no-store, max-age=0, must-revalidate 21: 58:31.051 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Pragma: no-cache 21:58:31.051 [main] DEBUG org.apache.http.headers - http-outgoing-0 < < 过期:0 21:58:31.051 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Strict-Transport-Security: max-age=31536000 ;includeSubDomains 21:58:31.051 [main] DEBUG org.apache.http.headers - http-outgoing-0 << X-Frame-Options: DENY 21:58:31.051 [main] DEBUG org.apache.http.headers - http -outgoing-0 << Transfer-Encoding: chunked 21:58:31.051 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Date: Wed, 11 Sep 2019 20:58:31 GMT 21: 58:31.063 [主]调试 org.apache.http.impl.execchain。

21:58:31.096 [main] 调试 org.apache.http.wire - http-outgoing-0 << "0[\r][\n]" 21:58:31.097 [main] 调试 org.apache.http。电线 - http-outgoing-0 << "[\r][\n]" 21:58:31.097 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - 连接 [id: 0] [路由: { s}->myendpoint.com:443] 可以无限期地保持活动状态 21:58:31.097 [main] DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-0: set socket timeout to 0 21:58 :31.097 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - 连接释放:[id: 0][route: {s}->myendpoint.com:443][保持活跃的总数:1;分配的路线:2 条中的 1 条;总分配:1 of 20]

进程以退出代码 0 结束

标签: javakerberosapache-httpclient-4.xresttemplatespring-security-kerberos

解决方案


推荐阅读