1
1
/*
2
- * Copyright 2012 -2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ * Copyright 2013 -2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License").
5
5
* You may not use this file except in compliance with the License.
38
38
*/
39
39
public class AWS4Signer extends AbstractAWSSigner {
40
40
41
- private static final String ALGORITHM = "AWS4-HMAC-SHA256" ;
42
- private static final String TERMINATOR = "aws4_request" ;
41
+ protected static final String ALGORITHM = "AWS4-HMAC-SHA256" ;
42
+ protected static final String TERMINATOR = "aws4_request" ;
43
43
44
44
/**
45
45
* Service name override for use when the endpoint can't be used to
46
46
* determine the service name.
47
47
*/
48
- private String serviceName ;
48
+ protected String serviceName ;
49
49
50
50
/**
51
51
* Region name override for use when the endpoint can't be used to
52
52
* determine the region name.
53
53
*/
54
- private String regionName ;
54
+ protected String regionName ;
55
55
10000
td>
56
56
/** Date override for testing only */
57
- private Date overriddenDate ;
57
+ protected Date overriddenDate ;
58
58
59
- private static final Log log = LogFactory .getLog (AWS4Signer .class );
59
+ protected static final Log log = LogFactory .getLog (AWS4Signer .class );
60
60
61
61
62
62
/* (non-Javadoc)
@@ -73,28 +73,8 @@ public void sign(Request<?> request, AWSCredentials credentials) throws AmazonCl
73
73
addSessionCredentials (request , (AWSSessionCredentials ) sanitizedCredentials );
74
74
}
75
75
76
- SimpleDateFormat dateStampFormat = new SimpleDateFormat ("yyyyMMdd" );
77
- dateStampFormat .setTimeZone (new SimpleTimeZone (0 , "UTC" ));
78
-
79
- SimpleDateFormat dateTimeFormat = new SimpleDateFormat ("yyyyMMdd'T'HHmmss'Z'" );
80
- dateTimeFormat .setTimeZone (new SimpleTimeZone (0 , "UTC" ));
81
-
82
- String regionName = extractRegionName (request .getEndpoint ());
83
- String serviceName = extractServiceName (request .getEndpoint ());
84
-
85
- // AWS4 requires that we sign the Host header so we
86
- // have to have it in the request by the time we sign.
87
- String hostHeader = request .getEndpoint ().getHost ();
88
- if (HttpUtils .isUsingNonDefaultPort (request .getEndpoint ())) {
89
- hostHeader += ":" + request .getEndpoint ().getPort ();
90
- }
91
- request .addHeader ("Host" , hostHeader );
92
-
93
- Date date = getSignatureDate (request .getTimeOffset ());
94
- if (overriddenDate != null ) date = overriddenDate ;
95
-
96
- String dateTime = dateTimeFormat .format (date );
97
- String dateStamp = dateStampFormat .format (date );
76
+ addHostHeader (request );
77
+ String scope = getScope (request );
98
78
99
79
InputStream payloadStream = getBinaryRequestPayloadStream (request );
100
80
payloadStream .mark (-1 );
@@ -105,36 +85,12 @@ public void sign(Request<?> request, AWSCredentials credentials) throws AmazonCl
105
85
throw new AmazonClientException ("Unable to reset stream after calculating AWS4 signature" , e );
106
86
}
107
87
108
- request .addHeader ("X-Amz-Date" , dateTime );
88
+ request .addHeader ("X-Amz-Date" , getDateTimeStamp ( getDateFromRequest ( request )) );
109
89
request .addHeader ("x-amz-content-sha256" , contentSha256 );
110
90
111
- String canonicalRequest =
112
- request .getHttpMethod ().toString () + "\n " +
113
- super .getCanonicalizedResourcePath (request .getResourcePath ()) + "\n " +
114
- getCanonicalizedQueryString (request ) + "\n " +
115
- getCanonicalizedHeaderString (request ) + "\n " +
116
- getSignedHeadersString (request ) + "\n " +
117
- contentSha256 ;
118
-
119
- log .debug ("AWS4 Canonical Request: '\" " + canonicalRequest + "\" " );
120
-
121
- String scope = dateStamp + "/" + regionName + "/" + serviceName + "/" + TERMINATOR ;
122
91
String signingCredentials = sanitizedCredentials .getAWSAccessKeyId () + "/" + scope ;
123
- String stringToSign =
124
- ALGORITHM + "\n " +
125
- dateTime + "\n " +
126
- scope + "\n " +
127
- BinaryUtils .toHex (hash (canonicalRequest ));
128
- log .debug ("AWS4 String to Sign: '\" " + stringToSign + "\" " );
129
-
130
- // AWS4 uses a series of derived keys, formed by hashing different pieces of data
131
- byte [] kSecret = ("AWS4" + sanitizedCredentials .getAWSSecretKey ()).getBytes ();
132
- byte [] kDate = sign (dateStamp , kSecret , SigningAlgorithm .HmacSHA256 );
133
- byte [] kRegion = sign (regionName , kDate , SigningAlgorithm .HmacSHA256 );
134
- byte [] kService = sign (serviceName , kRegion , SigningAlgorithm .HmacSHA256 );
135
- byte [] kSigning = sign (TERMINATOR , kService , SigningAlgorithm .HmacSHA256 );
136
92
137
- byte [] signature = sign ( stringToSign . getBytes (), kSigning , SigningAlgorithm . HmacSHA256 );
93
+ byte [] signature = computeSignature ( request , ALGORITHM , contentSha256 , sanitizedCredentials );
138
94
139
95
String credentialsAuthorizationHeader =
140
96
"Credential=" + signingCredentials ;
@@ -184,13 +140,13 @@ protected void addSessionCredentials(Request<?> request, AWSSessionCredentials c
184
140
request .addHeader ("x-amz-security-token" , credentials .getSessionToken ());
185
141
}
186
142
187
- private String extractRegionName (URI endpoint ) {
143
+ protected String extractRegionName (URI endpoint ) {
188
144
if (regionName != null ) return regionName ;
189
145
190
146
return AwsHostNameUtils .parseRegionName (endpoint );
191
147
}
192
148
193
- private String extractServiceName (URI endpoint ) {
149
+ protected String extractServiceName (URI endpoint ) {
194
150
if (serviceName != null ) return serviceName ;
195
151
196
152
return AwsHostNameUtils .parseServiceName (endpoint );
@@ -201,7 +157,7 @@ void overrideDate(Date overriddenDate) {
201
157
this .overriddenDate = overriddenDate ;
202
158
}
203
159
204
- private String getCanonicalizedHeaderString (Request <?> request ) {
160
+ protected String getCanonicalizedHeaderString (Request <?> request ) {
205
161
List <String > sortedHeaders = new ArrayList <String >();
206
162
sortedHeaders .addAll (request .getHeaders ().keySet ());
207
163
Collections .sort (sortedHeaders , String .CASE_INSENSITIVE_ORDER );
@@ -215,7 +171,7 @@ private String getCanonicalizedHeaderString(Request<?> request) {
215
171
return buffer .toString ();
216
172
}
217
173
218
- private String getSignedHeadersString (Request <?> request ) {
174
+ protected String getSignedHeadersString (Request <?> request ) {
219
175
List <String > sortedHeaders = new ArrayList <String >();
220
176
sortedHeaders .addAll (request .getHeaders ().keySet ());
221
177
Collections .sort (sortedHeaders , String .CASE_INSENSITIVE_ORDER );
@@ -229,4 +185,92 @@ private String getSignedHeadersString(Request<?> request) {
229
185
return buffer .toString ();
230
186
}
231
187
188
+ protected String getCanonicalRequest (Request <?> request , String contentSha256 ) {
189
+ String canonicalRequest =
190
+ request .getHttpMethod ().toString () + "\n " +
191
+ getCanonicalizedResourcePath (request .getResourcePath ()) + "\n " +
192
+ getCanonicalizedQueryString (request ) + "\n " +
193
+ getCanonicalizedHeaderString (request ) + "\n " +
194
+ getSignedHeadersString (request ) + "\n " +
195
+ contentSha256 ;
196
+ log .debug ("AWS4 Canonical Request: '\" " + canonicalRequest + "\" " );
197
+ return canonicalRequest ;
198
+ }
199
+
200
+ protected String getStringToSign (String algorithm , String dateTime , String scope , String canonicalRequest ) {
201
+ String stringToSign =
202
+ algorithm + "\n " +
203
+ dateTime + "\n " +
204
+ scope + "\n " +
205
+ BinaryUtils .toHex (hash (canonicalRequest ));
206
+ log .debug ("AWS4 String to Sign: '\" " + stringToSign + "\" " );
207
+ return stringToSign ;
208
+ }
209
+
210
+
211
+ protected byte [] computeSignature (Request <?> request , String algorithm , String contentSha256 , AWSCredentials sanitizedCredentials ) {
212
+
213
+ String regionName = extractRegionName (request .getEndpoint ());
214
+ String serviceName = extractServiceName (request .getEndpoint ());
215
+
216
+ Date date = getDateFromRequest (request );
217
+ String dateTime = getDateTimeStamp (date );
218
+ String dateStamp = getDateStamp (date );
219
+ String scope = dateStamp + "/" + regionName + "/" + serviceName + "/" + TERMINATOR ;
220
+
221
+ String stringToSign = getStringToSign (algorithm , dateTime , scope , getCanonicalRequest (request ,contentSha256 ));
222
+
223
+ // AWS4 uses a series of derived keys, formed by hashing different
224
+ // pieces of data
225
+ byte [] kSecret = ("AWS4" + sanitizedCredentials .getAWSSecretKey ()).getBytes ();
226
+ byte [] kDate = sign (dateStamp , kSecret , SigningAlgorithm .HmacSHA256 );
227
+ byte [] kRegion = sign (regionName , kDate , SigningAlgorithm .HmacSHA256 );
228
+ byte [] kService = sign (serviceName , kRegion , SigningAlgorithm .HmacSHA256 );
229
+ byte [] kSigning = sign (TERMINATOR , kService , SigningAlgorithm .HmacSHA256 );
230
+
231
+ byte [] signature = sign (stringToSign .getBytes (), kSigning , SigningAlgorithm .HmacSHA256 );
232
+ return signature ;
233
+ }
234
+
235
+ protected String getDateTimeStamp (Date date ) {
236
+ SimpleDateFormat dateTimeFormat ;
237
+ dateTimeFormat = new SimpleDateFormat ("yyyyMMdd'T'HHmmss'Z'" );
238
+ dateTimeFormat .setTimeZone (new SimpleTimeZone (0 , "UTC" ));
239
+ return dateTimeFormat .format (date );
240
+ }
241
+
242
+ protected String getDateStamp (Date date ) {
243
+ SimpleDateFormat dateStampFormat ;
244
+ dateStampFormat = new SimpleDateFormat ("yyyyMMdd" );
245
+ dateStampFormat .setTimeZone (new SimpleTimeZone (0 , "UTC" ));
246
+ return dateStampFormat .format (date );
247
+ }
248
+
249
+ protected Date getDateFromRequest (Request <?> request ) {
250
+ Date date = getSignatureDate (request .getTimeOffset ());
251
+ if (overriddenDate != null ) date = overriddenDate ;
252
+ return date ;
253
+ }
254
+
255
+
256
+ protected void addHostHeader (Request <?> request ) {
257
+ // AWS4 requires that we sign the Host header so we
258
+ // have to have it in the request by the time we sign.
259
+ String hostHeader = request .getEndpoint ().getHost ();
260
+ if (HttpUtils .isUsingNonDefaultPort (request .getEndpoint ())) {
261
+ hostHeader += ":" + request .getEndpoint ().getPort ();
262
+ }
263
+ request .addHeader ("Host" , hostHeader );
264
+ }
265
+
266
+ protected String getScope (Request <?> request ) {
267
+ String regionName = extractRegionName (request .getEndpoint ());
268
+ String serviceName = extractServiceName (request .getEndpoint ());
269
+
270
+ Date date = getDateFromRequest (request );
271
+ String dateStamp = getDateStamp (date );
272
+ String scope = dateStamp + "/" + regionName + "/" + serviceName + "/" + TERMINATOR ;
273
+ return scope ;
274
+ }
275
+
232
276
}
0 commit comments