Skip to content

Commit c21b9ce

Browse files
authored
Verify correct presigning for Outpost ARNs (#2753)
1 parent ecc9149 commit c21b9ce

File tree

3 files changed

+341
-193
lines changed

3 files changed

+341
-193
lines changed

core/auth/src/main/java/software/amazon/awssdk/auth/signer/AwsS3V4Signer.java

Lines changed: 2 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -15,209 +15,18 @@
1515

1616
package software.amazon.awssdk.auth.signer;
1717

18-
import static software.amazon.awssdk.auth.signer.internal.Aws4SignerUtils.calculateRequestContentLength;
19-
import static software.amazon.awssdk.auth.signer.internal.SignerConstant.X_AMZ_CONTENT_SHA256;
20-
21-
import java.io.InputStream;
22-
import java.util.Optional;
2318
import software.amazon.awssdk.annotations.SdkPublicApi;
24-
import software.amazon.awssdk.auth.credentials.CredentialUtils;
25-
import software.amazon.awssdk.auth.signer.internal.AbstractAws4Signer;
26-
import software.amazon.awssdk.auth.signer.internal.Aws4SignerRequestParams;
27-
import software.amazon.awssdk.auth.signer.internal.chunkedencoding.AwsChunkedEncodingConfig;
28-
import software.amazon.awssdk.auth.signer.internal.chunkedencoding.AwsChunkedEncodingInputStream;
29-
import software.amazon.awssdk.auth.signer.internal.chunkedencoding.AwsS3V4ChunkSigner;
30-
import software.amazon.awssdk.auth.signer.params.Aws4PresignerParams;
31-
import software.amazon.awssdk.auth.signer.params.AwsS3V4SignerParams;
32-
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
33-
import software.amazon.awssdk.http.ContentStreamProvider;
34-
import software.amazon.awssdk.http.SdkHttpFullRequest;
35-
import software.amazon.awssdk.utils.BinaryUtils;
19+
import software.amazon.awssdk.auth.signer.internal.AbstractAwsS3V4Signer;
3620

3721
/**
3822
* AWS4 signer implementation for AWS S3
3923
*/
4024
@SdkPublicApi
41-
public final class AwsS3V4Signer extends AbstractAws4Signer<AwsS3V4SignerParams, Aws4PresignerParams> {
42-
43-
private static final String CONTENT_SHA_256 = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD";
44-
45-
/**
46-
* Sent to S3 in lieu of a payload hash when unsigned payloads are enabled
47-
*/
48-
private static final String UNSIGNED_PAYLOAD = "UNSIGNED-PAYLOAD";
49-
private static final String CONTENT_LENGTH = "Content-Length";
50-
25+
public final class AwsS3V4Signer extends AbstractAwsS3V4Signer {
5126
private AwsS3V4Signer() {
5227
}
5328

5429
public static AwsS3V4Signer create() {
5530
return new AwsS3V4Signer();
5631
}
57-
58-
@Override
59-
public SdkHttpFullRequest sign(SdkHttpFullRequest request, ExecutionAttributes executionAttributes) {
60-
AwsS3V4SignerParams signingParams = constructAwsS3SignerParams(executionAttributes);
61-
62-
return sign(request, signingParams);
63-
}
64-
65-
/**
66-
* A method to sign the given #request. The parameters required for signing are provided through the modeled
67-
* {@link AwsS3V4Signer} class.
68-
*
69-
* @param request The request to sign
70-
* @param signingParams Class with the parameters used for signing the request
71-
* @return A signed version of the input request
72-
*/
73-
public SdkHttpFullRequest sign(SdkHttpFullRequest request, AwsS3V4SignerParams signingParams) {
74-
// anonymous credentials, don't sign
75-
if (CredentialUtils.isAnonymous(signingParams.awsCredentials())) {
76-
return request;
77-
}
78-
79-
Aws4SignerRequestParams requestParams = new Aws4SignerRequestParams(signingParams);
80-
81-
return doSign(request, requestParams, signingParams).build();
82-
}
83-
84-
private AwsS3V4SignerParams constructAwsS3SignerParams(ExecutionAttributes executionAttributes) {
85-
AwsS3V4SignerParams.Builder signerParams = extractSignerParams(AwsS3V4SignerParams.builder(),
86-
executionAttributes);
87-
88-
Optional.ofNullable(executionAttributes.getAttribute(S3SignerExecutionAttribute.ENABLE_CHUNKED_ENCODING))
89-
.ifPresent(signerParams::enableChunkedEncoding);
90-
91-
Optional.ofNullable(executionAttributes.getAttribute(S3SignerExecutionAttribute.ENABLE_PAYLOAD_SIGNING))
92-
.ifPresent(signerParams::enablePayloadSigning);
93-
94-
return signerParams.build();
95-
}
96-
97-
@Override
98-
public SdkHttpFullRequest presign(SdkHttpFullRequest request, ExecutionAttributes executionAttributes) {
99-
Aws4PresignerParams signingParams =
100-
extractPresignerParams(Aws4PresignerParams.builder(), executionAttributes).build();
101-
102-
return presign(request, signingParams);
103-
}
104-
105-
/**
106-
* A method to pre sign the given #request. The parameters required for pre signing are provided through the modeled
107-
* {@link Aws4PresignerParams} class.
108-
*
109-
* @param request The request to pre-sign
110-
* @param signingParams Class with the parameters used for pre signing the request
111-
* @return A pre signed version of the input request
112-
*/
113-
public SdkHttpFullRequest presign(SdkHttpFullRequest request, Aws4PresignerParams signingParams) {
114-
// anonymous credentials, don't sign
115-
if (CredentialUtils.isAnonymous(signingParams.awsCredentials())) {
116-
return request;
117-
}
118-
119-
Aws4SignerRequestParams requestParams = new Aws4SignerRequestParams(signingParams);
120-
121-
return doPresign(request, requestParams, signingParams).build();
122-
}
123-
124-
/**
125-
* If necessary, creates a chunk-encoding wrapper on the request payload.
126-
*/
127-
@Override
128-
protected void processRequestPayload(SdkHttpFullRequest.Builder mutableRequest,
129-
byte[] signature,
130-
byte[] signingKey,
131-
Aws4SignerRequestParams signerRequestParams,
132-
AwsS3V4SignerParams signerParams) {
133-
134-
if (useChunkEncoding(mutableRequest, signerParams)) {
135-
if (mutableRequest.contentStreamProvider() != null) {
136-
ContentStreamProvider streamProvider = mutableRequest.contentStreamProvider();
137-
mutableRequest.contentStreamProvider(() -> AwsS3V4Signer.this.asChunkEncodedStream(
138-
streamProvider.newStream(),
139-
signature,
140-
signingKey,
141-
signerRequestParams
142-
));
143-
}
144-
}
145-
}
146-
147-
@Override
148-
protected String calculateContentHashPresign(SdkHttpFullRequest.Builder mutableRequest, Aws4PresignerParams signerParams) {
149-
return UNSIGNED_PAYLOAD;
150-
}
151-
152-
private AwsChunkedEncodingInputStream asChunkEncodedStream(InputStream inputStream,
153-
byte[] signature,
154-
byte[] signingKey,
155-
Aws4SignerRequestParams signerRequestParams) {
156-
AwsS3V4ChunkSigner chunkSigner = new AwsS3V4ChunkSigner(signingKey,
157-
signerRequestParams.getFormattedRequestSigningDateTime(),
158-
signerRequestParams.getScope());
159-
String signatureHex = BinaryUtils.toHex(signature);
160-
return new AwsChunkedEncodingInputStream(inputStream, signatureHex, chunkSigner, AwsChunkedEncodingConfig.create());
161-
}
162-
163-
/**
164-
* Returns the pre-defined header value and set other necessary headers if
165-
* the request needs to be chunk-encoded. Otherwise calls the superclass
166-
* method which calculates the hash of the whole content for signing.
167-
*/
168-
@Override
169-
protected String calculateContentHash(SdkHttpFullRequest.Builder mutableRequest, AwsS3V4SignerParams signerParams) {
170-
// To be consistent with other service clients using sig-v4,
171-
// we just set the header as "required", and AWS4Signer.sign() will be
172-
// notified to pick up the header value returned by this method.
173-
mutableRequest.putHeader(X_AMZ_CONTENT_SHA256, "required");
174-
175-
if (isPayloadSigningEnabled(mutableRequest, signerParams)) {
176-
if (useChunkEncoding(mutableRequest, signerParams)) {
177-
long originalContentLength = calculateRequestContentLength(mutableRequest);
178-
mutableRequest.putHeader("x-amz-decoded-content-length", Long.toString(originalContentLength));
179-
mutableRequest.putHeader(CONTENT_LENGTH, Long.toString(
180-
AwsChunkedEncodingInputStream.calculateStreamContentLength(originalContentLength,
181-
AwsS3V4ChunkSigner.getSignatureLength(),
182-
AwsChunkedEncodingConfig.create())));
183-
return CONTENT_SHA_256;
184-
} else {
185-
return super.calculateContentHash(mutableRequest, signerParams);
186-
}
187-
}
188-
189-
return UNSIGNED_PAYLOAD;
190-
}
191-
192-
/**
193-
* Determine whether to use aws-chunked for signing
194-
*/
195-
private boolean useChunkEncoding(SdkHttpFullRequest.Builder mutableRequest, AwsS3V4SignerParams signerParams) {
196-
// Chunked encoding only makes sense to do when the payload is signed
197-
return isPayloadSigningEnabled(mutableRequest, signerParams) && isChunkedEncodingEnabled(signerParams);
198-
}
199-
200-
/**
201-
* @return True if chunked encoding has been enabled. Otherwise false.
202-
*/
203-
private boolean isChunkedEncodingEnabled(AwsS3V4SignerParams signerParams) {
204-
Boolean isChunkedEncodingEnabled = signerParams.enableChunkedEncoding();
205-
return isChunkedEncodingEnabled != null && isChunkedEncodingEnabled;
206-
}
207-
208-
/**
209-
* @return True if payload signing is explicitly enabled.
210-
*/
211-
private boolean isPayloadSigningEnabled(SdkHttpFullRequest.Builder request, AwsS3V4SignerParams signerParams) {
212-
/**
213-
* If we aren't using https we should always sign the payload unless there is no payload
214-
*/
215-
if (!request.protocol().equals("https") && request.contentStreamProvider() != null) {
216-
return true;
217-
}
218-
219-
Boolean isPayloadSigningEnabled = signerParams.enablePayloadSigning();
220-
return isPayloadSigningEnabled != null && isPayloadSigningEnabled;
221-
}
222-
22332
}

0 commit comments

Comments
 (0)