Skip to content

Commit

Permalink
Added support for key export. (#17183)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
vcolin7 committed Nov 11, 2020
1 parent ebb0083 commit ec65c91
Show file tree
Hide file tree
Showing 19 changed files with 763 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ Mono<Response<KeyVaultKey>> createKeyWithResponse(CreateKeyOptions createKeyOpti
KeyRequestParameters parameters = new KeyRequestParameters()
.setKty(createKeyOptions.getKeyType())
.setKeyOps(createKeyOptions.getKeyOperations())
.setKeyAttributes(new KeyRequestAttributes(createKeyOptions));
.setKeyAttributes(new KeyRequestAttributes(createKeyOptions))
.setReleasePolicy(createKeyOptions.getReleasePolicy());
return service.createKey(vaultUrl, createKeyOptions.getName(), apiVersion, ACCEPT_LANGUAGE, parameters,
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
.doOnRequest(ignored -> logger.info("Creating key - {}", createKeyOptions.getName()))
Expand Down Expand Up @@ -293,7 +294,9 @@ Mono<Response<KeyVaultKey>> createRsaKeyWithResponse(CreateRsaKeyOptions createR
.setKty(createRsaKeyOptions.getKeyType())
.setKeySize(createRsaKeyOptions.getKeySize())
.setKeyOps(createRsaKeyOptions.getKeyOperations())
.setKeyAttributes(new KeyRequestAttributes(createRsaKeyOptions));
.setKeyAttributes(new KeyRequestAttributes(createRsaKeyOptions))
.setReleasePolicy(createRsaKeyOptions.getReleasePolicy())
.setPublicExponent(createRsaKeyOptions.getPublicExponent());
return service.createKey(vaultUrl, createRsaKeyOptions.getName(), apiVersion, ACCEPT_LANGUAGE, parameters,
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
.doOnRequest(ignored -> logger.info("Creating Rsa key - {}", createRsaKeyOptions.getName()))
Expand Down Expand Up @@ -379,7 +382,8 @@ Mono<Response<KeyVaultKey>> createEcKeyWithResponse(CreateEcKeyOptions createEcK
.setKty(createEcKeyOptions.getKeyType())
.setCurve(createEcKeyOptions.getCurveName())
.setKeyOps(createEcKeyOptions.getKeyOperations())
.setKeyAttributes(new KeyRequestAttributes(createEcKeyOptions));
.setKeyAttributes(new KeyRequestAttributes(createEcKeyOptions))
.setReleasePolicy(createEcKeyOptions.getReleasePolicy());
return service.createKey(vaultUrl, createEcKeyOptions.getName(), apiVersion, ACCEPT_LANGUAGE, parameters,
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
.doOnRequest(ignored -> logger.info("Creating Ec key - {}", createEcKeyOptions.getName()))
Expand Down Expand Up @@ -492,14 +496,108 @@ Mono<Response<KeyVaultKey>> importKeyWithResponse(ImportKeyOptions importKeyOpti
KeyImportRequestParameters parameters = new KeyImportRequestParameters()
.setKey(importKeyOptions.getKey())
.setHsm(importKeyOptions.isHardwareProtected())
.setKeyAttributes(new KeyRequestAttributes(importKeyOptions));
.setKeyAttributes(new KeyRequestAttributes(importKeyOptions))
.setReleasePolicy(importKeyOptions.getReleasePolicy());
return service.importKey(vaultUrl, importKeyOptions.getName(), apiVersion, ACCEPT_LANGUAGE, parameters,
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
.doOnRequest(ignored -> logger.info("Importing key - {}", importKeyOptions.getName()))
.doOnSuccess(response -> logger.info("Imported key - {}", response.getValue().getName()))
.doOnError(error -> logger.warning("Failed to import key - {}", importKeyOptions.getName(), error));
}

/**
* Exports the latest version of a key from the key vault. The export key operation may be used to import any key
* from the Azure Key Vault as long as it is marked as exportable and its release policy is satisfied.
*
* <p><strong>Code Samples</strong></p>
* <p>Exports a key from a key vault. Subscribes to the call asynchronously and prints out the newly exported key
* details when a response has been received.</p>
*
* {@codesnippet com.azure.security.keyvault.keys.keyasyncclient.exportKey#String-String}
*
* @param name The name of the key to be exported.
* @param environment The target environment assertion.
* @return A {@link Mono} containing the {@link KeyVaultKey exported key}.
* @throws NullPointerException If the specified {@code name} or {@code environment} are {@code null}.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<KeyVaultKey> exportKey(String name, String environment) {
try {
return exportKeyWithResponse(name, "", environment).flatMap(FluxUtil::toMono);
} catch (RuntimeException ex) {
return monoError(logger, ex);
}
}

/**
* Exports a key from the key vault. The export key operation may be used to import any key from the Azure Key Vault
* as long as it is marked as exportable and its release policy is satisfied.
*
* <p><strong>Code Samples</strong></p>
* <p>Exports a key from a key vault. Subscribes to the call asynchronously and prints out the newly exported key
* details when a response has been received.</p>
*
* {@codesnippet com.azure.security.keyvault.keys.keyasyncclient.exportKey#String-String-String}
*
* @param name The name of the key to be exported.
* @param version The key version.
* @param environment The target environment assertion.
* @return A {@link Mono} containing the {@link KeyVaultKey exported key}.
* @throws NullPointerException If the specified {@code name}, {@code version} or {@code environment} are
* {@code null}.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<KeyVaultKey> exportKey(String name, String version, String environment) {
try {
return exportKeyWithResponse(name, version, environment).flatMap(FluxUtil::toMono);
} catch (RuntimeException ex) {
return monoError(logger, ex);
}
}

/**
* Exports a key from the key vault. The export key operation may be used to import any key from the Azure Key Vault
* as long as it is marked as exportable and its release policy is satisfied.
*
* <p><strong>Code Samples</strong></p>
* <p>Exports a key from a key vault. Subscribes to the call asynchronously and prints out the newly exported key
* details when a response has been received.</p>
*
* {@codesnippet com.azure.security.keyvault.keys.keyasyncclient.exportKeyWithResponse#String-String-String}
*
* @param name The name of the key to be exported.
* @param version The key version.
* @param environment The target environment assertion.
* @return A {@link Mono} containing a {@link Response} whose {@link Response#getValue() value} contains the
* {@link KeyVaultKey exported key}.
* @throws NullPointerException If the specified {@code name}, {@code version} or {@code environment} are
* {@code null}.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<Response<KeyVaultKey>> exportKeyWithResponse(String name, String version, String environment) {
try {
return withContext(context -> exportKeyWithResponse(name, version, environment, context));
} catch (RuntimeException ex) {
return monoError(logger, ex);
}
}

Mono<Response<KeyVaultKey>> exportKeyWithResponse(String name, String version, String environment,
Context context) {
Objects.requireNonNull(name, "The key name cannot be null.");
Objects.requireNonNull(version, "The key version cannot be null.");
Objects.requireNonNull(environment, "The environment parameter cannot be null.");

context = context == null ? Context.NONE : context;
KeyExportRequestParameters parameters = new KeyExportRequestParameters().setEnvironment(environment);

return service.exportKey(vaultUrl, name, version, apiVersion, ACCEPT_LANGUAGE, parameters,
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
.doOnRequest(ignored -> logger.info("Exporting key - {}", name))
.doOnSuccess(response -> logger.info("Exported key - {}", response.getValue().getName()))
.doOnError(error -> logger.warning("Failed to export key - {}", name, error));
}

/**
* Gets the public part of the specified key and key version. The get key operation is applicable to all key types
* and it requires the {@code keys/get} permission.
Expand Down Expand Up @@ -659,7 +757,8 @@ Mono<Response<KeyVaultKey>> updateKeyPropertiesWithResponse(KeyProperties keyPro
context = context == null ? Context.NONE : context;
KeyRequestParameters parameters = new KeyRequestParameters()
.setTags(keyProperties.getTags())
.setKeyAttributes(new KeyRequestAttributes(keyProperties));
.setKeyAttributes(new KeyRequestAttributes(keyProperties))
.setReleasePolicy(keyProperties.getReleasePolicy());
if (keyOperations.length > 0) {
parameters.setKeyOps(Arrays.asList(keyOperations));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,69 @@ public Response<KeyVaultKey> importKeyWithResponse(ImportKeyOptions importKeyOpt
return client.importKeyWithResponse(importKeyOptions, context).block();
}

/**
* Exports the latest version of a key from the key vault. The export key operation may be used to import any key
* from the Azure Key Vault as long as it is marked as exportable and its release policy is satisfied.
*
* <p><strong>Code Samples</strong></p>
* <p>Exports a key from a key vault. Subscribes to the call asynchronously and prints out the newly exported key
* details when a response has been received.</p>
*
* {@codesnippet com.azure.security.keyvault.keys.keyclient.exportKey#String-String}
*
* @param name The name of the key to be exported.
* @param environment The target environment assertion.
* @return The {@link KeyVaultKey exported key}.
* @throws NullPointerException If the specified {@code name} or {@code environment} are {@code null}.
*/
public KeyVaultKey exportKey(String name, String environment) {
return client.exportKey(name, environment).block();
}

/**
* Exports a key from the key vault. The export key operation may be used to import any key from the Azure Key Vault
* as long as it is marked as exportable and its release policy is satisfied.
*
* <p><strong>Code Samples</strong></p>
* <p>Exports a key from a key vault. Subscribes to the call asynchronously and prints out the newly exported key
* details when a response has been received.</p>
*
* {@codesnippet com.azure.security.keyvault.keys.keyclient.exportKey#String-String-String}
*
* @param name The name of the key to be exported.
* @param version The key version.
* @param environment The target environment assertion.
* @return The {@link KeyVaultKey exported key}.
* @throws NullPointerException If the specified {@code name}, {@code version} or {@code environment} are
* {@code null}.
*/
public KeyVaultKey exportKey(String name, String version, String environment) {
return client.exportKey(name, version, environment).block();
}

/**
* Exports a key from the key vault. The export key operation may be used to import any key from the Azure Key Vault
* as long as it is marked as exportable and its release policy is satisfied.
*
* <p><strong>Code Samples</strong></p>
* <p>Exports a key from a key vault. Subscribes to the call asynchronously and prints out the newly exported key
* details when a response has been received.</p>
*
* {@codesnippet com.azure.security.keyvault.keys.keyclient.exportKeyWithResponse#String-String-String-Context}
*
* @param name The name of the key to be exported.
* @param version The key version.
* @param environment The target environment assertion.
* @param context Additional context that is passed through the HTTP pipeline during the service call.
* @return A {@link Response} whose {@link Response#getValue() value} contains the {@link KeyVaultKey exported key}.
* @throws NullPointerException If the specified {@code name}, {@code version} or {@code environment} are
* {@code null}.
*/
public Response<KeyVaultKey> exportKeyWithResponse(String name, String version, String environment,
Context context) {
return client.exportKeyWithResponse(name, version, environment, context).block();
}

/**
* Gets the public part of the specified key and key version. The get key operation is applicable to all key types
* and it requires the {@code keys/get} permission.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.security.keyvault.keys;

import com.azure.core.annotation.Fluent;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
* The parameters for the key export operation.
*/
@Fluent
class KeyExportRequestParameters {
/**
* The target environment assertion.
*/
@JsonProperty(value = "env")
private String environment;

/**
* Get the target environment assertion.
*
* @return The environment.
*/
public String getEnvironment() {
return this.environment;
}

/**
* Set the target environment assertion.
*
* @param environment The environment value to set.
* @return The updated {@link KeyExportRequestParameters} object.
*/
public KeyExportRequestParameters setEnvironment(String environment) {
this.environment = environment;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import com.azure.core.annotation.Fluent;
import com.azure.security.keyvault.keys.models.JsonWebKey;
import com.azure.security.keyvault.keys.models.KeyReleasePolicy;
import com.fasterxml.jackson.annotation.JsonProperty;

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

/**
* The policy rules under which the key can be exported.
*/
@JsonProperty(value = "release_policy")
private KeyReleasePolicy releasePolicy;

/**
* Get the keyAttributes value.
*
Expand Down Expand Up @@ -115,4 +122,24 @@ public KeyImportRequestParameters setKey(JsonWebKey key) {
this.key = key;
return this;
}

/**
* Get the policy rules under which the key can be exported.
*
* @return The release policy.
*/
public KeyReleasePolicy getReleasePolicy() {
return releasePolicy;
}

/**
* Set the policy rules under which the key can be exported.
*
* @param releasePolicy The release policy to set.
* @return The updated {@link KeyImportRequestParameters} object.
*/
public KeyImportRequestParameters setReleasePolicy(KeyReleasePolicy releasePolicy) {
this.releasePolicy = releasePolicy;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class KeyRequestAttributes {
this.expires = keyProperties.getExpiresOn().toEpochSecond();
}
this.enabled = keyProperties.isEnabled();
this.exportable = keyProperties.isExportable();
}

/**
Expand All @@ -42,6 +43,7 @@ class KeyRequestAttributes {
this.expires = keyOptions.getExpiresOn().toEpochSecond();
}
this.enabled = keyOptions.isEnabled();
this.exportable = keyOptions.isExportable();
}

/**
Expand Down Expand Up @@ -74,6 +76,12 @@ class KeyRequestAttributes {
@JsonProperty(value = "updated", access = JsonProperty.Access.WRITE_ONLY)
private Long updated;

/**
* Indicates if the private key can be exported.
*/
@JsonProperty(value = "exportable")
private Boolean exportable;

/**
* Get the enabled value.
*
Expand Down Expand Up @@ -171,4 +179,24 @@ public OffsetDateTime getUpdated() {
}
return OffsetDateTime.ofInstant(Instant.ofEpochMilli(this.updated * 1000L), ZoneOffset.UTC);
}

/**
* Indicates if the private key can be exported.
*
* @return The exportable value.
*/
public Boolean isExportable() {
return this.exportable;
}

/**
* Set a value that indicates if the private key can be exported.
*
* @param exportable The exportable value to set.
* @return The updated {@link KeyRequestAttributes} object.
*/
public KeyRequestAttributes setExportable(Boolean exportable) {
this.exportable = exportable;
return this;
}
}
Loading

0 comments on commit ec65c91

Please sign in to comment.