3

我在403 forbidden尝试aws elasticsearch通过 java Jest(v6.3) elasticsearch 客户端删除索引时遇到 http 错误(它将 http 调用委托给apache httpclient(v4.5.2) 我知道我的权限在 AWS 中设置正确,因为我是能够成功使用邮递员(在 AWS 签名授权助手的帮助下)。但是,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连接javaJest客户端和底层apache httpclient的类)但我想如果我直接使用apache httpclient我会体验到同样的问题。

@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();
    }
}

由于它与邮递员合作,因此它指出了签名错误,但我不知道差异发生在哪里。上面的配置适用于apache httpclient除 http DELETE 请求之外的所有请求。

4

1 回答 1

1

经过大量研究后,我发现了一些线索,这些线索表明Content-Length向 aws 发出的请求中存在 (length=0) 可能导致签名不匹配。我猜测通过客户端拦截器完成的签名没有考虑到Content-Length标头,但由于我们将Content-Length标头发送到 aws 服务器,因此将其考虑在内,从而导致签名不匹配。我相信是这种情况,因为我添加了一个额外的拦截器(在 AWS 签名拦截器之前),它显式地删除了请求的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();
    }
}
于 2018-10-30T13:16:49.223 回答