com.azure.security.keyvault.secrets.SecretAsyncClient Maven / Gradle / Ivy
Show all versions of azure-security-keyvault-secrets Show documentation
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.security.keyvault.secrets;
import com.azure.core.annotation.ReturnType;
import com.azure.core.annotation.ServiceClient;
import com.azure.core.annotation.ServiceMethod;
import com.azure.core.exception.HttpResponseException;
import com.azure.core.exception.ResourceModifiedException;
import com.azure.core.exception.ResourceNotFoundException;
import com.azure.core.http.HttpPipeline;
import com.azure.core.http.rest.PagedFlux;
import com.azure.core.http.rest.PagedResponse;
import com.azure.core.http.rest.PagedResponseBase;
import com.azure.core.http.rest.Response;
import com.azure.core.http.rest.SimpleResponse;
import com.azure.core.util.CoreUtils;
import com.azure.core.util.FluxUtil;
import com.azure.core.util.logging.ClientLogger;
import com.azure.core.util.polling.LongRunningOperationStatus;
import com.azure.core.util.polling.PollResponse;
import com.azure.core.util.polling.PollerFlux;
import com.azure.core.util.polling.PollingContext;
import com.azure.security.keyvault.secrets.implementation.SecretClientImpl;
import com.azure.security.keyvault.secrets.implementation.models.DeletedSecretItem;
import com.azure.security.keyvault.secrets.implementation.models.KeyVaultErrorException;
import com.azure.security.keyvault.secrets.implementation.models.SecretItem;
import com.azure.security.keyvault.secrets.implementation.models.SecretsModelsUtils;
import com.azure.security.keyvault.secrets.models.DeletedSecret;
import com.azure.security.keyvault.secrets.models.KeyVaultSecret;
import com.azure.security.keyvault.secrets.models.SecretProperties;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import static com.azure.core.util.FluxUtil.monoError;
import static com.azure.security.keyvault.secrets.implementation.models.SecretsModelsUtils.createDeletedSecret;
import static com.azure.security.keyvault.secrets.implementation.models.SecretsModelsUtils.createKeyVaultSecret;
import static com.azure.security.keyvault.secrets.implementation.models.SecretsModelsUtils.createSecretAttributes;
import static com.azure.security.keyvault.secrets.implementation.models.SecretsModelsUtils.createSecretProperties;
/**
* The SecretAsyncClient provides asynchronous methods to manage {@link KeyVaultSecret secrets} in the Azure Key Vault.
* The client supports creating, retrieving, updating, deleting, purging, backing up, restoring, and listing the
* {@link KeyVaultSecret secrets}. The client also supports listing {@link DeletedSecret deleted secrets} for a
* soft-delete enabled key vault.
*
* Getting Started
*
* In order to interact with the Azure Key Vault service, you will need to create an instance of the
* {@link com.azure.security.keyvault.secrets.SecretAsyncClient} class, a vault url and a credential object.
*
* The examples shown in this document use a credential object named DefaultAzureCredential for authentication,
* which is appropriate for most scenarios, including local development and production environments. Additionally,
* we recommend using a
*
* managed identity for authentication in production environments.
* You can find more information on different ways of authenticating and their corresponding credential types in the
*
* Azure Identity documentation".
*
* Sample: Construct Asynchronous Secret Client
*
*
*
* SecretAsyncClient secretAsyncClient = new SecretClientBuilder()
* .credential(new DefaultAzureCredentialBuilder().build())
* .vaultUrl("<your-key-vault-url>")
* .buildAsyncClient();
*
*
*
*
*
*
*
* Create a Secret
* The {@link SecretAsyncClient} can be used to create a secret in the key vault.
*
* Code Sample:
* The following code sample demonstrates how to create and store a secret in the key vault, using the
* {@link SecretAsyncClient#setSecret(String, String)} API.
*
*
*
* secretAsyncClient.setSecret("secretName", "secretValue")
* .subscribe(secretResponse ->
* System.out.printf("Secret is created with name %s and value %s%n",
* secretResponse.getName(), secretResponse.getValue()));
*
*
*
* Note: For the synchronous sample, refer to {@link SecretClient}.
*
*
*
*
*
* Get a Secret
* The {@link SecretAsyncClient} can be used to retrieve a secret from the key vault.
*
* Code Sample:
* The following code sample demonstrates how to synchronously retrieve a previously stored secret from the
* key vault, using the {@link SecretAsyncClient#getSecret(String)} API.
*
*
*
* secretAsyncClient.getSecret("secretName")
* .subscribe(secretWithVersion ->
* System.out.printf("Secret is returned with name %s and value %s %n",
* secretWithVersion.getName(), secretWithVersion.getValue()));
*
*
*
* Note: For the synchronous sample, refer to {@link SecretClient}.
*
*
*
*
*
* Delete a Secret
* The {@link SecretAsyncClient} can be used to delete a secret from the key vault.
*
* Code Sample:
* The following code sample demonstrates how to delete a secret from the key vault, using the
* {@link SecretAsyncClient#beginDeleteSecret(String)} API.
*
*
*
* secretAsyncClient.beginDeleteSecret("secretName")
* .subscribe(pollResponse -> {
* System.out.println("Delete Status: " + pollResponse.getStatus().toString());
* System.out.println("Deleted Secret Name: " + pollResponse.getValue().getName());
* System.out.println("Deleted Secret Value: " + pollResponse.getValue().getValue());
* });
*
*
*
* Note: For the synchronous sample, refer to {@link SecretClient}.
*
* @see SecretClientBuilder
* @see PollerFlux
* @see PagedFlux
*/
@ServiceClient(builder = SecretClientBuilder.class, isAsync = true,
serviceInterfaces = SecretClientImpl.SecretClientService.class)
public final class SecretAsyncClient {
private static final ClientLogger LOGGER = new ClientLogger(SecretAsyncClient.class);
private final SecretClientImpl implClient;
private final String vaultUrl;
/**
* Creates a SecretAsyncClient to service requests
*
* @param implClient the implementation client.
* @param vaultUrl the vault url.
*/
SecretAsyncClient(SecretClientImpl implClient, String vaultUrl) {
this.implClient = implClient;
this.vaultUrl = vaultUrl;
}
/**
* Gets the vault endpoint url to which service requests are sent to.
* @return the vault endpoint url.
*/
public String getVaultUrl() {
return vaultUrl;
}
/**
* Gets the {@link HttpPipeline} powering this client.
*
* @return The pipeline.
*/
HttpPipeline getHttpPipeline() {
return implClient.getHttpPipeline();
}
/**
* Adds a secret to the key vault if it does not exist. If the named secret exists, a new version of the secret is
* created. This operation requires the {@code secrets/set} permission.
*
* The {@link SecretProperties#getExpiresOn() expires}, {@link SecretProperties#getContentType() contentType},
* and {@link SecretProperties#getNotBefore() notBefore} values in {@code secret} are optional.
* If not specified, {@link SecretProperties#isEnabled() enabled} is set to true by key vault.
*
* Code sample
* Creates a new secret which activates in one day and expires in one year. Subscribes to the call asynchronously
* and prints out the newly created secret details when a response is received.
*
*
*
* SecretProperties properties = new SecretProperties()
* .setExpiresOn(OffsetDateTime.now().plusDays(60));
* KeyVaultSecret newSecret = new KeyVaultSecret("secretName", "secretValue")
* .setProperties(properties);
*
* secretAsyncClient.setSecret(newSecret)
* .subscribe(secretResponse ->
* System.out.printf("Secret is created with name %s and value %s %n",
* secretResponse.getName(), secretResponse.getValue()));
*
*
*
* @param secret The Secret object containing information about the secret and its properties. The properties
* {@link KeyVaultSecret#getName() secret.name} and {@link KeyVaultSecret#getValue() secret.value} cannot be null.
* @return A {@link Mono} containing the {@link KeyVaultSecret created secret}.
* @throws NullPointerException if {@code secret} is {@code null}.
* @throws ResourceModifiedException if {@code secret} is malformed.
* @throws HttpResponseException if {@link KeyVaultSecret#getName() name} or {@link KeyVaultSecret#getValue() value}
* is an empty string.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono setSecret(KeyVaultSecret secret) {
return setSecretWithResponse(secret).flatMap(FluxUtil::toMono);
}
/**
* Adds a secret to the key vault if it does not exist. If the named secret exists, a new version of the secret is
* created. This operation requires the {@code secrets/set} permission.
*
* Code sample
* Creates a new secret in the key vault. Subscribes to the call asynchronously and prints out
* the newly created secret details when a response is received.
*
*
* secretAsyncClient.setSecret("secretName", "secretValue")
* .subscribe(secretResponse ->
* System.out.printf("Secret is created with name %s and value %s%n",
* secretResponse.getName(), secretResponse.getValue()));
*
*
*
* @param name The name of the secret. It is required and cannot be null.
* @param value The value of the secret. It is required and cannot be null.
* @return A {@link Mono} containing the {@link KeyVaultSecret created secret}.
* @throws ResourceModifiedException if invalid {@code name} or {@code value} are specified.
* @throws HttpResponseException if {@code name} or {@code value} is empty string.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono setSecret(String name, String value) {
return setSecretWithResponse(new KeyVaultSecret(name, value)).flatMap(FluxUtil::toMono);
}
/**
* Adds a secret to the key vault if it does not exist. If the named secret exists, a new version of the secret is
* created. This operation requires the {@code secrets/set} permission.
*
* The {@link SecretProperties#getExpiresOn() expires}, {@link SecretProperties#getContentType() contentType},
* and {@link SecretProperties#getNotBefore() notBefore} values in {@code secret} are optional.
* If not specified, {@link SecretProperties#isEnabled() enabled} is set to true by key vault.
*
* Code sample
* Creates a new secret which activates in one day and expires in one year. Subscribes to the call asynchronously
* and prints out the newly created secret details when a response is received.
*
*
*
* KeyVaultSecret newSecret = new KeyVaultSecret("secretName", "secretValue").
* setProperties(new SecretProperties().setExpiresOn(OffsetDateTime.now().plusDays(60)));
* secretAsyncClient.setSecretWithResponse(newSecret)
* .subscribe(secretResponse ->
* System.out.printf("Secret is created with name %s and value %s %n",
* secretResponse.getValue().getName(), secretResponse.getValue().getValue()));
*
*
*
* @param secret The Secret object containing information about the secret and its properties. The properties
* {@link KeyVaultSecret#getName() secret.name} and {@link KeyVaultSecret#getValue() secret.value} cannot be null.
* @return A {@link Mono} containing a {@link Response} whose {@link Response#getValue() value} contains the
* {@link KeyVaultSecret created secret}.
* @throws NullPointerException if {@code secret} is {@code null}.
* @throws ResourceModifiedException if {@code secret} is malformed.
* @throws HttpResponseException if {@link KeyVaultSecret#getName() name} or {@link KeyVaultSecret#getValue() value}
* is an empty string.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono> setSecretWithResponse(KeyVaultSecret secret) {
try {
SecretProperties secretProperties = secret.getProperties();
if (secretProperties == null) {
return implClient.setSecretWithResponseAsync(vaultUrl, secret.getName(), secret.getValue(),
null, null, null)
.onErrorMap(KeyVaultErrorException.class, SecretAsyncClient::mapSetSecretException)
.map(response -> new SimpleResponse<>(response, createKeyVaultSecret(response.getValue())));
} else {
return implClient.setSecretWithResponseAsync(vaultUrl, secret.getName(), secret.getValue(),
secretProperties.getTags(), secretProperties.getContentType(),
createSecretAttributes(secretProperties))
.onErrorMap(KeyVaultErrorException.class, SecretAsyncClient::mapSetSecretException)
.map(response -> new SimpleResponse<>(response, createKeyVaultSecret(response.getValue())));
}
} catch (RuntimeException ex) {
return monoError(LOGGER, ex);
}
}
// For backwards compatibility with the exception type mapping of the handwritten KeyVault Secrets REST proxy.
// Only specific error codes are mapped to certain HttpResponseException subclasses, the default before was
// HttpResponseException and the new default is KeyVaultErrorException which is a subclass of HttpResponseException
// and is a non-breaking change. Specific error codes used different subclasses of HttpResponseException and that
// is a breaking change, so this mapping preserves the old behavior.
static HttpResponseException mapSetSecretException(KeyVaultErrorException ex) {
return (ex.getResponse().getStatusCode() == 400)
? new ResourceModifiedException(ex.getMessage(), ex.getResponse(), ex.getValue())
: ex;
}
/**
* Gets the latest version of the specified secret from the key vault. This operation requires the
* {@code secrets/get} permission.
*
* Code sample
* Gets latest version of the secret in the key vault. Subscribes to the call asynchronously and prints out the
* returned secret details when a response is received.
*
*
* secretAsyncClient.getSecret("secretName")
* .subscribe(secretWithVersion ->
* System.out.printf("Secret is returned with name %s and value %s %n",
* secretWithVersion.getName(), secretWithVersion.getValue()));
*
*
*
* @param name The name of the secret.
* @return A {@link Mono} containing the requested {@link KeyVaultSecret secret}.
* @throws IllegalArgumentException If {@code name} is either {@code null} or empty.
* @throws ResourceNotFoundException When a secret with the given {@code name} doesn't exist in the vault.
* @throws HttpResponseException If the server reports an error when executing the request.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono getSecret(String name) {
return getSecretWithResponse(name, null).flatMap(FluxUtil::toMono);
}
/**
* Gets the specified secret with specified version from the key vault. This operation requires the
* {@code secrets/get} permission.
*
* Code sample
* Gets a specific version of the secret in the key vault. Subscribes to the call
* asynchronously and prints out the returned secret details when a response is received.
*
*
*
* String secretVersion = "6A385B124DEF4096AF1361A85B16C204";
* secretAsyncClient.getSecret("secretName", secretVersion)
* // Passing a Context is optional and useful if you want a set of data to flow through the request.
* // Otherwise, the line below can be removed.
* .contextWrite(Context.of(key1, value1, key2, value2))
* .subscribe(secretWithVersion ->
* System.out.printf("Secret is returned with name %s and value %s %n",
* secretWithVersion.getName(), secretWithVersion.getValue()));
*
*
*
* @param name The name of the secret, cannot be null.
* @param version The version of the secret to retrieve. If this is an empty string or null, this
* call is equivalent to calling {@link #getSecret(String)}, with the latest version being retrieved.
* @return A {@link Mono} containing a {@link Response} whose {@link Response#getValue() value} contains the
* requested {@link KeyVaultSecret secret}.
* @throws ResourceNotFoundException When a secret with the given {@code name} and {@code version} doesn't exist in
* the vault.
* @throws IllegalArgumentException If {@code name} is either {@code null} or empty.
* @throws HttpResponseException If the server reports an error when executing the request.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono getSecret(String name, String version) {
return getSecretWithResponse(name, version).flatMap(FluxUtil::toMono);
}
/**
* Gets the specified secret with specified version from the key vault. This operation requires the
* {@code secrets/get} permission.
*
* Code sample
* Gets a specific version of the secret in the key vault. Subscribes to the call asynchronously and prints out
* the returned secret details when a response is received.
*
*
* String secretVersion = "6A385B124DEF4096AF1361A85B16C204";
* secretAsyncClient.getSecretWithResponse("secretName", secretVersion)
* // Passing a Context is optional and useful if you want a set of data to flow through the request.
* // Otherwise, the line below can be removed.
* .contextWrite(Context.of(key1, value1, key2, value2))
* .subscribe(secretWithVersion ->
* System.out.printf("Secret is returned with name %s and value %s %n",
* secretWithVersion.getValue().getName(), secretWithVersion.getValue().getValue()));
*
*
*
* @param name The name of the secret, cannot be null.
* @param version The version of the secret to retrieve. If this is an empty string or null, this call is equivalent
* to calling {@link #getSecret(String)}, with the latest version being retrieved.
* @return A {@link Mono} containing a {@link Response} whose {@link Response#getValue() value} contains the
* requested {@link KeyVaultSecret secret}.
* @throws ResourceNotFoundException When a secret with the given {@code name} and {@code version} doesn't exist in
* the vault.
* @throws IllegalArgumentException If {@code name} is either {@code null} or empty.
* @throws HttpResponseException If the server reports an error when executing the request.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono> getSecretWithResponse(String name, String version) {
if (CoreUtils.isNullOrEmpty(name)) {
return monoError(LOGGER, new IllegalArgumentException("'name' cannot be null or empty."));
}
try {
return implClient.getSecretWithResponseAsync(vaultUrl, name, version)
.onErrorMap(KeyVaultErrorException.class, SecretAsyncClient::mapGetSecretException)
.map(response -> new SimpleResponse<>(response, createKeyVaultSecret(response.getValue())));
} catch (RuntimeException ex) {
return monoError(LOGGER, ex);
}
}
// See other map*Exception methods for explanation of why this is done.
static HttpResponseException mapGetSecretException(HttpResponseException ex) {
if (ex.getResponse().getStatusCode() == 404) {
return new ResourceNotFoundException(ex.getMessage(), ex.getResponse(), ex.getValue());
} else if (ex.getResponse().getStatusCode() == 403) {
return new ResourceModifiedException(ex.getMessage(), ex.getResponse(), ex.getValue());
} else {
return ex;
}
}
/**
* Updates the attributes associated with the secret. The value of the secret in the key vault cannot be changed.
* Only attributes populated in {@code secretProperties} are changed. Attributes not specified in the request are
* not changed. This operation requires the {@code secrets/set} permission.
*
* The {@code secret} is required and its fields {@link SecretProperties#getName() name} and
* {@link SecretProperties#getVersion() version} cannot be null.
*
* Code sample
* Gets latest version of the secret, changes its {@link SecretProperties#setNotBefore(OffsetDateTime) notBefore}
* time, and then updates it in the Azure Key Vault. Subscribes to the call asynchronously and prints out the
* returned secret details when a response is received.
*
*
*
* secretAsyncClient.getSecret("secretName")
* .subscribe(secretResponseValue -> {
* SecretProperties secretProperties = secretResponseValue.getProperties();
* //Update the not before time of the secret.
* secretProperties.setNotBefore(OffsetDateTime.now().plusDays(50));
* secretAsyncClient.updateSecretProperties(secretProperties)
* .subscribe(secretResponse ->
* System.out.printf("Secret's updated not before time %s %n",
* secretResponse.getNotBefore().toString()));
* });
*
*
*
* @param secretProperties The {@link SecretProperties secret properties} object with updated properties.
* @return A {@link Mono} containing the {@link SecretProperties updated secret}.
* @throws NullPointerException if {@code secret} is {@code null}.
* @throws ResourceNotFoundException when a secret with {@link SecretProperties#getName() name} and
* {@link SecretProperties#getVersion() version} doesn't exist in the key vault.
* @throws HttpResponseException if {@link SecretProperties#getName() name} or
* {@link SecretProperties#getVersion() version} is an empty string.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono updateSecretProperties(SecretProperties secretProperties) {
return updateSecretPropertiesWithResponse(secretProperties).flatMap(FluxUtil::toMono);
}
/**
* Updates the attributes associated with the secret. The value of the secret in the key vault cannot be changed.
* Only attributes populated in {@code secretProperties} are changed. Attributes not specified in the request are
* not changed. This operation requires the {@code secrets/set} permission.
*
* Code sample
* Gets latest version of the secret, changes its {@link SecretProperties#setNotBefore(OffsetDateTime) notBefore}
* time, and then updates it in the Azure Key Vault. Subscribes to the call asynchronously and prints out the
* returned secret details when a response is received.
*
*
*
* secretAsyncClient.getSecret("secretName")
* .subscribe(secretResponseValue -> {
* SecretProperties secretProperties = secretResponseValue.getProperties();
* //Update the not before time of the secret.
* secretProperties.setNotBefore(OffsetDateTime.now().plusDays(50));
* secretAsyncClient.updateSecretPropertiesWithResponse(secretProperties)
* .subscribe(secretResponse ->
* System.out.printf("Secret's updated not before time %s %n",
* secretResponse.getValue().getNotBefore().toString()));
* });
*
*
*
* The {@code secret} is required and its fields {@link SecretProperties#getName() name} and
* {@link SecretProperties#getVersion() version} cannot be null.
*
* @param secretProperties The {@link SecretProperties secret properties} object with updated properties.
* @return A {@link Mono} containing a {@link Response} whose {@link Response#getValue() value} contains the
* {@link SecretProperties updated secret}.
* @throws NullPointerException if {@code secret} is {@code null}.
* @throws ResourceNotFoundException when a secret with {@link SecretProperties#getName() name} and
* {@link SecretProperties#getVersion() version} doesn't exist in the key vault.
* @throws HttpResponseException if {@link SecretProperties#getName() name} or
* {@link SecretProperties#getVersion() version} is empty string.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono> updateSecretPropertiesWithResponse(SecretProperties secretProperties) {
try {
return implClient.updateSecretWithResponseAsync(vaultUrl, secretProperties.getName(),
secretProperties.getVersion(), secretProperties.getContentType(),
createSecretAttributes(secretProperties), secretProperties.getTags())
.map(response -> new SimpleResponse<>(response, createSecretProperties(response.getValue())));
} catch (RuntimeException ex) {
return monoError(LOGGER, ex);
}
}
/**
* Deletes a secret from the key vault. If soft-delete is enabled on the key vault then the secret is placed in the
* deleted state and for permanent deletion, needs to be purged. Otherwise, the secret is permanently deleted.
* All versions of a secret are deleted. This cannot be applied to individual versions of a secret.
* This operation requires the {@code secrets/delete} permission.
*
* Code sample
* Deletes the secret in the Azure Key Vault. Subscribes to the call asynchronously and prints out the deleted
* secret details when a response is received.
*
*
* secretAsyncClient.beginDeleteSecret("secretName")
* .subscribe(pollResponse -> {
* System.out.println("Delete Status: " + pollResponse.getStatus().toString());
* System.out.println("Deleted Secret Name: " + pollResponse.getValue().getName());
* System.out.println("Deleted Secret Value: " + pollResponse.getValue().getValue());
* });
*
*
*
* @param name The name of the secret to be deleted.
* @return A {@link PollerFlux} to poll on and retrieve {@link DeletedSecret deleted secret}.
* @throws ResourceNotFoundException when a secret with {@code name} doesn't exist in the key vault.
* @throws HttpResponseException when a secret with {@code name} is empty string.
*/
@ServiceMethod(returns = ReturnType.LONG_RUNNING_OPERATION)
public PollerFlux beginDeleteSecret(String name) {
return new PollerFlux<>(Duration.ofSeconds(1), deleteActivationOperation(name), deletePollOperation(name),
(context, firstResponse) -> Mono.empty(), context -> Mono.empty());
}
private Function, Mono> deleteActivationOperation(String name) {
return pollingContext -> implClient.deleteSecretAsync(vaultUrl, name)
.onErrorMap(KeyVaultErrorException.class, SecretAsyncClient::mapDeleteSecretException)
.map(SecretsModelsUtils::createDeletedSecret);
}
// See other map*Exception methods for explanation of why this is done.
static HttpResponseException mapDeleteSecretException(HttpResponseException ex) {
return (ex.getResponse().getStatusCode() == 404)
? new ResourceNotFoundException(ex.getMessage(), ex.getResponse(), ex.getValue())
: ex;
}
private Function, Mono>> deletePollOperation(
String name) {
return pollingContext -> implClient.getDeletedSecretAsync(vaultUrl, name)
.map(bundle -> new PollResponse<>(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED,
createDeletedSecret(bundle)))
.onErrorResume(HttpResponseException.class, exception -> {
if (exception.getResponse().getStatusCode() == 404) {
return Mono.just(new PollResponse<>(LongRunningOperationStatus.IN_PROGRESS,
pollingContext.getLatestResponse().getValue()));
} else {
// This means either vault has soft-delete disabled or permission is not granted for the get deleted
// key operation. In both cases deletion operation was successful when activation operation
// succeeded before reaching here.
return Mono.just(new PollResponse<>(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED,
pollingContext.getLatestResponse().getValue()));
}
})
// This means either vault has soft-delete disabled or permission is not granted for the get deleted key
// operation. In both cases deletion operation was successful when activation operation succeeded before
// reaching here.
.onErrorReturn(new PollResponse<>(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED,
pollingContext.getLatestResponse().getValue()));
}
/**
* Gets a secret that has been deleted for a soft-delete enabled key vault. This operation requires the
* {@code secrets/list} permission.
*
* Code sample
* Gets the deleted secret from the key vault enabled for soft-delete. Subscribes to the call
* asynchronously and prints out the deleted secret details when a response is received.
*
*
*
* secretAsyncClient.getDeletedSecret("secretName")
* .subscribe(deletedSecretResponse ->
* System.out.printf("Deleted Secret's Recovery Id %s %n", deletedSecretResponse.getRecoveryId()));
*
*
*
* @param name The name of the deleted secret.
* @return A {@link Mono} containing the {@link DeletedSecret deleted secret}.
* @throws ResourceNotFoundException when a secret with {@code name} doesn't exist in the key vault.
* @throws HttpResponseException when a secret with {@code name} is empty string.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono getDeletedSecret(String name) {
return getDeletedSecretWithResponse(name).flatMap(FluxUtil::toMono);
}
/**
* Gets a secret that has been deleted for a soft-delete enabled key vault. This operation requires the
* {@code secrets/list} permission.
*
* Code sample
* Gets the deleted secret from the key vault enabled for soft-delete. Subscribes to the call
* asynchronously and prints out the deleted secret details when a response is received.
*
*
*
* secretAsyncClient.getDeletedSecretWithResponse("secretName")
* .subscribe(deletedSecretResponse ->
* System.out.printf("Deleted Secret's Recovery Id %s %n",
* deletedSecretResponse.getValue().getRecoveryId()));
*
*
*
* @param name The name of the deleted secret.
* @return A {@link Mono} containing a {@link Response} whose {@link Response#getValue() value} contains the
* {@link DeletedSecret deleted secret}.
* @throws ResourceNotFoundException when a secret with {@code name} doesn't exist in the key vault.
* @throws HttpResponseException when a secret with {@code name} is empty string.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono> getDeletedSecretWithResponse(String name) {
try {
return implClient.getDeletedSecretWithResponseAsync(vaultUrl, name)
.onErrorMap(KeyVaultErrorException.class, SecretAsyncClient::mapGetDeletedSecretException)
.map(response -> new SimpleResponse<>(response, createDeletedSecret(response.getValue())));
} catch (RuntimeException ex) {
return monoError(LOGGER, ex);
}
}
// See other map*Exception methods for explanation of why this is done.
static HttpResponseException mapGetDeletedSecretException(HttpResponseException ex) {
return (ex.getResponse().getStatusCode() == 404)
? new ResourceNotFoundException(ex.getMessage(), ex.getResponse(), ex.getValue())
: ex;
}
/**
* Permanently removes a deleted secret, without the possibility of recovery. This operation can only be performed
* on a soft-delete enabled. This operation requires the {@code secrets/purge} permission.
*
* Code sample
* Purges the deleted secret from the key vault enabled for soft-delete. Subscribes to the call
* asynchronously and prints out the status code from the server response when a response is received.
*
*
*
* secretAsyncClient.purgeDeletedSecret("deletedSecretName")
* .doOnSuccess(purgeResponse ->
* System.out.println("Successfully Purged deleted Secret"))
* .subscribe();
*
*
*
* @param name The name of the secret.
* @return An empty {@link Mono}.
* @throws ResourceNotFoundException when a secret with {@code name} doesn't exist in the key vault.
* @throws HttpResponseException when a secret with {@code name} is empty string.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono purgeDeletedSecret(String name) {
return purgeDeletedSecretWithResponse(name).flatMap(FluxUtil::toMono);
}
/**
* Permanently removes a deleted secret, without the possibility of recovery. This operation can only be enabled on
* a soft-delete enabled vault. This operation requires the {@code secrets/purge} permission.
*
* Code sample
* Purges the deleted secret from the key vault enabled for soft-delete. Subscribes to the call
* asynchronously and prints out the status code from the server response when a response is received.
*
*
*
* secretAsyncClient.purgeDeletedSecretWithResponse("deletedSecretName")
* .subscribe(purgeResponse ->
* System.out.printf("Purge Status response %d %n", purgeResponse.getStatusCode()));
*
*
*
* @param name The name of the secret.
* @return A {@link Mono} containing a Response containing status code and HTTP headers.
* @throws ResourceNotFoundException when a secret with {@code name} doesn't exist in the key vault.
* @throws HttpResponseException when a secret with {@code name} is empty string.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono> purgeDeletedSecretWithResponse(String name) {
try {
return implClient.purgeDeletedSecretWithResponseAsync(vaultUrl, name)
.onErrorMap(KeyVaultErrorException.class, SecretAsyncClient::mapPurgeDeletedSecretException);
} catch (RuntimeException ex) {
return monoError(LOGGER, ex);
}
}
// See other map*Exception methods for explanation of why this is done.
static HttpResponseException mapPurgeDeletedSecretException(HttpResponseException ex) {
return (ex.getResponse().getStatusCode() == 404)
? new ResourceNotFoundException(ex.getMessage(), ex.getResponse(), ex.getValue())
: ex;
}
/**
* Recovers the deleted secret in the key vault to its latest version. Can only be performed on a soft-delete
* enabled vault. This operation requires the {@code secrets/recover} permission.
*
* Code sample
* Recovers the deleted secret from the key vault enabled for soft-delete. Subscribes to the call
* asynchronously and prints out the recovered secret details when a response is received.
*
*
*
* secretAsyncClient.beginRecoverDeletedSecret("deletedSecretName")
* .subscribe(pollResponse -> {
* System.out.println("Recovery Status: " + pollResponse.getStatus().toString());
* System.out.println("Recovered Secret Name: " + pollResponse.getValue().getName());
* System.out.println("Recovered Secret Value: " + pollResponse.getValue().getValue());
* });
*
*
*
* @param name The name of the deleted secret to be recovered.
* @return A {@link PollerFlux} to poll on and retrieve the {@link KeyVaultSecret recovered secret}.
* @throws ResourceNotFoundException when a secret with {@code name} doesn't exist in the key vault.
* @throws HttpResponseException when a secret with {@code name} is empty string.
*/
@ServiceMethod(returns = ReturnType.LONG_RUNNING_OPERATION)
public PollerFlux beginRecoverDeletedSecret(String name) {
return new PollerFlux<>(Duration.ofSeconds(1), recoverActivationOperation(name),
recoverPollOperation(name), (context, firstResponse) -> Mono.empty(), context -> Mono.empty());
}
private Function, Mono> recoverActivationOperation(String name) {
return pollingContext -> implClient.recoverDeletedSecretAsync(vaultUrl, name)
.onErrorMap(KeyVaultErrorException.class, SecretAsyncClient::mapRecoverDeletedSecretException)
.map(SecretsModelsUtils::createKeyVaultSecret);
}
// See other map*Exception methods for explanation of why this is done.
static HttpResponseException mapRecoverDeletedSecretException(HttpResponseException ex) {
return (ex.getResponse().getStatusCode() == 404)
? new ResourceNotFoundException(ex.getMessage(), ex.getResponse(), ex.getValue())
: ex;
}
private Function, Mono>> recoverPollOperation(
String name) {
return pollingContext -> implClient.getSecretWithResponseAsync(vaultUrl, name, null)
.map(response -> new PollResponse<>(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED,
createKeyVaultSecret(response.getValue())))
.onErrorResume(HttpResponseException.class, exception -> {
if (exception.getResponse().getStatusCode() == 404) {
return Mono.just(new PollResponse<>(LongRunningOperationStatus.IN_PROGRESS,
pollingContext.getLatestResponse().getValue()));
} else {
// This means permission is not granted for the get deleted key operation. In both cases the
// deletion operation was successful when activation operation succeeded before reaching here.
return Mono.just(new PollResponse<>(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED,
pollingContext.getLatestResponse().getValue()));
}
})
// This means permission is not granted for the get deleted key operation. In both cases the deletion
// operation was successful when activation operation succeeded before reaching here.
.onErrorReturn(new PollResponse<>(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED,
pollingContext.getLatestResponse().getValue()));
}
/**
* Requests a backup of the secret be downloaded to the client. All versions of the secret will be downloaded. This
* operation requires the {@code secrets/backup} permission.
*
* Code sample
* Backs up the secret from the key vault. Subscribes to the call asynchronously and prints out
* the length of the secret's backup byte array returned in the response.
*
*
*
* secretAsyncClient.backupSecret("secretName")
* .subscribe(secretBackupResponse ->
* System.out.printf("Secret's Backup Byte array's length %s%n", secretBackupResponse.length));
*
*
*
* @param name The name of the secret.
* @return A {@link Mono} containing the backed up secret blob.
* @throws ResourceNotFoundException when a secret with {@code name} doesn't exist in the key vault.
* @throws HttpResponseException when a secret with {@code name} is empty string.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono backupSecret(String name) {
return backupSecretWithResponse(name).flatMap(FluxUtil::toMono);
}
/**
* Requests a backup of the secret be downloaded to the client. All versions of the secret will be downloaded. This
* operation requires the {@code secrets/backup} permission.
*
* Code sample
* Backs up the secret from the key vault. Subscribes to the call asynchronously and prints out
* the length of the secret's backup byte array returned in the response.
*
*
*
* secretAsyncClient.backupSecretWithResponse("secretName")
* .subscribe(secretBackupResponse ->
* System.out.printf("Secret's Backup Byte array's length %s%n", secretBackupResponse.getValue().length));
*
*
*
* @param name The name of the secret.
* @return A {@link Mono} containing a {@link Response} whose {@link Response#getValue() value} contains the
* backed up secret blob.
* @throws ResourceNotFoundException when a secret with {@code name} doesn't exist in the key vault.
* @throws HttpResponseException when a secret with {@code name} is empty string.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono> backupSecretWithResponse(String name) {
try {
return implClient.backupSecretWithResponseAsync(vaultUrl, name)
.onErrorMap(KeyVaultErrorException.class, SecretAsyncClient::mapBackupSecretException)
.map(response -> new SimpleResponse<>(response, response.getValue().getValue()));
} catch (RuntimeException ex) {
return monoError(LOGGER, ex);
}
}
// See other map*Exception methods for explanation of why this is done.
static HttpResponseException mapBackupSecretException(HttpResponseException ex) {
return (ex.getResponse().getStatusCode() == 404)
? new ResourceNotFoundException(ex.getMessage(), ex.getResponse(), ex.getValue())
: ex;
}
/**
* Restores a backed up secret, and all its versions, to a vault. This operation requires the
* {@code secrets/restore} permission.
*
* Code sample
* Restores the secret in the key vault from its backup. Subscribes to the call asynchronously
* and prints out the restored secret details when a response is received.
*
*
*
* // Pass the secret backup byte array to the restore operation.
* byte[] secretBackupByteArray = {};
* secretAsyncClient.restoreSecretBackup(secretBackupByteArray)
* .subscribe(secretResponse -> System.out.printf("Restored Secret with name %s and value %s %n",
* secretResponse.getName(), secretResponse.getValue()));
*
*
*
* @param backup The backup blob associated with the secret.
* @return A {@link Mono} containing the {@link KeyVaultSecret restored secret}.
* @throws ResourceModifiedException when {@code backup} blob is malformed.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono restoreSecretBackup(byte[] backup) {
return restoreSecretBackupWithResponse(backup).flatMap(FluxUtil::toMono);
}
/**
* Restores a backed up secret, and all its versions, to a vault. This operation requires the
* {@code secrets/restore} permission.
*
* Code sample
* Restores the secret in the key vault from its backup. Subscribes to the call asynchronously
* and prints out the restored secret details when a response is received.
*
*
*
* // Pass the secret backup byte array to the restore operation.
* byte[] secretBackupByteArray = {};
* secretAsyncClient.restoreSecretBackupWithResponse(secretBackupByteArray)
* .subscribe(secretResponse -> System.out.printf("Restored Secret with name %s and value %s %n",
* secretResponse.getValue().getName(), secretResponse.getValue().getValue()));
*
*
*
* @param backup The backup blob associated with the secret.
* @return A {@link Mono} containing a {@link Response} whose {@link Response#getValue() value} contains the
* {@link KeyVaultSecret restored secret}.
* @throws ResourceModifiedException when {@code backup} blob is malformed.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono> restoreSecretBackupWithResponse(byte[] backup) {
try {
return implClient.restoreSecretWithResponseAsync(vaultUrl, backup)
.onErrorMap(KeyVaultErrorException.class, SecretAsyncClient::mapRestoreSecretException)
.map(response -> new SimpleResponse<>(response, createKeyVaultSecret(response.getValue())));
} catch (RuntimeException ex) {
return monoError(LOGGER, ex);
}
}
// See other map*Exception methods for explanation of why this is done.
static HttpResponseException mapRestoreSecretException(HttpResponseException ex) {
return (ex.getResponse().getStatusCode() == 400)
? new ResourceModifiedException(ex.getMessage(), ex.getResponse(), ex.getValue())
: ex;
}
/**
* Lists secrets in the key vault. Each {@link SecretProperties secret} returned only has its identifier and
* attributes populated. The secret values and their versions are not listed in the response.
* This operation requires the {@code secrets/list} permission.
*
* Code sample
* The sample below fetches the all the secret properties in the vault. For each secret retrieved, makes a call
* to {@link #getSecret(String, String) getSecret(String, String)} to get its value, and then prints it out.
*
*
*
* secretAsyncClient.listPropertiesOfSecrets()
* .flatMap(secretProperties -> {
* String name = secretProperties.getName();
* String version = secretProperties.getVersion();
*
* System.out.printf("Getting secret name: '%s', version: %s%n", name, version);
* return secretAsyncClient.getSecret(name, version);
* })
* .subscribe(secretResponse -> System.out.printf("Received secret with name %s and type %s",
* secretResponse.getName(), secretResponse.getValue()));
*
*
*
* @return A {@link PagedFlux} containing {@link SecretProperties properties} of all the secrets in the vault.
*/
@ServiceMethod(returns = ReturnType.COLLECTION)
public PagedFlux listPropertiesOfSecrets() {
return new PagedFlux<>(maxResults -> implClient.getSecretsSinglePageAsync(vaultUrl, maxResults)
.map(SecretAsyncClient::mapSecretItemPage),
(continuationToken, maxResults) -> implClient.getSecretsNextSinglePageAsync(continuationToken, vaultUrl)
.map(SecretAsyncClient::mapSecretItemPage));
}
/**
* Lists {@link DeletedSecret deleted secrets} of the key vault if it has enabled soft-delete. This operation
* requires the {@code secrets/list} permission.
*
* Code sample
* Lists the deleted secrets in the key vault. Subscribes to the call asynchronously and prints out the
* recovery id of each deleted secret when a response is received.
*
*
*
* secretAsyncClient.listDeletedSecrets()
* .subscribe(deletedSecretResponse -> System.out.printf("Deleted Secret's Recovery Id %s %n",
* deletedSecretResponse.getRecoveryId()));
*
*
*
* @return A {@link Flux} containing all of the {@link DeletedSecret deleted secrets} in the vault.
*/
@ServiceMethod(returns = ReturnType.COLLECTION)
public PagedFlux listDeletedSecrets() {
return new PagedFlux<>(maxResults -> implClient.getDeletedSecretsSinglePageAsync(vaultUrl, maxResults)
.map(SecretAsyncClient::mapDeletedSecretItemPage),
(continuationToken, maxResults) -> implClient.getDeletedSecretsNextSinglePageAsync(continuationToken,
vaultUrl).map(SecretAsyncClient::mapDeletedSecretItemPage));
}
static PagedResponse mapDeletedSecretItemPage(PagedResponse page) {
List converted = new ArrayList<>(page.getValue().size());
for (DeletedSecretItem deletedSecretItem : page.getValue()) {
converted.add(createDeletedSecret(deletedSecretItem));
}
return new PagedResponseBase<>(page.getRequest(), page.getStatusCode(), page.getHeaders(), converted,
page.getContinuationToken(), null);
}
/**
* Lists all versions of the specified secret. Each {@link SecretProperties secret} returned only has its identifier
* and attributes populated. The secret values and secret versions are not listed in the response.
* This operation requires the {@code secrets/list} permission.
*
* Code sample
* The sample below fetches the all the versions of the given secret. For each version retrieved, makes a call
* to {@link #getSecret(String, String) getSecret(String, String)} to get the version's value, and then prints it
* out.
*
*
*
* secretAsyncClient.listPropertiesOfSecretVersions("secretName")
* .flatMap(secretProperties -> {
* System.out.println("Get secret value for version: " + secretProperties.getVersion());
* return secretAsyncClient.getSecret(secretProperties.getName(), secretProperties.getVersion());
* })
* .subscribe(secret -> System.out.printf("Received secret with name %s and type %s%n",
* secret.getName(), secret.getValue()));
*
*
*
* @param name The name of the secret.
* @return A {@link PagedFlux} containing {@link SecretProperties properties} of all the versions of the specified
* secret in the vault. Flux is empty if secret with {@code name} does not exist in key vault
* @throws HttpResponseException when a secret with {@code name} is empty string.
*/
@ServiceMethod(returns = ReturnType.COLLECTION)
public PagedFlux listPropertiesOfSecretVersions(String name) {
return new PagedFlux<>(maxResults -> implClient.getSecretVersionsSinglePageAsync(vaultUrl, name, maxResults)
.map(SecretAsyncClient::mapSecretItemPage),
(continuationToken, maxResults) -> implClient.getSecretVersionsNextSinglePageAsync(continuationToken,
vaultUrl).map(SecretAsyncClient::mapSecretItemPage));
}
static PagedResponse mapSecretItemPage(PagedResponse page) {
List converted = new ArrayList<>(page.getValue().size());
for (SecretItem secretItem : page.getValue()) {
converted.add(createSecretProperties(secretItem));
}
return new PagedResponseBase<>(page.getRequest(), page.getStatusCode(), page.getHeaders(), converted,
page.getContinuationToken(), null);
}
}