RequestSignerImpl implements RequestSigner { @VisibleForTesting static String calculateStringToSign( String httpMethod, String path, Map<String, List<String>> allHeaders, List<String> requiredHeaders, Map<String, List<String>> originalHeaders) { List<String> signatureParts = new ArrayList<>(); for (String headerName : requiredHeaders) { List<String> headerValues = allHeaders.get(headerName); if (headerValues != null && headerValues.size() != 1) { final RequestSignerException exception = new RequestSignerException( "Expecting exactly one value for header " + headerName); LOG.error( "More than one value for header [{}] to be signed found. All headers: {}", headerName, transformHeadersToJsonString(originalHeaders), exception); throw exception; } String headerValue = (headerValues != null) ? headerValues.get(0) : null; if (headerName.equals(Constants.REQUEST_TARGET)) { headerValue = httpMethod + " " + path; } if (headerValue == null) { final RequestSignerException exception = new RequestSignerException( "Expecting exactly one value for header " + headerName); LOG.error( "No header value for header [{}] to be signed found. All headers: {}", headerName, transformHeadersToJsonString(originalHeaders), exception); throw exception; } signatureParts.add(String.format("%s: %s", headerName, headerValue)); } return StringUtils.join(signatureParts, "\n"); } RequestSignerImpl(
            @Nonnull final KeySupplier<RSAPrivateKey> keySupplier,
            @Nonnull final SigningStrategy signingStrategy,
            @Nonnull final Supplier<String> keyIdSupplier);  RequestSignerImpl(
            @Nonnull final KeySupplier<RSAPrivateKey> keySupplier,
            @Nonnull final SigningConfiguration signingConfiguration,
            @Nonnull final Supplier<String> keyIdSupplier); @Override Map<String, String> signRequest(
            @Nonnull final URI uri,
            @Nonnull final String httpMethod,
            @Nonnull final Map<String, List<String>> headers,
            @Nullable final Object body); static Map<String, String> signRequest(
            final Algorithm algorithm,
            final URI uri,
            final String httpMethod,
            final Map<String, List<String>> headers,
            final Object body,
            final String versionName,
            final String keyId,
            final KeySupplier<RSAPrivateKey> keySupplier,
            final SigningConfiguration signingConfiguration);  }
@PrepareForTest({LoggerFactory.class, RestClientFactory.class, RequestSignerImpl.class}) @Test public void calculateStringToSign_whenDuplicateHeaderKeysExists() { final Map<String, List<String>> headers = new HashMap<>(); headers.put("content-length", Collections.singletonList("238")); headers.put("opc-request-id", Lists.newArrayList("ID1", "ID2")); try { RequestSignerImpl.calculateStringToSign( "get", "/path", headers, ImmutableList.of("opc-request-id"), headers); fail("Should have thrown"); } catch (RequestSignerException e) { assertEquals("Expecting exactly one value for header opc-request-id", e.getMessage()); } }