Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update readme and changelog for jca #22283

Merged
merged 12 commits into from
Jun 17, 2021
1 change: 1 addition & 0 deletions sdk/keyvault/azure-security-keyvault-jca/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## 1.0.0-beta.8 (Unreleased)
### New Features
- Load JRE key store certificates to AzureKeyVault key store. ([#21845](https://github.com/Azure/azure-sdk-for-java/pull/21845))
- Support properties of azure.cert-path.well-known and azure.cert-path.custom to support load cert from file system. ([#21947](https://github.com/Azure/azure-sdk-for-java/pull/21947))

## 1.0.0-beta.7 (2021-05-24)
### New Features
Expand Down
10 changes: 10 additions & 0 deletions sdk/keyvault/azure-security-keyvault-jca/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,16 @@ try (CloseableHttpClient client = HttpClients.custom().setConnectionManager(mana

Note if you want to use Azure managed identity, you should set the value of `azure.keyvault.uri`, and the rest of the parameters would be `null`.

### File-System certificates
You can load the certificate in the file system as a trusted certificate by configure the following properties.

```yaml
azure:
cert-path:
well-known: # The file location where you store the well-known certificate
custom: # The file location where you store the custom certificate
```

## Troubleshooting
### General
Azure Key Vault JCA clients raise exceptions. For example, if you try to check a client's identity with a certificate chain that does not include a trusted certificate, a `CertificateException` will be thrown. In the following snippet, the error is handled gracefully by catching the exception and displaying additional information about the error.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.HashMap;
import java.util.logging.Logger;

import static java.util.logging.Level.FINE;
import static java.util.logging.Level.WARNING;

/**
Expand Down Expand Up @@ -50,14 +51,14 @@ public final class KeyVaultKeyStore extends KeyStoreSpi {
private final JreCertificates jreCertificates;

/**
* Store well Know certificates loaded from file system.
* Store well Know certificates loaded from specific path.
*/
private final FileSystemCertificates wellKnowCertificates;
private final SpecificPathCertificates wellKnowCertificates;

/**
* Store custom certificates loaded from file system.
* Store custom certificates loaded from specific path.
*/
private final FileSystemCertificates customCertificates;
private final SpecificPathCertificates customCertificates;

/**
* Store certificates loaded from KeyVault.
Expand Down Expand Up @@ -131,8 +132,8 @@ public KeyVaultKeyStore() {
.map(Boolean::parseBoolean)
.orElse(false);
jreCertificates = JreCertificates.getInstance();
wellKnowCertificates = FileSystemCertificates.FileSystemCertificatesFactory.getWellKnownFileSystemCertificates(wellKnowPath);
customCertificates = FileSystemCertificates.FileSystemCertificatesFactory.getCustomFileSystemCertificates(customPath);
wellKnowCertificates = SpecificPathCertificates.getFileSystemCertificates(wellKnowPath);
customCertificates = SpecificPathCertificates.getFileSystemCertificates(customPath);
zhichengliu12581 marked this conversation as resolved.
Show resolved Hide resolved
keyVaultCertificates = new KeyVaultCertificates(refreshInterval, keyVaultClient);
classpathCertificates = new ClasspathCertificates();
allCertificates = Arrays.asList(jreCertificates, wellKnowCertificates, customCertificates, keyVaultCertificates, classpathCertificates);
Expand Down Expand Up @@ -281,7 +282,7 @@ private List<String> getAllAliases() {
aliasLists.forEach((key, value) -> {
value.forEach(a -> {
if (allAliases.contains(a)) {
LOGGER.log(WARNING, String.format("The certificate with alias %s under %s already exists", a, key));
LOGGER.log(FINE, String.format("The certificate with alias %s under %s already exists", a, key));
} else {
allAliases.add(a);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,27 @@
/**
* Store certificates loaded from file system.
*/
public final class FileSystemCertificates implements AzureCertificates {
public final class SpecificPathCertificates implements AzureCertificates {
zhichengliu12581 marked this conversation as resolved.
Show resolved Hide resolved

private static final Map<String, SpecificPathCertificates> CACHE = new HashMap<>();

/**
* Stores the logger.
*/
private static final Logger LOGGER = Logger.getLogger(FileSystemCertificates.class.getName());
private static final Logger LOGGER = Logger.getLogger(SpecificPathCertificates.class.getName());

/**
* Stores the jre key store aliases.
* Stores the specific path aliases.
*/
private final List<String> aliases = new ArrayList<>();

/**
* Stores the file system certificates by alias.
* Stores the specific path certificates by alias.
*/
private final Map<String, Certificate> certificates = new HashMap<>();

/**
* Stores the file system certificate keys by alias.
* Stores the specific path certificate keys by alias.
*/
private final Map<String, Key> certificateKeys = new HashMap<>();

Expand Down Expand Up @@ -80,7 +82,7 @@ public void deleteEntry(String alias) {
*
* @param certificatePath Store the file path where certificates are placed
*/
private FileSystemCertificates(String certificatePath) {
private SpecificPathCertificates(String certificatePath) {
this.certificatePath = certificatePath;
}

Expand All @@ -93,7 +95,7 @@ private FileSystemCertificates(String certificatePath) {
public void setCertificateEntry(String alias, Certificate certificate) {
//Add verification to avoid certificate files with the same file name but different suffixes
if (aliases.contains(alias)) {
LOGGER.log(WARNING, "Cannot load certificates with the same alias in file system", alias);
LOGGER.log(WARNING, "Cannot load certificates with the same alias in specific path", alias);
return;
}
aliases.add(alias);
Expand All @@ -119,7 +121,7 @@ private void setCertificateByFile(File file) throws IOException {
new Object[]{alias, file.getName()});
}
} catch (CertificateException e) {
LOGGER.log(WARNING, "Unable to load file system certificate from: " + file.getName(), e);
LOGGER.log(WARNING, "Unable to load specific path certificate from: " + file.getName(), e);
}
}

Expand All @@ -133,12 +135,13 @@ void loadCertificatesFromFileSystem() {
setCertificateByFile(file);
}
} catch (IOException ioe) {
LOGGER.log(WARNING, "Unable to determine certificates to file system", ioe);
LOGGER.log(WARNING, "Unable to determine certificates to specific path", ioe);
}
}

/**
* Get alias from file
*
* @param file File containing certificate information
* @return certificate alias
*/
Expand Down Expand Up @@ -170,45 +173,17 @@ private List<File> getFiles() {
}

/**
* Factory of FileSystemCertificate, to avoid loading files multiple times
* Get File System certificates by path
*
* @param path certificate path, which works only in first time
* @return file certificate
*/
public static class FileSystemCertificatesFactory {

private static volatile FileSystemCertificates customFileSystemCertificates;

/**
* Get Singleton custom file system certificates
* @param path custom certificate path, which works only in first time
* @return custom file certificate
*/
public static FileSystemCertificates getCustomFileSystemCertificates(String path) {
if (customFileSystemCertificates == null) {
synchronized (FileSystemCertificatesFactory.class) {
if (customFileSystemCertificates == null) {
customFileSystemCertificates = new FileSystemCertificates(path);
}
}
}
return customFileSystemCertificates;
}

private static volatile FileSystemCertificates wellKnownFileSystemCertificates;

/**
* Get Singleton well known file system certificates
* @param path well known certificate path, which works only in first time
* @return well known file certificate
*/
public static FileSystemCertificates getWellKnownFileSystemCertificates(String path) {
if (wellKnownFileSystemCertificates == null) {
synchronized (FileSystemCertificatesFactory.class) {
if (wellKnownFileSystemCertificates == null) {
wellKnownFileSystemCertificates = new FileSystemCertificates(path);
}
}
}
return wellKnownFileSystemCertificates;
public static synchronized SpecificPathCertificates getFileSystemCertificates(String path) {
SpecificPathCertificates result = CACHE.getOrDefault(path, null);
if (result == null) {
result = new SpecificPathCertificates(path);
zhichengliu12581 marked this conversation as resolved.
Show resolved Hide resolved
CACHE.put(path, result);
}
return result;
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.security.keyvault.jca;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class SpecificPathCertificatesTest {

SpecificPathCertificates specificPathCertificates;

public static String getFilePath(String packageName) {
String filepath = "\\src\\test\\resources\\" + packageName;
return System.getProperty("user.dir") + filepath.replace("\\", System.getProperty("file.separator"));
}

@Test
public void testSetCertificateEntry() {
specificPathCertificates = SpecificPathCertificates.getFileSystemCertificates(getFilePath("custom\\"));
specificPathCertificates.loadCertificatesFromFileSystem();
zhichengliu12581 marked this conversation as resolved.
Show resolved Hide resolved
Assertions.assertTrue(specificPathCertificates.getAliases().contains("sideload"));
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static void init() {
/*
* Set system properties.
*/
PropertyConvertorUtils.putEnvironmentPropertyToSystemPropertyForKeyVaultJca(PropertyConvertorUtils.SYSTEM_PROPERTIES);
PropertyConvertorUtils.putEnvironmentPropertyToSystemPropertyForKeyVaultJca();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public class KeyVaultCertificatesTest {

@BeforeAll
public static void setEnvironmentProperty() {
PropertyConvertorUtils.putEnvironmentPropertyToSystemPropertyForKeyVaultJca(PropertyConvertorUtils.SYSTEM_PROPERTIES);
PropertyConvertorUtils.putEnvironmentPropertyToSystemPropertyForKeyVaultJca();
PropertyConvertorUtils.addKeyVaultJcaProvider();
certificateName = System.getenv("AZURE_KEYVAULT_CERTIFICATE_NAME");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class KeyVaultJcaProviderTest {
*/
@Test
public void testGetCertificate() throws Exception {
PropertyConvertorUtils.putEnvironmentPropertyToSystemPropertyForKeyVaultJca(PropertyConvertorUtils.SYSTEM_PROPERTIES);
PropertyConvertorUtils.putEnvironmentPropertyToSystemPropertyForKeyVaultJca();
PropertyConvertorUtils.addKeyVaultJcaProvider();
KeyStore keystore = PropertyConvertorUtils.getKeyVaultKeyStore();
assertNotNull(keystore.getCertificate(System.getenv("AZURE_KEYVAULT_CERTIFICATE_NAME")));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class KeyVaultKeyManagerTest {
@BeforeAll
public static void setEnvironmentProperty() throws KeyStoreException, NoSuchAlgorithmException, IOException,
CertificateException {
PropertyConvertorUtils.putEnvironmentPropertyToSystemPropertyForKeyVaultJca(PropertyConvertorUtils.SYSTEM_PROPERTIES);
PropertyConvertorUtils.putEnvironmentPropertyToSystemPropertyForKeyVaultJca();
PropertyConvertorUtils.addKeyVaultJcaProvider();
KeyStore keyStore = PropertyConvertorUtils.getKeyVaultKeyStore();
manager = new KeyVaultKeyManager(keyStore, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public class KeyVaultKeyStoreTest {

@BeforeAll
public static void setEnvironmentProperty() {
PropertyConvertorUtils.putEnvironmentPropertyToSystemPropertyForKeyVaultJca(PropertyConvertorUtils.SYSTEM_PROPERTIES);
PropertyConvertorUtils.putEnvironmentPropertyToSystemPropertyForKeyVaultJca();
keystore = new KeyVaultKeyStore();
KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
System.getenv("AZURE_KEYVAULT_URI"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

public class PropertyConvertorUtils {

public static void putEnvironmentPropertyToSystemPropertyForKeyVaultJca(List<String> key) {
key.forEach(
public static void putEnvironmentPropertyToSystemPropertyForKeyVaultJca() {
KEYVAULT_JCA_SYSTEM_PROPERTIES.forEach(
environmentPropertyKey -> {
String value = System.getenv(environmentPropertyKey);
String systemPropertyKey = environmentPropertyKey.toLowerCase().replaceFirst("azure_keyvault_",
Expand All @@ -28,7 +28,7 @@ public static void putEnvironmentPropertyToSystemPropertyForKeyVaultJca(List<Str
);
}

public static final List<String> SYSTEM_PROPERTIES = Arrays.asList("AZURE_KEYVAULT_URI",
public static final List<String> KEYVAULT_JCA_SYSTEM_PROPERTIES = Arrays.asList("AZURE_KEYVAULT_URI",
"AZURE_KEYVAULT_TENANT_ID",
"AZURE_KEYVAULT_CLIENT_ID",
"AZURE_KEYVAULT_CLIENT_SECRET");
Expand Down
Loading