|
15 | 15 |
|
16 | 16 | package software.amazon.awssdk.auth.signer;
|
17 | 17 |
|
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; |
23 | 18 | 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; |
36 | 20 |
|
37 | 21 | /**
|
38 | 22 | * AWS4 signer implementation for AWS S3
|
39 | 23 | */
|
40 | 24 | @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 { |
51 | 26 | private AwsS3V4Signer() {
|
52 | 27 | }
|
53 | 28 |
|
54 | 29 | public static AwsS3V4Signer create() {
|
55 | 30 | return new AwsS3V4Signer();
|
56 | 31 | }
|
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 |
| - |
223 | 32 | }
|
0 commit comments