aws elasticsearch签名的删除请求返回禁止的403(使用apache httpclient)

时间:2018-10-30 13:02:28

标签: spring-boot jest apache-httpclient-4.x http-delete aws-elasticsearch

我收到一个http 403 forbidden错误,试图通过Java Jest(v6.3) elasticsearch客户端(将http调用委托给apache httpclient(v4.5.2)的客户端)删除aws elasticsearch索引,我知道在AWS上正确设置了权限,因为我能够成功使用邮递员(借助AWS Signature授权帮助器)。但是,在使用apache httpclient时,当我发出DELETE /{myIndexName}时,收到以下错误:

    The request signature we calculated does not match the signature you provided. 
    Check your AWS Secret Access Key and signing method. 
Consult the service documentation for details.

我正在通过为aws配置一个带有签署请求的拦截器来签署apache httpclient请求。(下面的代码适用于Spring Framework @Configuration类,它将Java {{ 1}}客户和底层的Apache httpclient),但我想如果我直接使用apache httpclient也会遇到同样的问题。

Jest

由于它与邮递员一起工作,因此它指向一个签名错误,但是我对出现差异的地方不知所措。上面的配置适用于除http DELETE请求之外的所有@Configuration public class ElasticSearchConfiguration { @Autowired private CredentialsProviderFactoryBean awsCredentialsProvider; @Bean public JestClient awsJestClient(@Value("${elasticsearch.url}") String connectionUrl) throws Exception { com.amazonaws.auth.AWSCredentialsProvider provider = awsCredentialsProvider.getObject(); final com.google.common.base.Supplier<LocalDateTime> clock = () -> LocalDateTime.now(ZoneOffset.UTC); final vc.inreach.aws.request.AWSSigner awsSigner = new vc.inreach.aws.request.AWSSigner(provider, "us-east-1", "es", clock); final vc.inreach.aws.request.AWSSigningRequestInterceptor requestInterceptor = new vc.inreach.aws.request.AWSSigningRequestInterceptor(awsSigner); final JestClientFactory factory = new JestClientFactory() { @Override protected HttpClientBuilder configureHttpClient(HttpClientBuilder builder) { builder.addInterceptorLast(requestInterceptor); return builder; } @Override protected HttpAsyncClientBuilder configureHttpClient(HttpAsyncClientBuilder builder) { builder.addInterceptorLast(requestInterceptor); return builder; } }; factory.setHttpClientConfig(new HttpClientConfig .Builder(connectionUrl) .connTimeout(60000) .multiThreaded(true) .build()); return factory.getObject(); } } 请求。

1 个答案:

答案 0 :(得分:1)

经过一堆研究,我发现了一些线索,这些线索指出了向aws发出的请求中Content-Length(长度= 0)的存在导致签名不匹配的可能性。我猜想通过客户端拦截器完成的签名未考虑到Content-Length头中,但是由于我们将Content-Length头发送到了aws服务器,因此将其考虑在内,从而导致签名不匹配。我相信是这样,因为我在AWS Signing拦截器之前添加了一个额外的拦截器,该拦截器显式删除了Content-Length请求的DELETE头,并且请求成功通过。 (即我可以删除索引)。下面更新了代码:

@Configuration
public class ElasticSearchConfiguration {
    private static final Logger log = LoggerFactory.getLogger(ElasticSearchConfiguration.class);
    @Autowired
    private CredentialsProviderFactoryBean awsCredentialsProvider;


    @Bean
    public JestClient awsJestClient(@Value("${elasticsearch.url}") String connectionUrl) throws Exception {
        com.amazonaws.auth.AWSCredentialsProvider provider = awsCredentialsProvider.getObject();

        final com.google.common.base.Supplier<LocalDateTime> clock = () -> LocalDateTime.now(ZoneOffset.UTC);
        final vc.inreach.aws.request.AWSSigner awsSigner = new vc.inreach.aws.request.AWSSigner(provider, "us-east-1", "es", clock);
        final vc.inreach.aws.request.AWSSigningRequestInterceptor requestInterceptor = new vc.inreach.aws.request.AWSSigningRequestInterceptor(awsSigner);

        final HttpRequestInterceptor removeDeleteMethodContentLengthHeaderRequestInterceptor = (request, context) ->  {
            if(request.getRequestLine().getMethod().equals("DELETE")) {
                log.warn("intercepted aws es DELETE request, will remove 'Content-Length' header as it's presence invalidates the signature check on AWS' end");
                request.removeHeaders("Content-Length");
            }
        };

        final JestClientFactory factory = new JestClientFactory() {
            @Override
            protected HttpClientBuilder configureHttpClient(HttpClientBuilder builder) {
                builder.addInterceptorLast(removeDeleteMethodContentLengthHeaderRequestInterceptor);
                builder.addInterceptorLast(requestInterceptor);
                return builder;
            }
            @Override
            protected HttpAsyncClientBuilder configureHttpClient(HttpAsyncClientBuilder builder) {
                builder.addInterceptorLast(removeDeleteMethodContentLengthHeaderRequestInterceptor);
                builder.addInterceptorLast(requestInterceptor);
                return builder;
            }
        };

        factory.setHttpClientConfig(new HttpClientConfig
                .Builder(connectionUrl)
                .connTimeout(60000)
                .multiThreaded(true)
                .build());

        return factory.getObject();
    }
}