Skip to content

Commit ec65c91

Browse files
authored
Added support for key export. (Azure#17183)
* Added support for exporting keys from an Azure Key Vault. * Removed ExportKeyOptions. * Fixed build error. * Added samples. * Fixed test issues. * Fixed samples issues. * Fixed checkstyle issues. * Fixed spotbugs issues. * Applied PR feedback: renamed KeyReleasePolicy to ReleasePolicy and removed it from KeyVaultKey. * Fixed spotbugs issues. * Added unit tests. * Renamed ReleasePolicy to KeyReleasePolicy. Added tests for creating an RSA key with publicExponent.
1 parent ebb0083 commit ec65c91

File tree

19 files changed

+763
-10
lines changed

19 files changed

+763
-10
lines changed

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

Lines changed: 104 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,8 @@ Mono<Response<KeyVaultKey>> createKeyWithResponse(CreateKeyOptions createKeyOpti
213213
KeyRequestParameters parameters = new KeyRequestParameters()
214214
.setKty(createKeyOptions.getKeyType())
215215
.setKeyOps(createKeyOptions.getKeyOperations())
216-
.setKeyAttributes(new KeyRequestAttributes(createKeyOptions));
216+
.setKeyAttributes(new KeyRequestAttributes(createKeyOptions))
217+
.setReleasePolicy(createKeyOptions.getReleasePolicy());
217218
return service.createKey(vaultUrl, createKeyOptions.getName(), apiVersion, ACCEPT_LANGUAGE, parameters,
218219
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
219220
.doOnRequest(ignored -> logger.info("Creating key - {}", createKeyOptions.getName()))
@@ -293,7 +294,9 @@ Mono<Response<KeyVaultKey>> createRsaKeyWithResponse(CreateRsaKeyOptions createR
293294
.setKty(createRsaKeyOptions.getKeyType())
294295
.setKeySize(createRsaKeyOptions.getKeySize())
295296
.setKeyOps(createRsaKeyOptions.getKeyOperations())
296-
.setKeyAttributes(new KeyRequestAttributes(createRsaKeyOptions));
297+
.setKeyAttributes(new KeyRequestAttributes(createRsaKeyOptions))
298+
.setReleasePolicy(createRsaKeyOptions.getReleasePolicy())
299+
.setPublicExponent(createRsaKeyOptions.getPublicExponent());
297300
return service.createKey(vaultUrl, createRsaKeyOptions.getName(), apiVersion, ACCEPT_LANGUAGE, parameters,
298301
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
299302
.doOnRequest(ignored -> logger.info("Creating Rsa key - {}", createRsaKeyOptions.getName()))
@@ -379,7 +382,8 @@ Mono<Response<KeyVaultKey>> createEcKeyWithResponse(CreateEcKeyOptions createEcK
379382
.setKty(createEcKeyOptions.getKeyType())
380383
.setCurve(createEcKeyOptions.getCurveName())
381384
.setKeyOps(createEcKeyOptions.getKeyOperations())
382-
.setKeyAttributes(new KeyRequestAttributes(createEcKeyOptions));
385+
.setKeyAttributes(new KeyRequestAttributes(createEcKeyOptions))
386+
.setReleasePolicy(createEcKeyOptions.getReleasePolicy());
383387
return service.createKey(vaultUrl, createEcKeyOptions.getName(), apiVersion, ACCEPT_LANGUAGE, parameters,
384388
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
385389
.doOnRequest(ignored -> logger.info("Creating Ec key - {}", createEcKeyOptions.getName()))
@@ -492,14 +496,108 @@ Mono<Response<KeyVaultKey>> importKeyWithResponse(ImportKeyOptions importKeyOpti
492496
KeyImportRequestParameters parameters = new KeyImportRequestParameters()
493497
.setKey(importKeyOptions.getKey())
494498
.setHsm(importKeyOptions.isHardwareProtected())
495-
.setKeyAttributes(new KeyRequestAttributes(importKeyOptions));
499+
.setKeyAttributes(new KeyRequestAttributes(importKeyOptions))
500+
.setReleasePolicy(importKeyOptions.getReleasePolicy());
496501
return service.importKey(vaultUrl, importKeyOptions.getName(), apiVersion, ACCEPT_LANGUAGE, parameters,
497502
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
498503
.doOnRequest(ignored -> logger.info("Importing key - {}", importKeyOptions.getName()))
499504
.doOnSuccess(response -> logger.info("Imported key - {}", response.getValue().getName()))
500505
.doOnError(error -> logger.warning("Failed to import key - {}", importKeyOptions.getName(), error));
501506
}
502507

508+
/**
509+
* Exports the latest version of a key from the key vault. The export key operation may be used to import any key
510+
* from the Azure Key Vault as long as it is marked as exportable and its release policy is satisfied.
511+
*
512+
* <p><strong>Code Samples</strong></p>
513+
* <p>Exports a key from a key vault. Subscribes to the call asynchronously and prints out the newly exported key
514+
* details when a response has been received.</p>
515+
*
516+
* {@codesnippet com.azure.security.keyvault.keys.keyasyncclient.exportKey#String-String}
517+
*
518+
* @param name The name of the key to be exported.
519+
* @param environment The target environment assertion.
520+
* @return A {@link Mono} containing the {@link KeyVaultKey exported key}.
521+
* @throws NullPointerException If the specified {@code name} or {@code environment} are {@code null}.
522+
*/
523+
@ServiceMethod(returns = ReturnType.SINGLE)
524+
public Mono<KeyVaultKey> exportKey(String name, String environment) {
525+
try {
526+
return exportKeyWithResponse(name, "", environment).flatMap(FluxUtil::toMono);
527+
} catch (RuntimeException ex) {
528+
return monoError(logger, ex);
529+
}
530+
}
531+
532+
/**
533+
* Exports a key from the key vault. The export key operation may be used to import any key from the Azure Key Vault
534+
* as long as it is marked as exportable and its release policy is satisfied.
535+
*
536+
* <p><strong>Code Samples</strong></p>
537+
* <p>Exports a key from a key vault. Subscribes to the call asynchronously and prints out the newly exported key
538+
* details when a response has been received.</p>
539+
*
540+
* {@codesnippet com.azure.security.keyvault.keys.keyasyncclient.exportKey#String-String-String}
541+
*
542+
* @param name The name of the key to be exported.
543+
* @param version The key version.
544+
* @param environment The target environment assertion.
545+
* @return A {@link Mono} containing the {@link KeyVaultKey exported key}.
546+
* @throws NullPointerException If the specified {@code name}, {@code version} or {@code environment} are
547+
* {@code null}.
548+
*/
549+
@ServiceMethod(returns = ReturnType.SINGLE)
550+
public Mono<KeyVaultKey> exportKey(String name, String version, String environment) {
551+
try {
552+
return exportKeyWithResponse(name, version, environment).flatMap(FluxUtil::toMono);
553+
} catch (RuntimeException ex) {
554+
return monoError(logger, ex);
555+
}
556+
}
557+
558+
/**
559+
* Exports a key from the key vault. The export key operation may be used to import any key from the Azure Key Vault
560+
* as long as it is marked as exportable and its release policy is satisfied.
561+
*
562+
* <p><strong>Code Samples</strong></p>
563+
* <p>Exports a key from a key vault. Subscribes to the call asynchronously and prints out the newly exported key
564+
* details when a response has been received.</p>
565+
*
566+
* {@codesnippet com.azure.security.keyvault.keys.keyasyncclient.exportKeyWithResponse#String-String-String}
567+
*
568+
* @param name The name of the key to be exported.
569+
* @param version The key version.
570+
* @param environment The target environment assertion.
571+
* @return A {@link Mono} containing a {@link Response} whose {@link Response#getValue() value} contains the
572+
* {@link KeyVaultKey exported key}.
573+
* @throws NullPointerException If the specified {@code name}, {@code version} or {@code environment} are
574+
* {@code null}.
575+
*/
576+
@ServiceMethod(returns = ReturnType.SINGLE)
577+
public Mono<Response<KeyVaultKey>> exportKeyWithResponse(String name, String version, String environment) {
578+
try {
579+
return withContext(context -> exportKeyWithResponse(name, version, environment, context));
580+
} catch (RuntimeException ex) {
581+
return monoError(logger, ex);
582+
}
583+
}
584+
585+
Mono<Response<KeyVaultKey>> exportKeyWithResponse(String name, String version, String environment,
586+
Context context) {
587+
Objects.requireNonNull(name, "The key name cannot be null.");
588+
Objects.requireNonNull(version, "The key version cannot be null.");
589+
Objects.requireNonNull(environment, "The environment parameter cannot be null.");
590+
591+
context = context == null ? Context.NONE : context;
592+
KeyExportRequestParameters parameters = new KeyExportRequestParameters().setEnvironment(environment);
593+
594+
return service.exportKey(vaultUrl, name, version, apiVersion, ACCEPT_LANGUAGE, parameters,
595+
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
596+
.doOnRequest(ignored -> logger.info("Exporting key - {}", name))
597+
.doOnSuccess(response -> logger.info("Exported key - {}", response.getValue().getName()))
598+
.doOnError(error -> logger.warning("Failed to export key - {}", name, error));
599+
}
600+
503601
/**
504602
* Gets the public part of the specified key and key version. The get key operation is applicable to all key types
505603
* and it requires the {@code keys/get} permission.
@@ -659,7 +757,8 @@ Mono<Response<KeyVaultKey>> updateKeyPropertiesWithResponse(KeyProperties keyPro
659757
context = context == null ? Context.NONE : context;
660758
KeyRequestParameters parameters = new KeyRequestParameters()
661759
.setTags(keyProperties.getTags())
662-
.setKeyAttributes(new KeyRequestAttributes(keyProperties));
760+
.setKeyAttributes(new KeyRequestAttributes(keyProperties))
761+
.setReleasePolicy(keyProperties.getReleasePolicy());
663762
if (keyOperations.length > 0) {
664763
parameters.setKeyOps(Arrays.asList(keyOperations));
665764
}

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

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,69 @@ public Response<KeyVaultKey> importKeyWithResponse(ImportKeyOptions importKeyOpt
319319
return client.importKeyWithResponse(importKeyOptions, context).block();
320320
}
321321

322+
/**
323+
* Exports the latest version of a key from the key vault. The export key operation may be used to import any key
324+
* from the Azure Key Vault as long as it is marked as exportable and its release policy is satisfied.
325+
*
326+
* <p><strong>Code Samples</strong></p>
327+
* <p>Exports a key from a key vault. Subscribes to the call asynchronously and prints out the newly exported key
328+
* details when a response has been received.</p>
329+
*
330+
* {@codesnippet com.azure.security.keyvault.keys.keyclient.exportKey#String-String}
331+
*
332+
* @param name The name of the key to be exported.
333+
* @param environment The target environment assertion.
334+
* @return The {@link KeyVaultKey exported key}.
335+
* @throws NullPointerException If the specified {@code name} or {@code environment} are {@code null}.
336+
*/
337+
public KeyVaultKey exportKey(String name, String environment) {
338+
return client.exportKey(name, environment).block();
339+
}
340+
341+
/**
342+
* Exports a key from the key vault. The export key operation may be used to import any key from the Azure Key Vault
343+
* as long as it is marked as exportable and its release policy is satisfied.
344+
*
345+
* <p><strong>Code Samples</strong></p>
346+
* <p>Exports a key from a key vault. Subscribes to the call asynchronously and prints out the newly exported key
347+
* details when a response has been received.</p>
348+
*
349+
* {@codesnippet com.azure.security.keyvault.keys.keyclient.exportKey#String-String-String}
350+
*
351+
* @param name The name of the key to be exported.
352+
* @param version The key version.
353+
* @param environment The target environment assertion.
354+
* @return The {@link KeyVaultKey exported key}.
355+
* @throws NullPointerException If the specified {@code name}, {@code version} or {@code environment} are
356+
* {@code null}.
357+
*/
358+
public KeyVaultKey exportKey(String name, String version, String environment) {
359+
return client.exportKey(name, version, environment).block();
360+
}
361+
362+
/**
363+
* Exports a key from the key vault. The export key operation may be used to import any key from the Azure Key Vault
364+
* as long as it is marked as exportable and its release policy is satisfied.
365+
*
366+
* <p><strong>Code Samples</strong></p>
367+
* <p>Exports a key from a key vault. Subscribes to the call asynchronously and prints out the newly exported key
368+
* details when a response has been received.</p>
369+
*
370+
* {@codesnippet com.azure.security.keyvault.keys.keyclient.exportKeyWithResponse#String-String-String-Context}
371+
*
372+
* @param name The name of the key to be exported.
373+
* @param version The key version.
374+
* @param environment The target environment assertion.
375+
* @param context Additional context that is passed through the HTTP pipeline during the service call.
376+
* @return A {@link Response} whose {@link Response#getValue() value} contains the {@link KeyVaultKey exported key}.
377+
* @throws NullPointerException If the specified {@code name}, {@code version} or {@code environment} are
378+
* {@code null}.
379+
*/
380+
public Response<KeyVaultKey> exportKeyWithResponse(String name, String version, String environment,
381+
Context context) {
382+
return client.exportKeyWithResponse(name, version, environment, context).block();
383+
}
384+
322385
/**
323386
* Gets the public part of the specified key and key version. The get key operation is applicable to all key types
324387
* and it requires the {@code keys/get} permission.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.security.keyvault.keys;
5+
6+
import com.azure.core.annotation.Fluent;
7+
import com.fasterxml.jackson.annotation.JsonProperty;
8+
9+
/**
10+
* The parameters for the key export operation.
11+
*/
12+
@Fluent
13+
class KeyExportRequestParameters {
14+
/**
15+
* The target environment assertion.
16+
*/
17+
@JsonProperty(value = "env")
18+
private String environment;
19+
20+
/**
21+
* Get the target environment assertion.
22+
*
23+
* @return The environment.
24+
*/
25+
public String getEnvironment() {
26+
return this.environment;
27+
}
28+
29+
/**
30+
* Set the target environment assertion.
31+
*
32+
* @param environment The environment value to set.
33+
* @return The updated {@link KeyExportRequestParameters} object.
34+
*/
35+
public KeyExportRequestParameters setEnvironment(String environment) {
36+
this.environment = environment;
37+
return this;
38+
}
39+
}

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import com.azure.core.annotation.Fluent;
77
import com.azure.security.keyvault.keys.models.JsonWebKey;
8+
import com.azure.security.keyvault.keys.models.KeyReleasePolicy;
89
import com.fasterxml.jackson.annotation.JsonProperty;
910

1011
import java.util.Map;
@@ -36,6 +37,12 @@ class KeyImportRequestParameters {
3637
@JsonProperty(value = "tags")
3738
private Map<String, String> tags;
3839

40+
/**
41+
* The policy rules under which the key can be exported.
42+
*/
43+
@JsonProperty(value = "release_policy")
44+
private KeyReleasePolicy releasePolicy;
45+
3946
/**
4047
* Get the keyAttributes value.
4148
*
@@ -115,4 +122,24 @@ public KeyImportRequestParameters setKey(JsonWebKey key) {
115122
this.key = key;
116123
return this;
117124
}
125+
126+
/**
127+
* Get the policy rules under which the key can be exported.
128+
*
129+
* @return The release policy.
130+
*/
131+
public KeyReleasePolicy getReleasePolicy() {
132+
return releasePolicy;
133+
}
134+
135+
/**
136+
* Set the policy rules under which the key can be exported.
137+
*
138+
* @param releasePolicy The release policy to set.
139+
* @return The updated {@link KeyImportRequestParameters} object.
140+
*/
141+
public KeyImportRequestParameters setReleasePolicy(KeyReleasePolicy releasePolicy) {
142+
this.releasePolicy = releasePolicy;
143+
return this;
144+
}
118145
}

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class KeyRequestAttributes {
2626
this.expires = keyProperties.getExpiresOn().toEpochSecond();
2727
}
2828
this.enabled = keyProperties.isEnabled();
29+
this.exportable = keyProperties.isExportable();
2930
}
3031

3132
/**
@@ -42,6 +43,7 @@ class KeyRequestAttributes {
4243
this.expires = keyOptions.getExpiresOn().toEpochSecond();
4344
}
4445
this.enabled = keyOptions.isEnabled();
46+
this.exportable = keyOptions.isExportable();
4547
}
4648

4749
/**
@@ -74,6 +76,12 @@ class KeyRequestAttributes {
7476
@JsonProperty(value = "updated", access = JsonProperty.Access.WRITE_ONLY)
7577
private Long updated;
7678

79+
/**
80+
* Indicates if the private key can be exported.
81+
*/
82+
@JsonProperty(value = "exportable")
83+
private Boolean exportable;
84+
7785
/**
7886
* Get the enabled value.
7987
*
@@ -171,4 +179,24 @@ public OffsetDateTime getUpdated() {
171179
}
172180
return OffsetDateTime.ofInstant(Instant.ofEpochMilli(this.updated * 1000L), ZoneOffset.UTC);
173181
}
182+
183+
/**
184+
* Indicates if the private key can be exported.
185+
*
186+
* @return The exportable value.
187+
*/
188+
public Boolean isExportable() {
189+
return this.exportable;
190+
}
191+
192+
/**
193+
* Set a value that indicates if the private key can be exported.
194+
*
195+
* @param exportable The exportable value to set.
196+
* @return The updated {@link KeyRequestAttributes} object.
197+
*/
198+
public KeyRequestAttributes setExportable(Boolean exportable) {
199+
this.exportable = exportable;
200+
return this;
201+
}
174202
}

0 commit comments

Comments
 (0)