|
18 | 18 |
|
19 | 19 | package org.apache.hadoop.fs.s3a; |
20 | 20 |
|
21 | | -import com.fasterxml.jackson.databind.ObjectMapper; |
22 | 21 | import software.amazon.awssdk.awscore.exception.AwsServiceException; |
23 | 22 | import software.amazon.awssdk.core.exception.AbortedException; |
24 | 23 | import software.amazon.awssdk.core.exception.ApiCallAttemptTimeoutException; |
|
28 | 27 | import software.amazon.awssdk.services.s3.model.S3Exception; |
29 | 28 | import software.amazon.awssdk.services.s3.model.S3Object; |
30 | 29 |
|
31 | | -import org.apache.commons.codec.binary.Base64; |
32 | 30 | import org.apache.commons.lang3.StringUtils; |
33 | 31 | import org.apache.hadoop.classification.InterfaceAudience; |
34 | 32 | import org.apache.hadoop.classification.InterfaceStability; |
|
39 | 37 | import org.apache.hadoop.fs.PathFilter; |
40 | 38 | import org.apache.hadoop.fs.PathIOException; |
41 | 39 | import org.apache.hadoop.fs.RemoteIterator; |
| 40 | +import org.apache.hadoop.fs.s3a.impl.S3AEncryption; |
42 | 41 | import org.apache.hadoop.util.functional.RemoteIterators; |
43 | 42 | import org.apache.hadoop.fs.s3a.auth.delegation.EncryptionSecrets; |
44 | 43 | import org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException; |
|
64 | 63 | import java.lang.reflect.Modifier; |
65 | 64 | import java.net.SocketTimeoutException; |
66 | 65 | import java.net.URI; |
67 | | -import java.nio.charset.StandardCharsets; |
68 | 66 | import java.nio.file.AccessDeniedException; |
69 | 67 | import java.util.ArrayList; |
70 | 68 | import java.util.Collection; |
@@ -127,7 +125,6 @@ public final class S3AUtils { |
127 | 125 | S3AEncryptionMethods.SSE_S3.getMethod() |
128 | 126 | + " is enabled but an encryption key was set in " |
129 | 127 | + Constants.S3_ENCRYPTION_KEY; |
130 | | - |
131 | 128 | public static final String EOF_MESSAGE_IN_XML_PARSER |
132 | 129 | = "Failed to sanitize XML document destined for handler class"; |
133 | 130 |
|
@@ -1316,7 +1313,7 @@ static void patchSecurityCredentialProviders(Configuration conf) { |
1316 | 1313 | * @throws IOException on any IO problem |
1317 | 1314 | * @throws IllegalArgumentException bad arguments |
1318 | 1315 | */ |
1319 | | - private static String lookupBucketSecret( |
| 1316 | + public static String lookupBucketSecret( |
1320 | 1317 | String bucket, |
1321 | 1318 | Configuration conf, |
1322 | 1319 | String baseKey) |
@@ -1406,79 +1403,6 @@ public static String getS3EncryptionKey( |
1406 | 1403 | } |
1407 | 1404 | } |
1408 | 1405 |
|
1409 | | - /** |
1410 | | - * Get any SSE context, without propagating exceptions from |
1411 | | - * JCEKs files. |
1412 | | - * @param bucket bucket to query for |
1413 | | - * @param conf configuration to examine |
1414 | | - * @return the encryption context value or "" |
1415 | | - * @throws IllegalArgumentException bad arguments. |
1416 | | - */ |
1417 | | - public static String getS3EncryptionContext( |
1418 | | - String bucket, |
1419 | | - Configuration conf) { |
1420 | | - try { |
1421 | | - return getEncryptionContextValue(bucket, conf); |
1422 | | - } catch (IOException e) { |
1423 | | - // never going to happen, but to make sure, covert to |
1424 | | - // runtime exception |
1425 | | - throw new UncheckedIOException(e); |
1426 | | - } |
1427 | | - } |
1428 | | - |
1429 | | - /** |
1430 | | - * Get any SSE context from a configuration/credential provider. |
1431 | | - * This includes converting the values to a base64-encoded UTF-8 string |
1432 | | - * holding JSON with the encryption context key-value pairs |
1433 | | - * @param bucket bucket to query for |
1434 | | - * @param conf configuration to examine |
1435 | | - * @param propagateExceptions should IO exceptions be rethrown? |
1436 | | - * @return the Base64 encryption context or "" |
1437 | | - * @throws IllegalArgumentException bad arguments. |
1438 | | - * @throws IOException if propagateExceptions==true and reading a JCEKS file raised an IOE |
1439 | | - */ |
1440 | | - public static String getS3EncryptionContextBase64Encoded( |
1441 | | - String bucket, |
1442 | | - Configuration conf, |
1443 | | - boolean propagateExceptions) throws IOException { |
1444 | | - try { |
1445 | | - final String encryptionContextValue = getEncryptionContextValue(bucket, conf); |
1446 | | - if (StringUtils.isBlank(encryptionContextValue)) { |
1447 | | - return ""; |
1448 | | - } |
1449 | | - final Map<String, String> encryptionContextMap = getTrimmedStringCollectionSplitByEquals( |
1450 | | - encryptionContextValue); |
1451 | | - if (encryptionContextMap.isEmpty()) { |
1452 | | - return ""; |
1453 | | - } |
1454 | | - final String encryptionContextJson = new ObjectMapper().writeValueAsString( |
1455 | | - encryptionContextMap); |
1456 | | - return Base64.encodeBase64String(encryptionContextJson.getBytes(StandardCharsets.UTF_8)); |
1457 | | - } catch (IOException e) { |
1458 | | - if (propagateExceptions) { |
1459 | | - throw e; |
1460 | | - } |
1461 | | - LOG.warn("Cannot retrieve {} for bucket {}", |
1462 | | - S3_ENCRYPTION_CONTEXT, bucket, e); |
1463 | | - return ""; |
1464 | | - } |
1465 | | - } |
1466 | | - |
1467 | | - private static String getEncryptionContextValue(String bucket, Configuration conf) |
1468 | | - throws IOException { |
1469 | | - // look up the per-bucket value of the encryption context |
1470 | | - String encryptionContext = lookupBucketSecret(bucket, conf, S3_ENCRYPTION_CONTEXT); |
1471 | | - if (encryptionContext == null) { |
1472 | | - // look up the global value of the encryption context |
1473 | | - encryptionContext = lookupPassword(null, conf, S3_ENCRYPTION_CONTEXT); |
1474 | | - } |
1475 | | - if (encryptionContext == null) { |
1476 | | - // no encryption context, return "" |
1477 | | - return ""; |
1478 | | - } |
1479 | | - return encryptionContext; |
1480 | | - } |
1481 | | - |
1482 | 1406 | /** |
1483 | 1407 | * Get the server-side encryption or client side encryption algorithm. |
1484 | 1408 | * This includes validation of the configuration, checking the state of |
@@ -1535,6 +1459,8 @@ public static EncryptionSecrets buildEncryptionSecrets(String bucket, |
1535 | 1459 | int encryptionKeyLen = |
1536 | 1460 | StringUtils.isBlank(encryptionKey) ? 0 : encryptionKey.length(); |
1537 | 1461 | String diagnostics = passwordDiagnostics(encryptionKey, "key"); |
| 1462 | + String encryptionContext = S3AEncryption.getS3EncryptionContextBase64Encoded(bucket, conf, |
| 1463 | + encryptionMethod.requiresSecret()); |
1538 | 1464 | switch (encryptionMethod) { |
1539 | 1465 | case SSE_C: |
1540 | 1466 | LOG.debug("Using SSE-C with {}", diagnostics); |
@@ -1570,9 +1496,6 @@ public static EncryptionSecrets buildEncryptionSecrets(String bucket, |
1570 | 1496 | LOG.debug("Data is unencrypted"); |
1571 | 1497 | break; |
1572 | 1498 | } |
1573 | | - |
1574 | | - String encryptionContext = getS3EncryptionContextBase64Encoded(bucket, conf, |
1575 | | - encryptionMethod.requiresSecret()); |
1576 | 1499 | return new EncryptionSecrets(encryptionMethod, encryptionKey, encryptionContext); |
1577 | 1500 | } |
1578 | 1501 |
|
@@ -1779,7 +1702,7 @@ public static Map<String, String> getTrimmedStringCollectionSplitByEquals( |
1779 | 1702 | * @return property value as a <code>Map</code> of <code>String</code>s, or empty |
1780 | 1703 | * <code>Map</code>. |
1781 | 1704 | */ |
1782 | | - private static Map<String, String> getTrimmedStringCollectionSplitByEquals( |
| 1705 | + public static Map<String, String> getTrimmedStringCollectionSplitByEquals( |
1783 | 1706 | final String valueString) { |
1784 | 1707 | if (null == valueString) { |
1785 | 1708 | return new HashMap<>(); |
|
0 commit comments