|
50 | 50 | import com.google.common.collect.ImmutableMap;
|
51 | 51 | import com.google.common.collect.Iterables;
|
52 | 52 | import com.google.common.io.BaseEncoding;
|
| 53 | +import com.google.common.net.UrlEscapers; |
53 | 54 |
|
54 | 55 | import org.easymock.Capture;
|
55 | 56 | import org.easymock.EasyMock;
|
@@ -1252,16 +1253,17 @@ public void testSignUrlLeadingSlash() throws NoSuchAlgorithmException, InvalidKe
|
1252 | 1253 | ServiceAccountAuthCredentials.createFor(ACCOUNT, privateKey);
|
1253 | 1254 | storage = options.toBuilder().authCredentials(authCredentials).build().service();
|
1254 | 1255 | URL url = storage.signUrl(BlobInfo.builder(BUCKET_NAME1, blobName).build(), 14, TimeUnit.DAYS);
|
| 1256 | + String escapedBlobName = UrlEscapers.urlPathSegmentEscaper().escape(blobName); |
1255 | 1257 | String stringUrl = url.toString();
|
1256 | 1258 | String expectedUrl = new StringBuilder("https://storage.googleapis.com/").append(BUCKET_NAME1)
|
1257 |
| - .append(blobName).append("?GoogleAccessId=").append(ACCOUNT).append("&Expires=") |
| 1259 | + .append(escapedBlobName).append("?GoogleAccessId=").append(ACCOUNT).append("&Expires=") |
1258 | 1260 | .append(42L + 1209600).append("&Signature=").toString();
|
1259 | 1261 | assertTrue(stringUrl.startsWith(expectedUrl));
|
1260 | 1262 | String signature = stringUrl.substring(expectedUrl.length());
|
1261 | 1263 |
|
1262 | 1264 | StringBuilder signedMessageBuilder = new StringBuilder();
|
1263 | 1265 | signedMessageBuilder.append(HttpMethod.GET).append("\n\n\n").append(42L + 1209600).append("\n/")
|
1264 |
| - .append(BUCKET_NAME1).append(blobName); |
| 1266 | + .append(BUCKET_NAME1).append(escapedBlobName); |
1265 | 1267 |
|
1266 | 1268 | Signature signer = Signature.getInstance("SHA256withRSA");
|
1267 | 1269 | signer.initVerify(publicKey);
|
@@ -1299,6 +1301,42 @@ public void testSignUrlWithOptions() throws NoSuchAlgorithmException, InvalidKey
|
1299 | 1301 | URLDecoder.decode(signature, UTF_8.name()))));
|
1300 | 1302 | }
|
1301 | 1303 |
|
| 1304 | + @Test |
| 1305 | + public void testSignUrlForBlobWithSpecialChars() throws NoSuchAlgorithmException, |
| 1306 | + InvalidKeyException, SignatureException, UnsupportedEncodingException { |
| 1307 | + // List of chars under test were taken from |
| 1308 | + // https://en.wikipedia.org/wiki/Percent-encoding#Percent-encoding_reserved_characters |
| 1309 | + char[] specialChars = |
| 1310 | + new char[]{'!','#','$','&','\'','(',')','*','+',',',':',';','=','?','@','[',']'}; |
| 1311 | + EasyMock.replay(storageRpcMock); |
| 1312 | + ServiceAccountAuthCredentials authCredentials = |
| 1313 | + ServiceAccountAuthCredentials.createFor(ACCOUNT, privateKey); |
| 1314 | + storage = options.toBuilder().authCredentials(authCredentials).build().service(); |
| 1315 | + |
| 1316 | + for (char specialChar : specialChars) { |
| 1317 | + String blobName = "/a" + specialChar + "b"; |
| 1318 | + URL url = |
| 1319 | + storage.signUrl(BlobInfo.builder(BUCKET_NAME1, blobName).build(), 14, TimeUnit.DAYS); |
| 1320 | + String escapedBlobName = UrlEscapers.urlPathSegmentEscaper().escape(blobName); |
| 1321 | + String stringUrl = url.toString(); |
| 1322 | + String expectedUrl = new StringBuilder("https://storage.googleapis.com/").append(BUCKET_NAME1) |
| 1323 | + .append(escapedBlobName).append("?GoogleAccessId=").append(ACCOUNT).append("&Expires=") |
| 1324 | + .append(42L + 1209600).append("&Signature=").toString(); |
| 1325 | + assertTrue(stringUrl.startsWith(expectedUrl)); |
| 1326 | + String signature = stringUrl.substring(expectedUrl.length()); |
| 1327 | + |
| 1328 | + StringBuilder signedMessageBuilder = new StringBuilder(); |
| 1329 | + signedMessageBuilder.append(HttpMethod.GET).append("\n\n\n").append(42L + 1209600) |
| 1330 | + .append("\n/").append(BUCKET_NAME1).append(escapedBlobName); |
| 1331 | + |
| 1332 | + Signature signer = Signature.getInstance("SHA256withRSA"); |
| 1333 | + signer.initVerify(publicKey); |
| 1334 | + signer.update(signedMessageBuilder.toString().getBytes(UTF_8)); |
| 1335 | + assertTrue(signer.verify(BaseEncoding.base64().decode( |
| 1336 | + URLDecoder.decode(signature, UTF_8.name())))); |
| 1337 | + } |
| 1338 | + } |
| 1339 | + |
1302 | 1340 | @Test
|
1303 | 1341 | public void testGetAllArray() {
|
1304 | 1342 | BlobId blobId1 = BlobId.of(BUCKET_NAME1, BLOB_NAME1);
|
|
0 commit comments