подписанный запрос на удаление awsasticsearch возвращает 403 запрещенных (с использованием apache httpclient) - PullRequest
0 голосов
/ 30 октября 2018

Я получаю ошибку http 403 forbidden при попытке удалить индекс aws elasticsearch с помощью клиента java Jest (v6.3) asticsearch (который делегирует вызовы 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, который подключает клиента java Jest и базовый 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.

1 Ответ

0 голосов
/ 30 октября 2018

После нескольких исследований я обнаружил некоторые подсказки, указывающие на возможность того, что присутствие Content-Length (length = 0) в запросе, выданном aws, вызывало несоответствие сигнатур. Я предполагаю, что подпись, сделанная через клиентский перехватчик, не учитывала заголовок 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();
    }
}
...