Skip to content

Commit 70d8722

Browse files
vcolin7heaths
andauthored
Added fallback logic to use service-side cryptography if a key cannot be retrieved for local operations. (#38334)
* Added fallback logic to use service-side cryptography if a key cannot be retrieved for local operations. * Updated CHANGELOG * Fixed issue. * Update sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md Co-authored-by: Heath Stewart <[email protected]> * Improved error handling when receiving a 403 when fetching a key in the cryptography clients. * Refactored how we initialize local crypto clients to avoid using async APIs. * Fixed test issues and refactored internal local crypto clients. * Updated test recordings. * Fixed CheckStyle issues. * Applied more PR feedback. * Fixed a CheckStyle error. * Added CheckStyle suppressions. * Fixed NPE when using a local client. * Update pom.xml * Applied more PR feedback. * Fixed CheckStyle issue. * Applied more PR feedback. * Updated CheckStyle suppressions. * Updated code snippets. --------- Co-authored-by: Heath Stewart <[email protected]>
1 parent 1f43591 commit 70d8722

File tree

11 files changed

+844
-1109
lines changed

11 files changed

+844
-1109
lines changed

eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml

+5
Original file line numberDiff line numberDiff line change
@@ -480,4 +480,9 @@ the main ServiceBusClientBuilder. -->
480480

481481
<!-- Suppress checks for defender Easm -->
482482
<suppress checks="com.azure.tools.checkstyle.checks.EnforceFinalFieldsCheck" files="com.azure.analytics.defender.easm.models.CountPagedResponse"/>
483+
484+
<!-- Exceptions thrown here are caught in the calling method. -->
485+
<suppress checks="com.azure.tools.checkstyle.checks.ThrowFromClientLogger"
486+
files="com.azure.security.keyvault.keys.cryptography.CryptographyClient.java"
487+
lines="1234,1237,1243"/>
483488
</suppressions>

sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
### Bugs Fixed
1010

11+
- Added fallback logic to use service-side cryptography if a key cannot be retrieved for local operations. ([#38334](https://github.com/Azure/azure-sdk-for-java/pull/38334))
12+
1113
### Other Changes
1214

1315
## 4.7.3 (2023-12-04)

sdk/keyvault/azure-security-keyvault-keys/assets.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "java",
44
"TagPrefix": "java/keyvault/azure-security-keyvault-keys",
5-
"Tag": "java/keyvault/azure-security-keyvault-keys_c6d608b5d8"
5+
"Tag": "java/keyvault/azure-security-keyvault-keys_b32c8c4df8"
66
}

sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/CryptographyAsyncClient.java

+124-180
Large diffs are not rendered by default.

sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/CryptographyClient.java

+157-188
Large diffs are not rendered by default.

sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/implementation/AesKeyCryptographyClient.java

+198-253
Large diffs are not rendered by default.

sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/implementation/CryptographyClientImpl.java

-3
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ public final class CryptographyClientImpl {
6464
public CryptographyClientImpl(String keyId, HttpPipeline pipeline, CryptographyServiceVersion serviceVersion) {
6565
Objects.requireNonNull(keyId);
6666

67-
//Arrays.asList(vaultUrl, keyCollection, keyName, keyVersion);
6867
List<String> data = unpackAndValidateId(keyId, LOGGER);
6968

7069
this.vaultUrl = data.get(0);
@@ -183,7 +182,6 @@ private EncryptResult encrypt(EncryptionAlgorithm algorithm, byte[] plainText, b
183182
result.getAuthenticationTag(), result.getAdditionalAuthenticatedData());
184183
}
185184

186-
187185
public Mono<DecryptResult> decryptAsync(EncryptionAlgorithm algorithm, byte[] ciphertext, Context context) {
188186
Objects.requireNonNull(algorithm, "Encryption algorithm cannot be null.");
189187
Objects.requireNonNull(ciphertext, "Ciphertext cannot be null.");
@@ -323,7 +321,6 @@ public UnwrapResult unwrapKey(KeyWrapAlgorithm algorithm, byte[] encryptedKey, C
323321
return new UnwrapResult(result.getResult(), algorithm, keyId);
324322
}
325323

326-
327324
public Mono<SignResult> signDataAsync(SignatureAlgorithm algorithm, byte[] data, Context context) {
328325
Objects.requireNonNull(algorithm, "Signature algorithm cannot be null.");
329326
Objects.requireNonNull(data, "Data to be signed cannot be null.");

sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/implementation/CryptographyUtils.java

+37-19
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License.
33
package com.azure.security.keyvault.keys.cryptography.implementation;
44

5+
import com.azure.core.exception.HttpResponseException;
56
import com.azure.core.util.CoreUtils;
67
import com.azure.core.util.logging.ClientLogger;
78
import com.azure.security.keyvault.keys.cryptography.models.EncryptionAlgorithm;
@@ -19,6 +20,7 @@
1920
import java.util.Arrays;
2021
import java.util.Base64;
2122
import java.util.List;
23+
import java.util.Locale;
2224
import java.util.Objects;
2325

2426
import static com.azure.security.keyvault.keys.models.KeyType.EC;
@@ -32,6 +34,10 @@
3234
* Utility methods for the Cryptography portion of KeyVault Keys.
3335
*/
3436
public final class CryptographyUtils {
37+
private CryptographyUtils() {
38+
// No-op
39+
}
40+
3541
public static final String SECRETS_COLLECTION = "secrets";
3642

3743
public static List<String> unpackAndValidateId(String keyId, ClientLogger logger) {
@@ -66,32 +72,44 @@ public static List<String> unpackAndValidateId(String keyId, ClientLogger logger
6672
}
6773
}
6874

69-
public static LocalKeyCryptographyClient initializeCryptoClient(JsonWebKey jsonWebKey,
70-
CryptographyClientImpl implClient, ClientLogger logger) {
75+
public static LocalKeyCryptographyClient initializeLocalClient(JsonWebKey jsonWebKey,
76+
CryptographyClientImpl implClient) {
7177
if (!KeyType.values().contains(jsonWebKey.getKeyType())) {
72-
throw logger.logExceptionAsError(new IllegalArgumentException(String.format(
73-
"The JSON Web Key type: %s is not supported.", jsonWebKey.getKeyType().toString())));
78+
throw new IllegalArgumentException(String.format(
79+
"The JSON Web Key type: %s is not supported.", jsonWebKey.getKeyType().toString()));
7480
}
7581

76-
try {
77-
if (jsonWebKey.getKeyType().equals(RSA) || jsonWebKey.getKeyType().equals(RSA_HSM)) {
78-
return new RsaKeyCryptographyClient(jsonWebKey, implClient);
79-
} else if (jsonWebKey.getKeyType().equals(EC) || jsonWebKey.getKeyType().equals(EC_HSM)) {
80-
return new EcKeyCryptographyClient(jsonWebKey, implClient);
81-
} else if (jsonWebKey.getKeyType().equals(OCT) || jsonWebKey.getKeyType().equals(OCT_HSM)) {
82-
return new AesKeyCryptographyClient(jsonWebKey, implClient);
83-
}
84-
} catch (RuntimeException e) {
85-
throw logger.logExceptionAsError(new RuntimeException("Could not initialize local cryptography client.",
86-
e));
82+
if (jsonWebKey.getKeyType().equals(RSA) || jsonWebKey.getKeyType().equals(RSA_HSM)) {
83+
return new RsaKeyCryptographyClient(jsonWebKey, implClient);
84+
} else if (jsonWebKey.getKeyType().equals(EC) || jsonWebKey.getKeyType().equals(EC_HSM)) {
85+
return new EcKeyCryptographyClient(jsonWebKey, implClient);
86+
} else if (jsonWebKey.getKeyType().equals(OCT) || jsonWebKey.getKeyType().equals(OCT_HSM)) {
87+
return new AesKeyCryptographyClient(jsonWebKey, implClient);
8788
}
8889

89-
// Should not reach here.
90-
return null;
90+
// Should never reach this point.
91+
throw new IllegalStateException("Could not create local cryptography client.");
9192
}
9293

93-
public static boolean checkKeyPermissions(List<KeyOperation> operations, KeyOperation keyOperation) {
94-
return operations.contains(keyOperation);
94+
public static void verifyKeyPermissions(JsonWebKey jsonWebKey, KeyOperation keyOperation) {
95+
if (!jsonWebKey.getKeyOps().contains(keyOperation)) {
96+
throw new UnsupportedOperationException(
97+
String.format("The %s operation is not allowed for key with id: %s",
98+
keyOperation.toString().toLowerCase(Locale.ROOT), jsonWebKey.getId()));
99+
}
100+
}
101+
102+
public static boolean isThrowableRetryable(Throwable e) {
103+
if (e instanceof HttpResponseException) {
104+
int statusCode = ((HttpResponseException) e).getResponse().getStatusCode();
105+
106+
// Not a retriable error code.
107+
return statusCode != 501 && statusCode != 505
108+
&& (statusCode >= 500 || statusCode == 408 || statusCode == 429);
109+
} else {
110+
// Not a service-related transient error.
111+
return false;
112+
}
95113
}
96114

97115
/*

0 commit comments

Comments
 (0)