* updatet keyvault sdk
This commit is contained in:
Zhou Liu 2020-01-13 09:50:46 +08:00 коммит произвёл Shichao Qiu
Родитель 646a458325
Коммит 4543480ed2
27 изменённых файлов: 259 добавлений и 662 удалений

Просмотреть файл

@ -70,6 +70,7 @@ Open `application.properties` file and add below properties to specify your Azur
azure.keyvault.uri=put-your-azure-keyvault-uri-here
azure.keyvault.client-id=put-your-azure-client-id-here
azure.keyvault.client-key=put-your-azure-client-key-here
azure.keyvault.tenant-id=put-your-azure-tenant-id-here
# Uncomment following property if you want to specify the secrets to load from Key Vault
# azure.keyvault.secret.keys=yourSecretPropertyName1,yourSecretPropertyName2

Просмотреть файл

@ -1,3 +1,4 @@
azure.keyvault.client-id=put-your-azure-client-id-here
azure.keyvault.client-key=put-your-azure-client-key-here
azure.keyvault.uri=put-your-azure-keyvault-uri-here
azure.keyvault.tenant-id=

Просмотреть файл

@ -15,7 +15,7 @@ If you are using Maven, add the following dependency.
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault-secrets-spring-boot-starter</artifactId>
<version>0.2.3</version>
<version>2.2.1</version>
</dependency>
```
@ -26,6 +26,7 @@ azure.keyvault.enabled=true
azure.keyvault.uri=put-your-azure-keyvault-uri-here
azure.keyvault.client-id=put-your-azure-client-id-here
azure.keyvault.client-key=put-your-azure-client-key-here
azure.keyvault.tenant-id=put-your-azure-tenant-id-here
azure.keyvault.token-acquire-timeout-seconds=60
azure.keyvault.refresh-interval=1800000
azure.keyvault.secret.keys=key1,key2,key3

Просмотреть файл

@ -34,16 +34,6 @@
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-spring-boot</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault</artifactId>
<exclusions>
<exclusion>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-client-runtime</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-client-authentication</artifactId>

Просмотреть файл

@ -20,6 +20,7 @@
<project.rootdir>${project.basedir}/../..</project.rootdir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<fastjson.version>1.2.61</fastjson.version>
</properties>
<dependencies>
@ -38,6 +39,12 @@
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault-secrets-spring-boot-starter</artifactId>
</dependency>
<!-- util dependencies -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
</dependencies>
<dependencyManagement>

Просмотреть файл

@ -4,23 +4,41 @@
* license information.
*/
package com.microsoft.azure.test;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@Slf4j
@SpringBootApplication
@RestController
public class Application implements CommandLineRunner {
@Autowired
private ConfigurableEnvironment environment;
@Value("${azure.cosmosdb.key:local}")
private String cosmosDBkey;
private static ObjectMapper mapper = new ObjectMapper();
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@ -40,6 +58,36 @@ public class Application implements CommandLineRunner {
return cosmosDBkey;
}
@GetMapping("env/{key}")
public String env(@PathVariable String key) {
final String property = environment.getProperty(key);
return property;
}
@GetMapping("list")
public String list() {
final List list = new ArrayList();
final MutablePropertySources propertySources = this.environment.getPropertySources();
final Iterator<PropertySource<?>> iterator = propertySources.iterator();
while (iterator.hasNext()) {
final PropertySource<?> next = iterator.next();
list.add(next.getName());
}
return JSON.toJSONString(list);
}
@GetMapping("getSpecificProperty/{ps}/{key}")
public String getSpecificProperty(@PathVariable String ps, @PathVariable String key) {
final MutablePropertySources propertySources = this.environment.getPropertySources();
final PropertySource<?> propertySource = propertySources.get(ps);
if (propertySource != null) {
final Object property = propertySource.getProperty(key);
return property == null ? null : property.toString();
} else {
return null;
}
}
public void run(String... varl) throws Exception {
System.out.println("property your-property-name value is: " + cosmosDBkey);
}

Просмотреть файл

@ -43,6 +43,18 @@ public class AppRunner implements AutoCloseable {
}
}
public ConfigurableApplicationContext start(String dummy) {
if (app == null) {
final SpringApplicationBuilder builder = new SpringApplicationBuilder(appClass);
builder.properties("spring.jmx.enabled=false");
builder.properties(String.format("server.port=%d", availableTcpPort()));
builder.properties(props());
app = builder.build().run();
}
return app;
}
private int availableTcpPort() {
return SocketUtils.findAvailableTcpPort();
}

Просмотреть файл

@ -22,6 +22,10 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
@ -85,8 +89,16 @@ public class KeyVaultIT {
app.property("azure.keyvault.uri", vault.vaultUri());
app.property("azure.keyvault.client-id", access.clientId());
app.property("azure.keyvault.client-key", access.clientSecret());
app.property("azure.keyvault.tenant-id", access.tenant());
final ConfigurableApplicationContext dummy = app.start("dummy");
final ConfigurableEnvironment environment = dummy.getEnvironment();
final MutablePropertySources propertySources = environment.getPropertySources();
for (final PropertySource<?> propertySource : propertySources) {
System.out.println("name = " + propertySource.getName() + "\nsource = " + propertySource
.getSource().getClass() + "\n");
}
app.start();
assertEquals(KEY_VAULT_VALUE, app.getProperty("key"));
app.close();
log.info("--------------------->test over");
@ -100,6 +112,7 @@ public class KeyVaultIT {
app.property("azure.keyvault.uri", vault.vaultUri());
app.property("azure.keyvault.client-id", access.clientId());
app.property("azure.keyvault.client-key", access.clientSecret());
app.property("azure.keyvault.tenant-id", access.tenant());
app.property("azure.keyvault.secret.keys", "key");
app.start();
@ -133,6 +146,7 @@ public class KeyVaultIT {
appService.zipDeploy(zipFile);
log.info(String.format("Successfully deployed the artifact to https://%s",
appService.defaultHostName()));
break;
} catch (Exception e) {
log.debug(
String.format("Exception occurred when deploying the zip package: %s, " +
@ -141,7 +155,9 @@ public class KeyVaultIT {
}
// Restart App Service
log.info("restarting app service...");
appService.restart();
log.info("restarting app service finished...");
final String resourceUrl = "https://" + appService.name() + ".azurewebsites.net" + "/get";
// warm up
@ -179,7 +195,13 @@ public class KeyVaultIT {
// run java application
final List<String> commands = new ArrayList<>();
commands.add(String.format("cd /home/%s", VM_USER_NAME));
commands.add(String.format("nohup java -jar -Dazure.keyvault.uri=%s %s &", vault.vaultUri(),
commands.add(
String.
format("nohup java -jar -Xdebug " +
"-Xrunjdwp:server=y,transport=dt_socket,address=4000,suspend=n " +
"-Dazure.keyvault.uri=%s %s &" +
" >/log.txt 2>&1"
, vault.vaultUri(),
TEST_KEY_VAULT_JAR_FILE_NAME));
vmTool.runCommandOnVM(vm, commands);
@ -191,6 +213,7 @@ public class KeyVaultIT {
assertEquals(response.getStatusCode(), HttpStatus.OK);
assertEquals(response.getBody(), KEY_VAULT_VALUE);
log.info("key vault value is: {}", response.getBody());
log.info("--------------------->test virtual machine with MSI over");
}

Просмотреть файл

@ -36,6 +36,7 @@
<cobertura.version>2.1.1</cobertura.version>
<secure.channel.version>0.1.53</secure.channel.version>
<expect4j.version>1.6</expect4j.version>
<commons.net.version>3.3</commons.net.version>
</properties>
<dependencyManagement>
@ -92,9 +93,8 @@
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
<version>${commons.net.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
@ -168,8 +168,12 @@
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<keyvault.app.jar.path>${project.rootdir}/azure-spring-boot-tests/azure-spring-boot-test-application/target/app.jar</keyvault.app.jar.path>
<keyvault.app.zip.path>${project.rootdir}/azure-spring-boot-tests/azure-spring-boot-test-application/target/app.zip</keyvault.app.zip.path>
<keyvault.app.jar.path>
${project.rootdir}/azure-spring-boot-tests/azure-spring-boot-test-application/target/app.jar
</keyvault.app.jar.path>
<keyvault.app.zip.path>
${project.rootdir}/azure-spring-boot-tests/azure-spring-boot-test-application/target/app.zip
</keyvault.app.zip.path>
</systemPropertyVariables>
</configuration>
<executions>

Просмотреть файл

@ -151,16 +151,17 @@
<artifactId>azure-storage-blob</artifactId>
<optional>true</optional>
</dependency>
<!-- declare version in current pom temporarily, move to azure-dependency-bom later -->
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault</artifactId>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-client-runtime</artifactId>
</exclusion>
</exclusions>
<groupId>com.azure</groupId>
<artifactId>azure-security-keyvault-secrets</artifactId>
<version>4.1.0</version>
</dependency>
<!-- declare version in current pom temporarily, move to azure-dependency-bom later -->
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>

Просмотреть файл

@ -1,74 +0,0 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.keyvault.spring;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials;
import com.microsoft.azure.utils.AADAuthUtil;
import org.apache.commons.lang3.StringUtils;
import java.util.concurrent.atomic.AtomicLong;
public class AzureKeyVaultCredential extends KeyVaultCredentials {
private static final long DEFAULT_TOKEN_ACQUIRE_TIMEOUT_IN_SECONDS = 60L;
private String clientId;
private String clientKey;
private long timeoutInSeconds;
private AADAuthUtil aadAuthUtil;
private String token = "";
private AtomicLong lastAcquireTokenTime = new AtomicLong();
private AtomicLong expireIn = new AtomicLong();
private static final long EXPIRE_BUFFER_TIME = 10 * 1000; //buffer time 10s
public AzureKeyVaultCredential(String clientId, String clientKey, long timeoutInSeconds, AADAuthUtil aadAuthUtil) {
this.clientId = clientId;
this.clientKey = clientKey;
this.timeoutInSeconds = timeoutInSeconds;
this.aadAuthUtil = aadAuthUtil;
}
public AzureKeyVaultCredential(String clientId, String clientKey, long timeoutInSeconds) {
this(clientId, clientKey, timeoutInSeconds, new AADAuthUtil());
}
public AzureKeyVaultCredential(String clientId, String clientKey) {
this(clientId, clientKey, DEFAULT_TOKEN_ACQUIRE_TIMEOUT_IN_SECONDS);
}
@Override
public String doAuthenticate(String authorization, String resource, String scope) {
if (StringUtils.isEmpty(token) || needRefresh()) {
refreshToken(authorization, resource);
}
return token;
}
private synchronized void refreshToken(String authorization, String resource) {
if (!needRefresh()) { //double check
return;
}
try {
final AuthenticationResult result = aadAuthUtil.getToken(authorization,
resource,
clientId,
clientKey,
timeoutInSeconds);
token = result.getAccessToken();
expireIn.set(result.getExpiresAfter());
lastAcquireTokenTime.set(System.currentTimeMillis());
} catch (Exception ex) {
throw new IllegalStateException("Failed to do authentication.", ex);
}
}
private boolean needRefresh() {
return ((System.currentTimeMillis() - lastAcquireTokenTime.get() + EXPIRE_BUFFER_TIME) / 1000) >=
expireIn.get();
}
}

Просмотреть файл

@ -1,38 +0,0 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.keyvault.spring;
import com.microsoft.azure.AzureEnvironment;
import com.microsoft.azure.credentials.AzureTokenCredentials;
import com.microsoft.azure.credentials.MSICredentials;
import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials;
import java.io.IOException;
public class AzureKeyVaultMSICredential extends KeyVaultCredentials {
private final AzureTokenCredentials tokenCredentials;
public AzureKeyVaultMSICredential(AzureTokenCredentials tokenCredentials) {
this.tokenCredentials = tokenCredentials;
}
public AzureKeyVaultMSICredential(AzureEnvironment environment) {
this.tokenCredentials = new MSICredentials(environment);
}
public AzureKeyVaultMSICredential(AzureEnvironment environment, String clientId) {
this.tokenCredentials = new MSICredentials(environment).withClientId(clientId);
}
@Override
public String doAuthenticate(String authorization, String resource, String scope) {
try {
return tokenCredentials.getToken(resource);
} catch (IOException e) {
throw new IllegalStateException("Failed to do authentication.", e);
}
}
}

Просмотреть файл

@ -12,6 +12,7 @@ public class Constants {
public static final String AZURE_KEYVAULT_USER_AGENT = "spring-boot-starter/" + PropertyLoader.getProjectVersion();
public static final String AZURE_KEYVAULT_CLIENT_ID = "azure.keyvault.client-id";
public static final String AZURE_KEYVAULT_CLIENT_KEY = "azure.keyvault.client-key";
public static final String AZURE_KEYVAULT_TENANT_ID = "azure.keyvault.tenant-id";
public static final String AZURE_KEYVAULT_CERTIFICATE_PATH = "azure.keyvault.certificate.path";
public static final String AZURE_KEYVAULT_CERTIFICATE_PASSWORD = "azure.keyvault.certificate.password";
public static final String AZURE_KEYVAULT_ENABLED = "azure.keyvault.enabled";

Просмотреть файл

@ -1,74 +0,0 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.keyvault.spring;
import com.microsoft.aad.adal4j.AsymmetricKeyCredential;
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials;
import com.microsoft.azure.keyvault.spring.certificate.KeyCert;
import com.microsoft.azure.keyvault.spring.certificate.KeyCertReader;
import com.microsoft.azure.keyvault.spring.certificate.KeyCertReaderFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import java.net.MalformedURLException;
import java.security.PrivateKey;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@Slf4j
public class KeyVaultCertificateCredential extends KeyVaultCredentials {
private static final long DEFAULT_TOKEN_ACQUIRE_TIMEOUT_IN_SECONDS = 60L;
private final String clientId;
private final Resource certResource;
private final String certPassword;
private final long timeoutInSeconds;
public KeyVaultCertificateCredential(String clientId, Resource certResource, String certPassword,
long timeoutInSeconds) {
Assert.isTrue(certResource.exists(), String.format("Certificate file %s should exist.",
certResource.getFilename()));
this.clientId = clientId;
this.certResource = certResource;
this.certPassword = certPassword;
this.timeoutInSeconds = timeoutInSeconds <= 0 ? DEFAULT_TOKEN_ACQUIRE_TIMEOUT_IN_SECONDS : timeoutInSeconds;
}
public KeyVaultCertificateCredential(String clientId, Resource certResource, String certPassword) {
this(clientId, certResource, certPassword, DEFAULT_TOKEN_ACQUIRE_TIMEOUT_IN_SECONDS);
}
@Override
public String doAuthenticate(String authorization, String resource, String scope) {
final String certFileName = certResource.getFilename();
final KeyCertReader certReader = KeyCertReaderFactory.getReader(certFileName);
final KeyCert keyCert = certReader.read(certResource, certPassword);
try {
final AuthenticationContext context = new AuthenticationContext(authorization, false,
Executors.newSingleThreadExecutor());
final AsymmetricKeyCredential asymmetricKeyCredential = AsymmetricKeyCredential.create(clientId,
keyCert.getKey(), keyCert.getCertificate());
final AuthenticationResult authResult = context.acquireToken(resource, asymmetricKeyCredential, null)
.get(timeoutInSeconds, TimeUnit.SECONDS);
return authResult.getAccessToken();
} catch (MalformedURLException | InterruptedException | ExecutionException | TimeoutException e) {
final String errMsg = String.format("Failed to authenticate with Key Vault using certificate %s",
certFileName);
log.error(errMsg, e);
throw new IllegalStateException(errMsg, e);
}
}
}

Просмотреть файл

@ -6,6 +6,7 @@
package com.microsoft.azure.keyvault.spring;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.config.ConfigFileApplicationListener;
import org.springframework.boot.env.EnvironmentPostProcessor;
@ -13,13 +14,13 @@ import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.ClassUtils;
@Slf4j
public class KeyVaultEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
public static final int DEFAULT_ORDER = ConfigFileApplicationListener.DEFAULT_ORDER + 1;
private int order = DEFAULT_ORDER;
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
if (isKeyVaultEnabled(environment)) {
final KeyVaultEnvironmentPostProcessorHelper helper =
new KeyVaultEnvironmentPostProcessorHelper(environment);
@ -37,7 +38,7 @@ public class KeyVaultEnvironmentPostProcessor implements EnvironmentPostProcesso
}
private boolean isKeyVaultClientAvailable() {
return ClassUtils.isPresent("com.microsoft.azure.keyvault.KeyVaultClient",
return ClassUtils.isPresent("com.azure.security.keyvault.secrets.SecretClient",
KeyVaultEnvironmentPostProcessor.class.getClassLoader());
}

Просмотреть файл

@ -6,24 +6,21 @@
package com.microsoft.azure.keyvault.spring;
import com.microsoft.azure.AzureEnvironment;
import com.microsoft.azure.AzureResponseBuilder;
import com.microsoft.azure.credentials.AppServiceMSICredentials;
import com.microsoft.azure.keyvault.KeyVaultClient;
import com.microsoft.azure.serializer.AzureJacksonAdapter;
import com.microsoft.azure.spring.support.UserAgent;
import com.azure.core.credential.TokenCredential;
import com.azure.identity.ClientCertificateCredentialBuilder;
import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ClientSecretCredentialBuilder;
import com.azure.identity.ManagedIdentityCredentialBuilder;
import com.azure.security.keyvault.secrets.SecretClient;
import com.azure.security.keyvault.secrets.SecretClientBuilder;
import com.microsoft.azure.telemetry.TelemetrySender;
import com.microsoft.rest.RestClient;
import com.microsoft.rest.credentials.ServiceClientCredentials;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
@ -32,14 +29,13 @@ import java.util.Optional;
import static com.microsoft.azure.telemetry.TelemetryData.SERVICE_NAME;
import static com.microsoft.azure.telemetry.TelemetryData.getClassPackageSimpleName;
@Slf4j
class KeyVaultEnvironmentPostProcessorHelper {
private static final Logger LOG = LoggerFactory.getLogger(KeyVaultEnvironmentPostProcessorHelper.class);
private final ConfigurableEnvironment environment;
public KeyVaultEnvironmentPostProcessorHelper(final ConfigurableEnvironment environment) {
this.environment = environment;
// As @PostConstructor not available when post processor, call it explicitly.
sendTelemetry();
}
@ -50,21 +46,15 @@ class KeyVaultEnvironmentPostProcessorHelper {
this.environment.getProperty(Constants.AZURE_KEYVAULT_REFRESH_INTERVAL))
.map(Long::valueOf).orElse(Constants.DEFAULT_REFRESH_INTERVAL_MS);
final String secretKeys = this.environment.getProperty(Constants.AZURE_KEYVAULT_SECRET_KEYS);
final ServiceClientCredentials credentials = getCredentials();
final RestClient restClient = new RestClient.Builder().withBaseUrl(vaultUri)
.withCredentials(credentials)
.withSerializerAdapter(new AzureJacksonAdapter())
.withResponseBuilderFactory(new AzureResponseBuilder.Factory())
.withUserAgent(UserAgent.getUserAgent(Constants.AZURE_KEYVAULT_USER_AGENT,
allowTelemetry(this.environment)))
.build();
final KeyVaultClient kvClient = new KeyVaultClient(restClient);
final TokenCredential tokenCredential = getCredentials();
final SecretClient secretClient = new SecretClientBuilder()
.vaultUrl(vaultUri)
.credential(tokenCredential)
.buildClient();
try {
final MutablePropertySources sources = this.environment.getPropertySources();
final KeyVaultOperation kvOperation = new KeyVaultOperation(kvClient,
final KeyVaultOperation kvOperation = new KeyVaultOperation(secretClient,
vaultUri,
refreshInterval,
secretKeys);
@ -81,62 +71,58 @@ class KeyVaultEnvironmentPostProcessorHelper {
}
}
ServiceClientCredentials getCredentials() {
if (this.environment.containsProperty("MSI_ENDPOINT")
&& this.environment.containsProperty("MSI_SECRET")) {
LOG.debug("Will use MSI credentials for app services");
final String msiEndpoint = getProperty(this.environment, "MSI_ENDPOINT");
final String msiSecret = getProperty(this.environment, "MSI_SECRET");
final AppServiceMSICredentials msiCredentials = new AppServiceMSICredentials(AzureEnvironment.AZURE,
msiEndpoint, msiSecret);
if (this.environment.containsProperty(Constants.AZURE_KEYVAULT_CLIENT_ID)) {
LOG.debug("Will use MSI credentials for app services with user assigned identity");
final String clientId = getProperty(this.environment, Constants.AZURE_KEYVAULT_CLIENT_ID);
msiCredentials.withClientId(clientId);
}
return msiCredentials;
}
final long timeAcquiringTimeoutInSeconds = this.environment.getProperty(
Constants.AZURE_TOKEN_ACQUIRE_TIMEOUT_IN_SECONDS, Long.class, Constants.TOKEN_ACQUIRE_TIMEOUT_SECS);
public TokenCredential getCredentials() {
//use service principle to authenticate
if (this.environment.containsProperty(Constants.AZURE_KEYVAULT_CLIENT_ID)
&& this.environment.containsProperty(Constants.AZURE_KEYVAULT_CLIENT_KEY)) {
LOG.debug("Will use custom credentials");
&& this.environment.containsProperty(Constants.AZURE_KEYVAULT_CLIENT_KEY)
&& this.environment.containsProperty(Constants.AZURE_KEYVAULT_TENANT_ID)) {
log.debug("Will use custom credentials");
final String clientId = getProperty(this.environment, Constants.AZURE_KEYVAULT_CLIENT_ID);
final String clientKey = getProperty(this.environment, Constants.AZURE_KEYVAULT_CLIENT_KEY);
return new AzureKeyVaultCredential(clientId, clientKey, timeAcquiringTimeoutInSeconds);
final String tenantId = getProperty(this.environment, Constants.AZURE_KEYVAULT_TENANT_ID);
final ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder()
.clientId(clientId)
.clientSecret(clientKey)
.tenantId(tenantId)
.build();
return clientSecretCredential;
}
if (this.environment.containsProperty(Constants.AZURE_KEYVAULT_CLIENT_ID) &&
this.environment.containsProperty(Constants.AZURE_KEYVAULT_CERTIFICATE_PATH)) {
final String clientId = getProperty(this.environment, Constants.AZURE_KEYVAULT_CLIENT_ID);
//use certificate to authenticate
if (this.environment.containsProperty(Constants.AZURE_KEYVAULT_CLIENT_ID)
&& this.environment.containsProperty(Constants.AZURE_KEYVAULT_CERTIFICATE_PATH)
&& this.environment.containsProperty(Constants.AZURE_KEYVAULT_TENANT_ID)) {
// Password can be empty
final String certPwd = this.environment.getProperty(Constants.AZURE_KEYVAULT_CERTIFICATE_PASSWORD);
final String certPath = getProperty(this.environment, Constants.AZURE_KEYVAULT_CERTIFICATE_PATH);
LOG.info("Read certificate from {}...", certPath);
final Resource certResource = new DefaultResourceLoader().getResource(certPath);
return new KeyVaultCertificateCredential(clientId, certResource, certPwd, timeAcquiringTimeoutInSeconds);
if (StringUtils.isEmpty(certPwd)) {
return new ClientCertificateCredentialBuilder()
.tenantId(getProperty(this.environment, Constants.AZURE_KEYVAULT_TENANT_ID))
.clientId(getProperty(this.environment, Constants.AZURE_KEYVAULT_CLIENT_ID))
.pemCertificate(certPath)
.build();
} else {
return new ClientCertificateCredentialBuilder()
.tenantId(getProperty(this.environment, Constants.AZURE_KEYVAULT_TENANT_ID))
.clientId(getProperty(this.environment, Constants.AZURE_KEYVAULT_CLIENT_ID))
.pfxCertificate(certPath, certPwd)
.build();
}
}
//use MSI to authenticate
if (this.environment.containsProperty(Constants.AZURE_KEYVAULT_CLIENT_ID)) {
LOG.debug("Will use MSI credentials for VMs with specified clientId");
log.debug("Will use MSI credentials with specified clientId");
final String clientId = getProperty(this.environment, Constants.AZURE_KEYVAULT_CLIENT_ID);
return new AzureKeyVaultMSICredential(AzureEnvironment.AZURE, clientId);
return new ManagedIdentityCredentialBuilder().clientId(clientId).build();
}
LOG.debug("Will use MSI credentials for VM");
return new AzureKeyVaultMSICredential(AzureEnvironment.AZURE);
log.debug("Will use MSI credentials");
return new ManagedIdentityCredentialBuilder().build();
}
private String getProperty(final ConfigurableEnvironment env, final String propertyName) {
Assert.notNull(env, "env must not be null!");
Assert.notNull(propertyName, "propertyName must not be null!");
final String property = env.getProperty(propertyName);
if (property == null || property.isEmpty()) {
throw new IllegalArgumentException("property " + propertyName + " must not be null");
}
@ -145,7 +131,6 @@ class KeyVaultEnvironmentPostProcessorHelper {
private boolean allowTelemetry(final ConfigurableEnvironment env) {
Assert.notNull(env, "env must not be null!");
return env.getProperty(Constants.AZURE_KEYVAULT_ALLOW_TELEMETRY, Boolean.class, true);
}

Просмотреть файл

@ -6,10 +6,10 @@
package com.microsoft.azure.keyvault.spring;
import com.microsoft.azure.PagedList;
import com.microsoft.azure.keyvault.KeyVaultClient;
import com.microsoft.azure.keyvault.models.SecretBundle;
import com.microsoft.azure.keyvault.models.SecretItem;
import com.azure.core.http.rest.PagedIterable;
import com.azure.security.keyvault.secrets.SecretClient;
import com.azure.security.keyvault.secrets.models.KeyVaultSecret;
import com.azure.security.keyvault.secrets.models.SecretProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
@ -27,7 +27,7 @@ public class KeyVaultOperation {
private final String[] secretKeys;
private final Object refreshLock = new Object();
private final KeyVaultClient keyVaultClient;
private final SecretClient keyVaultClient;
private final String vaultUri;
private ArrayList<String> propertyNames = new ArrayList<>();
@ -36,7 +36,7 @@ public class KeyVaultOperation {
private final AtomicLong lastUpdateTime = new AtomicLong();
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
public KeyVaultOperation(final KeyVaultClient keyVaultClient,
public KeyVaultOperation(final SecretClient keyVaultClient,
String vaultUri,
final long refreshInterval,
final String secretKeysConfig) {
@ -111,8 +111,8 @@ public class KeyVaultOperation {
refreshPropertyNames();
}
if (this.propertyNames.contains(secretName)) {
final SecretBundle secretBundle = this.keyVaultClient.getSecret(this.vaultUri, secretName);
return secretBundle == null ? null : secretBundle.value();
final KeyVaultSecret secret = this.keyVaultClient.getSecret(secretName);
return secret == null ? null : secret.getValue();
} else {
return null;
}
@ -135,11 +135,9 @@ public class KeyVaultOperation {
if (this.secretKeys == null || secretKeys.length == 0) {
this.propertyNames.clear();
final PagedList<SecretItem> secrets = this.keyVaultClient.listSecrets(this.vaultUri);
secrets.loadAll();
secrets.forEach(s -> {
final String secretName = s.id().replace(vaultUri + "/secrets/", "");
final PagedIterable<SecretProperties> secretProperties = keyVaultClient.listPropertiesOfSecrets();
secretProperties.forEach(s -> {
final String secretName = s.getName().replace(vaultUri + "/secrets/", "");
addSecretIfNotExist(secretName);
});
@ -157,12 +155,9 @@ public class KeyVaultOperation {
private void addSecretIfNotExist(final String secretName) {
final String secretNameLowerCase = secretName.toLowerCase(Locale.US);
if (!propertyNames.contains(secretNameLowerCase)) {
propertyNames.add(secretNameLowerCase);
}
final String secretNameSeparatedByDot = secretNameLowerCase.replaceAll("-", ".");
if (!propertyNames.contains(secretNameSeparatedByDot)) {
propertyNames.add(secretNameSeparatedByDot);

Просмотреть файл

@ -1,19 +0,0 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.keyvault.spring.certificate;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
@Getter
@AllArgsConstructor
public class KeyCert {
private final X509Certificate certificate;
private final PrivateKey key;
}

Просмотреть файл

@ -1,12 +0,0 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.keyvault.spring.certificate;
import org.springframework.core.io.Resource;
public interface KeyCertReader {
KeyCert read(Resource resource, String password);
}

Просмотреть файл

@ -1,31 +0,0 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.keyvault.spring.certificate;
import org.apache.commons.io.FilenameUtils;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Factory to create different certificate reader based on extension.
*/
public class KeyCertReaderFactory {
private static final ConcurrentMap<String, KeyCertReader> readerMap = new ConcurrentHashMap<>();
private static final String NOT_SUPPORTED_CERT = "Certificate type %s not supported.";
private static final String PFX_EXTENSION = "pfx";
public static KeyCertReader getReader(String certFile) {
final String extension = FilenameUtils.getExtension(certFile);
switch (extension) {
case PFX_EXTENSION:
return readerMap.computeIfAbsent(PFX_EXTENSION, k -> new PfxCertReader());
default:
throw new IllegalStateException(String.format(NOT_SUPPORTED_CERT, extension));
}
}
}

Просмотреть файл

@ -1,55 +0,0 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.keyvault.spring.certificate;
import org.springframework.core.io.Resource;
import java.io.*;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
public class PfxCertReader implements KeyCertReader {
private String CERT_NOT_FOUND = "Cert file %s not found.";
private String CERT_READ_FAILURE = "Failed to read cert file %s.";
private KeyStore store;
@Override
public KeyCert read(Resource resource, String password) {
try (InputStream inputStream = resource.getInputStream()) {
getOrInitPKCS12Store();
final char[] passwordArray = password == null ? new char[]{} : password.toCharArray();
store.load(inputStream, passwordArray);
final Enumeration<String> aliases = store.aliases();
while (aliases.hasMoreElements()) {
final String alias = aliases.nextElement();
if (store.getCertificate(alias).getType().equals("X.509") && store.isKeyEntry(alias)) {
final X509Certificate certificate = (X509Certificate) store.getCertificate(alias);
final PrivateKey key = (PrivateKey) store.getKey(alias, passwordArray);
return new KeyCert(certificate, key);
}
}
throw new IllegalStateException(String.format(CERT_READ_FAILURE, resource.getFilename()));
} catch (FileNotFoundException e) {
throw new IllegalStateException(String.format(CERT_NOT_FOUND, resource.getFilename()), e);
} catch (IOException | KeyStoreException | NoSuchProviderException | NoSuchAlgorithmException |
UnrecoverableKeyException | CertificateException e) {
throw new IllegalStateException(String.format(CERT_READ_FAILURE, resource.getFilename()), e);
}
}
private void getOrInitPKCS12Store() throws KeyStoreException, NoSuchProviderException {
if (this.store == null) {
this.store = KeyStore.getInstance("pkcs12", "SunJSSE");
}
}
}

Просмотреть файл

@ -1,37 +0,0 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.utils;
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;
import java.net.MalformedURLException;
import java.util.concurrent.*;
public class AADAuthUtil {
public AuthenticationResult getToken(String authorization,
String resource,
String clientId,
String clientKey,
long tokenAcquireTimeout) {
AuthenticationContext context = null;
AuthenticationResult result = null;
final ExecutorService executorService = Executors.newSingleThreadExecutor();
try {
context = new AuthenticationContext(authorization, false, executorService);
final ClientCredential credential = new ClientCredential(clientId, clientKey);
final Future<AuthenticationResult> future = context.acquireToken(resource, credential, null);
result = future.get(tokenAcquireTimeout, TimeUnit.SECONDS);
} catch (MalformedURLException | TimeoutException | InterruptedException | ExecutionException ex) {
throw new IllegalStateException("Failed to do authentication.", ex);
} finally {
executorService.shutdown();
}
return result;
}
}

Просмотреть файл

@ -1,76 +0,0 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.keyvault.spring;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.azure.utils.AADAuthUtil;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class AzureKeyVaultCredentialUnitTest {
@Test(expected = RuntimeException.class)
public void testDoAuthenticationRejctIfInvalidCredential() {
final AzureKeyVaultCredential keyVaultCredential = new AzureKeyVaultCredential("fakeClientId",
"fakeClientKey",
Constants.TOKEN_ACQUIRE_TIMEOUT_SECS);
keyVaultCredential.doAuthenticate("https://fakeauthorizationurl.com", "keyvault", "scope");
}
@Test
public void testDoAuthenticationPass() throws Exception {
final MockAADAuthUtil mockAADAuthUtil = new MockAADAuthUtil("token1", 11L);
final AzureKeyVaultCredential keyVaultCredential = new AzureKeyVaultCredential("fakeClientId",
"fakeClientKey",
Constants.TOKEN_ACQUIRE_TIMEOUT_SECS,
mockAADAuthUtil);
final String token = keyVaultCredential.doAuthenticate("https://fakeauthorizationurl.com", "keyvault", "scope");
//assert token from cache
mockAADAuthUtil.updateToken("token2");
assertThat(keyVaultCredential.doAuthenticate("https://fakeauthorizationurl.com",
"keyvault",
"scope")).isEqualTo(token);
//assert token refresh
Thread.sleep(1000L);
assertThat(keyVaultCredential.doAuthenticate("https://fakeauthorizationurl.com",
"keyvault",
"scope")).isNotEqualTo(token);
}
class MockAADAuthUtil extends AADAuthUtil {
private AuthenticationResult result;
public void updateToken(String token) {
result = new AuthenticationResult("mockType",
token,
"mockRefreshToken",
result.getExpiresAfter(),
"mockIdToken",
null,
true);
}
public MockAADAuthUtil(String token, long expiresIn) {
this.result = new AuthenticationResult("mockType",
token,
"mockRefreshToken",
expiresIn,
"mockIdToken",
null,
true);
}
@Override
public AuthenticationResult getToken(String authorization,
String resource,
String clientId,
String clientKey,
long tokenAcquireTimeout) {
return result;
}
}
}

Просмотреть файл

@ -1,23 +0,0 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.keyvault.spring;
import com.microsoft.azure.keyvault.spring.certificate.KeyCertReader;
import com.microsoft.azure.keyvault.spring.certificate.KeyCertReaderFactory;
import com.microsoft.azure.keyvault.spring.certificate.PfxCertReader;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class KeyCertReaderFactoryTest {
private static final String FAKE_PFX_CERT = "fake-pfx-cert.pfx";
@Test
public void testPfxCertificateReader() {
final KeyCertReader certReader = KeyCertReaderFactory.getReader(FAKE_PFX_CERT);
assertThat(certReader).isInstanceOf(PfxCertReader.class);
}
}

Просмотреть файл

@ -1,45 +0,0 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.keyvault.spring;
import com.microsoft.azure.keyvault.spring.certificate.KeyCert;
import com.microsoft.azure.keyvault.spring.certificate.PfxCertReader;
import org.junit.Test;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import static org.assertj.core.api.Assertions.assertThat;
public class KeyCertReaderTest {
private static final String TEST_PFX_FILE = "testkeyvault.pfx";
private static final String TEST_SUBJECT = "CN=testkeyvault";
private static final String TEST_PFX_PASSWORD = "123456";
private static final String TEST_NO_PASSWORD_PFX_FILE = "nopwdcert.pfx";
private static final String TEST_NO_PASSWORD_SUBJECT = "CN=nopwdcert";
private static final String TEST_NO_PASSWORD = null;
@Test
public void testPfxCertReaderCanRead() {
validatePfxCertRead(TEST_PFX_FILE, TEST_PFX_PASSWORD, TEST_SUBJECT);
}
@Test
public void testPfxCertNoPasswordReaderCanRead() {
validatePfxCertRead(TEST_NO_PASSWORD_PFX_FILE, TEST_NO_PASSWORD, TEST_NO_PASSWORD_SUBJECT);
}
private void validatePfxCertRead(String file, String password, String expectedSubject) {
final Resource resource = new DefaultResourceLoader().getResource(file);
final PfxCertReader reader = new PfxCertReader();
final KeyCert pfxCert = reader.read(resource, password);
assertThat(pfxCert).isNotNull();
assertThat(pfxCert.getCertificate()).isNotNull();
assertThat(pfxCert.getCertificate().getSubjectX500Principal().getName()).isEqualTo(expectedSubject);
assertThat(pfxCert.getKey()).isNotNull();
}
}

Просмотреть файл

@ -6,9 +6,10 @@
package com.microsoft.azure.keyvault.spring;
import com.microsoft.azure.credentials.AppServiceMSICredentials;
import com.microsoft.azure.credentials.MSICredentials;
import com.microsoft.rest.credentials.ServiceClientCredentials;
import com.azure.core.credential.TokenCredential;
import com.azure.identity.ClientCertificateCredential;
import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ManagedIdentityCredential;
import org.hamcrest.core.IsInstanceOf;
import org.junit.Before;
import org.junit.Test;
@ -25,8 +26,8 @@ import org.springframework.mock.env.MockEnvironment;
import java.util.HashMap;
import java.util.Map;
import static com.microsoft.azure.keyvault.spring.Constants.AZURE_KEYVAULT_CLIENT_ID;
import static com.microsoft.azure.keyvault.spring.Constants.AZURE_KEYVAULT_CERTIFICATE_PATH;
import static com.microsoft.azure.keyvault.spring.Constants.AZURE_KEYVAULT_CLIENT_ID;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
@ -43,6 +44,33 @@ public class KeyVaultEnvironmentPostProcessorTest {
propertySources = environment.getPropertySources();
}
@Test
public void testGetCredentialsWhenUsingClientAndKey() {
testProperties.put("azure.keyvault.client-id", "aaaa-bbbb-cccc-dddd");
testProperties.put("azure.keyvault.client-key", "mySecret");
testProperties.put("azure.keyvault.tenant-id", "myid");
propertySources.addLast(new MapPropertySource("Test_Properties", testProperties));
keyVaultEnvironmentPostProcessorHelper = new KeyVaultEnvironmentPostProcessorHelper(environment);
final TokenCredential credentials = keyVaultEnvironmentPostProcessorHelper.getCredentials();
assertThat(credentials, IsInstanceOf.instanceOf(ClientSecretCredential.class));
}
@Test
public void testGetCredentialsWhenPFXCertConfigured() {
testProperties.put(AZURE_KEYVAULT_CLIENT_ID, "aaaa-bbbb-cccc-dddd");
testProperties.put("azure.keyvault.tenant-id", "myid");
testProperties.put(AZURE_KEYVAULT_CERTIFICATE_PATH, "fake-pfx-cert.pfx");
propertySources.addLast(new MapPropertySource("Test_Properties", testProperties));
keyVaultEnvironmentPostProcessorHelper = new KeyVaultEnvironmentPostProcessorHelper(environment);
final TokenCredential credentials = keyVaultEnvironmentPostProcessorHelper.getCredentials();
assertThat(credentials, IsInstanceOf.instanceOf(ClientCertificateCredential.class));
}
@Test
public void testGetCredentialsWhenMSIEnabledInAppService() {
testProperties.put("MSI_ENDPOINT", "fakeendpoint");
@ -51,23 +79,12 @@ public class KeyVaultEnvironmentPostProcessorTest {
keyVaultEnvironmentPostProcessorHelper = new KeyVaultEnvironmentPostProcessorHelper(environment);
final ServiceClientCredentials credentials = keyVaultEnvironmentPostProcessorHelper.getCredentials();
final TokenCredential credentials = keyVaultEnvironmentPostProcessorHelper.getCredentials();
assertThat(credentials, IsInstanceOf.instanceOf(AppServiceMSICredentials.class));
assertThat(credentials, IsInstanceOf.instanceOf(ManagedIdentityCredential.class));
}
@Test
public void testGetCredentialsWhenUsingClientAndKey() {
testProperties.put("azure.keyvault.client-id", "aaaa-bbbb-cccc-dddd");
testProperties.put("azure.keyvault.client-key", "mySecret");
propertySources.addLast(new MapPropertySource("Test_Properties", testProperties));
keyVaultEnvironmentPostProcessorHelper = new KeyVaultEnvironmentPostProcessorHelper(environment);
final ServiceClientCredentials credentials = keyVaultEnvironmentPostProcessorHelper.getCredentials();
assertThat(credentials, IsInstanceOf.instanceOf(AzureKeyVaultCredential.class));
}
@Test
public void testGetCredentialsWhenMSIEnabledInVMWithClientId() {
@ -76,30 +93,18 @@ public class KeyVaultEnvironmentPostProcessorTest {
keyVaultEnvironmentPostProcessorHelper = new KeyVaultEnvironmentPostProcessorHelper(environment);
final ServiceClientCredentials credentials = keyVaultEnvironmentPostProcessorHelper.getCredentials();
final TokenCredential credentials = keyVaultEnvironmentPostProcessorHelper.getCredentials();
assertThat(credentials, IsInstanceOf.instanceOf(AzureKeyVaultMSICredential.class));
assertThat(credentials, IsInstanceOf.instanceOf(ManagedIdentityCredential.class));
}
@Test
public void testGetCredentialsWhenMSIEnabledInVMWithoutClientId() {
keyVaultEnvironmentPostProcessorHelper = new KeyVaultEnvironmentPostProcessorHelper(environment);
final ServiceClientCredentials credentials = keyVaultEnvironmentPostProcessorHelper.getCredentials();
final TokenCredential credentials = keyVaultEnvironmentPostProcessorHelper.getCredentials();
assertThat(credentials, IsInstanceOf.instanceOf(AzureKeyVaultMSICredential.class));
}
@Test
public void testGetCredentialsWhenPFXCertConfigured() {
testProperties.put(AZURE_KEYVAULT_CLIENT_ID, "aaaa-bbbb-cccc-dddd");
testProperties.put(AZURE_KEYVAULT_CERTIFICATE_PATH, "fake-pfx-cert.pfx");
propertySources.addLast(new MapPropertySource("Test_Properties", testProperties));
keyVaultEnvironmentPostProcessorHelper = new KeyVaultEnvironmentPostProcessorHelper(environment);
final ServiceClientCredentials credentials = keyVaultEnvironmentPostProcessorHelper.getCredentials();
assertThat(credentials, IsInstanceOf.instanceOf(KeyVaultCertificateCredential.class));
assertThat(credentials, IsInstanceOf.instanceOf(ManagedIdentityCredential.class));
}
@Test

Просмотреть файл

@ -5,20 +5,19 @@
*/
package com.microsoft.azure.keyvault.spring;
import com.microsoft.azure.Page;
import com.microsoft.azure.PagedList;
import com.microsoft.azure.keyvault.KeyVaultClient;
import com.microsoft.azure.keyvault.models.SecretBundle;
import com.microsoft.azure.keyvault.models.SecretItem;
import com.microsoft.rest.RestException;
import com.azure.core.http.rest.PagedFlux;
import com.azure.core.http.rest.PagedIterable;
import com.azure.security.keyvault.secrets.SecretClient;
import com.azure.security.keyvault.secrets.models.KeyVaultSecret;
import com.azure.security.keyvault.secrets.models.SecretProperties;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
@ -32,7 +31,7 @@ public class KeyVaultOperationUnitTest {
private static final String secretKey1 = "key1";
private static final String fakeVaultUri = "https://fake.vault.com";
private static final String fakeVaultUri = "https:fake.vault.com";
private static final String TEST_SPRING_RELAXED_BINDING_NAME_0 = "acme.my-project.person.first-name";
@ -52,27 +51,15 @@ public class KeyVaultOperationUnitTest {
);
@Mock
private KeyVaultClient keyVaultClient;
private SecretClient keyVaultClient;
private KeyVaultOperation keyVaultOperation;
public void setupSecretBundle(String id, String value, String secretKeysConfig) {
final PagedList<SecretItem> mockResult = new PagedList<SecretItem>() {
@Override
public Page<SecretItem> nextPage(String s) throws RestException {
return new MockPage();
}
};
final SecretItem secretItem = new SecretItem();
secretItem.withId(id);
mockResult.add(secretItem);
final SecretBundle secretBundle = new SecretBundle();
secretBundle.withId(id).withValue(value);
when(keyVaultClient.listSecrets(anyString())).thenReturn(mockResult);
when(keyVaultClient.getSecret(anyString(), anyString())).thenReturn(secretBundle);
//provision for list
when(keyVaultClient.listPropertiesOfSecrets()).thenReturn(new MockPage(new PagedFlux<>(() -> null), id));
//provison for get
final KeyVaultSecret secretBundle = new KeyVaultSecret(id, value);
when(keyVaultClient.getSecret(anyString())).thenReturn(secretBundle);
keyVaultOperation = new KeyVaultOperation(keyVaultClient,
fakeVaultUri,
Constants.TOKEN_ACQUIRE_TIMEOUT_SECS,
@ -135,20 +122,39 @@ public class KeyVaultOperationUnitTest {
);
}
class MockPage extends PagedIterable<SecretProperties> {
private String name;
class MockPage implements Page<SecretItem> {
public MockPage(PagedFlux<SecretProperties> pagedFlux, String name) {
super(pagedFlux);
this.name = name;
}
final SecretItem mockSecretItem = new SecretItem();
@Override
public String nextPageLink() {
return null;
/**
* Creates instance given {@link PagedFlux}.
*
* @param pagedFlux to use as iterable
*/
public MockPage(PagedFlux<SecretProperties> pagedFlux) {
super(pagedFlux);
}
@Override
public List<SecretItem> items() {
mockSecretItem.withId("testPropertyName1");
return Collections.singletonList(mockSecretItem);
public void forEach(Consumer<? super SecretProperties> action) {
action.accept(new MockSecretProperties(name));
}
}
class MockSecretProperties extends SecretProperties {
private String name;
public MockSecretProperties(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
}