diff --git a/examples/TppClient.java b/examples/TppClient.java index 74d7855..b9cf29a 100644 --- a/examples/TppClient.java +++ b/examples/TppClient.java @@ -1,72 +1,62 @@ +import java.security.cert.CertificateEncodingException; +import java.util.Arrays; +import java.util.Collections; import com.venafi.vcert.sdk.Config; -import com.venafi.vcert.sdk.VCertException; import com.venafi.vcert.sdk.VCertClient; - +import com.venafi.vcert.sdk.VCertException; import com.venafi.vcert.sdk.certificate.CertificateRequest; import com.venafi.vcert.sdk.certificate.KeyType; import com.venafi.vcert.sdk.certificate.PEMCollection; -import com.venafi.vcert.sdk.certificate.RenewalRequest; import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; import com.venafi.vcert.sdk.endpoint.Authentication; import com.venafi.vcert.sdk.endpoint.ConnectorType; -import org.apache.commons.codec.digest.DigestUtils; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Collections; +public class TppClient { + public static void main(String... args) throws VCertException, CertificateEncodingException { + String tpp_user = System.getenv("TPP_USER"); + String tpp_passwd = System.getenv("TPP_PASSWORD"); + String url = System.getenv("VENAFI_URL"); + String zone = System.getenv("VENAFI_ZONE"); -public class TppClient -{ - public static void main(String ... args) throws VCertException, CertificateEncodingException - { - String tpp_user = System.getenv("TPP_USER"); - String tpp_passwd = System.getenv("TPP_PASSWORD"); - String url = System.getenv("VENAFI_URL"); - String zone = System.getenv("VENAFI_ZONE"); + if (tpp_user == null) + tpp_user = "local:admin"; + if (tpp_passwd == null) + tpp_passwd = "Passw0rd"; + if (url == null) + url = "https://tpp.venafi.example/vedsdk"; + if (zone == null) + zone = "Default"; - if ( tpp_user == null ) tpp_user = "local:admin"; - if ( tpp_passwd == null ) tpp_passwd = "Passw0rd"; - if ( url == null ) url = "https://tpp.venafi.example/vedsdk"; - if ( zone == null ) zone = "Default"; + final Config config = Config.builder().connectorType(ConnectorType.TPP).baseUrl(url).build(); - final Config config = Config.builder() - .connectorType(ConnectorType.TPP) - .baseUrl(url) - .build(); + final VCertClient client = new VCertClient(config); - final VCertClient client = new VCertClient(config); + final Authentication auth = + Authentication.builder().user(tpp_user).password(tpp_passwd).build(); - final Authentication auth = Authentication.builder() - .user(tpp_user) - .password(tpp_passwd) - .build(); + client.authenticate(auth); - client.authenticate(auth); - - final ZoneConfiguration zoneConfiguration = client.readZoneConfiguration(zone); + final ZoneConfiguration zoneConfiguration = client.readZoneConfiguration(zone); - // Generate a certificate - CertificateRequest certificateRequest = new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName("vcert-java.venafi.example") - .organization(Collections.singletonList("Venafi, Inc.")) - .organizationalUnit(Arrays.asList("Product Management")) - .country(Collections.singletonList("US")) - .locality(Collections.singletonList("Salt Lake City")) - .province(Collections.singletonList("Utah"))) + // Generate a certificate + CertificateRequest certificateRequest = new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName("vcert-java.venafi.example") + .organization(Collections.singletonList("Venafi, Inc.")) + .organizationalUnit(Arrays.asList("Product Management")) + .country(Collections.singletonList("US")) + .locality(Collections.singletonList("Salt Lake City")) + .province(Collections.singletonList("Utah"))) - .keyType(KeyType.RSA) - .keyLength(2048); + .keyType(KeyType.RSA).keyLength(2048); - certificateRequest = client.generateRequest(zoneConfiguration, certificateRequest); + certificateRequest = client.generateRequest(zoneConfiguration, certificateRequest); - // Submit the certificate request - String newCertId = client.requestCertificate(certificateRequest, zone); + // Submit the certificate request + String newCertId = client.requestCertificate(certificateRequest, zone); - // Retrieve PEM collection from Venafi - final CertificateRequest pickupRequest = new CertificateRequest().pickupId(newCertId); - PEMCollection pemCollection = client.retrieveCertificate(pickupRequest); - System.out.println(pemCollection.certificate()); - } + // Retrieve PEM collection from Venafi + final CertificateRequest pickupRequest = new CertificateRequest().pickupId(newCertId); + PEMCollection pemCollection = client.retrieveCertificate(pickupRequest); + System.out.println(pemCollection.certificate()); + } } diff --git a/pom.xml b/pom.xml index d3dd8cd..d709d35 100644 --- a/pom.xml +++ b/pom.xml @@ -5,8 +5,8 @@ 4.0.0 com.venafi.vcert.sdk - venafi-vcert-java - 1.0-SNAPSHOT + vcert-java + 0.1.1 1.18.6 @@ -164,4 +164,4 @@ - \ No newline at end of file + diff --git a/src/main/java/com/venafi/vcert/sdk/Config.java b/src/main/java/com/venafi/vcert/sdk/Config.java index c973cf0..80ed3be 100644 --- a/src/main/java/com/venafi/vcert/sdk/Config.java +++ b/src/main/java/com/venafi/vcert/sdk/Config.java @@ -1,101 +1,103 @@ package com.venafi.vcert.sdk; -import com.venafi.vcert.sdk.endpoint.Authentication; -import com.venafi.vcert.sdk.endpoint.ConnectorType; -import lombok.Builder; -import lombok.Data; -import org.ini4j.Profile; -import org.ini4j.Wini; - +import static java.util.Arrays.asList; import java.io.IOException; import java.nio.file.Path; import java.util.List; import java.util.Objects; - -import static java.util.Arrays.asList; +import org.ini4j.Profile; +import org.ini4j.Wini; +import lombok.Builder; +import lombok.Data; +import com.venafi.vcert.sdk.endpoint.Authentication; +import com.venafi.vcert.sdk.endpoint.ConnectorType; @Data @Builder public class Config { - public static final String DEFAULT_SECTION = "?"; - public static final List VALID_TPP_KEYS = - asList("tpp_url", "tpp_user", "tpp_password", "tpp_zone", "trust_bundle"); + public static final String DEFAULT_SECTION = "?"; + public static final List VALID_TPP_KEYS = + asList("tpp_url", "tpp_user", "tpp_password", "tpp_zone", "trust_bundle"); - public static final List VALID_CLOUD_KEYS = - asList("cloud_url", "cloud_apikey", "cloud_zone", "trust_bundle"); + public static final List VALID_CLOUD_KEYS = + asList("cloud_url", "cloud_apikey", "cloud_zone", "trust_bundle"); - private ConnectorType connectorType; - private String baseUrl; - private String zone; - private Authentication credentials; - private String connectionTrust; - private boolean logVerbose; - private String configFile; - private String configSection; + private ConnectorType connectorType; + private String baseUrl; + private String zone; + private Authentication credentials; + private String connectionTrust; + private boolean logVerbose; + private String configFile; + private String configSection; - public static Config loadConfigFromFile(Path path) throws VCertException { - final ConfigBuilder builder = Config.builder(); - final Authentication.AuthenticationBuilder authBuilder = Authentication.builder(); + public static Config loadConfigFromFile(Path path) throws VCertException { + final ConfigBuilder builder = Config.builder(); + final Authentication.AuthenticationBuilder authBuilder = Authentication.builder(); - try { - final Wini ini = new Wini(path.toFile()); - final Profile.Section defaultSection = ini.get(DEFAULT_SECTION); - validateConfigFile(defaultSection); + try { + final Wini ini = new Wini(path.toFile()); + final Profile.Section defaultSection = ini.get(DEFAULT_SECTION); + validateConfigFile(defaultSection); - if (defaultSection.containsKey("tpp_url")) { - builder.connectorType(ConnectorType.TPP); - builder.baseUrl(defaultSection.get("tpp_url")); - authBuilder.user(defaultSection.get("tpp_user")); - authBuilder.password(defaultSection.get("tpp_password")); + if (defaultSection.containsKey("tpp_url")) { + builder.connectorType(ConnectorType.TPP); + builder.baseUrl(defaultSection.get("tpp_url")); + authBuilder.user(defaultSection.get("tpp_user")); + authBuilder.password(defaultSection.get("tpp_password")); - if (defaultSection.containsKey("tpp_zone")) { - builder.zone(defaultSection.get("tpp_zone")); - } - } else if (defaultSection.containsKey("cloud_apikey")) { - authBuilder.apiKey(defaultSection.get("cloud_apikey")); - if (defaultSection.containsKey("cloud_url")) { - builder.baseUrl(defaultSection.get("cloud_url")); - } - if (defaultSection.containsKey("cloud_zone")) { - builder.zone(defaultSection.get("cloud_zone")); - } - } - builder.credentials(authBuilder.build()); - return builder.build(); - } catch (IOException e) { - throw new VCertException(String.format("Access error to the configuration file: %s", path.toString())); + if (defaultSection.containsKey("tpp_zone")) { + builder.zone(defaultSection.get("tpp_zone")); } + } else if (defaultSection.containsKey("cloud_apikey")) { + authBuilder.apiKey(defaultSection.get("cloud_apikey")); + if (defaultSection.containsKey("cloud_url")) { + builder.baseUrl(defaultSection.get("cloud_url")); + } + if (defaultSection.containsKey("cloud_zone")) { + builder.zone(defaultSection.get("cloud_zone")); + } + } + builder.credentials(authBuilder.build()); + return builder.build(); + } catch (IOException e) { + throw new VCertException( + String.format("Access error to the configuration file: %s", path.toString())); } + } - private static void validateConfigFile(Profile.Section defaultSection) throws VCertException { - if (Objects.isNull(defaultSection)) { - throw new VCertException("The configuration file is empty"); - } + private static void validateConfigFile(Profile.Section defaultSection) throws VCertException { + if (Objects.isNull(defaultSection)) { + throw new VCertException("The configuration file is empty"); + } - if (defaultSection.containsKey("tpp_url")) { - for (String key : defaultSection.keySet()) { - if (!VALID_TPP_KEYS.contains(key)) { - throw new VCertException(String.format("illegal key %s in section %s", key, defaultSection.getName())); - } - } - if (!defaultSection.containsKey("tpp_user")) { - throw new VCertException(String.format("configuration issue section %s: missing TTP user", - defaultSection.getName())); - } - if (!defaultSection.containsKey("tpp_password")) { - throw new VCertException(String.format("configuration issue section %s: missing TTP password", - defaultSection.getName())); - } - } else if (defaultSection.containsKey("cloud_apikey")){ - for (String key : defaultSection.keySet()) { - if (!VALID_CLOUD_KEYS.contains(key)) { - throw new VCertException(String.format("illegal key %s in section %s", key, defaultSection.getName())); - } - } - } else { - throw new VCertException(String.format("Section %s requires 'tpp_url' or 'cloud_apikey'", defaultSection.getName())); + if (defaultSection.containsKey("tpp_url")) { + for (String key : defaultSection.keySet()) { + if (!VALID_TPP_KEYS.contains(key)) { + throw new VCertException( + String.format("illegal key %s in section %s", key, defaultSection.getName())); + } + } + if (!defaultSection.containsKey("tpp_user")) { + throw new VCertException(String.format("configuration issue section %s: missing TPP user", + defaultSection.getName())); + } + if (!defaultSection.containsKey("tpp_password")) { + throw new VCertException(String.format( + "configuration issue section %s: missing TPP password", defaultSection.getName())); + } + } else if (defaultSection.containsKey("cloud_apikey")) { + for (String key : defaultSection.keySet()) { + if (!VALID_CLOUD_KEYS.contains(key)) { + throw new VCertException( + String.format("illegal key %s in section %s", key, defaultSection.getName())); } + } + } else { + throw new VCertException(String.format("Section %s requires 'tpp_url' or 'cloud_apikey'", + defaultSection.getName())); } + } } diff --git a/src/main/java/com/venafi/vcert/sdk/SignatureAlgorithm.java b/src/main/java/com/venafi/vcert/sdk/SignatureAlgorithm.java index 391e956..a8e474b 100644 --- a/src/main/java/com/venafi/vcert/sdk/SignatureAlgorithm.java +++ b/src/main/java/com/venafi/vcert/sdk/SignatureAlgorithm.java @@ -4,31 +4,33 @@ public enum SignatureAlgorithm { - UnknownSignatureAlgorithm(""), - MD2withRSA("MD2withRSA"), - MD5WithRSA("MD5withRSA"), - SHA1WithRSA("SHA1withRSA"), - SHA256WithRSA("SHA256withRSA"), - SHA384WithRSA("SHA384withRSA"), - SHA512WithRSA("SHA512withRSA"), - DSAWithSHA1("SHA1withDSA"), - DSAWithSHA256("SHA256withDSA"), - ECDSAWithSHA1("SHA1withECDSA"), - ECDSAWithSHA256("SHA256withECDSA"), - ECDSAWithSHA384("SHA384withECDSA"), - ECDSAWithSHA512("SHA512withECDSA"), - SHA256WithRSAPSS("RSAPSSwithSHA256"), - SHA384WithRSAPSS("RSAPSSwithSHA384"), - SHA512WithRSAPSS("RSAPSSwithSHA512"); + UnknownSignatureAlgorithm(""), + MD2withRSA("MD2withRSA"), + MD5WithRSA("MD5withRSA"), + SHA1WithRSA("SHA1withRSA"), + SHA256WithRSA("SHA256withRSA"), + SHA384WithRSA("SHA384withRSA"), + SHA512WithRSA("SHA512withRSA"), + DSAWithSHA1("SHA1withDSA"), + DSAWithSHA256("SHA256withDSA"), + ECDSAWithSHA1("SHA1withECDSA"), + ECDSAWithSHA256("SHA256withECDSA"), + ECDSAWithSHA384("SHA384withECDSA"), + ECDSAWithSHA512("SHA512withECDSA"), + SHA256WithRSAPSS("RSAPSSwithSHA256"), + SHA384WithRSAPSS("RSAPSSwithSHA384"), + SHA512WithRSAPSS("RSAPSSwithSHA512"); - /** - * @param standardName - * @see Standard Signature Algorithm Names - */ - SignatureAlgorithm(String standardName) { - this.standardName = standardName; - } + /** + * @param standardName + * @see Standard + * Signature Algorithm Names + */ + SignatureAlgorithm(String standardName) { + this.standardName = standardName; + } - @Getter - private String standardName; + @Getter + private String standardName; } diff --git a/src/main/java/com/venafi/vcert/sdk/VCertClient.java b/src/main/java/com/venafi/vcert/sdk/VCertClient.java index 389a804..704f251 100644 --- a/src/main/java/com/venafi/vcert/sdk/VCertClient.java +++ b/src/main/java/com/venafi/vcert/sdk/VCertClient.java @@ -1,7 +1,16 @@ package com.venafi.vcert.sdk; +import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isNotBlank; +import java.security.Security; import com.google.common.annotations.VisibleForTesting; -import com.venafi.vcert.sdk.certificate.*; +import feign.FeignException; +import com.venafi.vcert.sdk.certificate.CertificateRequest; +import com.venafi.vcert.sdk.certificate.ImportRequest; +import com.venafi.vcert.sdk.certificate.ImportResponse; +import com.venafi.vcert.sdk.certificate.PEMCollection; +import com.venafi.vcert.sdk.certificate.RenewalRequest; +import com.venafi.vcert.sdk.certificate.RevocationRequest; import com.venafi.vcert.sdk.connectors.Connector; import com.venafi.vcert.sdk.connectors.Policy; import com.venafi.vcert.sdk.connectors.cloud.Cloud; @@ -11,212 +20,205 @@ import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; import com.venafi.vcert.sdk.endpoint.Authentication; import com.venafi.vcert.sdk.endpoint.ConnectorType; -import feign.FeignException; - -import java.security.Security; - -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.apache.commons.lang3.StringUtils.isNotBlank; public class VCertClient implements Connector { - private Config config; - private Connector connector; - - public VCertClient(Config config) throws VCertException { - this.config = config; - Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); - switch (config.connectorType()) { - case TPP: - if (isBlank(config.baseUrl())) - throw new VCertException("TPP client requires a base url"); - - connector = new TppConnector(Tpp.connect(config.baseUrl())); - break; - - case CLOUD: - connector = new CloudConnector(Cloud.connect(isNotBlank(config.baseUrl()) - ? config.baseUrl() : "https://api.venafi.cloud")); - break; - default: - throw new VCertException("ConnectorType is not defined"); - - } - + private Config config; + private Connector connector; + + public VCertClient(Config config) throws VCertException { + this.config = config; + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + switch (config.connectorType()) { + case TPP: + if (isBlank(config.baseUrl())) + throw new VCertException("TPP client requires a base url"); + + connector = new TppConnector(Tpp.connect(config.baseUrl())); + break; + + case CLOUD: + connector = new CloudConnector(Cloud + .connect(isNotBlank(config.baseUrl()) ? config.baseUrl() : "https://api.venafi.cloud")); + break; + default: + throw new VCertException("ConnectorType is not defined"); } - - @VisibleForTesting - VCertClient(Connector connector) { - this.connector = connector; + } + + @VisibleForTesting + VCertClient(Connector connector) { + this.connector = connector; + } + + + /** + * {@inheritDoc} + */ + @Override + public ConnectorType getType() { + return connector.getType(); + } + + /** + * {@inheritDoc} + */ + @Override + public void setBaseUrl(String url) throws VCertException { + connector.setBaseUrl(url); + + } + + /** + * {@inheritDoc} + */ + @Override + public void setZone(String zone) { + connector.setZone(zone); + } + + /** + * {@inheritDoc} + */ + @Override + public void ping() throws VCertException { + try { + connector.ping(); + } catch (FeignException e) { + throw VCertException.fromFeignException(e); + } catch (Exception e) { + throw new VCertException("Unexpected exception", e); } - - - /** - * {@inheritDoc} - */ - @Override - public ConnectorType getType() { - return connector.getType(); + } + + /** + * {@inheritDoc} + */ + @Override + public void authenticate(Authentication auth) throws VCertException { + try { + connector.authenticate(auth); + } catch (FeignException e) { + throw VCertException.fromFeignException(e); + } catch (Exception e) { + throw new VCertException("Unexpected exception", e); } - - /** - * {@inheritDoc} - */ - @Override - public void setBaseUrl(String url) throws VCertException { - connector.setBaseUrl(url); - + } + + /** + * {@inheritDoc} + */ + @Override + public ZoneConfiguration readZoneConfiguration(String zone) throws VCertException { + try { + return connector.readZoneConfiguration(zone); + } catch (FeignException e) { + throw VCertException.fromFeignException(e); + } catch (Exception e) { + throw new VCertException("Unexpected exception", e); } - - /** - * {@inheritDoc} - */ - @Override - public void setZone(String zone) { - connector.setZone(zone); + } + + /** + * {@inheritDoc} + */ + @Override + public CertificateRequest generateRequest(ZoneConfiguration config, CertificateRequest request) + throws VCertException { + try { + return connector.generateRequest(config, request); + } catch (FeignException e) { + throw VCertException.fromFeignException(e); + } catch (Exception e) { + throw new VCertException("Unexpected exception", e); } - - /** - * {@inheritDoc} - */ - @Override - public void ping() throws VCertException { - try { - connector.ping(); - } catch (FeignException e) { - throw VCertException.fromFeignException(e); - } catch (Exception e) { - throw new VCertException("Unexpected exception", e); - } + } + + /** + * {@inheritDoc} + */ + @Override + public String requestCertificate(CertificateRequest request, String zone) throws VCertException { + try { + return connector.requestCertificate(request, zone); + } catch (FeignException e) { + throw VCertException.fromFeignException(e); + } catch (Exception e) { + throw new VCertException("Unexpected exception", e); } - - /** - * {@inheritDoc} - */ - @Override - public void authenticate(Authentication auth) throws VCertException { - try { - connector.authenticate(auth); - } catch (FeignException e) { - throw VCertException.fromFeignException(e); - } catch (Exception e) { - throw new VCertException("Unexpected exception", e); - } + } + + /** + * {@inheritDoc} + */ + @Override + public PEMCollection retrieveCertificate(CertificateRequest request) throws VCertException { + try { + return connector.retrieveCertificate(request); + } catch (FeignException e) { + throw VCertException.fromFeignException(e); + } catch (Exception e) { + throw new VCertException("Unexpected exception", e); } - - /** - * {@inheritDoc} - */ - @Override - public ZoneConfiguration readZoneConfiguration(String zone) throws VCertException { - try { - return connector.readZoneConfiguration(zone); - } catch (FeignException e) { - throw VCertException.fromFeignException(e); - } catch (Exception e) { - throw new VCertException("Unexpected exception", e); - } + } + + /** + * {@inheritDoc} + */ + @Override + public void revokeCertificate(RevocationRequest request) throws VCertException { + try { + connector.revokeCertificate(request); + } catch (FeignException e) { + throw VCertException.fromFeignException(e); + } catch (Exception e) { + throw new VCertException("Unexpected exception", e); } - - /** - * {@inheritDoc} - */ - @Override - public CertificateRequest generateRequest(ZoneConfiguration config, CertificateRequest request) throws VCertException { - try { - return connector.generateRequest(config, request); - } catch (FeignException e) { - throw VCertException.fromFeignException(e); - } catch (Exception e) { - throw new VCertException("Unexpected exception", e); - } + } + + /** + * {@inheritDoc} + */ + @Override + public String renewCertificate(RenewalRequest request) throws VCertException { + try { + connector.renewCertificate(request); + } catch (FeignException e) { + throw VCertException.fromFeignException(e); + } catch (Exception e) { + throw new VCertException("Unexpected exception", e); } - - /** - * {@inheritDoc} - */ - @Override - public String requestCertificate(CertificateRequest request, String zone) throws VCertException { - try { - return connector.requestCertificate(request, zone); - } catch (FeignException e) { - throw VCertException.fromFeignException(e); - } catch (Exception e) { - throw new VCertException("Unexpected exception", e); - } + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public ImportResponse importCertificate(ImportRequest request) throws VCertException { + try { + connector.importCertificate(request); + } catch (FeignException e) { + throw VCertException.fromFeignException(e); + } catch (Exception e) { + throw new VCertException("Unexpected exception", e); } - - /** - * {@inheritDoc} - */ - @Override - public PEMCollection retrieveCertificate(CertificateRequest request) throws VCertException { - try { - return connector.retrieveCertificate(request); - } catch (FeignException e) { - throw VCertException.fromFeignException(e); - } catch (Exception e) { - throw new VCertException("Unexpected exception", e); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void revokeCertificate(RevocationRequest request) throws VCertException { - try { - connector.revokeCertificate(request); - } catch (FeignException e) { - throw VCertException.fromFeignException(e); - } catch (Exception e) { - throw new VCertException("Unexpected exception", e); - } - } - - /** - * {@inheritDoc} - */ - @Override - public String renewCertificate(RenewalRequest request) throws VCertException { - try { - connector.renewCertificate(request); - } catch (FeignException e) { - throw VCertException.fromFeignException(e); - } catch (Exception e) { - throw new VCertException("Unexpected exception", e); - } - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public ImportResponse importCertificate(ImportRequest request) throws VCertException { - try { - connector.importCertificate(request); - } catch (FeignException e) { - throw VCertException.fromFeignException(e); - } catch (Exception e) { - throw new VCertException("Unexpected exception", e); - } - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public Policy readPolicyConfiguration(String zone) throws VCertException { - try { - connector.readPolicyConfiguration(zone); - } catch (FeignException e) { - throw VCertException.fromFeignException(e); - } catch (Exception e) { - throw new VCertException("Unexpected exception", e); - } - return null; + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public Policy readPolicyConfiguration(String zone) throws VCertException { + try { + connector.readPolicyConfiguration(zone); + } catch (FeignException e) { + throw VCertException.fromFeignException(e); + } catch (Exception e) { + throw new VCertException("Unexpected exception", e); } + return null; + } } diff --git a/src/main/java/com/venafi/vcert/sdk/VCertException.java b/src/main/java/com/venafi/vcert/sdk/VCertException.java index 63470b9..357db31 100644 --- a/src/main/java/com/venafi/vcert/sdk/VCertException.java +++ b/src/main/java/com/venafi/vcert/sdk/VCertException.java @@ -1,74 +1,76 @@ package com.venafi.vcert.sdk; +import java.util.Collection; +import java.util.Objects; +import java.util.stream.Collectors; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.annotations.SerializedName; import feign.FeignException; import lombok.Data; -import java.util.Collection; -import java.util.Objects; -import java.util.stream.Collectors; - public class VCertException extends Exception { - public VCertException() { - super(); - } + public VCertException() { + super(); + } - public VCertException(String message) { - super(message); - } + public VCertException(String message) { + super(message); + } - public VCertException(Exception cause) { - super(cause); - } + public VCertException(Exception cause) { + super(cause); + } - public VCertException(String message, Exception cause) { - super(message, cause); - } + public VCertException(String message, Exception cause) { + super(message, cause); + } - public static void throwIfNull(Object testee, String message) throws VCertException { - if(testee != null) { - return; - } - if(message != null) { - throw new VCertException(message); - } - throw new VCertException(); + public static void throwIfNull(Object testee, String message) throws VCertException { + if (testee != null) { + return; } - - public static VCertException fromFeignException(FeignException feignException) { - Gson gson = new GsonBuilder().create(); - VenafiTppErrorResponse tppResponse = gson.fromJson(feignException.contentUTF8(), VenafiTppErrorResponse.class); - if(Objects.nonNull(tppResponse) && tppResponse.error() != null) { - return new VCertException( - feignException.getMessage() + ": " + tppResponse.error(), feignException); - } - VenafiCloudErrorResponse response = gson.fromJson(feignException.contentUTF8(), VenafiCloudErrorResponse.class); - if(Objects.nonNull(response) && response.errors() != null && !response.errors().isEmpty()) { - return new VCertException( - feignException.getMessage() + ": " - + response.errors().stream().map(VenafiServerError::message).collect(Collectors.joining(System.lineSeparator())), feignException); - } - return new VCertException(feignException); + if (message != null) { + throw new VCertException(message); } + throw new VCertException(); + } - @Data - private static class VenafiCloudErrorResponse { - private Collection errors; + public static VCertException fromFeignException(FeignException feignException) { + Gson gson = new GsonBuilder().create(); + VenafiTppErrorResponse tppResponse = + gson.fromJson(feignException.contentUTF8(), VenafiTppErrorResponse.class); + if (Objects.nonNull(tppResponse) && tppResponse.error() != null) { + return new VCertException(feignException.getMessage() + ": " + tppResponse.error(), + feignException); } - - @Data - private static class VenafiTppErrorResponse { - @SerializedName("Error") - private String error; + VenafiCloudErrorResponse response = + gson.fromJson(feignException.contentUTF8(), VenafiCloudErrorResponse.class); + if (Objects.nonNull(response) && response.errors() != null && !response.errors().isEmpty()) { + return new VCertException( + feignException.getMessage() + ": " + response.errors().stream() + .map(VenafiServerError::message).collect(Collectors.joining(System.lineSeparator())), + feignException); } + return new VCertException(feignException); + } - @Data - private static class VenafiServerError { - private int code; - private String message; - private Collection args; - } + @Data + private static class VenafiCloudErrorResponse { + private Collection errors; + } + + @Data + private static class VenafiTppErrorResponse { + @SerializedName("Error") + private String error; + } + + @Data + private static class VenafiServerError { + private int code; + private String message; + private Collection args; + } } diff --git a/src/main/java/com/venafi/vcert/sdk/certificate/CertificateRequest.java b/src/main/java/com/venafi/vcert/sdk/certificate/CertificateRequest.java index d6f143e..16f414d 100644 --- a/src/main/java/com/venafi/vcert/sdk/certificate/CertificateRequest.java +++ b/src/main/java/com/venafi/vcert/sdk/certificate/CertificateRequest.java @@ -1,321 +1,335 @@ package com.venafi.vcert.sdk.certificate; -import com.google.common.annotations.VisibleForTesting; -import com.venafi.vcert.sdk.SignatureAlgorithm; -import com.venafi.vcert.sdk.VCertException; -import lombok.Data; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x500.X500NameBuilder; -import org.bouncycastle.asn1.x500.style.BCStyle; -import org.bouncycastle.jce.PKCS10CertificationRequest; -import org.bouncycastle.util.io.pem.PemReader; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.GeneralNames; -import org.bouncycastle.asn1.x509.X509Extension; -import org.bouncycastle.asn1.x509.X509Extensions; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.Attribute; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSet; - -import javax.security.auth.x500.X500Principal; +import static java.lang.String.format; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.util.Collections.emptyList; +import static org.apache.commons.lang3.StringUtils.isBlank; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; import java.net.InetAddress; -import java.security.*; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; import java.security.cert.Certificate; -import java.security.interfaces.RSAPublicKey; import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPublicKey; import java.security.spec.ECGenParameterSpec; import java.time.Duration; +import java.util.ArrayList; +import java.util.Base64; import java.util.Collection; import java.util.List; import java.util.Objects; -import java.util.ArrayList; import java.util.Vector; -import java.util.Base64; - -import static java.lang.String.format; -import static java.time.temporal.ChronoUnit.MINUTES; -import static java.util.Collections.emptyList; -import static org.apache.commons.lang3.StringUtils.isBlank; +import javax.security.auth.x500.X500Principal; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSet; +import org.bouncycastle.asn1.pkcs.Attribute; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.asn1.x509.X509Extension; +import org.bouncycastle.asn1.x509.X509Extensions; +import org.bouncycastle.jce.PKCS10CertificationRequest; +import org.bouncycastle.util.io.pem.PemReader; +import com.google.common.annotations.VisibleForTesting; +import lombok.Data; +import com.venafi.vcert.sdk.SignatureAlgorithm; +import com.venafi.vcert.sdk.VCertException; @Data public class CertificateRequest { - private PKIXName subject; // TODO change to X500Name - private Collection dnsNames; - private Collection emailAddresses; - private Collection ipAddresses; - private Collection attributes; - private SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.UnknownSignatureAlgorithm; - private String friendlyName; - private KeyType keyType = KeyType.defaultKeyType(); - private int keyLength; - private EllipticCurve keyCurve; - private byte[] csr; - private KeyPair keyPair; - private CsrOriginOption csrOrigin = CsrOriginOption.defaultCsrOrigin(); - private String pickupId; - private ChainOption chainOption; - private String keyPassword; - private boolean fetchPrivateKey; - private String thumbprint; - private Duration timeout; - - public CertificateRequest() { - this.dnsNames = emptyList(); - this.emailAddresses = emptyList(); - this.ipAddresses = emptyList(); - this.attributes = emptyList(); - } - - public Duration timeout() { - return (!Objects.isNull(timeout)) - ?timeout - :Duration.of(5, MINUTES); - } - - public ChainOption chainOption() { - return (!Objects.isNull(chainOption)) - ?chainOption - :ChainOption.ChainOptionRootFirst; + private PKIXName subject; // TODO change to X500Name + private Collection dnsNames; + private Collection emailAddresses; + private Collection ipAddresses; + private Collection attributes; + private SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.UnknownSignatureAlgorithm; + private String friendlyName; + private KeyType keyType = KeyType.defaultKeyType(); + private int keyLength; + private EllipticCurve keyCurve; + private byte[] csr; + private KeyPair keyPair; + private CsrOriginOption csrOrigin = CsrOriginOption.defaultCsrOrigin(); + private String pickupId; + private ChainOption chainOption; + private String keyPassword; + private boolean fetchPrivateKey; + private String thumbprint; + private Duration timeout; + + public CertificateRequest() { + this.dnsNames = emptyList(); + this.emailAddresses = emptyList(); + this.ipAddresses = emptyList(); + this.attributes = emptyList(); + } + + public Duration timeout() { + return (!Objects.isNull(timeout)) ? timeout : Duration.of(5, MINUTES); + } + + public ChainOption chainOption() { + return (!Objects.isNull(chainOption)) ? chainOption : ChainOption.ChainOptionRootFirst; + } + + public PrivateKey privateKey() { + return (!Objects.isNull(keyPair)) ? keyPair.getPrivate() : null; + } + + public void generatePrivateKey() throws VCertException { + if (keyPair != null) { + return; } - - public PrivateKey privateKey() { - return (!Objects.isNull(keyPair)) - ?keyPair.getPrivate() - :null; - } - - public void generatePrivateKey() throws VCertException { - if(keyPair != null) { - return; - } - switch(keyType) { - case ECDSA: { - keyPair = generateECDSAKeyPair(keyCurve); - break; - } - case RSA: { - if(keyLength == 0) { - keyLength = KeyType.defaultRsaLength(); - } - keyPair = generateRSAKeyPair(keyLength); - break; - } - default: - throw new VCertException(format("Unable to generate certificate request, key type %s is not supported", keyType.name())); + switch (keyType) { + case ECDSA: { + keyPair = generateECDSAKeyPair(keyCurve); + break; + } + case RSA: { + if (keyLength == 0) { + keyLength = KeyType.defaultRsaLength(); } + keyPair = generateRSAKeyPair(keyLength); + break; + } + default: + throw new VCertException( + format("Unable to generate certificate request, key type %s is not supported", + keyType.name())); } - - public void generateCSR() throws VCertException { - try { - List sans = new ArrayList(); - - for ( String san : dnsNames ) { - sans.add(new GeneralName(GeneralName.dNSName, san)); - } - for ( InetAddress san : ipAddresses ) { - sans.add(new GeneralName(GeneralName.iPAddress, new DEROctetString(san.getAddress()))); - } - for ( String san : emailAddresses ) { - sans.add(new GeneralName(GeneralName.rfc822Name, san)); - } - - GeneralNames names = new GeneralNames(sans.toArray(new GeneralName[] {})); - Vector oids = new Vector(); - Vector values = new Vector(); - - oids.add(X509Extensions.SubjectAlternativeName); - values.add(new X509Extension(false, new DEROctetString(names))); - - X509Extensions extensions = new X509Extensions(oids, values); - Attribute attribute = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, new DERSet(extensions)); - - PKCS10CertificationRequest certificationRequest = new PKCS10CertificationRequest( - signatureAlgorithm.standardName(), - subject.toX500Principal(), - keyPair.getPublic(), - new DERSet(attribute), - keyPair.getPrivate()); - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - outputStream.write("-----BEGIN CERTIFICATE REQUEST-----".getBytes()); - outputStream.write(System.lineSeparator().getBytes()); - outputStream.write(Base64.getMimeEncoder().encode(certificationRequest.getEncoded())); - outputStream.write(System.lineSeparator().getBytes()); - outputStream.write("-----END CERTIFICATE REQUEST-----".getBytes()); - csr = outputStream.toByteArray(); - } catch(Exception e) { - throw new VCertException("Unable to generate CSR", e); - } + } + + public void generateCSR() throws VCertException { + try { + List sans = new ArrayList(); + + for (String san : dnsNames) { + sans.add(new GeneralName(GeneralName.dNSName, san)); + } + for (InetAddress san : ipAddresses) { + sans.add(new GeneralName(GeneralName.iPAddress, new DEROctetString(san.getAddress()))); + } + for (String san : emailAddresses) { + sans.add(new GeneralName(GeneralName.rfc822Name, san)); + } + + GeneralNames names = new GeneralNames(sans.toArray(new GeneralName[] {})); + Vector oids = new Vector(); + Vector values = new Vector(); + + oids.add(X509Extensions.SubjectAlternativeName); + values.add(new X509Extension(false, new DEROctetString(names))); + + X509Extensions extensions = new X509Extensions(oids, values); + Attribute attribute = + new Attribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, new DERSet(extensions)); + + PKCS10CertificationRequest certificationRequest = new PKCS10CertificationRequest( + signatureAlgorithm.standardName(), subject.toX500Principal(), keyPair.getPublic(), + new DERSet(attribute), keyPair.getPrivate()); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + outputStream.write("-----BEGIN CERTIFICATE REQUEST-----".getBytes()); + outputStream.write(System.lineSeparator().getBytes()); + outputStream.write(Base64.getMimeEncoder().encode(certificationRequest.getEncoded())); + outputStream.write(System.lineSeparator().getBytes()); + outputStream.write("-----END CERTIFICATE REQUEST-----".getBytes()); + csr = outputStream.toByteArray(); + } catch (Exception e) { + throw new VCertException("Unable to generate CSR", e); } - - @VisibleForTesting - KeyPair generateECDSAKeyPair(EllipticCurve keyCurve) throws VCertException { - try { - KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC"); - ECGenParameterSpec spec = new ECGenParameterSpec(keyCurve.bcName()); - g.initialize(spec); - return g.generateKeyPair(); - } catch (NoSuchAlgorithmException | NoSuchProviderException e) { - throw new VCertException("No security provider found for KeyFactory.EC", e); - } catch (InvalidAlgorithmParameterException e) { - throw new VCertException(format("No algorithmn provider for curve %s", keyCurve.bcName()) , e); - } + } + + @VisibleForTesting + KeyPair generateECDSAKeyPair(EllipticCurve keyCurve) throws VCertException { + try { + KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC"); + ECGenParameterSpec spec = new ECGenParameterSpec(keyCurve.bcName()); + g.initialize(spec); + return g.generateKeyPair(); + } catch (NoSuchAlgorithmException | NoSuchProviderException e) { + throw new VCertException("No security provider found for KeyFactory.EC", e); + } catch (InvalidAlgorithmParameterException e) { + throw new VCertException(format("No algorithmn provider for curve %s", keyCurve.bcName()), e); } - - @VisibleForTesting - KeyPair generateRSAKeyPair(Integer keyLength) throws VCertException { - try { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC"); - keyPairGenerator.initialize(keyLength); - return keyPairGenerator.generateKeyPair(); - } catch(NoSuchAlgorithmException e) { - throw new VCertException("No security provider found for KeyFactory.RSA", e); - } catch(NoSuchProviderException e) { - throw new VCertException(format("No algorithm provider for RSA with key length %s", Integer.toString(keyLength)) , e); - } + } + + @VisibleForTesting + KeyPair generateRSAKeyPair(Integer keyLength) throws VCertException { + try { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC"); + keyPairGenerator.initialize(keyLength); + return keyPairGenerator.generateKeyPair(); + } catch (NoSuchAlgorithmException e) { + throw new VCertException("No security provider found for KeyFactory.RSA", e); + } catch (NoSuchProviderException e) { + throw new VCertException( + format("No algorithm provider for RSA with key length %s", Integer.toString(keyLength)), + e); } + } - @Data - public static class PKIXName { - - private static void addAll(X500NameBuilder builder, ASN1ObjectIdentifier identifier, Collection values) { - if(values != null) { - values.stream().filter(Objects::nonNull).forEach(value -> builder.addRDN(identifier, value)); - } - } - - private String commonName; - private String serialNumber; - private List country; - private List organization; - private List organizationalUnit; - private List locality; - private List province; - private List streetAddress; - private List postalCode; - - private Collection names; - private Collection extraNames; - - public X500Principal toX500Principal() throws VCertException { - if(isBlank(commonName)) { - throw new VCertException("common name must not be null or emtpy"); - } - X500NameBuilder x500NameBuilder = new X500NameBuilder(); - x500NameBuilder.addRDN(BCStyle.CN, commonName); - addAll(x500NameBuilder, BCStyle.C, country); - addAll(x500NameBuilder, BCStyle.O, organization); - addAll(x500NameBuilder, BCStyle.OU, organizationalUnit); - addAll(x500NameBuilder, BCStyle.L, locality); - addAll(x500NameBuilder, BCStyle.ST, province); - addAll(x500NameBuilder, BCStyle.STREET, streetAddress); - addAll(x500NameBuilder, BCStyle.POSTAL_CODE, postalCode); - - // todo: serialNumber, names, extraNames - - return new X500Principal(x500NameBuilder.build().toString()); - } - } + @Data + public static class PKIXName { - // Todo do we need this? - @Data - public static class AttributeTypeAndValue { - private Collection type; - private Object value; + private static void addAll(X500NameBuilder builder, ASN1ObjectIdentifier identifier, + Collection values) { + if (values != null) { + values.stream().filter(Objects::nonNull) + .forEach(value -> builder.addRDN(identifier, value)); + } } - // Todo do we need this? - @Data - public static class AttributeTypeAndValueSET { - private Collection type; - private Collection> value; + private String commonName; + private String serialNumber; + private List country; + private List organization; + private List organizationalUnit; + private List locality; + private List province; + private List streetAddress; + private List postalCode; + + private Collection names; + private Collection extraNames; + + public X500Principal toX500Principal() throws VCertException { + if (isBlank(commonName)) { + throw new VCertException("common name must not be null or emtpy"); + } + X500NameBuilder x500NameBuilder = new X500NameBuilder(); + x500NameBuilder.addRDN(BCStyle.CN, commonName); + addAll(x500NameBuilder, BCStyle.C, country); + addAll(x500NameBuilder, BCStyle.O, organization); + addAll(x500NameBuilder, BCStyle.OU, organizationalUnit); + addAll(x500NameBuilder, BCStyle.L, locality); + addAll(x500NameBuilder, BCStyle.ST, province); + addAll(x500NameBuilder, BCStyle.STREET, streetAddress); + addAll(x500NameBuilder, BCStyle.POSTAL_CODE, postalCode); + + // todo: serialNumber, names, extraNames + + return new X500Principal(x500NameBuilder.build().toString()); } + } + + // Todo do we need this? + @Data + public static class AttributeTypeAndValue { + private Collection type; + private Object value; + } + + // Todo do we need this? + @Data + public static class AttributeTypeAndValueSET { + private Collection type; + private Collection> value; + } + + public boolean checkCertificate(Certificate certificate) throws VCertException { + PublicKeyAlgorithm publicKeyAlgorithm = + KeyType.from(certificate.getPublicKey().getAlgorithm()).X509Type(); + + if (keyPair != null && keyPair.getPublic() != null && keyPair.getPrivate() != null) { + if (keyType.X509Type() != publicKeyAlgorithm) { + throw new VCertException( + format("unmatched key type: %s, %s", keyType.X509Type(), publicKeyAlgorithm.name())); + } + switch (publicKeyAlgorithm) { + case RSA: + RSAPublicKey certPublicKey = (RSAPublicKey) certificate.getPublicKey(); + RSAPublicKey reqPublicKey = (RSAPublicKey) keyPair.getPublic(); + // TODO can be equals? + if (certPublicKey.getModulus().compareTo(reqPublicKey.getModulus()) != 0) { + throw new VCertException("unmatched key modules"); + } + break; + case ECDSA: + ECPublicKey certEcPublicKey = (ECPublicKey) certificate.getPublicKey(); + ECPublicKey reqEcPublicKey = (ECPublicKey) keyPair.getPublic(); + + // https://stackoverflow.com/questions/24121801/how-to-verify-if-the-private-key-matches-with-the-certificate + java.security.spec.ECParameterSpec certSpec = certEcPublicKey.getParams(), + csrSpec = reqEcPublicKey.getParams(); + java.security.spec.EllipticCurve certCurve = certSpec.getCurve(), + csrCurve = csrSpec.getCurve(); + java.security.spec.ECField certField = certCurve.getField(), + csrField = csrCurve.getField(); + if (certSpec != csrSpec // + && (certSpec.getCofactor() != csrSpec.getCofactor() // + || !certSpec.getOrder().equals(csrSpec.getOrder()) // + || !certSpec.getGenerator().equals(csrSpec.getGenerator()) // + || certCurve != csrCurve // + && (!certCurve.getA().equals(csrCurve.getA()) // + || !certCurve.getB().equals(csrCurve.getB()) // + || certField.getFieldSize() != csrField.getFieldSize()))) { + throw new VCertException("unmatched parameters for elliptic keys"); + } + break; + default: + throw new VCertException(format("unknown key algorithm %s", publicKeyAlgorithm.name())); + } + } else if (Objects.nonNull(csr) && csr.length != 0) { + try { + PemReader pemReader = new PemReader(new StringReader(new String(csr))); + PKCS10CertificationRequest csr = + new PKCS10CertificationRequest(pemReader.readPemObject().getContent()); + pemReader.close(); + + PublicKeyAlgorithm csrPublicKeyAlgorithm = + PublicKeyAlgorithm.valueOf(csr.getPublicKey("BC").getAlgorithm()); + if (publicKeyAlgorithm != csrPublicKeyAlgorithm) { + throw new VCertException( + format("unmatched key type: %s, %s", publicKeyAlgorithm, csrPublicKeyAlgorithm)); + } - public boolean checkCertificate(Certificate certificate) throws VCertException { - PublicKeyAlgorithm publicKeyAlgorithm = KeyType.from(certificate.getPublicKey().getAlgorithm()).X509Type(); - - if(keyPair != null && keyPair.getPublic() != null && keyPair.getPrivate() != null) { - if( keyType.X509Type() != publicKeyAlgorithm) { - throw new VCertException(format("unmatched key type: %s, %s", keyType.X509Type(), publicKeyAlgorithm.name())); - } - switch(publicKeyAlgorithm) { - case RSA: - RSAPublicKey certPublicKey = (RSAPublicKey) certificate.getPublicKey(); - RSAPublicKey reqPublicKey = (RSAPublicKey) keyPair.getPublic(); - // TODO can be equals? - if(certPublicKey.getModulus().compareTo(reqPublicKey.getModulus()) != 0) { - throw new VCertException("unmatched key modules"); - } - break; - case ECDSA: - ECPublicKey certEcPublicKey = (ECPublicKey) certificate.getPublicKey(); - ECPublicKey reqEcPublicKey = (ECPublicKey) keyPair.getPublic(); - - // https://stackoverflow.com/questions/24121801/how-to-verify-if-the-private-key-matches-with-the-certificate - java.security.spec.ECParameterSpec certSpec = certEcPublicKey.getParams(), csrSpec = reqEcPublicKey.getParams(); - java.security.spec.EllipticCurve certCurve = certSpec.getCurve(), csrCurve = csrSpec.getCurve(); - java.security.spec.ECField certField = certCurve.getField(), csrField = csrCurve.getField(); - if ( certSpec != csrSpec // - && ( certSpec.getCofactor() != csrSpec.getCofactor() // - || ! certSpec.getOrder().equals( csrSpec.getOrder() ) // - || ! certSpec.getGenerator().equals( csrSpec.getGenerator() ) // - || certCurve != csrCurve // - && ( ! certCurve.getA().equals( csrCurve.getA() ) // - || ! certCurve.getB().equals( csrCurve.getB() ) // - || certField.getFieldSize() != csrField.getFieldSize() ) ) ) { - throw new VCertException("unmatched parameters for elliptic keys"); - } - break; - default: - throw new VCertException(format("unknown key algorithm %s", publicKeyAlgorithm.name())); + switch (csrPublicKeyAlgorithm) { + case RSA: + RSAPublicKey certPublicKey = (RSAPublicKey) certificate.getPublicKey(); + RSAPublicKey reqPublicKey = (RSAPublicKey) csr.getPublicKey(); + if (certPublicKey.getModulus().compareTo(reqPublicKey.getModulus()) != 0) { + throw new VCertException("unmatched key modules"); } - } else if(Objects.nonNull(csr) && csr.length != 0) { - try { - PemReader pemReader = new PemReader(new StringReader(new String(csr))); - PKCS10CertificationRequest csr = new PKCS10CertificationRequest(pemReader.readPemObject().getContent()); - pemReader.close(); - - PublicKeyAlgorithm csrPublicKeyAlgorithm = PublicKeyAlgorithm.valueOf(csr.getPublicKey("BC").getAlgorithm()); - if(publicKeyAlgorithm != csrPublicKeyAlgorithm) { - throw new VCertException(format("unmatched key type: %s, %s", publicKeyAlgorithm, csrPublicKeyAlgorithm)); - } - - switch(csrPublicKeyAlgorithm) { - case RSA: - RSAPublicKey certPublicKey = (RSAPublicKey) certificate.getPublicKey(); - RSAPublicKey reqPublicKey = (RSAPublicKey) csr.getPublicKey(); - if(certPublicKey.getModulus().compareTo(reqPublicKey.getModulus()) != 0) { - throw new VCertException("unmatched key modules"); - } - break; - case ECDSA: - ECPublicKey certEcPublicKey = (ECPublicKey) certificate.getPublicKey(); - ECPublicKey reqEcPublicKey = (ECPublicKey) csr.getPublicKey(); - - // https://stackoverflow.com/questions/24121801/how-to-verify-if-the-private-key-matches-with-the-certificate - java.security.spec.ECParameterSpec certSpec = certEcPublicKey.getParams(), csrSpec = reqEcPublicKey.getParams(); - java.security.spec.EllipticCurve certCurve = certSpec.getCurve(), csrCurve = csrSpec.getCurve(); - java.security.spec.ECField certField = certCurve.getField(), csrField = csrCurve.getField(); - if ( certSpec != csrSpec // - && ( certSpec.getCofactor() != csrSpec.getCofactor() // - || ! certSpec.getOrder().equals( csrSpec.getOrder() ) // - || ! certSpec.getGenerator().equals( csrSpec.getGenerator() ) // - || certCurve != csrCurve // - && ( ! certCurve.getA().equals( csrCurve.getA() ) // - || ! certCurve.getB().equals( csrCurve.getB() ) // - || certField.getFieldSize() != csrField.getFieldSize() ) ) ) { - throw new VCertException("unmatched parameters for elliptic keys"); - } - break; - } - } catch(NoSuchAlgorithmException | NoSuchProviderException | InvalidKeyException | IOException e) { - throw new VCertException(format("bad csr: %s", e.getMessage()), e); + break; + case ECDSA: + ECPublicKey certEcPublicKey = (ECPublicKey) certificate.getPublicKey(); + ECPublicKey reqEcPublicKey = (ECPublicKey) csr.getPublicKey(); + + // https://stackoverflow.com/questions/24121801/how-to-verify-if-the-private-key-matches-with-the-certificate + java.security.spec.ECParameterSpec certSpec = certEcPublicKey.getParams(), + csrSpec = reqEcPublicKey.getParams(); + java.security.spec.EllipticCurve certCurve = certSpec.getCurve(), + csrCurve = csrSpec.getCurve(); + java.security.spec.ECField certField = certCurve.getField(), + csrField = csrCurve.getField(); + if (certSpec != csrSpec // + && (certSpec.getCofactor() != csrSpec.getCofactor() // + || !certSpec.getOrder().equals(csrSpec.getOrder()) // + || !certSpec.getGenerator().equals(csrSpec.getGenerator()) // + || certCurve != csrCurve // + && (!certCurve.getA().equals(csrCurve.getA()) // + || !certCurve.getB().equals(csrCurve.getB()) // + || certField.getFieldSize() != csrField.getFieldSize()))) { + throw new VCertException("unmatched parameters for elliptic keys"); } + break; } - return true; + } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeyException + | IOException e) { + throw new VCertException(format("bad csr: %s", e.getMessage()), e); + } } + return true; + } } diff --git a/src/main/java/com/venafi/vcert/sdk/certificate/CertificateStatus.java b/src/main/java/com/venafi/vcert/sdk/certificate/CertificateStatus.java index 8f5c053..b149cf5 100644 --- a/src/main/java/com/venafi/vcert/sdk/certificate/CertificateStatus.java +++ b/src/main/java/com/venafi/vcert/sdk/certificate/CertificateStatus.java @@ -1,30 +1,29 @@ package com.venafi.vcert.sdk.certificate; +import java.util.Collection; import com.google.gson.annotations.SerializedName; import lombok.Data; import lombok.ToString; -import java.util.Collection; - @Data @ToString public class CertificateStatus { - @SerializedName("Id") - private String id; - private String managedCertificateId; - private String zoneId; - private String status; - private CertificateStatueErrorInfomation errorInformation; - private String creationDate; - private String modificationDate; - private String certificateSigningRequest; - private String subjectDN; + @SerializedName("Id") + private String id; + private String managedCertificateId; + private String zoneId; + private String status; + private CertificateStatueErrorInfomation errorInformation; + private String creationDate; + private String modificationDate; + private String certificateSigningRequest; + private String subjectDN; - @Data - private static class CertificateStatueErrorInfomation { - private String type; - private Integer code; - private String message; - private Collection args; - } + @Data + private static class CertificateStatueErrorInfomation { + private String type; + private Integer code; + private String message; + private Collection args; + } } diff --git a/src/main/java/com/venafi/vcert/sdk/certificate/ChainOption.java b/src/main/java/com/venafi/vcert/sdk/certificate/ChainOption.java index 318b23e..db8142d 100644 --- a/src/main/java/com/venafi/vcert/sdk/certificate/ChainOption.java +++ b/src/main/java/com/venafi/vcert/sdk/certificate/ChainOption.java @@ -1,21 +1,22 @@ package com.venafi.vcert.sdk.certificate; public enum ChainOption { - //ChainOptionRootLast specifies the root certificate should be in the last position of the chain - ChainOptionRootLast, - //ChainOptionRootFirst specifies the root certificate should be in the first position of the chain - ChainOptionRootFirst, - //ChainOptionIgnore specifies the chain should be ignored - ChainOptionIgnore; + // ChainOptionRootLast specifies the root certificate should be in the last position of the chain + ChainOptionRootLast, + // ChainOptionRootFirst specifies the root certificate should be in the first position of the + // chain + ChainOptionRootFirst, + // ChainOptionIgnore specifies the chain should be ignored + ChainOptionIgnore; - public static ChainOption fromString(String order) { - switch(order.toLowerCase()) { - case "root-first": - return ChainOptionRootFirst; - case "ignore": - return ChainOptionIgnore; - default: - return ChainOptionRootLast; - } + public static ChainOption fromString(String order) { + switch (order.toLowerCase()) { + case "root-first": + return ChainOptionRootFirst; + case "ignore": + return ChainOptionIgnore; + default: + return ChainOptionRootLast; } -} \ No newline at end of file + } +} diff --git a/src/main/java/com/venafi/vcert/sdk/certificate/CsrOriginOption.java b/src/main/java/com/venafi/vcert/sdk/certificate/CsrOriginOption.java index 658a847..9c753a0 100644 --- a/src/main/java/com/venafi/vcert/sdk/certificate/CsrOriginOption.java +++ b/src/main/java/com/venafi/vcert/sdk/certificate/CsrOriginOption.java @@ -1,11 +1,11 @@ package com.venafi.vcert.sdk.certificate; public enum CsrOriginOption { - LocalGeneratedCSR, - ServiceGeneratedCSR, - UserProvidedCSR; + LocalGeneratedCSR, + ServiceGeneratedCSR, + UserProvidedCSR; - public static CsrOriginOption defaultCsrOrigin() { - return LocalGeneratedCSR; - } + public static CsrOriginOption defaultCsrOrigin() { + return LocalGeneratedCSR; + } } diff --git a/src/main/java/com/venafi/vcert/sdk/certificate/EllipticCurve.java b/src/main/java/com/venafi/vcert/sdk/certificate/EllipticCurve.java index 5ae553b..d615c07 100644 --- a/src/main/java/com/venafi/vcert/sdk/certificate/EllipticCurve.java +++ b/src/main/java/com/venafi/vcert/sdk/certificate/EllipticCurve.java @@ -1,49 +1,48 @@ package com.venafi.vcert.sdk.certificate; -import lombok.Getter; - import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import lombok.Getter; public enum EllipticCurve { - EllipticCurveP224("P224", "P-224"), - EllipticCurveP256("P256", "P-256"), - EllipticCurveP384("P384", "P-384"), - EllipticCurveP521("P521", "P-521"); + EllipticCurveP224("P224", "P-224"), + EllipticCurveP256("P256", "P-256"), + EllipticCurveP384("P384", "P-384"), + EllipticCurveP521("P521", "P-521"); - @Getter - private final String value; + @Getter + private final String value; - @Getter - private final String bcName; + @Getter + private final String bcName; - EllipticCurve(String value, String bcName) { - this.value = value; - this.bcName = bcName; - } + EllipticCurve(String value, String bcName) { + this.value = value; + this.bcName = bcName; + } - private static Map LOOKUP = new HashMap<>(EllipticCurve.values().length); + private static Map LOOKUP = new HashMap<>(EllipticCurve.values().length); - static { - for(EllipticCurve curve : EllipticCurve.values()) { - LOOKUP.put(curve.value().toLowerCase(), curve); - } + static { + for (EllipticCurve curve : EllipticCurve.values()) { + LOOKUP.put(curve.value().toLowerCase(), curve); } + } - public static EllipticCurve from(String value) { - if(LOOKUP.containsKey(value.toLowerCase())) { - return LOOKUP.get(value.toLowerCase()); - } - return ellipticCurveDefault(); + public static EllipticCurve from(String value) { + if (LOOKUP.containsKey(value.toLowerCase())) { + return LOOKUP.get(value.toLowerCase()); } + return ellipticCurveDefault(); + } - public static EllipticCurve ellipticCurveDefault() { - return EllipticCurveP521; - } + public static EllipticCurve ellipticCurveDefault() { + return EllipticCurveP521; + } - public static List allSupportedCures() { - return Arrays.asList(EllipticCurve.values()); - } + public static List allSupportedCures() { + return Arrays.asList(EllipticCurve.values()); + } } diff --git a/src/main/java/com/venafi/vcert/sdk/certificate/ImportRequest.java b/src/main/java/com/venafi/vcert/sdk/certificate/ImportRequest.java index bb6ca5a..d5e2195 100644 --- a/src/main/java/com/venafi/vcert/sdk/certificate/ImportRequest.java +++ b/src/main/java/com/venafi/vcert/sdk/certificate/ImportRequest.java @@ -1,16 +1,15 @@ package com.venafi.vcert.sdk.certificate; -import lombok.Data; - import java.util.Map; +import lombok.Data; @Data public class ImportRequest { - String policyDN; - String objectName; - String certificateData; - String privateKeyData; - String password; - boolean reconcile; - Map cASpecificAttributes; + String policyDN; + String objectName; + String certificateData; + String privateKeyData; + String password; + boolean reconcile; + Map cASpecificAttributes; } diff --git a/src/main/java/com/venafi/vcert/sdk/certificate/ImportResponse.java b/src/main/java/com/venafi/vcert/sdk/certificate/ImportResponse.java index e29e3ef..437ce3c 100644 --- a/src/main/java/com/venafi/vcert/sdk/certificate/ImportResponse.java +++ b/src/main/java/com/venafi/vcert/sdk/certificate/ImportResponse.java @@ -4,8 +4,8 @@ @Data public class ImportResponse { - private String certificateDN; - private int certificateVaultId; - private String guid; - private int privateKeyVaultId; + private String certificateDN; + private int certificateVaultId; + private String guid; + private int privateKeyVaultId; } diff --git a/src/main/java/com/venafi/vcert/sdk/certificate/KeyType.java b/src/main/java/com/venafi/vcert/sdk/certificate/KeyType.java index 427f688..610c822 100644 --- a/src/main/java/com/venafi/vcert/sdk/certificate/KeyType.java +++ b/src/main/java/com/venafi/vcert/sdk/certificate/KeyType.java @@ -4,38 +4,41 @@ import java.util.List; public enum KeyType { - RSA, ECDSA; + RSA, ECDSA; - public static KeyType from(String value) { - switch (value.toLowerCase()) { - case "rsa": return RSA; - case "ecdsa": - case "ec": - case "ecc": return ECDSA; - default: throw new IllegalArgumentException(String.format("unknown key type: %s", value)); - } + public static KeyType from(String value) { + switch (value.toLowerCase()) { + case "rsa": + return RSA; + case "ecdsa": + case "ec": + case "ecc": + return ECDSA; + default: + throw new IllegalArgumentException(String.format("unknown key type: %s", value)); } + } - public PublicKeyAlgorithm X509Type() { - switch(this) { - case RSA: - return PublicKeyAlgorithm.RSA; - case ECDSA: - return PublicKeyAlgorithm.ECDSA; - default: - return PublicKeyAlgorithm.Unknown; - } + public PublicKeyAlgorithm X509Type() { + switch (this) { + case RSA: + return PublicKeyAlgorithm.RSA; + case ECDSA: + return PublicKeyAlgorithm.ECDSA; + default: + return PublicKeyAlgorithm.Unknown; } + } - public static List allSupportedKeySizes() { - return Arrays.asList(512, 1024, 2048, 4096, 8192); - } + public static List allSupportedKeySizes() { + return Arrays.asList(512, 1024, 2048, 4096, 8192); + } - public static Integer defaultRsaLength() { - return 2048; - } + public static Integer defaultRsaLength() { + return 2048; + } - public static KeyType defaultKeyType() { - return RSA; - } + public static KeyType defaultKeyType() { + return RSA; + } } diff --git a/src/main/java/com/venafi/vcert/sdk/certificate/ManagedCertificate.java b/src/main/java/com/venafi/vcert/sdk/certificate/ManagedCertificate.java index 46f18e0..d7d7625 100644 --- a/src/main/java/com/venafi/vcert/sdk/certificate/ManagedCertificate.java +++ b/src/main/java/com/venafi/vcert/sdk/certificate/ManagedCertificate.java @@ -4,8 +4,8 @@ @Data public class ManagedCertificate { - private String id; - private String companyId; - private String latestCertificateRequestId; - private String certificateName; + private String id; + private String companyId; + private String latestCertificateRequestId; + private String certificateName; } diff --git a/src/main/java/com/venafi/vcert/sdk/certificate/PEMCollection.java b/src/main/java/com/venafi/vcert/sdk/certificate/PEMCollection.java index 61bb34c..c0f171f 100644 --- a/src/main/java/com/venafi/vcert/sdk/certificate/PEMCollection.java +++ b/src/main/java/com/venafi/vcert/sdk/certificate/PEMCollection.java @@ -1,161 +1,165 @@ package com.venafi.vcert.sdk.certificate; -import com.venafi.vcert.sdk.VCertException; -import lombok.Data; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; -import org.bouncycastle.openssl.PEMKeyPair; -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.util.io.pem.PemObject; -import org.bouncycastle.util.io.pem.PemWriter; - +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; import java.io.StringReader; import java.security.PrivateKey; import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.io.ByteArrayOutputStream; -import java.io.OutputStreamWriter; -import java.security.cert.CertificateEncodingException; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemWriter; +import lombok.Data; +import com.venafi.vcert.sdk.VCertException; @Data public class PEMCollection { - private Certificate certificate; - private PrivateKey privateKey; - private List chain = new ArrayList<>(); - - public static PEMCollection fromResponse(String body, ChainOption chainOption, PrivateKey privateKey) throws VCertException { - List chain = new ArrayList<>(); + private Certificate certificate; + private PrivateKey privateKey; + private List chain = new ArrayList<>(); - PEMParser pemParser = new PEMParser(new StringReader(body)); - JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter(); - JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); - try { - Object object = pemParser.readObject(); - while(object != null) { - if(object instanceof X509CertificateHolder) { - Certificate certificate = certificateConverter.getCertificate((X509CertificateHolder) object); - chain.add(certificate); - } else if(object instanceof PEMKeyPair) { - privateKey = keyConverter.getPrivateKey(((PEMKeyPair) object).getPrivateKeyInfo()); - } + public static PEMCollection fromResponse(String body, ChainOption chainOption, + PrivateKey privateKey) throws VCertException { + List chain = new ArrayList<>(); - object = pemParser.readObject(); - } - } catch(IOException | CertificateException e) { - throw new VCertException("Unable to parse certificate from response", e); + PEMParser pemParser = new PEMParser(new StringReader(body)); + JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter(); + JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); + try { + Object object = pemParser.readObject(); + while (object != null) { + if (object instanceof X509CertificateHolder) { + Certificate certificate = + certificateConverter.getCertificate((X509CertificateHolder) object); + chain.add(certificate); + } else if (object instanceof PEMKeyPair) { + privateKey = keyConverter.getPrivateKey(((PEMKeyPair) object).getPrivateKeyInfo()); } - PEMCollection pemCollection; - if(chain.size() > 0) { - switch(chainOption) { - case ChainOptionRootFirst: - pemCollection = newPemCollection(chain.get(chain.size() - 1), null, null); - if(chain.size() > 1 && chainOption != ChainOption.ChainOptionIgnore) { - for(int i = 0; i < chain.size() - 1; i++) { - pemCollection.chain().add(chain.get(i)); - } - } - break; - default: - pemCollection = newPemCollection(chain.get(0), null, null); - if(chain.size() > 1 && chainOption != ChainOption.ChainOptionIgnore) { - for(int i = 1; i < chain.size(); i++) { - pemCollection.chain().add(chain.get(i)); - } - } - break; - } - } else { - pemCollection = new PEMCollection(); - } - pemCollection.privateKey(privateKey); - - return pemCollection; + object = pemParser.readObject(); + } + } catch (IOException | CertificateException e) { + throw new VCertException("Unable to parse certificate from response", e); } - public static PEMCollection fromResponse(String body, ChainOption chainOption) throws VCertException { - return fromResponse(body, chainOption, null); + PEMCollection pemCollection; + if (chain.size() > 0) { + switch (chainOption) { + case ChainOptionRootFirst: + pemCollection = newPemCollection(chain.get(chain.size() - 1), null, null); + if (chain.size() > 1 && chainOption != ChainOption.ChainOptionIgnore) { + for (int i = 0; i < chain.size() - 1; i++) { + pemCollection.chain().add(chain.get(i)); + } + } + break; + default: + pemCollection = newPemCollection(chain.get(0), null, null); + if (chain.size() > 1 && chainOption != ChainOption.ChainOptionIgnore) { + for (int i = 1; i < chain.size(); i++) { + pemCollection.chain().add(chain.get(i)); + } + } + break; + } + } else { + pemCollection = new PEMCollection(); } + pemCollection.privateKey(privateKey); - // TODO deal with password? is it required? - public static PEMCollection newPemCollection(Certificate certificate, PrivateKey privateKey, byte[] privateKeyPassword) { - PEMCollection pemCollection = new PEMCollection(); - pemCollection.certificate(certificate); - if(privateKey != null) { - pemCollection.privateKey(privateKey); - } - return pemCollection; + return pemCollection; + } + + public static PEMCollection fromResponse(String body, ChainOption chainOption) + throws VCertException { + return fromResponse(body, chainOption, null); + } + + // TODO deal with password? is it required? + public static PEMCollection newPemCollection(Certificate certificate, PrivateKey privateKey, + byte[] privateKeyPassword) { + PEMCollection pemCollection = new PEMCollection(); + pemCollection.certificate(certificate); + if (privateKey != null) { + pemCollection.privateKey(privateKey); } + return pemCollection; + } - public String pemCertificate() { - String pem = null; - if (!Objects.isNull(this.certificate)) { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStream))) { - pemWriter.writeObject(new PemObject("CERTIFICATE", this.certificate.getEncoded())); - } catch (CertificateEncodingException e) { - throw new RuntimeException(e); - } catch (IOException e) { - throw new RuntimeException(e); - } - pem = new String(outputStream.toByteArray()); - } - return pem; + public String pemCertificate() { + String pem = null; + if (!Objects.isNull(this.certificate)) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStream))) { + pemWriter.writeObject(new PemObject("CERTIFICATE", this.certificate.getEncoded())); + } catch (CertificateEncodingException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + pem = new String(outputStream.toByteArray()); } + return pem; + } - public String pemPrivateKey() { - String pem = null; - if (!Objects.isNull(this.privateKey)) { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - switch(KeyType.from(this.privateKey.getAlgorithm())) { - case RSA: - try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStream))) { - PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(this.privateKey.getEncoded()); - ASN1Encodable privateKeyPKCS1ASN1Encodable = pkInfo.parsePrivateKey(); - ASN1Primitive privateKeyPKCS1ASN1 = privateKeyPKCS1ASN1Encodable.toASN1Primitive(); - pemWriter.writeObject(new PemObject("RSA PRIVATE KEY", privateKeyPKCS1ASN1.getEncoded())); - } catch (IOException e) { - throw new RuntimeException(e); - } - pem = new String(outputStream.toByteArray()); - break; - case ECDSA: - try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStream))) { - pemWriter.writeObject(new PemObject("EC PRIVATE KEY", this.privateKey.getEncoded())); - } catch (IOException e) { - throw new RuntimeException(e); - } - pem = new String(outputStream.toByteArray()); - break; - } - } - return pem; + public String pemPrivateKey() { + String pem = null; + if (!Objects.isNull(this.privateKey)) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + switch (KeyType.from(this.privateKey.getAlgorithm())) { + case RSA: + try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStream))) { + PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(this.privateKey.getEncoded()); + ASN1Encodable privateKeyPKCS1ASN1Encodable = pkInfo.parsePrivateKey(); + ASN1Primitive privateKeyPKCS1ASN1 = privateKeyPKCS1ASN1Encodable.toASN1Primitive(); + pemWriter + .writeObject(new PemObject("RSA PRIVATE KEY", privateKeyPKCS1ASN1.getEncoded())); + } catch (IOException e) { + throw new RuntimeException(e); + } + pem = new String(outputStream.toByteArray()); + break; + case ECDSA: + try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStream))) { + pemWriter.writeObject(new PemObject("EC PRIVATE KEY", this.privateKey.getEncoded())); + } catch (IOException e) { + throw new RuntimeException(e); + } + pem = new String(outputStream.toByteArray()); + break; + } } + return pem; + } - public String pemCertificateChain() { - StringBuilder pem = new StringBuilder(); - if (!Objects.isNull(this.chain)) { - for(Certificate cert : this.chain) { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStream))) { - pemWriter.writeObject(new PemObject("CERTIFICATE", cert.getEncoded())); - } catch (CertificateEncodingException e) { - throw new RuntimeException(e); - } catch (IOException e) { - throw new RuntimeException(e); - } - pem.append(new String(outputStream.toByteArray())); - } + public String pemCertificateChain() { + StringBuilder pem = new StringBuilder(); + if (!Objects.isNull(this.chain)) { + for (Certificate cert : this.chain) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStream))) { + pemWriter.writeObject(new PemObject("CERTIFICATE", cert.getEncoded())); + } catch (CertificateEncodingException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); } - return pem.toString(); + pem.append(new String(outputStream.toByteArray())); + } } + return pem.toString(); + } } diff --git a/src/main/java/com/venafi/vcert/sdk/certificate/PublicKeyAlgorithm.java b/src/main/java/com/venafi/vcert/sdk/certificate/PublicKeyAlgorithm.java index 78f2fae..b717d10 100644 --- a/src/main/java/com/venafi/vcert/sdk/certificate/PublicKeyAlgorithm.java +++ b/src/main/java/com/venafi/vcert/sdk/certificate/PublicKeyAlgorithm.java @@ -1,8 +1,8 @@ package com.venafi.vcert.sdk.certificate; public enum PublicKeyAlgorithm { - Unknown, - RSA, - DSA, - ECDSA + Unknown, + RSA, + DSA, + ECDSA } diff --git a/src/main/java/com/venafi/vcert/sdk/certificate/RenewalRequest.java b/src/main/java/com/venafi/vcert/sdk/certificate/RenewalRequest.java index e591db8..35e2343 100644 --- a/src/main/java/com/venafi/vcert/sdk/certificate/RenewalRequest.java +++ b/src/main/java/com/venafi/vcert/sdk/certificate/RenewalRequest.java @@ -6,7 +6,7 @@ @Data @NoArgsConstructor public class RenewalRequest { - private String certificateDN; - private String thumbprint; - private CertificateRequest request; + private String certificateDN; + private String thumbprint; + private CertificateRequest request; } diff --git a/src/main/java/com/venafi/vcert/sdk/certificate/RevocationRequest.java b/src/main/java/com/venafi/vcert/sdk/certificate/RevocationRequest.java index 9c60383..3e5fc66 100644 --- a/src/main/java/com/venafi/vcert/sdk/certificate/RevocationRequest.java +++ b/src/main/java/com/venafi/vcert/sdk/certificate/RevocationRequest.java @@ -1,18 +1,17 @@ package com.venafi.vcert.sdk.certificate; -import lombok.Data; - import java.util.Objects; +import lombok.Data; @Data public class RevocationRequest { - private String certificateDN; - private String thumbprint; - private String reason; - private String comments; - private boolean disable; + private String certificateDN; + private String thumbprint; + private String reason; + private String comments; + private boolean disable; - public String reason(){ - return Objects.nonNull(reason)? reason : ""; - } + public String reason() { + return Objects.nonNull(reason) ? reason : ""; + } } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/Connector.java b/src/main/java/com/venafi/vcert/sdk/connectors/Connector.java index 6d30ec1..2c28efc 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/Connector.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/Connector.java @@ -1,105 +1,125 @@ package com.venafi.vcert.sdk.connectors; import com.venafi.vcert.sdk.VCertException; -import com.venafi.vcert.sdk.certificate.*; +import com.venafi.vcert.sdk.certificate.CertificateRequest; +import com.venafi.vcert.sdk.certificate.ImportRequest; +import com.venafi.vcert.sdk.certificate.ImportResponse; +import com.venafi.vcert.sdk.certificate.PEMCollection; +import com.venafi.vcert.sdk.certificate.RenewalRequest; +import com.venafi.vcert.sdk.certificate.RevocationRequest; import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; import com.venafi.vcert.sdk.endpoint.Authentication; import com.venafi.vcert.sdk.endpoint.ConnectorType; public interface Connector { - /** - * @return ConnectorType the type of connector Cloud or TPP - */ - ConnectorType getType(); + /** + * @return ConnectorType the type of connector Cloud or TPP + */ + ConnectorType getType(); - /** - * Allows overriding the default URL used to communicate with Venafi - * @param url - * @throws VCertException - */ - void setBaseUrl(String url) throws VCertException; + /** + * Allows overriding the default URL used to communicate with Venafi + * + * @param url + * @throws VCertException + */ + void setBaseUrl(String url) throws VCertException; - /** - * Set the default zone - * @param zone - */ - void setZone(String zone); + /** + * Set the default zone + * + * @param zone + */ + void setZone(String zone); - /** - * Attempt to connect the Venafi API and returns an error if it cannot - * @throws VCertException - */ - void ping() throws VCertException; + /** + * Attempt to connect the Venafi API and returns an error if it cannot + * + * @throws VCertException + */ + void ping() throws VCertException; - /** - * Authenticate the user with Venafi using either API key for venafi Cloud or user and password for TPP - * @param auth - * @throws VCertException - */ - void authenticate(Authentication auth) throws VCertException; + /** + * Authenticate the user with Venafi using either API key for venafi Cloud or user and password + * for TPP + * + * @param auth + * @throws VCertException + */ + void authenticate(Authentication auth) throws VCertException; - /** - * Reads the zone configuration needed for generating and requesting a certificate - * @param zone - * @return - * @throws VCertException - */ - ZoneConfiguration readZoneConfiguration(String zone) throws VCertException; + /** + * Reads the zone configuration needed for generating and requesting a certificate + * + * @param zone + * @return + * @throws VCertException + */ + ZoneConfiguration readZoneConfiguration(String zone) throws VCertException; - /** - * GenerateRequest creates a new certificate request, based on the zone/policy configuration and the user data - * @param config - * @return - * @throws VCertException - */ - CertificateRequest generateRequest(ZoneConfiguration config, CertificateRequest request) throws VCertException; + /** + * GenerateRequest creates a new certificate request, based on the zone/policy configuration and + * the user data + * + * @param config + * @return + * @throws VCertException + */ + CertificateRequest generateRequest(ZoneConfiguration config, CertificateRequest request) + throws VCertException; - /** - * Submits the CSR to venafi for processing - * @param request - * @param zone - * @return request id to track the certificate status. - * @throws VCertException - */ - String requestCertificate(CertificateRequest request, String zone) throws VCertException; + /** + * Submits the CSR to venafi for processing + * + * @param request + * @param zone + * @return request id to track the certificate status. + * @throws VCertException + */ + String requestCertificate(CertificateRequest request, String zone) throws VCertException; - /** - * Retrives the certificate for the specific ID - * @param request - * @return A collection of PEM files including certificate, chain and potentially a private key. - * @throws VCertException - */ - PEMCollection retrieveCertificate(CertificateRequest request) throws VCertException; + /** + * Retrives the certificate for the specific ID + * + * @param request + * @return A collection of PEM files including certificate, chain and potentially a private key. + * @throws VCertException + */ + PEMCollection retrieveCertificate(CertificateRequest request) throws VCertException; - /** - * Attempts to revoke a certificate - * @param request - * @throws VCertException - */ - void revokeCertificate(RevocationRequest request) throws VCertException; + /** + * Attempts to revoke a certificate + * + * @param request + * @throws VCertException + */ + void revokeCertificate(RevocationRequest request) throws VCertException; - /** - * Attempts to renew a certificate - * @param request - * @return - * @throws VCertException - */ - String renewCertificate(RenewalRequest request) throws VCertException; + /** + * Attempts to renew a certificate + * + * @param request + * @return + * @throws VCertException + */ + String renewCertificate(RenewalRequest request) throws VCertException; - /** - * Import an external certificate into venafi. - * @param request - * @return - * @throws VCertException - */ - ImportResponse importCertificate(ImportRequest request) throws VCertException; + /** + * Import an external certificate into venafi. + * + * @param request + * @return + * @throws VCertException + */ + ImportResponse importCertificate(ImportRequest request) throws VCertException; - /** - * Reads the policy configuration for a specific zone in venafi - * @param zone - * @return - * @throws VCertException - */ - Policy readPolicyConfiguration(String zone) throws VCertException; + /** + * Reads the policy configuration for a specific zone in venafi + * + * @param zone + * @return + * @throws VCertException + */ + Policy readPolicyConfiguration(String zone) throws VCertException; } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/LockableValue.java b/src/main/java/com/venafi/vcert/sdk/connectors/LockableValue.java index 323302e..bf51af8 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/LockableValue.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/LockableValue.java @@ -8,6 +8,6 @@ @AllArgsConstructor @VisibleForTesting public class LockableValue { - boolean locked; - T value; + boolean locked; + T value; } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/LockableValues.java b/src/main/java/com/venafi/vcert/sdk/connectors/LockableValues.java index 70a7bc5..011798f 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/LockableValues.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/LockableValues.java @@ -1,15 +1,14 @@ package com.venafi.vcert.sdk.connectors; +import java.util.List; import com.google.common.annotations.VisibleForTesting; import lombok.AllArgsConstructor; import lombok.Data; -import java.util.List; - @Data @AllArgsConstructor @VisibleForTesting public class LockableValues { - boolean locked; - List values; + boolean locked; + List values; } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/Policy.java b/src/main/java/com/venafi/vcert/sdk/connectors/Policy.java index c638845..4e6282c 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/Policy.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/Policy.java @@ -1,25 +1,24 @@ package com.venafi.vcert.sdk.connectors; -import com.venafi.vcert.sdk.endpoint.AllowedKeyConfiguration; -import lombok.Data; - import java.util.Collection; import java.util.List; +import lombok.Data; +import com.venafi.vcert.sdk.endpoint.AllowedKeyConfiguration; @Data public class Policy { - private Collection subjectCNRegexes; - private Collection subjectORegexes; - private Collection subjectOURegexes; - private Collection subjectSTRegexes; - private Collection subjectLRegexes; - private Collection subjectCRegexes; - private List allowedKeyConfigurations; - private Collection dnsSanRegExs; - private Collection ipSanRegExs; - private Collection emailSanRegExs; - private Collection uriSanRegExs; - private Collection upnSanRegExs; - private boolean allowWildcards; - private boolean allowKeyReuse; + private Collection subjectCNRegexes; + private Collection subjectORegexes; + private Collection subjectOURegexes; + private Collection subjectSTRegexes; + private Collection subjectLRegexes; + private Collection subjectCRegexes; + private List allowedKeyConfigurations; + private Collection dnsSanRegExs; + private Collection ipSanRegExs; + private Collection emailSanRegExs; + private Collection uriSanRegExs; + private Collection upnSanRegExs; + private boolean allowWildcards; + private boolean allowKeyReuse; } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/ServerPolicy.java b/src/main/java/com/venafi/vcert/sdk/connectors/ServerPolicy.java index aad9de2..75610ad 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/ServerPolicy.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/ServerPolicy.java @@ -1,177 +1,184 @@ package com.venafi.vcert.sdk.connectors; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.function.Function; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import com.google.common.annotations.VisibleForTesting; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; import com.venafi.vcert.sdk.SignatureAlgorithm; import com.venafi.vcert.sdk.certificate.EllipticCurve; import com.venafi.vcert.sdk.certificate.KeyType; import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; import com.venafi.vcert.sdk.endpoint.AllowedKeyConfiguration; import com.venafi.vcert.sdk.utils.Is; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.*; -import java.util.function.Function; -import java.util.regex.Pattern; -import java.util.stream.Collectors; @Data @NoArgsConstructor // for testing @AllArgsConstructor public class ServerPolicy { - private static transient final String allAllowedRegex = ".*"; - public static transient final Function addStartEnd = s -> { - if (!s.startsWith("^")) { - s = "^" + s; - } - if(!s.endsWith("$")) { - s += "$"; - } - return s; + private static transient final String allAllowedRegex = ".*"; + public static transient final Function addStartEnd = s -> { + if (!s.startsWith("^")) { + s = "^" + s; + } + if (!s.endsWith("$")) { + s += "$"; + } + return s; + }; + + private LockableValue certificateAuthority; + private LockableValue csrGeneration; + private LockableValue keyGeneration; + private KeyPair keyPair; + private LockableValue managementType; + + private boolean privateKeyReuseAllowed; + private boolean subjAltNameDnsAllowed; + private boolean subjAltNameEmailAllowed; + private boolean subjAltNameIpAllowed; + private boolean subjAltNameUpnAllowed; + private boolean subjAltNameUriAllowed; + private Subject subject; + private boolean uniqueSubjectEnforced; + private Collection whitelistedDomains; + private boolean wildcardsAllowed; + + public Policy toPolicy() { + Function escapeOne = s -> addStartEnd.apply(Pattern.quote(s)); + Function, Collection> escapeCollection = + in -> in.stream().map(escapeOne).collect(Collectors.toList()); + Function, Collection> selectValue = in -> { + if (null == in) { + return Collections.singleton(allAllowedRegex); // Go would provide empty structs with + // default values, so in Java, we have to + // deal with null instead + } + return in.locked() ? Collections.singleton(escapeOne.apply(in.value())) + : Collections.singleton(allAllowedRegex); }; - - private LockableValue certificateAuthority; - private LockableValue csrGeneration; - private LockableValue keyGeneration; - private KeyPair keyPair; - private LockableValue managementType; - - private boolean privateKeyReuseAllowed; - private boolean subjAltNameDnsAllowed; - private boolean subjAltNameEmailAllowed; - private boolean subjAltNameIpAllowed; - private boolean subjAltNameUpnAllowed; - private boolean subjAltNameUriAllowed; - private Subject subject; - private boolean uniqueSubjectEnforced; - private Collection whitelistedDomains; - private boolean wildcardsAllowed; - - public Policy toPolicy() { - Function escapeOne = s -> addStartEnd.apply(Pattern.quote(s)); - Function, Collection> escapeCollection = in -> in.stream().map(escapeOne).collect(Collectors.toList()); - Function, Collection> selectValue = in -> { - if(null == in) { - return Collections.singleton(allAllowedRegex); // Go would provide empty structs with default values, so in Java, we have to deal with null instead - } - return in.locked() ? - Collections.singleton(escapeOne.apply(in.value())) : - Collections.singleton(allAllowedRegex); - }; - Function> allOrNothing = bool -> bool ? Collections.singleton(allAllowedRegex) : Collections.emptyList(); - - Policy policy = new Policy().allowedKeyConfigurations(new ArrayList<>()); - if(Is.blank(whitelistedDomains)) { - policy.subjectCNRegexes(Collections.singleton(allAllowedRegex)); + Function> allOrNothing = + bool -> bool ? Collections.singleton(allAllowedRegex) : Collections.emptyList(); + + Policy policy = new Policy().allowedKeyConfigurations(new ArrayList<>()); + if (Is.blank(whitelistedDomains)) { + policy.subjectCNRegexes(Collections.singleton(allAllowedRegex)); + } else { + ArrayList subjectCNRegexes = new ArrayList<>(whitelistedDomains.size()); + for (String whitelistedDomain : whitelistedDomains()) { + if (wildcardsAllowed()) { + subjectCNRegexes + .add(addStartEnd.apply(allAllowedRegex + Pattern.quote("." + whitelistedDomain))); } else { - ArrayList subjectCNRegexes = new ArrayList<>(whitelistedDomains.size()); - for(String whitelistedDomain : whitelistedDomains()) { - if(wildcardsAllowed()) { - subjectCNRegexes.add(addStartEnd.apply(allAllowedRegex + Pattern.quote("." + whitelistedDomain))); - } else { - subjectCNRegexes.add(escapeOne.apply(whitelistedDomain)); - } - } - policy.subjectCNRegexes(subjectCNRegexes); - + subjectCNRegexes.add(escapeOne.apply(whitelistedDomain)); } - if(this.subject.organizationalUnit().locked()) { - policy.subjectOURegexes(escapeCollection.apply(this.subject.organizationalUnit().values())); - } else { - policy.subjectOURegexes(Collections.singleton(allAllowedRegex)); + } + policy.subjectCNRegexes(subjectCNRegexes); + + } + if (this.subject.organizationalUnit().locked()) { + policy.subjectOURegexes(escapeCollection.apply(this.subject.organizationalUnit().values())); + } else { + policy.subjectOURegexes(Collections.singleton(allAllowedRegex)); + } + + policy.subjectORegexes(selectValue.apply(subject.organization())); + policy.subjectLRegexes(selectValue.apply(subject.city())); + policy.subjectSTRegexes(selectValue.apply(subject.state())); + policy.subjectCRegexes(selectValue.apply(subject.country())); + + if (subjAltNameDnsAllowed) { + if (Is.blank(whitelistedDomains)) { + policy.dnsSanRegExs(Collections.singleton(allAllowedRegex)); + } else { + List regExs = new ArrayList<>(whitelistedDomains.size()); + for (String whitelistedDomain : whitelistedDomains) { + if (wildcardsAllowed) { + regExs.add(addStartEnd.apply(allAllowedRegex + Pattern.quote("." + whitelistedDomain))); + } else { + regExs.add(escapeOne.apply(whitelistedDomain)); + } } + policy.dnsSanRegExs(regExs); + } + } else { + policy.dnsSanRegExs(Collections.emptyList()); + } - policy.subjectORegexes(selectValue.apply(subject.organization())); - policy.subjectLRegexes(selectValue.apply(subject.city())); - policy.subjectSTRegexes(selectValue.apply(subject.state())); - policy.subjectCRegexes(selectValue.apply(subject.country())); - - if(subjAltNameDnsAllowed) { - if(Is.blank(whitelistedDomains)) { - policy.dnsSanRegExs(Collections.singleton(allAllowedRegex)); - } else { - List regExs = new ArrayList<>(whitelistedDomains.size()); - for(String whitelistedDomain : whitelistedDomains) { - if(wildcardsAllowed) { - regExs.add(addStartEnd.apply(allAllowedRegex + Pattern.quote("." + whitelistedDomain))); - } else { - regExs.add(escapeOne.apply(whitelistedDomain)); - } - } - policy.dnsSanRegExs(regExs); + policy.ipSanRegExs(allOrNothing.apply(subjAltNameIpAllowed)); + policy.emailSanRegExs(allOrNothing.apply(subjAltNameEmailAllowed)); + policy.uriSanRegExs(allOrNothing.apply(subjAltNameUriAllowed)); + policy.upnSanRegExs(allOrNothing.apply(subjAltNameUpnAllowed)); + + if (keyPair.keyAlgorithm().locked()) { + KeyType keyType = KeyType.from(keyPair.keyAlgorithm().value()); + AllowedKeyConfiguration key = + new AllowedKeyConfiguration().keyType(keyType).keySizes(new ArrayList<>()); + if (KeyType.RSA.equals(keyType)) { + if (keyPair.keySize().locked()) { + for (Integer keySize : KeyType.allSupportedKeySizes()) { + if (keySize >= keyPair.keySize().value() || keyPair.keySize().value() == null) { + key.keySizes().add(keySize); } + } } else { - policy.dnsSanRegExs(Collections.emptyList()); + key.keySizes(KeyType.allSupportedKeySizes()); } - - policy.ipSanRegExs(allOrNothing.apply(subjAltNameIpAllowed)); - policy.emailSanRegExs(allOrNothing.apply(subjAltNameEmailAllowed)); - policy.uriSanRegExs(allOrNothing.apply(subjAltNameUriAllowed)); - policy.upnSanRegExs(allOrNothing.apply(subjAltNameUpnAllowed)); - - if(keyPair.keyAlgorithm().locked()) { - KeyType keyType = KeyType.from(keyPair.keyAlgorithm().value()); - AllowedKeyConfiguration key = new AllowedKeyConfiguration().keyType(keyType).keySizes(new ArrayList<>()); - if(KeyType.RSA.equals(keyType)) { - if(keyPair.keySize().locked()) { - for(Integer keySize : KeyType.allSupportedKeySizes()) { - if(keySize >= keyPair.keySize().value() || keyPair.keySize().value() == null) { - key.keySizes().add(keySize); - } - } - } else { - key.keySizes(KeyType.allSupportedKeySizes()); - } - } else { - if(keyPair.ellipticCurve().locked()) { - EllipticCurve curve = EllipticCurve.from(keyPair.ellipticCurve().value()); - key.keyCurves().add(curve); - } else { - key.keyCurves(EllipticCurve.allSupportedCures()); - } - } - policy.allowedKeyConfigurations().add(key); + } else { + if (keyPair.ellipticCurve().locked()) { + EllipticCurve curve = EllipticCurve.from(keyPair.ellipticCurve().value()); + key.keyCurves().add(curve); } else { - policy.allowedKeyConfigurations().add(new AllowedKeyConfiguration().keyType(KeyType.RSA).keySizes(KeyType.allSupportedKeySizes())); - policy.allowedKeyConfigurations().add(new AllowedKeyConfiguration().keyType(KeyType.ECDSA).keyCurves(EllipticCurve.allSupportedCures())); + key.keyCurves(EllipticCurve.allSupportedCures()); } - policy.allowWildcards(wildcardsAllowed); - policy.allowKeyReuse(privateKeyReuseAllowed); - return policy; + } + policy.allowedKeyConfigurations().add(key); + } else { + policy.allowedKeyConfigurations().add(new AllowedKeyConfiguration().keyType(KeyType.RSA) + .keySizes(KeyType.allSupportedKeySizes())); + policy.allowedKeyConfigurations().add(new AllowedKeyConfiguration().keyType(KeyType.ECDSA) + .keyCurves(EllipticCurve.allSupportedCures())); } - - public ZoneConfiguration toZoneConfig() { - return new ZoneConfiguration() - .customAttributeValues(new HashMap<>()) - .hashAlgorithm(SignatureAlgorithm.SHA256WithRSA) - .country(subject.country().value()) - .organization(subject.organization().value()) - .organizationalUnit(subject.organizationalUnit().values()) - .province(subject.state().value()) - .locality(subject.city().value()); - } - - @Data - @AllArgsConstructor - @VisibleForTesting - public static class KeyPair { - private LockableValue keyAlgorithm; - private LockableValue keySize; - private LockableValue ellipticCurve; - } - - @Data - @NoArgsConstructor // for testing - @AllArgsConstructor - @VisibleForTesting - public static class Subject { - private LockableValue city; - private LockableValue country; - private LockableValue organization; - private LockableValues organizationalUnit; - private LockableValue state; - } - -} \ No newline at end of file + policy.allowWildcards(wildcardsAllowed); + policy.allowKeyReuse(privateKeyReuseAllowed); + return policy; + } + + public ZoneConfiguration toZoneConfig() { + return new ZoneConfiguration().customAttributeValues(new HashMap<>()) + .hashAlgorithm(SignatureAlgorithm.SHA256WithRSA).country(subject.country().value()) + .organization(subject.organization().value()) + .organizationalUnit(subject.organizationalUnit().values()).province(subject.state().value()) + .locality(subject.city().value()); + } + + @Data + @AllArgsConstructor + @VisibleForTesting + public static class KeyPair { + private LockableValue keyAlgorithm; + private LockableValue keySize; + private LockableValue ellipticCurve; + } + + @Data + @NoArgsConstructor // for testing + @AllArgsConstructor + @VisibleForTesting + public static class Subject { + private LockableValue city; + private LockableValue country; + private LockableValue organization; + private LockableValues organizationalUnit; + private LockableValue state; + } + +} diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/CertificatePolicy.java b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/CertificatePolicy.java index f7d7d93..a046688 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/CertificatePolicy.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/CertificatePolicy.java @@ -1,14 +1,5 @@ package com.venafi.vcert.sdk.connectors.cloud; -import com.google.gson.annotations.SerializedName; -import com.venafi.vcert.sdk.certificate.KeyType; -import com.venafi.vcert.sdk.connectors.Policy; -import com.venafi.vcert.sdk.connectors.ServerPolicy; -import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; -import com.venafi.vcert.sdk.endpoint.AllowedKeyConfiguration; -import com.venafi.vcert.sdk.utils.Is; -import lombok.Data; - import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Collection; @@ -17,108 +8,117 @@ import java.util.function.Function; import java.util.regex.Pattern; import java.util.stream.Collectors; +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import com.venafi.vcert.sdk.certificate.KeyType; +import com.venafi.vcert.sdk.connectors.Policy; +import com.venafi.vcert.sdk.connectors.ServerPolicy; +import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; +import com.venafi.vcert.sdk.endpoint.AllowedKeyConfiguration; +import com.venafi.vcert.sdk.utils.Is; @Data @SuppressWarnings("WeakerAccess") public class CertificatePolicy { - private String certificatePolicyType; - private String id; - private String companyId; - private String name; - //@SerializedName("systemGeneratedate") // todo: Go SDK uses this spelling, but server returns the one below - private String systemGenerated; - private OffsetDateTime creationDate; - private String certificateProviderId; - private Collection subjectCNRegexes; - private List subjectORegexes; - private Collection subjectOURegexes; - private List subjectSTRegexes; - private List subjectLRegexes; - @SerializedName("subjectCValues") - private List subjectCRegexes; - private Collection sanRegexes; - private Collection keyTypes; - private boolean keyReuse; + private String certificatePolicyType; + private String id; + private String companyId; + private String name; + // @SerializedName("systemGeneratedate") // todo: Go SDK uses this spelling, but server returns + // the one below + private String systemGenerated; + private OffsetDateTime creationDate; + private String certificateProviderId; + private Collection subjectCNRegexes; + private List subjectORegexes; + private Collection subjectOURegexes; + private List subjectSTRegexes; + private List subjectLRegexes; + @SerializedName("subjectCValues") + private List subjectCRegexes; + private Collection sanRegexes; + private Collection keyTypes; + private boolean keyReuse; - private static transient final Pattern nonRegEx = Pattern.compile("[a-zA-Z0-9 ]+"); + private static transient final Pattern nonRegEx = Pattern.compile("[a-zA-Z0-9 ]+"); - Policy toPolicy() { - Function, Collection> addStartEndToCollection = cs -> { - if(cs == null) { - return Collections.emptyList(); - } - return cs.stream().map(ServerPolicy.addStartEnd).collect(Collectors.toList()); - }; - Policy policy = new Policy() - .allowedKeyConfigurations(new ArrayList<>()) - .subjectCNRegexes(addStartEndToCollection.apply(subjectCNRegexes)) - .subjectOURegexes(addStartEndToCollection.apply(subjectOURegexes)) - .subjectCRegexes(addStartEndToCollection.apply(subjectCRegexes)) - .subjectSTRegexes(addStartEndToCollection.apply(subjectSTRegexes)) - .subjectLRegexes(addStartEndToCollection.apply(subjectLRegexes)) - .subjectORegexes(addStartEndToCollection.apply(subjectORegexes)) - .dnsSanRegExs(addStartEndToCollection.apply(sanRegexes)) - .allowKeyReuse(keyReuse); - boolean allowWildcards = false; - for(String s : policy.subjectCNRegexes()) { - if (s.startsWith("^.*")) { - allowWildcards = true; - } - } - if(!allowWildcards) { - for(String s : policy.dnsSanRegExs()) { - if (s.startsWith("^.*")) { - allowWildcards = true; - } - } - } - policy.allowWildcards(allowWildcards); - if(keyTypes != null) { - for (AllowedKeyType keyType : keyTypes) { - AllowedKeyConfiguration keyConfiguration = new AllowedKeyConfiguration(); - // error checking; throws exception (i.e. panics) if invalid keyType - keyConfiguration.keyType(KeyType.from(keyType.keyType())); - keyConfiguration.keySizes(keyType.keyLengths != null ? new ArrayList<>(keyType.keyLengths) : Collections.emptyList()); - policy.allowedKeyConfigurations().add(keyConfiguration); - } + Policy toPolicy() { + Function, Collection> addStartEndToCollection = cs -> { + if (cs == null) { + return Collections.emptyList(); + } + return cs.stream().map(ServerPolicy.addStartEnd).collect(Collectors.toList()); + }; + Policy policy = new Policy().allowedKeyConfigurations(new ArrayList<>()) + .subjectCNRegexes(addStartEndToCollection.apply(subjectCNRegexes)) + .subjectOURegexes(addStartEndToCollection.apply(subjectOURegexes)) + .subjectCRegexes(addStartEndToCollection.apply(subjectCRegexes)) + .subjectSTRegexes(addStartEndToCollection.apply(subjectSTRegexes)) + .subjectLRegexes(addStartEndToCollection.apply(subjectLRegexes)) + .subjectORegexes(addStartEndToCollection.apply(subjectORegexes)) + .dnsSanRegExs(addStartEndToCollection.apply(sanRegexes)).allowKeyReuse(keyReuse); + boolean allowWildcards = false; + for (String s : policy.subjectCNRegexes()) { + if (s.startsWith("^.*")) { + allowWildcards = true; + } + } + if (!allowWildcards) { + for (String s : policy.dnsSanRegExs()) { + if (s.startsWith("^.*")) { + allowWildcards = true; } - return policy; + } } + policy.allowWildcards(allowWildcards); + if (keyTypes != null) { + for (AllowedKeyType keyType : keyTypes) { + AllowedKeyConfiguration keyConfiguration = new AllowedKeyConfiguration(); + // error checking; throws exception (i.e. panics) if invalid keyType + keyConfiguration.keyType(KeyType.from(keyType.keyType())); + keyConfiguration.keySizes(keyType.keyLengths != null ? new ArrayList<>(keyType.keyLengths) + : Collections.emptyList()); + policy.allowedKeyConfigurations().add(keyConfiguration); + } + } + return policy; + } - void toZoneConfig(ZoneConfiguration zoneConfig) { // todo: rename to augmentZoneConfig or addToZoneConfig ? - if(!Is.blank(subjectCRegexes) && isNotRegexp(subjectCRegexes.get(0))) { - zoneConfig.country(subjectCRegexes.get(0)); - } - if(!Is.blank(subjectORegexes) && isNotRegexp(subjectORegexes.get(0))) { - zoneConfig.organization(subjectORegexes.get(0)); - } - if(!Is.blank(subjectSTRegexes) && isNotRegexp(subjectSTRegexes.get(0))) { - zoneConfig.province(subjectSTRegexes.get(0)); - } - if(!Is.blank(subjectLRegexes) && isNotRegexp(subjectLRegexes.get(0))) { - zoneConfig.locality(subjectLRegexes.get(0)); - } - if(null != subjectOURegexes) { - for (String ou : subjectOURegexes) { - if (isNotRegexp(ou)) { - if(zoneConfig.organizationalUnit() == null) { - zoneConfig.organizationalUnit(new ArrayList<>()); - } - zoneConfig.organizationalUnit().add(ou); - } - } + void toZoneConfig(ZoneConfiguration zoneConfig) { // todo: rename to augmentZoneConfig or + // addToZoneConfig ? + if (!Is.blank(subjectCRegexes) && isNotRegexp(subjectCRegexes.get(0))) { + zoneConfig.country(subjectCRegexes.get(0)); + } + if (!Is.blank(subjectORegexes) && isNotRegexp(subjectORegexes.get(0))) { + zoneConfig.organization(subjectORegexes.get(0)); + } + if (!Is.blank(subjectSTRegexes) && isNotRegexp(subjectSTRegexes.get(0))) { + zoneConfig.province(subjectSTRegexes.get(0)); + } + if (!Is.blank(subjectLRegexes) && isNotRegexp(subjectLRegexes.get(0))) { + zoneConfig.locality(subjectLRegexes.get(0)); + } + if (null != subjectOURegexes) { + for (String ou : subjectOURegexes) { + if (isNotRegexp(ou)) { + if (zoneConfig.organizationalUnit() == null) { + zoneConfig.organizationalUnit(new ArrayList<>()); + } + zoneConfig.organizationalUnit().add(ou); } + } } + } - private boolean isNotRegexp(String s) { - return nonRegEx.matcher(s).matches(); - } + private boolean isNotRegexp(String s) { + return nonRegEx.matcher(s).matches(); + } - @Data - private static class AllowedKeyType { - private String keyType; - private Collection keyLengths; + @Data + private static class AllowedKeyType { + private String keyType; + private Collection keyLengths; - } + } } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/Cloud.java b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/Cloud.java index 5c32382..abce904 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/Cloud.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/Cloud.java @@ -1,10 +1,8 @@ package com.venafi.vcert.sdk.connectors.cloud; -import com.venafi.vcert.sdk.certificate.CertificateStatus; -import com.venafi.vcert.sdk.certificate.ManagedCertificate; -import com.venafi.vcert.sdk.connectors.cloud.domain.UserDetails; -import com.venafi.vcert.sdk.utils.FeignUtils; +import static java.util.Collections.singletonList; +import java.util.List; import feign.Headers; import feign.Param; import feign.RequestLine; @@ -12,106 +10,108 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; - -import java.util.List; - -import static java.util.Collections.singletonList; +import com.venafi.vcert.sdk.certificate.CertificateStatus; +import com.venafi.vcert.sdk.certificate.ManagedCertificate; +import com.venafi.vcert.sdk.connectors.cloud.domain.UserDetails; +import com.venafi.vcert.sdk.utils.FeignUtils; public interface Cloud { - @Headers("tppl-api-key: {apiKey}") - @RequestLine("GET /v1/useraccounts") - UserDetails authorize(@Param("apiKey") String apiKey); - - @Headers("tppl-api-key: {apiKey}") - @RequestLine("GET /v1/zones/tag/{zone}") - Zone zoneByTag(@Param("zone") String zone, @Param("apiKey") String apiKey); - - @Headers("tppl-api-key: {apiKey}") - @RequestLine("GET /v1/certificatepolicies/{id}") - CertificatePolicy policyById(@Param("id") String id, @Param("apiKey") String apiKey); - - @Headers({"tppl-api-key: {apiKey}", "Content-Type: application/json", "Accept: application/json"}) - @RequestLine("POST /v1/certificatesearch") - CertificateSearchResponse searchCertificates(@Param("apiKey") String apiKey, SearchRequest searchRequest); - - @Headers({"tppl-api-key: {apiKey}", "Content-Type: application/json"}) - @RequestLine("POST /v1/certificaterequests") - CloudConnector.CertificateRequestsResponse certificateRequest(@Param("apiKey") String apiKey, CloudConnector.CertificateRequestsPayload csr); - - @Headers("tppl-api-key: {apiKey}") - @RequestLine("GET /v1/certificaterequests/{id}") - CertificateStatus certificateStatus(@Param("id") String id, @Param("apiKey") String apiKey); - - @Headers("tppl-api-key: {apiKey}") - @RequestLine("GET /v1/certificaterequests/{id}/certificate?chainOrder={chainOrder}&format=PEM") - Response certificateViaCSR(@Param("id") String id, @Param("apiKey") String apiKey, @Param("chainOrder") String chainOrder); - - @Headers("tppl-api-key: {apiKey}") - @RequestLine("GET /v1/certificates/{id}/encoded") - String certificateAsPem(@Param("id") String id, @Param("apiKey") String apiKey); - - @Headers("tppl-api-key: {apiKey}") - @RequestLine("GET /v1/managedcertificates/{id}") - ManagedCertificate managedCertificate(@Param("id") String id, @Param("apiKey") String apiKey); - - @RequestLine("GET ping") - @Headers("x-venafi-api-key: {apiKey}") - Response ping(@Param("apiKey") String apiKey); - - static Cloud connect(String baseUrl) { - return FeignUtils.client(Cloud.class, baseUrl); - } - - @Data - @NoArgsConstructor - class SearchRequest { - private Expression expression; - private Object ordering; - private Paging paging; - - SearchRequest(Expression expression) { - this.expression = expression; - } - - static SearchRequest findByFingerPrint(String fingerprint) { - return new SearchRequest( - new Cloud.Expression(singletonList( - new Cloud.Operand("fingerprint", "MATCH", fingerprint)))); - } - } - - @Data - @AllArgsConstructor - class Expression { - private List operands; - } - - @Data - @NoArgsConstructor - @AllArgsConstructor - class Operand { - private String field; - private String operator; - private Object value; - } - - @Data - class Paging { - private Integer pageNumber; - private Integer pageSize; - } - - @Data - class CertificateSearchResponse { - private Integer count; - private List certificates; + @Headers("tppl-api-key: {apiKey}") + @RequestLine("GET /v1/useraccounts") + UserDetails authorize(@Param("apiKey") String apiKey); + + @Headers("tppl-api-key: {apiKey}") + @RequestLine("GET /v1/zones/tag/{zone}") + Zone zoneByTag(@Param("zone") String zone, @Param("apiKey") String apiKey); + + @Headers("tppl-api-key: {apiKey}") + @RequestLine("GET /v1/certificatepolicies/{id}") + CertificatePolicy policyById(@Param("id") String id, @Param("apiKey") String apiKey); + + @Headers({"tppl-api-key: {apiKey}", "Content-Type: application/json", "Accept: application/json"}) + @RequestLine("POST /v1/certificatesearch") + CertificateSearchResponse searchCertificates(@Param("apiKey") String apiKey, + SearchRequest searchRequest); + + @Headers({"tppl-api-key: {apiKey}", "Content-Type: application/json"}) + @RequestLine("POST /v1/certificaterequests") + CloudConnector.CertificateRequestsResponse certificateRequest(@Param("apiKey") String apiKey, + CloudConnector.CertificateRequestsPayload csr); + + @Headers("tppl-api-key: {apiKey}") + @RequestLine("GET /v1/certificaterequests/{id}") + CertificateStatus certificateStatus(@Param("id") String id, @Param("apiKey") String apiKey); + + @Headers("tppl-api-key: {apiKey}") + @RequestLine("GET /v1/certificaterequests/{id}/certificate?chainOrder={chainOrder}&format=PEM") + Response certificateViaCSR(@Param("id") String id, @Param("apiKey") String apiKey, + @Param("chainOrder") String chainOrder); + + @Headers("tppl-api-key: {apiKey}") + @RequestLine("GET /v1/certificates/{id}/encoded") + String certificateAsPem(@Param("id") String id, @Param("apiKey") String apiKey); + + @Headers("tppl-api-key: {apiKey}") + @RequestLine("GET /v1/managedcertificates/{id}") + ManagedCertificate managedCertificate(@Param("id") String id, @Param("apiKey") String apiKey); + + @RequestLine("GET ping") + @Headers("x-venafi-api-key: {apiKey}") + Response ping(@Param("apiKey") String apiKey); + + static Cloud connect(String baseUrl) { + return FeignUtils.client(Cloud.class, baseUrl); + } + + @Data + @NoArgsConstructor + class SearchRequest { + private Expression expression; + private Object ordering; + private Paging paging; + + SearchRequest(Expression expression) { + this.expression = expression; } - @Data - class Certificate { - private String id; - private String managedCertificateId; - private String certificateRequestId; - private List subjectCN; + static SearchRequest findByFingerPrint(String fingerprint) { + return new SearchRequest(new Cloud.Expression( + singletonList(new Cloud.Operand("fingerprint", "MATCH", fingerprint)))); } + } + + @Data + @AllArgsConstructor + class Expression { + private List operands; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + class Operand { + private String field; + private String operator; + private Object value; + } + + @Data + class Paging { + private Integer pageNumber; + private Integer pageSize; + } + + @Data + class CertificateSearchResponse { + private Integer count; + private List certificates; + } + + @Data + class Certificate { + private String id; + private String managedCertificateId; + private String certificateRequestId; + private List subjectCN; + } } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnector.java b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnector.java index fddca28..246d9b7 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnector.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnector.java @@ -1,402 +1,430 @@ package com.venafi.vcert.sdk.connectors.cloud; +import static java.lang.String.format; +import static java.time.Duration.ZERO; +import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isNotBlank; +import java.io.IOException; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import org.bouncycastle.util.Strings; import com.google.common.io.CharStreams; import com.google.gson.annotations.SerializedName; +import feign.Response; +import lombok.Data; +import lombok.Getter; import com.venafi.vcert.sdk.VCertException; -import com.venafi.vcert.sdk.certificate.*; +import com.venafi.vcert.sdk.certificate.CertificateRequest; +import com.venafi.vcert.sdk.certificate.CertificateStatus; +import com.venafi.vcert.sdk.certificate.ChainOption; +import com.venafi.vcert.sdk.certificate.CsrOriginOption; +import com.venafi.vcert.sdk.certificate.ImportRequest; +import com.venafi.vcert.sdk.certificate.ImportResponse; +import com.venafi.vcert.sdk.certificate.ManagedCertificate; +import com.venafi.vcert.sdk.certificate.PEMCollection; +import com.venafi.vcert.sdk.certificate.RenewalRequest; +import com.venafi.vcert.sdk.certificate.RevocationRequest; import com.venafi.vcert.sdk.connectors.Connector; import com.venafi.vcert.sdk.connectors.Policy; import com.venafi.vcert.sdk.connectors.cloud.domain.UserDetails; import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; import com.venafi.vcert.sdk.endpoint.Authentication; import com.venafi.vcert.sdk.endpoint.ConnectorType; -import feign.Response; -import lombok.Data; -import lombok.Getter; -import org.bouncycastle.util.Strings; - -import java.io.IOException; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import static java.lang.String.format; -import static java.time.Duration.ZERO; -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.apache.commons.lang3.StringUtils.isNotBlank; public class CloudConnector implements Connector { - private Cloud cloud; - - @Getter - private UserDetails user; - private Authentication auth; - private String zone; - - public CloudConnector(Cloud cloud) { - this.cloud = cloud; - } - - @Override - public ConnectorType getType() { - return ConnectorType.CLOUD; - } - - @Override - public void setBaseUrl(String url) throws VCertException { - throw new UnsupportedOperationException("Method not yet implemented"); - } - - @Override - public void setZone(String zone) { - this.zone = zone; + private Cloud cloud; + + @Getter + private UserDetails user; + private Authentication auth; + private String zone; + + public CloudConnector(Cloud cloud) { + this.cloud = cloud; + } + + @Override + public ConnectorType getType() { + return ConnectorType.CLOUD; + } + + @Override + public void setBaseUrl(String url) throws VCertException { + throw new UnsupportedOperationException("Method not yet implemented"); + } + + @Override + public void setZone(String zone) { + this.zone = zone; + } + + @Override + public void ping() throws VCertException { + Response response = doPing(); + if (response.status() != 200) { + throw new VCertException(format("Unexpected status code on Venafi Cloud ping. Status: %d %s", + response.status(), response.reason())); } - - @Override - public void ping() throws VCertException { - Response response = doPing(); - if(response.status() != 200) { - throw new VCertException(format("Unexpected status code on Venafi Cloud ping. Status: %d %s", response.status(), response.reason())); + } + + private Response doPing() { + return cloud.ping(auth.apiKey()); + } + + @Override + public void authenticate(Authentication auth) throws VCertException { + VCertException.throwIfNull(auth, "failed to authenticate: missing credentials"); + this.auth = auth; + this.user = cloud.authorize(auth.apiKey()); + } + + @Override + public ZoneConfiguration readZoneConfiguration(String tag) throws VCertException { + VCertException.throwIfNull(tag, "empty zone name"); + Zone zone = getZoneByTag(tag); + CertificatePolicy policy = getPoliciesById( + Arrays.asList(zone.defaultCertificateIdentityPolicy(), zone.defaultCertificateUsePolicy())); + return zone.getZoneConfiguration(user, policy); + } + + @Override + public CertificateRequest generateRequest(ZoneConfiguration config, CertificateRequest request) + throws VCertException { + switch (request.csrOrigin()) { + case LocalGeneratedCSR: + if (config == null) { + config = readZoneConfiguration(zone); + } + config.validateCertificateRequest(request); + config.updateCertificateRequest(request); + request.generatePrivateKey(); + request.generateCSR(); + break; + case UserProvidedCSR: + if (request.csr().length == 0) { + throw new VCertException("CSR was supposed to be provided by user, but it's empty"); } + break; + case ServiceGeneratedCSR: + request.csr(null); + break; + default: + throw new VCertException(format("Unrecognized request CSR origin %s", request.csrOrigin())); } - private Response doPing() { - return cloud.ping(auth.apiKey()); - } + return request; + } - @Override - public void authenticate(Authentication auth) throws VCertException { - VCertException.throwIfNull(auth, "failed to authenticate: missing credentials"); - this.auth = auth; - this.user = cloud.authorize(auth.apiKey()); + @Override + public String requestCertificate(CertificateRequest request, String zone) throws VCertException { + if (isBlank(zone)) { + zone = this.zone; } - - @Override - public ZoneConfiguration readZoneConfiguration(String tag) throws VCertException { - VCertException.throwIfNull(tag, "empty zone name"); - Zone zone = getZoneByTag(tag); - CertificatePolicy policy = getPoliciesById(Arrays.asList(zone.defaultCertificateIdentityPolicy(), zone.defaultCertificateUsePolicy())); - return zone.getZoneConfiguration(user, policy); + if (CsrOriginOption.ServiceGeneratedCSR == request.csrOrigin()) { + throw new VCertException("service generated CSR is not supported by Saas service"); } - - @Override - public CertificateRequest generateRequest(ZoneConfiguration config, CertificateRequest request) throws VCertException { - switch (request.csrOrigin()) { - case LocalGeneratedCSR: - if (config == null) { - config = readZoneConfiguration(zone); - } - config.validateCertificateRequest(request); - config.updateCertificateRequest(request); - request.generatePrivateKey(); - request.generateCSR(); - break; - case UserProvidedCSR: - if(request.csr().length == 0) { - throw new VCertException("CSR was supposed to be provided by user, but it's empty"); - } - break; - case ServiceGeneratedCSR: - request.csr(null); - break; - default: - throw new VCertException(format("Unrecognized request CSR origin %s", request.csrOrigin())); - } - - return request; + if (user == null || user.company() == null) { + throw new VCertException("Must be authenticated to request a certificate"); } - - @Override - public String requestCertificate(CertificateRequest request, String zone) throws VCertException { - if (isBlank(zone)) { - zone = this.zone; - } - if (CsrOriginOption.ServiceGeneratedCSR == request.csrOrigin()) { - throw new VCertException("service generated CSR is not supported by Saas service"); - } - if (user == null || user.company() == null) { - throw new VCertException("Must be authenticated to request a certificate"); - } - Zone z = getZoneByTag(zone); - CertificateRequestsResponse response = cloud.certificateRequest( - auth.apiKey(), - new CertificateRequestsPayload() - .zoneId(z.id()) - .csr(new String(request.csr()))); - String requestId = response.certificateRequests().get(0).id(); - request.pickupId(requestId); - return requestId; + Zone z = getZoneByTag(zone); + CertificateRequestsResponse response = cloud.certificateRequest(auth.apiKey(), + new CertificateRequestsPayload().zoneId(z.id()).csr(new String(request.csr()))); + String requestId = response.certificateRequests().get(0).id(); + request.pickupId(requestId); + return requestId; + } + + @Override + public PEMCollection retrieveCertificate(CertificateRequest request) throws VCertException { + if (request.fetchPrivateKey()) { + throw new VCertException( + "Failed to retrieve private key from Venafi Cloud service: not supported"); } - - @Override - public PEMCollection retrieveCertificate(CertificateRequest request) throws VCertException { - if(request.fetchPrivateKey()) { - throw new VCertException("Failed to retrieve private key from Venafi Cloud service: not supported"); - } - String certId = ""; - if(isBlank(request.pickupId()) && isNotBlank(request.thumbprint())) { - String certificateRequestId = null; - Cloud.CertificateSearchResponse certificateSearchResponse = searchCertificatesByFingerprint(request.thumbprint()); - if(certificateSearchResponse.certificates().size() == 0) { - throw new VCertException(format("No certificate found using fingerprint %s", request.thumbprint())); - } - - List reqIds = new ArrayList<>(); - boolean isOnlyOneCertificateRequestId = true; - for(Cloud.Certificate certificate : certificateSearchResponse.certificates()) { - reqIds.add(certificate.certificateRequestId()); - if(isNotBlank(certificateRequestId) && certificateRequestId.equals(certificate.certificateRequestId())) { - isOnlyOneCertificateRequestId = true; - } - if(isNotBlank(certificate.certificateRequestId())) { - certificateRequestId = certificate.certificateRequestId(); - } else { - certId = certificate.id(); - } - } - if(!isOnlyOneCertificateRequestId) { - throw new VCertException(format("More than one CertificateRequestId was found with the same Fingerprint: %s", reqIds)); - } - request.pickupId(certificateRequestId); - } - - // TODO move this retry logic to feign client - Instant startTime = Instant.now(); - while(true) { - if(isBlank(request.pickupId())) { - break; - } - - CertificateStatus certificateStatus = getCertificateStatus(request.pickupId()); - if("ISSUED".equals(certificateStatus.status())) { - break; - } else if("FAILED".equals(certificateStatus.status())) { - throw new VCertException(format("Failed to retrieve certificate. Status: %s", certificateStatus.toString())); - } - - // Status either REQUESTED or PENDING - if(ZERO.equals(request.timeout())) { - throw new VCertException(format("Failed to retrieve certificate %s. Status %s", request.pickupId(), certificateStatus.status())); - } - - if(Instant.now().isAfter(startTime.plus(request.timeout()))) { - throw new VCertException(format("Timeout trying to retrieve certificate %s", request.pickupId())); - } - - try { - TimeUnit.SECONDS.sleep(2); - } catch(InterruptedException e) { - e.printStackTrace(); - throw new VCertException("Error attempting to retry", e); - } + String certId = ""; + if (isBlank(request.pickupId()) && isNotBlank(request.thumbprint())) { + String certificateRequestId = null; + Cloud.CertificateSearchResponse certificateSearchResponse = + searchCertificatesByFingerprint(request.thumbprint()); + if (certificateSearchResponse.certificates().size() == 0) { + throw new VCertException( + format("No certificate found using fingerprint %s", request.thumbprint())); + } + + List reqIds = new ArrayList<>(); + boolean isOnlyOneCertificateRequestId = true; + for (Cloud.Certificate certificate : certificateSearchResponse.certificates()) { + reqIds.add(certificate.certificateRequestId()); + if (isNotBlank(certificateRequestId) + && certificateRequestId.equals(certificate.certificateRequestId())) { + isOnlyOneCertificateRequestId = true; } - - if(user == null || user.company() == null) { - throw new VCertException("Must be authenticated to retieve certificate"); - } - - if(isNotBlank(request.pickupId())) { - - // Todo cleanup unnecessary switch - String chainOption; - switch(request.chainOption()) { - case ChainOptionRootFirst: - chainOption = "ROOT_FIRST"; - break; - case ChainOptionRootLast: - case ChainOptionIgnore: - default: - chainOption = "EE_FIRST"; - break; - } - String body = certificateViaCSR(request.pickupId(), chainOption); - PEMCollection pemCollection = PEMCollection.fromResponse(body, request.chainOption(), request.privateKey()); - request.checkCertificate(pemCollection.certificate()); - return pemCollection; + if (isNotBlank(certificate.certificateRequestId())) { + certificateRequestId = certificate.certificateRequestId(); } else { - String body = certificateAsPem(certId); - return PEMCollection.fromResponse(body, ChainOption.ChainOptionIgnore); + certId = certificate.id(); } + } + if (!isOnlyOneCertificateRequestId) { + throw new VCertException(format( + "More than one CertificateRequestId was found with the same Fingerprint: %s", reqIds)); + } + request.pickupId(certificateRequestId); } - private String certificateViaCSR(String requestId, String chainOrder) throws VCertException { - // We should decode this as is not REST, multiple decoders should be supported - // by feign as a potential improvement. - Response response = cloud.certificateViaCSR(requestId, auth.apiKey(), chainOrder); - if (response.status() != 200) { - throw new VCertException(String.format("Invalid response fetching the certificate via CSR: %s", - response.reason())); - } - try { - return CharStreams.toString(response.body().asReader()); - }catch (IOException e) { - throw new VCertException("Unable to read the PEM certificate"); - } - + // TODO move this retry logic to feign client + Instant startTime = Instant.now(); + while (true) { + if (isBlank(request.pickupId())) { + break; + } + + CertificateStatus certificateStatus = getCertificateStatus(request.pickupId()); + if ("ISSUED".equals(certificateStatus.status())) { + break; + } else if ("FAILED".equals(certificateStatus.status())) { + throw new VCertException( + format("Failed to retrieve certificate. Status: %s", certificateStatus.toString())); + } + + // Status either REQUESTED or PENDING + if (ZERO.equals(request.timeout())) { + throw new VCertException(format("Failed to retrieve certificate %s. Status %s", + request.pickupId(), certificateStatus.status())); + } + + if (Instant.now().isAfter(startTime.plus(request.timeout()))) { + throw new VCertException( + format("Timeout trying to retrieve certificate %s", request.pickupId())); + } + + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + e.printStackTrace(); + throw new VCertException("Error attempting to retry", e); + } } - private String certificateAsPem(String requestId) { - return cloud.certificateAsPem(requestId, auth.apiKey()); + if (user == null || user.company() == null) { + throw new VCertException("Must be authenticated to retieve certificate"); } - private CertificateStatus getCertificateStatus(String requestId) { - return cloud.certificateStatus(requestId, auth.apiKey()); + if (isNotBlank(request.pickupId())) { + + // Todo cleanup unnecessary switch + String chainOption; + switch (request.chainOption()) { + case ChainOptionRootFirst: + chainOption = "ROOT_FIRST"; + break; + case ChainOptionRootLast: + case ChainOptionIgnore: + default: + chainOption = "EE_FIRST"; + break; + } + String body = certificateViaCSR(request.pickupId(), chainOption); + PEMCollection pemCollection = + PEMCollection.fromResponse(body, request.chainOption(), request.privateKey()); + request.checkCertificate(pemCollection.certificate()); + return pemCollection; + } else { + String body = certificateAsPem(certId); + return PEMCollection.fromResponse(body, ChainOption.ChainOptionIgnore); } - - @Override - public void revokeCertificate(RevocationRequest request) throws VCertException { - throw new UnsupportedOperationException("not supported by endpoint"); + } + + private String certificateViaCSR(String requestId, String chainOrder) throws VCertException { + // We should decode this as is not REST, multiple decoders should be supported + // by feign as a potential improvement. + Response response = cloud.certificateViaCSR(requestId, auth.apiKey(), chainOrder); + if (response.status() != 200) { + throw new VCertException(String + .format("Invalid response fetching the certificate via CSR: %s", response.reason())); + } + try { + return CharStreams.toString(response.body().asReader()); + } catch (IOException e) { + throw new VCertException("Unable to read the PEM certificate"); } - @Override - public String renewCertificate(RenewalRequest request) throws VCertException { - - String certificateRequestId = null; - - if (isNotBlank(request.thumbprint())) { - Cloud.CertificateSearchResponse result = this.searchCertificatesByFingerprint(request.thumbprint()); - Set requestIds = result.certificates() - .stream() - .map(c -> c.certificateRequestId()) - .collect(Collectors.toSet()); - - if (requestIds.size() > 1) { - throw new VCertException( - String.format("More than one CertificateRequestId was found with the same Fingerprint: %s", - request.thumbprint())); - - } else if (requestIds.size() == 0) { - throw new VCertException(String.format("Cloud service can not find a certificate with Fingerprint: %s", - request.thumbprint())); - } - - certificateRequestId = requestIds.iterator().next(); - - } else if (isNotBlank(request.certificateDN())) { - certificateRequestId = request.certificateDN(); - } else { - throw new VCertException("failed to create renewal request: CertificateDN or Thumbprint required"); - } - - - final CertificateStatus status = cloud.certificateStatus(certificateRequestId, auth.apiKey()); - VCertException.throwIfNull(status.managedCertificateId(), - String.format("failed to submit renewal request for certificate: ManagedCertificateId is empty, certificate status is %s", status.status())); - VCertException.throwIfNull(status.zoneId(), - String.format("failed to submit renewal request for certificate: ZoneId is empty, certificate status is %s", status.status())); - + } - ManagedCertificate managedCertificate = cloud.managedCertificate(status.managedCertificateId(), auth.apiKey()); - if (!managedCertificate.latestCertificateRequestId().equals(certificateRequestId)) { - final StringBuilder errorStr = new StringBuilder(); - errorStr.append("Certificate under requestId %s "); - errorStr.append(isNotBlank(request.thumbprint())? String.format("with thumbprint %s ", request.thumbprint()):""); - errorStr.append("is not the latest under ManagedCertificateId %s. The latest request is %s. "); - errorStr.append("This error may happen when revoked certificate is requested to be renewed."); + private String certificateAsPem(String requestId) { + return cloud.certificateAsPem(requestId, auth.apiKey()); + } - throw new VCertException(String.format(errorStr.toString(), certificateRequestId, managedCertificate.id(), - managedCertificate.latestCertificateRequestId())); - } + private CertificateStatus getCertificateStatus(String requestId) { + return cloud.certificateStatus(requestId, auth.apiKey()); + } - final CertificateRequestsPayload certificateRequest = new CertificateRequestsPayload(); - certificateRequest.zoneId(status.zoneId()); - certificateRequest.existingManagedCertificateId(managedCertificate.id()); + @Override + public void revokeCertificate(RevocationRequest request) throws VCertException { + throw new UnsupportedOperationException("not supported by endpoint"); + } - certificateRequest.reuseCSR(!(Objects.nonNull(request.request()) && request.request().csr().length > 0)); - if (!certificateRequest.reuseCSR) { - certificateRequest.csr(Strings.fromByteArray(request.request().csr())); - } + @Override + public String renewCertificate(RenewalRequest request) throws VCertException { - CertificateRequestsResponse response = cloud.certificateRequest(auth.apiKey(), certificateRequest); - return response.certificateRequests().get(0).id(); - } + String certificateRequestId = null; - @Override - public ImportResponse importCertificate(ImportRequest request) throws VCertException { - throw new UnsupportedOperationException("Method not yet implemented"); - } + if (isNotBlank(request.thumbprint())) { + Cloud.CertificateSearchResponse result = + this.searchCertificatesByFingerprint(request.thumbprint()); + Set requestIds = result.certificates().stream().map(c -> c.certificateRequestId()) + .collect(Collectors.toSet()); - @Override - public Policy readPolicyConfiguration(String zone) throws VCertException { - throw new UnsupportedOperationException("Method not yet implemented"); - } + if (requestIds.size() > 1) { + throw new VCertException(String.format( + "More than one CertificateRequestId was found with the same Fingerprint: %s", + request.thumbprint())); - private CertificatePolicy getPoliciesById(Collection ids) throws VCertException { - CertificatePolicy policy = new CertificatePolicy(); - VCertException.throwIfNull(user, "must be authenticated to read the zone configuration"); - for (String id : ids) { - CertificatePolicy certificatePolicy = cloud.policyById(id, auth.apiKey()); - switch(certificatePolicy.certificatePolicyType()) { - case "CERTIFICATE_IDENTITY": { - policy.subjectCNRegexes(certificatePolicy.subjectCNRegexes()); - policy.subjectORegexes(certificatePolicy.subjectORegexes()); - policy.subjectOURegexes(certificatePolicy.subjectOURegexes()); - policy.subjectSTRegexes(certificatePolicy.subjectSTRegexes()); - policy.subjectLRegexes(certificatePolicy.subjectLRegexes()); - policy.subjectCRegexes(certificatePolicy.subjectCRegexes()); - policy.sanRegexes(certificatePolicy.sanRegexes()); - break; - } - case "CERTIFICATE_USE": { - policy.keyTypes(certificatePolicy.keyTypes()); - policy.keyReuse(certificatePolicy.keyReuse()); - break; - } - default: - throw new IllegalArgumentException(format("unknown type %s", certificatePolicy.certificatePolicyType())); - } - } - return policy; - } + } else if (requestIds.size() == 0) { + throw new VCertException(String.format( + "Cloud service can not find a certificate with Fingerprint: %s", request.thumbprint())); + } - private Zone getZoneByTag(String zone) throws VCertException { - VCertException.throwIfNull(user, "must be authenticated to read the zone configuration"); - return cloud.zoneByTag(zone, auth.apiKey()); - } + certificateRequestId = requestIds.iterator().next(); - private Cloud.CertificateSearchResponse searchCertificates(Cloud.SearchRequest searchRequest) { - return cloud.searchCertificates(auth.apiKey(), searchRequest); + } else if (isNotBlank(request.certificateDN())) { + certificateRequestId = request.certificateDN(); + } else { + throw new VCertException( + "failed to create renewal request: CertificateDN or Thumbprint required"); } - private Cloud.CertificateSearchResponse searchCertificatesByFingerprint(String fingerprint) { - String cleanFingerprint = fingerprint - .replaceAll(":", "") - .replaceAll("/.", ""); - return searchCertificates(Cloud.SearchRequest.findByFingerPrint(cleanFingerprint)); + final CertificateStatus status = cloud.certificateStatus(certificateRequestId, auth.apiKey()); + VCertException.throwIfNull(status.managedCertificateId(), String.format( + "failed to submit renewal request for certificate: ManagedCertificateId is empty, certificate status is %s", + status.status())); + VCertException.throwIfNull(status.zoneId(), String.format( + "failed to submit renewal request for certificate: ZoneId is empty, certificate status is %s", + status.status())); + + + ManagedCertificate managedCertificate = + cloud.managedCertificate(status.managedCertificateId(), auth.apiKey()); + if (!managedCertificate.latestCertificateRequestId().equals(certificateRequestId)) { + final StringBuilder errorStr = new StringBuilder(); + errorStr.append("Certificate under requestId %s "); + errorStr.append(isNotBlank(request.thumbprint()) + ? String.format("with thumbprint %s ", request.thumbprint()) + : ""); + errorStr + .append("is not the latest under ManagedCertificateId %s. The latest request is %s. "); + errorStr.append("This error may happen when revoked certificate is requested to be renewed."); + + throw new VCertException(String.format(errorStr.toString(), certificateRequestId, + managedCertificate.id(), managedCertificate.latestCertificateRequestId())); } - @Data - static class CertificateRequestsPayload { - // private String companyId; - // private String downloadFormat; - @SerializedName("certificateSigningRequest") - private String csr; - private String zoneId; - private String existingManagedCertificateId; - private boolean reuseCSR; - } + final CertificateRequestsPayload certificateRequest = new CertificateRequestsPayload(); + certificateRequest.zoneId(status.zoneId()); + certificateRequest.existingManagedCertificateId(managedCertificate.id()); - @Data - @SuppressWarnings("WeakerAccess") - public static class CertificateRequestsResponse { - private List certificateRequests; + certificateRequest + .reuseCSR(!(Objects.nonNull(request.request()) && request.request().csr().length > 0)); + if (!certificateRequest.reuseCSR) { + certificateRequest.csr(Strings.fromByteArray(request.request().csr())); } - @Data - static class CertificateRequestsResponseData { - private String id; - private String zoneId; - private String status; - private String subjectDN; - private boolean generatedKey; - private boolean defaultKeyPassword; - private Collection certificateInstanceIds; - private OffsetDateTime creationDate; - private String pem; - private String der; + CertificateRequestsResponse response = + cloud.certificateRequest(auth.apiKey(), certificateRequest); + return response.certificateRequests().get(0).id(); + } + + @Override + public ImportResponse importCertificate(ImportRequest request) throws VCertException { + throw new UnsupportedOperationException("Method not yet implemented"); + } + + @Override + public Policy readPolicyConfiguration(String zone) throws VCertException { + throw new UnsupportedOperationException("Method not yet implemented"); + } + + private CertificatePolicy getPoliciesById(Collection ids) throws VCertException { + CertificatePolicy policy = new CertificatePolicy(); + VCertException.throwIfNull(user, "must be authenticated to read the zone configuration"); + for (String id : ids) { + CertificatePolicy certificatePolicy = cloud.policyById(id, auth.apiKey()); + switch (certificatePolicy.certificatePolicyType()) { + case "CERTIFICATE_IDENTITY": { + policy.subjectCNRegexes(certificatePolicy.subjectCNRegexes()); + policy.subjectORegexes(certificatePolicy.subjectORegexes()); + policy.subjectOURegexes(certificatePolicy.subjectOURegexes()); + policy.subjectSTRegexes(certificatePolicy.subjectSTRegexes()); + policy.subjectLRegexes(certificatePolicy.subjectLRegexes()); + policy.subjectCRegexes(certificatePolicy.subjectCRegexes()); + policy.sanRegexes(certificatePolicy.sanRegexes()); + break; + } + case "CERTIFICATE_USE": { + policy.keyTypes(certificatePolicy.keyTypes()); + policy.keyReuse(certificatePolicy.keyReuse()); + break; + } + default: + throw new IllegalArgumentException( + format("unknown type %s", certificatePolicy.certificatePolicyType())); + } } + return policy; + } + + private Zone getZoneByTag(String zone) throws VCertException { + VCertException.throwIfNull(user, "must be authenticated to read the zone configuration"); + return cloud.zoneByTag(zone, auth.apiKey()); + } + + private Cloud.CertificateSearchResponse searchCertificates(Cloud.SearchRequest searchRequest) { + return cloud.searchCertificates(auth.apiKey(), searchRequest); + } + + private Cloud.CertificateSearchResponse searchCertificatesByFingerprint(String fingerprint) { + String cleanFingerprint = fingerprint.replaceAll(":", "").replaceAll("/.", ""); + + return searchCertificates(Cloud.SearchRequest.findByFingerPrint(cleanFingerprint)); + } + + @Data + static class CertificateRequestsPayload { + // private String companyId; + // private String downloadFormat; + @SerializedName("certificateSigningRequest") + private String csr; + private String zoneId; + private String existingManagedCertificateId; + private boolean reuseCSR; + } + + @Data + @SuppressWarnings("WeakerAccess") + public static class CertificateRequestsResponse { + private List certificateRequests; + } + + @Data + static class CertificateRequestsResponseData { + private String id; + private String zoneId; + private String status; + private String subjectDN; + private boolean generatedKey; + private boolean defaultKeyPassword; + private Collection certificateInstanceIds; + private OffsetDateTime creationDate; + private String pem; + private String der; + } } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/Zone.java b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/Zone.java index 10810eb..74f0693 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/Zone.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/Zone.java @@ -1,44 +1,44 @@ package com.venafi.vcert.sdk.connectors.cloud; -import com.google.gson.annotations.SerializedName; -import com.venafi.vcert.sdk.connectors.cloud.domain.UserDetails; -import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; -import lombok.Data; - import java.time.OffsetDateTime; import java.util.Collection; import java.util.HashMap; +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import com.venafi.vcert.sdk.connectors.cloud.domain.UserDetails; +import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; @Data @SuppressWarnings("WeakerAccess") public class Zone { - private String id; - private String companyId; - private String tag; - private String zoneType; - private CertificatePolicyId certificatePolicyIds; - @SerializedName("defaultCertificateIdentityPolicyId") - private String defaultCertificateIdentityPolicy; - @SerializedName("defaultCertificateUsePolicyId") - private String defaultCertificateUsePolicy; - private boolean systemGenerated; // TODO: Go SDK has this as bool systemGeneratedate, but server returns our spelling - private OffsetDateTime creationDate; + private String id; + private String companyId; + private String tag; + private String zoneType; + private CertificatePolicyId certificatePolicyIds; + @SerializedName("defaultCertificateIdentityPolicyId") + private String defaultCertificateIdentityPolicy; + @SerializedName("defaultCertificateUsePolicyId") + private String defaultCertificateUsePolicy; + private boolean systemGenerated; // TODO: Go SDK has this as bool systemGeneratedate, but server + // returns our spelling + private OffsetDateTime creationDate; - ZoneConfiguration getZoneConfiguration(UserDetails user, CertificatePolicy policy) { - ZoneConfiguration zoneConfig = new ZoneConfiguration().customAttributeValues(new HashMap<>()); - if(policy == null) { - return zoneConfig; - } - zoneConfig.policy(policy.toPolicy()); - policy.toZoneConfig(zoneConfig); - return zoneConfig; + ZoneConfiguration getZoneConfiguration(UserDetails user, CertificatePolicy policy) { + ZoneConfiguration zoneConfig = new ZoneConfiguration().customAttributeValues(new HashMap<>()); + if (policy == null) { + return zoneConfig; } + zoneConfig.policy(policy.toPolicy()); + policy.toZoneConfig(zoneConfig); + return zoneConfig; + } - @Data - private static class CertificatePolicyId { - @SerializedName("CERTIFICATE_IDENTITY") - Collection certificateIdentity; - @SerializedName("CERTIFICATE_USE") - Collection certificateUse; - } + @Data + private static class CertificatePolicyId { + @SerializedName("CERTIFICATE_IDENTITY") + Collection certificateIdentity; + @SerializedName("CERTIFICATE_USE") + Collection certificateUse; + } } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/ApiKey.java b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/ApiKey.java index 78517be..e12352b 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/ApiKey.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/ApiKey.java @@ -1,25 +1,24 @@ package com.venafi.vcert.sdk.connectors.cloud.domain; -import com.google.gson.annotations.SerializedName; -import lombok.Data; - import java.time.OffsetDateTime; import java.util.Collection; +import com.google.gson.annotations.SerializedName; +import lombok.Data; @Data public class ApiKey { - private String username; - private String apiVersion; - private String apiKeyStatus; - private OffsetDateTime creationDate; - private OffsetDateTime validityStartDate; - private OffsetDateTime validityEndDate; + private String username; + private String apiVersion; + private String apiKeyStatus; + private OffsetDateTime creationDate; + private OffsetDateTime validityStartDate; + private OffsetDateTime validityEndDate; - @SerializedName("apitypes") - private Collection apiTypes; + @SerializedName("apitypes") + private Collection apiTypes; - // present in JSON but not in Go SDK -// private String userId; -// private String companyId; + // present in JSON but not in Go SDK + // private String userId; + // private String companyId; } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/Company.java b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/Company.java index 024e029..eef6cca 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/Company.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/Company.java @@ -1,17 +1,15 @@ package com.venafi.vcert.sdk.connectors.cloud.domain; -import lombok.Data; - import java.time.OffsetDateTime; import java.util.Collection; +import lombok.Data; @Data public class Company { - private String id; - private String name; - private String companyType; - private boolean active; - private Collection domains; - private OffsetDateTime creationDate; - + private String id; + private String name; + private String companyType; + private boolean active; + private Collection domains; + private OffsetDateTime creationDate; } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/User.java b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/User.java index 066f4fa..e946af6 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/User.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/User.java @@ -1,27 +1,25 @@ package com.venafi.vcert.sdk.connectors.cloud.domain; -import lombok.Data; - import java.time.OffsetDateTime; +import lombok.Data; @Data public class User { - private String username; - private String id; - private String companyId; - private String emailAddress; - private String userType; - private String userAccountType; - private String userStatus; - private OffsetDateTime creationDate; - - // present in JSON but not in Go SDK -// @SerializedName("firstname") -// private String firstName; -// @SerializedName("lastname") -// private String lastName; -// private Collection roles; -// private OffsetDateTime firstLoginDate; + private String username; + private String id; + private String companyId; + private String emailAddress; + private String userType; + private String userAccountType; + private String userStatus; + private OffsetDateTime creationDate; + // present in JSON but not in Go SDK + // @SerializedName("firstname") + // private String firstName; + // @SerializedName("lastname") + // private String lastName; + // private Collection roles; + // private OffsetDateTime firstLoginDate; } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/UserDetails.java b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/UserDetails.java index 72f2b54..e4899c0 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/UserDetails.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/cloud/domain/UserDetails.java @@ -5,8 +5,7 @@ @Data public class UserDetails { - private User user; - private Company company; - private ApiKey apiKey; - + private User user; + private Company company; + private ApiKey apiKey; } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/tpp/AuthorizeResponse.java b/src/main/java/com/venafi/vcert/sdk/connectors/tpp/AuthorizeResponse.java index 28e2019..38faa45 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/tpp/AuthorizeResponse.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/tpp/AuthorizeResponse.java @@ -1,17 +1,15 @@ package com.venafi.vcert.sdk.connectors.tpp; +import java.time.OffsetDateTime; import com.google.gson.annotations.SerializedName; import lombok.Data; -import java.time.OffsetDateTime; - @Data @SuppressWarnings("WeakerAccess") public class AuthorizeResponse { - @SerializedName("APIKey") - private String apiKey; - - private OffsetDateTime validUntil; + @SerializedName("APIKey") + private String apiKey; + private OffsetDateTime validUntil; } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/tpp/Tpp.java b/src/main/java/com/venafi/vcert/sdk/connectors/tpp/Tpp.java index d4a789e..2c53016 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/tpp/Tpp.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/tpp/Tpp.java @@ -1,117 +1,111 @@ package com.venafi.vcert.sdk.connectors.tpp; +import java.util.List; +import java.util.Map; import com.google.gson.annotations.SerializedName; +import feign.Headers; +import feign.Param; +import feign.QueryMap; +import feign.RequestLine; +import feign.Response; +import lombok.Data; import com.venafi.vcert.sdk.certificate.ImportRequest; import com.venafi.vcert.sdk.certificate.ImportResponse; import com.venafi.vcert.sdk.utils.FeignUtils; -import feign.*; -import lombok.Data; - -import java.util.List; -import java.util.Map; public interface Tpp { - @RequestLine("POST authorize/") - @Headers("Content-Type: application/json") - AuthorizeResponse authorize(TppConnector.AuthorizeRequest authorizeRequest); - - @RequestLine("POST certificates/checkpolicy") - @Headers({ - "Content-Type: application/json", - "x-venafi-api-key: {apiKey}" - }) - TppConnector.ReadZoneConfigurationResponse readZoneConfiguration(TppConnector.ReadZoneConfigurationRequest readZoneConfigurationRequest, @Param("apiKey") String apiKey); - - @RequestLine("POST certificates/request") - @Headers({ - "Content-Type: application/json", - "x-venafi-api-key: {apiKey}" - }) - CertificateRequestResponse requestCertificate(TppConnector.CertificateRequestsPayload payload, @Param("apiKey") String apiKey); - - @RequestLine("GET certificates/") - @Headers("x-venafi-api-key: {apiKey}") - Tpp.CertificateSearchResponse searchCertificates(@QueryMap Map query, @Param("apiKey") String apiKey); - - @RequestLine("POST certificates/retrieve") - @Headers({ - "Content-Type: application/json", - "x-venafi-api-key: {apiKey}" - }) - CertificateRetrieveResponse certificateRetrieve(TppConnector.CertificateRetrieveRequest certificateRetrieveRequest, @Param("apiKey") String apiKey); - - @RequestLine("POST certificates/revoke") - @Headers({ - "Content-Type: application/json", - "x-venafi-api-key: {apiKey}" - }) - Tpp.CertificateRevokeResponse revokeCertificate(TppConnector.CertificateRevokeRequest request, @Param("apiKey") String apiKey); - - - @RequestLine("POST certificates/renew") - @Headers({ - "Content-Type: application/json", - "x-venafi-api-key: {apiKey}" - }) - Tpp.CertificateRenewalResponse renewCertificate(TppConnector.CertificateRenewalRequest request, @Param("apiKey") String apiKey); - - - @RequestLine("POST certificates/import") - @Headers({ - "Content-Type: application/json", - "x-venafi-api-key: {apiKey}" - }) - ImportResponse importCertificate(ImportRequest request, @Param("apiKey") String apiKey); - - @RequestLine("GET /") - @Headers("x-venafi-api-key: {apiKey}") - Response ping(@Param("apiKey") String apiKey); - - static Tpp connect(String baseUrl) { - return FeignUtils.client(Tpp.class, baseUrl); - } - - @Data - class CertificateSearchResponse { - private Integer count; - private List certificates; - } - - @Data - class Certificate { - @SerializedName("DN") private String certificateRequestId; - } - - @Data - class CertificateRequestResponse { - @SerializedName("CertificateDN") - private String certificateDN; - @SerializedName("Guid") - private String guid; - } - - @Data - class CertificateRetrieveResponse { - private String certificateData; - private String format; - private String filename; - private String status; - private int stage; - } - - @Data - class CertificateRenewalResponse { - private boolean success; - private String error; - } - - @Data - class CertificateRevokeResponse { - private boolean requested; - private boolean success; - private String error; - } -} \ No newline at end of file + @RequestLine("POST authorize/") + @Headers("Content-Type: application/json") + AuthorizeResponse authorize(TppConnector.AuthorizeRequest authorizeRequest); + + @RequestLine("POST certificates/checkpolicy") + @Headers({"Content-Type: application/json", "x-venafi-api-key: {apiKey}"}) + TppConnector.ReadZoneConfigurationResponse readZoneConfiguration( + TppConnector.ReadZoneConfigurationRequest readZoneConfigurationRequest, + @Param("apiKey") String apiKey); + + @RequestLine("POST certificates/request") + @Headers({"Content-Type: application/json", "x-venafi-api-key: {apiKey}"}) + CertificateRequestResponse requestCertificate(TppConnector.CertificateRequestsPayload payload, + @Param("apiKey") String apiKey); + + @RequestLine("GET certificates/") + @Headers("x-venafi-api-key: {apiKey}") + Tpp.CertificateSearchResponse searchCertificates(@QueryMap Map query, + @Param("apiKey") String apiKey); + + @RequestLine("POST certificates/retrieve") + @Headers({"Content-Type: application/json", "x-venafi-api-key: {apiKey}"}) + CertificateRetrieveResponse certificateRetrieve( + TppConnector.CertificateRetrieveRequest certificateRetrieveRequest, + @Param("apiKey") String apiKey); + + @RequestLine("POST certificates/revoke") + @Headers({"Content-Type: application/json", "x-venafi-api-key: {apiKey}"}) + Tpp.CertificateRevokeResponse revokeCertificate(TppConnector.CertificateRevokeRequest request, + @Param("apiKey") String apiKey); + + + @RequestLine("POST certificates/renew") + @Headers({"Content-Type: application/json", "x-venafi-api-key: {apiKey}"}) + Tpp.CertificateRenewalResponse renewCertificate(TppConnector.CertificateRenewalRequest request, + @Param("apiKey") String apiKey); + + + @RequestLine("POST certificates/import") + @Headers({"Content-Type: application/json", "x-venafi-api-key: {apiKey}"}) + ImportResponse importCertificate(ImportRequest request, @Param("apiKey") String apiKey); + + @RequestLine("GET /") + @Headers("x-venafi-api-key: {apiKey}") + Response ping(@Param("apiKey") String apiKey); + + static Tpp connect(String baseUrl) { + return FeignUtils.client(Tpp.class, baseUrl); + } + + @Data + class CertificateSearchResponse { + private Integer count; + private List certificates; + } + + @Data + class Certificate { + @SerializedName("DN") + private String certificateRequestId; + } + + @Data + class CertificateRequestResponse { + @SerializedName("CertificateDN") + private String certificateDN; + @SerializedName("Guid") + private String guid; + } + + @Data + class CertificateRetrieveResponse { + private String certificateData; + private String format; + private String filename; + private String status; + private int stage; + } + + @Data + class CertificateRenewalResponse { + private boolean success; + private String error; + } + + @Data + class CertificateRevokeResponse { + private boolean requested; + private boolean success; + private String error; + } +} diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/tpp/TppConnector.java b/src/main/java/com/venafi/vcert/sdk/connectors/tpp/TppConnector.java index 688e53e..7f131e0 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/tpp/TppConnector.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/tpp/TppConnector.java @@ -1,479 +1,507 @@ package com.venafi.vcert.sdk.connectors.tpp; +import static java.lang.String.format; +import static java.time.Duration.ZERO; +import static java.util.Objects.isNull; +import static java.util.stream.Collectors.toList; +import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isNotBlank; +import java.net.InetAddress; +import java.text.MessageFormat; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import com.google.common.annotations.VisibleForTesting; import com.google.gson.annotations.SerializedName; +import feign.Response; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; import com.venafi.vcert.sdk.VCertException; -import com.venafi.vcert.sdk.certificate.*; +import com.venafi.vcert.sdk.certificate.CertificateRequest; +import com.venafi.vcert.sdk.certificate.ChainOption; +import com.venafi.vcert.sdk.certificate.CsrOriginOption; +import com.venafi.vcert.sdk.certificate.ImportRequest; +import com.venafi.vcert.sdk.certificate.ImportResponse; +import com.venafi.vcert.sdk.certificate.PEMCollection; +import com.venafi.vcert.sdk.certificate.PublicKeyAlgorithm; +import com.venafi.vcert.sdk.certificate.RenewalRequest; +import com.venafi.vcert.sdk.certificate.RevocationRequest; import com.venafi.vcert.sdk.connectors.Connector; import com.venafi.vcert.sdk.connectors.Policy; import com.venafi.vcert.sdk.connectors.ServerPolicy; import com.venafi.vcert.sdk.endpoint.Authentication; import com.venafi.vcert.sdk.endpoint.ConnectorType; import com.venafi.vcert.sdk.utils.Is; -import feign.Response; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.Getter; - -import java.text.MessageFormat; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.net.InetAddress; - -import static java.lang.String.format; -import static java.time.Duration.ZERO; -import static java.util.Objects.isNull; -import static java.util.stream.Collectors.toList; -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.apache.commons.lang3.StringUtils.isNotBlank; public class TppConnector implements Connector { - private static final Pattern policy = Pattern.compile("^\\\\VED\\\\Policy"); - private static final Pattern path = Pattern.compile("^\\\\"); - private final Tpp tpp; - - @VisibleForTesting - OffsetDateTime bestBeforeEnd; - @Getter - private String apiKey; - - @Getter - private String zone; - private static final String tppAttributeManagementType = "Management Type"; - private static final String tppAttributeManualCSR = "Manual Csr"; - - // TODO can be enum - private static Map revocationReasons = new HashMap() {{ - put("", 0); // NoReason - put("none", 0); // - put("key-compromise", 1); // UserKeyCompromised - put("ca-compromise", 2); // CAKeyCompromised - put("affiliation-changed", 3); // UserChangedAffiliation - put("superseded", 4); // CertificateSuperseded - put("cessation-of-operation", 5); // OriginalUseNoLongerValid - }}; - - public TppConnector(Tpp tpp) { - this.tpp = tpp; - } - - @Override - public ConnectorType getType() { - return ConnectorType.TPP; - } - - @Override - public void setBaseUrl(String url) throws VCertException { - throw new UnsupportedOperationException("Method not yet implemented"); - } - - @Override - public void setZone(String zone) { - this.zone = zone; - } - - @Override - public void ping() throws VCertException { - Response response = doPing(); - if(response.status() != 200) { - throw new VCertException(format("ping failed with status %d and reason %s", response.status(), response.reason())); + private static final Pattern policy = Pattern.compile("^\\\\VED\\\\Policy"); + private static final Pattern path = Pattern.compile("^\\\\"); + private final Tpp tpp; + + @VisibleForTesting + OffsetDateTime bestBeforeEnd; + @Getter + private String apiKey; + + @Getter + private String zone; + private static final String tppAttributeManagementType = "Management Type"; + private static final String tppAttributeManualCSR = "Manual Csr"; + + // TODO can be enum + private static Map revocationReasons = new HashMap() { + { + put("", 0); // NoReason + put("none", 0); // + put("key-compromise", 1); // UserKeyCompromised + put("ca-compromise", 2); // CAKeyCompromised + put("affiliation-changed", 3); // UserChangedAffiliation + put("superseded", 4); // CertificateSuperseded + put("cessation-of-operation", 5); // OriginalUseNoLongerValid + } + }; + + public TppConnector(Tpp tpp) { + this.tpp = tpp; + } + + @Override + public ConnectorType getType() { + return ConnectorType.TPP; + } + + @Override + public void setBaseUrl(String url) throws VCertException { + throw new UnsupportedOperationException("Method not yet implemented"); + } + + @Override + public void setZone(String zone) { + this.zone = zone; + } + + @Override + public void ping() throws VCertException { + Response response = doPing(); + if (response.status() != 200) { + throw new VCertException( + format("ping failed with status %d and reason %s", response.status(), response.reason())); + } + } + + private Response doPing() { + return tpp.ping(apiKey); + } + + public void authenticate(Authentication auth) throws VCertException { + VCertException.throwIfNull(auth, "failed to authenticate: missing credentials"); + AuthorizeResponse response = tpp.authorize(new AuthorizeRequest(auth.user(), auth.password())); + apiKey = response.apiKey(); + bestBeforeEnd = response.validUntil(); + } + + @Override + public ZoneConfiguration readZoneConfiguration(String zone) throws VCertException { + VCertException.throwIfNull(zone, "empty zone"); + ReadZoneConfigurationRequest request = new ReadZoneConfigurationRequest(getPolicyDN(zone)); + ReadZoneConfigurationResponse response = tpp.readZoneConfiguration(request, apiKey); + ServerPolicy serverPolicy = response.policy(); + Policy policy = serverPolicy.toPolicy(); + ZoneConfiguration zoneConfig = serverPolicy.toZoneConfig(); + zoneConfig.policy(policy); + return zoneConfig; + } + + @Override + public CertificateRequest generateRequest(ZoneConfiguration config, CertificateRequest request) + throws VCertException { + // todo: should one really have to pass a request into a "generate request" method? + if (config == null) { + config = readZoneConfiguration(zone); + } + String tppMgmtType = config.customAttributeValues().get(tppAttributeManagementType); + if ("Monitoring".equals(tppMgmtType) || "Unassigned".equals(tppMgmtType)) { + throw new VCertException( + "Unable to request certificate from TPP, current TPP configuration would not allow the request to be processed"); + } + + config.updateCertificateRequest(request); + + switch (request.csrOrigin()) { + case LocalGeneratedCSR: { + if ("0".equals(config.customAttributeValues().get(tppAttributeManualCSR))) { + throw new VCertException( + "Unable to request certificate by local generated CSR when zone configuration is 'Manual Csr' = 0"); } - } - - private Response doPing() { - return tpp.ping(apiKey); - } - - public void authenticate(Authentication auth) throws VCertException { - VCertException.throwIfNull(auth, "failed to authenticate: missing credentials"); - AuthorizeResponse response = tpp.authorize(new AuthorizeRequest(auth.user(), auth.password())); - apiKey = response.apiKey(); - bestBeforeEnd = response.validUntil(); - } - - @Override - public ZoneConfiguration readZoneConfiguration(String zone) throws VCertException { - VCertException.throwIfNull(zone, "empty zone"); - ReadZoneConfigurationRequest request = new ReadZoneConfigurationRequest(getPolicyDN(zone)); - ReadZoneConfigurationResponse response = tpp.readZoneConfiguration(request, apiKey); - ServerPolicy serverPolicy = response.policy(); - Policy policy = serverPolicy.toPolicy(); - ZoneConfiguration zoneConfig = serverPolicy.toZoneConfig(); - zoneConfig.policy(policy); - return zoneConfig; - } - - @Override - public CertificateRequest generateRequest(ZoneConfiguration config, CertificateRequest request) throws VCertException { - // todo: should one really have to pass a request into a "generate request" method? - if(config == null) { - config = readZoneConfiguration(zone); - } - String tppMgmtType = config.customAttributeValues().get(tppAttributeManagementType); - if("Monitoring".equals(tppMgmtType) || "Unassigned".equals(tppMgmtType)) { - throw new VCertException("Unable to request certificate from TPP, current TPP configuration would not allow the request to be processed"); - } - - config.updateCertificateRequest(request); - - switch(request.csrOrigin()) { - case LocalGeneratedCSR: { - if("0".equals(config.customAttributeValues().get(tppAttributeManualCSR))) { - throw new VCertException("Unable to request certificate by local generated CSR when zone configuration is 'Manual Csr' = 0"); - } - request.generatePrivateKey(); - request.generateCSR(); - break; - } - case UserProvidedCSR: { - if("0".equals(config.customAttributeValues().get(tppAttributeManualCSR))) { - throw new VCertException("Unable to request certificate with user provided CSR when zone configuration is 'Manual Csr' = 0"); - } - if(Is.blank(request.csr())) { - throw new VCertException("CSR was supposed to be provided by user, but it's empty"); - } - break; - } - case ServiceGeneratedCSR: { - request.csr(null); - break; - } - } - return request; // TODO: should we return the request we modified? It's not a copy, it's the one that was passed in, mutated. - } - - @Override - public String requestCertificate(CertificateRequest request, String zone) throws VCertException { - if(isBlank(zone)) { - zone = this.zone; - } - CertificateRequestsPayload payload = prepareRequest(request, zone); - Tpp.CertificateRequestResponse response = tpp.requestCertificate(payload, apiKey); - String requestId = response.certificateDN(); - request.pickupId(requestId); - return requestId; - } - - private CertificateRequestsPayload prepareRequest(CertificateRequest request, String zone) throws VCertException { - CertificateRequestsPayload payload; - switch(request.csrOrigin()) { - case LocalGeneratedCSR: - payload = new CertificateRequestsPayload() - .policyDN(getPolicyDN(zone)) - .pkcs10(new String(request.csr())) - .objectName(request.friendlyName()) - .disableAutomaticRenewal(true); - break; - case UserProvidedCSR: - payload = new CertificateRequestsPayload() - .policyDN(getPolicyDN(zone)) - .pkcs10(new String(request.csr())) - .objectName(request.friendlyName()) - .subjectAltNames(wrapAltNames(request)) - .disableAutomaticRenewal(true); - break; - case ServiceGeneratedCSR: - payload = new CertificateRequestsPayload() - .policyDN(getPolicyDN(zone)) - .objectName(request.friendlyName()) - .subject(request.subject().commonName()) // TODO (Go SDK): there is some problem because Subject is not only CN - .subjectAltNames(wrapAltNames(request)) - .disableAutomaticRenewal(true); - break; - default: - throw new VCertException(MessageFormat.format("Unexpected option in PrivateKeyOrigin: {0}", request.csrOrigin())); + request.generatePrivateKey(); + request.generateCSR(); + break; + } + case UserProvidedCSR: { + if ("0".equals(config.customAttributeValues().get(tppAttributeManualCSR))) { + throw new VCertException( + "Unable to request certificate with user provided CSR when zone configuration is 'Manual Csr' = 0"); } - - switch(request.keyType()) { - case RSA: { - payload.keyAlgorithm(PublicKeyAlgorithm.RSA.name()); - payload.keyBitSize(request.keyLength()); - break; - } - case ECDSA: { - payload.keyAlgorithm("ECC"); - payload.ellipticCurve(request.keyCurve().value()); - break; - } + if (Is.blank(request.csr())) { + throw new VCertException("CSR was supposed to be provided by user, but it's empty"); } - return payload; - } - - private Collection wrapAltNames(CertificateRequest request) { - List sanItems = new ArrayList<>(); - sanItems.addAll(toSanItems(request.emailAddresses(), 1)); - sanItems.addAll(toSanItems(request.dnsNames(), 2)); - sanItems.addAll(toSanItems(request.ipAddresses(), 7)); - return sanItems; - } - - private List toSanItems(Collection collection, int type) { - return Optional - .ofNullable(collection) - .orElse(Collections.emptyList()) - .stream() - .filter(Objects::nonNull) - .map(entry -> new SANItem().type(type).name( type == 7 ? ((InetAddress)entry).getHostAddress() : entry.toString()) ) - .collect(toList()); - } - - @Override - public PEMCollection retrieveCertificate(CertificateRequest request) throws VCertException { - boolean includeChain = request.chainOption() != ChainOption.ChainOptionIgnore; - boolean rootFirstOrder = includeChain && request.chainOption() == ChainOption.ChainOptionRootFirst; - - if(isNotBlank(request.pickupId()) && isNotBlank(request.thumbprint())) { - Tpp.CertificateSearchResponse searchResult = searchCertificatesByFingerprint(request.thumbprint()); - if(searchResult.certificates().size() == 0) { - throw new VCertException(format("No certificate found using fingerprint %s", request.thumbprint())); - } - if(searchResult.certificates().size() > 1) { - throw new VCertException(format("Error: more than one CertificateRequestId was found with the same thumbprint %s", request.thumbprint())); - } - request.pickupId(searchResult.certificates().get(0).certificateRequestId()); - } - - CertificateRetrieveRequest certReq = new CertificateRetrieveRequest() - .certificateDN(request.pickupId()) - .format("base64") - .rootFirstOrder(rootFirstOrder) - .includeChain(includeChain); - - if(request.csrOrigin() == CsrOriginOption.ServiceGeneratedCSR || request.fetchPrivateKey()) { - certReq.includePrivateKey(true); - certReq.password(request.keyPassword()); - } - - // TODO move this retry logic to feign client - Instant startTime = Instant.now(); - while(true) { - Tpp.CertificateRetrieveResponse retrieveResponse = retrieveCertificateOnce(certReq); - if(isNotBlank(retrieveResponse.certificateData())) { - PEMCollection pemCollection = PEMCollection.fromResponse( - org.bouncycastle.util.Strings.fromByteArray(Base64.getDecoder().decode(retrieveResponse.certificateData())), - request.chainOption(), request.privateKey()); - request.checkCertificate(pemCollection.certificate()); - return pemCollection; - } - - if(ZERO.equals(request.timeout())) { - throw new VCertException(format("Failed to retrieve certificate %s. Status %s", request.pickupId(), retrieveResponse.status())); - } - - if(Instant.now().isAfter(startTime.plus(request.timeout()))) { - throw new VCertException(format("Timeout trying to retrieve certificate %s", request.pickupId())); - } - - try { - TimeUnit.SECONDS.sleep(2); - } catch(InterruptedException e) { - e.printStackTrace(); - throw new VCertException("Error attempting to retry", e); - } - } - } - - private Tpp.CertificateRetrieveResponse retrieveCertificateOnce(CertificateRetrieveRequest certificateRetrieveRequest) { - return tpp.certificateRetrieve(certificateRetrieveRequest, apiKey); - } - - - private Tpp.CertificateSearchResponse searchCertificatesByFingerprint(String fingerprint) { - final String cleanFingerprint = fingerprint - .replaceAll(":", "") - .replaceAll("/.", "") - .toUpperCase(); - - final Map searchRequest = new HashMap(); - searchRequest.put("Thumbprint", fingerprint); - - return searchCertificates(searchRequest); - } - - private Tpp.CertificateSearchResponse searchCertificates(Map searchRequest) { - return tpp.searchCertificates(searchRequest, apiKey); - } - - @Override - public void revokeCertificate(RevocationRequest request) throws VCertException { - Integer reason = revocationReasons.get(request.reason()); - if(reason == null) { - throw new VCertException(format("could not parse revocation reason `%s`", request.reason())); - } - - CertificateRevokeRequest revokeRequest = new CertificateRevokeRequest() - .certificateDN(request.certificateDN()) - .thumbprint(request.thumbprint()) - .reason(reason) - .comments(request.comments()) - .disable(request.disable()); - - Tpp.CertificateRevokeResponse revokeResponse = revokeCertificate(revokeRequest); - if(!revokeResponse.success()) { - throw new VCertException(format("Revocation error: %s", revokeResponse.error())); - } - } - - private Tpp.CertificateRevokeResponse revokeCertificate(CertificateRevokeRequest request) { - return tpp.revokeCertificate(request, apiKey); - } - - @Override - public String renewCertificate(RenewalRequest request) throws VCertException { - String certificateDN; - - if(isNotBlank(request.thumbprint()) && isBlank(request.certificateDN())) { - Tpp.CertificateSearchResponse searchResult = searchCertificatesByFingerprint(request.thumbprint()); - if(searchResult.certificates().isEmpty()) { - throw new VCertException(String.format("No certificate found using fingerprint %s", request.thumbprint())); - } - if(searchResult.certificates().size() > 1) { - throw new VCertException(String.format("More than one certificate was found with the same thumbprint")); - } - certificateDN = searchResult.certificates().get(0).certificateRequestId(); - } else { - certificateDN = request.certificateDN(); - } - - if(isNull(certificateDN)) { - throw new VCertException("Failed to create renewal request: CertificateDN or Thumbprint required"); - } - - final CertificateRenewalRequest renewalRequest = new CertificateRenewalRequest(); - renewalRequest.certificateDN(certificateDN); - - if(Objects.nonNull(request.request()) && request.request().csr().length > 0) { - renewalRequest.PKCS10 = org.bouncycastle.util.Strings.fromByteArray(request.request().csr()); - } - - final Tpp.CertificateRenewalResponse response = tpp.renewCertificate(renewalRequest, apiKey()); - if(!response.success()) { - throw new VCertException(String.format("Certificate renewal error: %s", response.error())); - } - - return certificateDN; - } - - - @Override - public ImportResponse importCertificate(ImportRequest request) throws VCertException { - if(isBlank(request.policyDN())) { - request.policyDN(getPolicyDN(zone)); - } - - return doImportCertificate(request); - } - - private ImportResponse doImportCertificate(ImportRequest request) { - return tpp.importCertificate(request, apiKey); - } - - @Override - public Policy readPolicyConfiguration(String zone) throws VCertException { - throw new UnsupportedOperationException("Method not yet implemented"); - } - - @VisibleForTesting - String getPolicyDN(final String zone) { - String result = zone; - Matcher candidate = policy.matcher(zone); - if(!candidate.matches()) { - if(!policy.matcher(zone).matches()) { - result = "\\" + result; - } - result = "\\VED\\Policy" + result; - } - return result; - } - - @Data - @AllArgsConstructor - static class AuthorizeRequest { - private String username; - private String password; - } - - @Data - @AllArgsConstructor - static class ReadZoneConfigurationRequest { - String policyDN; - } - - @Data - @SuppressWarnings("WeakerAccess") - public static class ReadZoneConfigurationResponse { - Object error; - ServerPolicy policy; - } - - @Data - static class CertificateRequestsPayload { - @SerializedName("PolicyDN") - private String policyDN; - @SerializedName("CADN") - private String cadn; - private String objectName; - private String subject; - private String organizationalUnit; - private String organization; - private String city; - private String state; - private String country; - @SerializedName("SubjectAltNames") - private Collection subjectAltNames; - private String contact; - @SerializedName("CASpecificAttributes") - private Collection> caSpecificAttributes; - @SerializedName("PKCS10") - private String pkcs10; - private String keyAlgorithm; - private int keyBitSize; - private String ellipticCurve; - private boolean disableAutomaticRenewal; - } - - @Data - private static class SANItem { - private int type; - private String name; - } - - @Data - private static class NameValuePair { - private K key; - private V value; - } - - @Data - class CertificateRetrieveRequest { - private String certificateDN; - private String format; - private String password; - private boolean includePrivateKey; - private boolean includeChain; - private String friendlyName; - private boolean rootFirstOrder; - } - - @Data - class CertificateRevokeRequest { - private String certificateDN; - private String thumbprint; - private Integer reason; - private String comments; - private boolean disable; - } - - @Data - class CertificateRenewalRequest { - private String certificateDN; - private String PKCS10; - } + break; + } + case ServiceGeneratedCSR: { + request.csr(null); + break; + } + } + return request; // TODO: should we return the request we modified? It's not a copy, it's the one + // that was passed in, mutated. + } + + @Override + public String requestCertificate(CertificateRequest request, String zone) throws VCertException { + if (isBlank(zone)) { + zone = this.zone; + } + CertificateRequestsPayload payload = prepareRequest(request, zone); + Tpp.CertificateRequestResponse response = tpp.requestCertificate(payload, apiKey); + String requestId = response.certificateDN(); + request.pickupId(requestId); + return requestId; + } + + private CertificateRequestsPayload prepareRequest(CertificateRequest request, String zone) + throws VCertException { + CertificateRequestsPayload payload; + switch (request.csrOrigin()) { + case LocalGeneratedCSR: + payload = new CertificateRequestsPayload().policyDN(getPolicyDN(zone)) + .pkcs10(new String(request.csr())).objectName(request.friendlyName()) + .disableAutomaticRenewal(true); + break; + case UserProvidedCSR: + payload = new CertificateRequestsPayload().policyDN(getPolicyDN(zone)) + .pkcs10(new String(request.csr())).objectName(request.friendlyName()) + .subjectAltNames(wrapAltNames(request)).disableAutomaticRenewal(true); + break; + case ServiceGeneratedCSR: + payload = new CertificateRequestsPayload().policyDN(getPolicyDN(zone)) + .objectName(request.friendlyName()).subject(request.subject().commonName()) // TODO (Go + // SDK): + // there is + // some + // problem + // because + // Subject + // is not + // only CN + .subjectAltNames(wrapAltNames(request)).disableAutomaticRenewal(true); + break; + default: + throw new VCertException(MessageFormat.format("Unexpected option in PrivateKeyOrigin: {0}", + request.csrOrigin())); + } + + switch (request.keyType()) { + case RSA: { + payload.keyAlgorithm(PublicKeyAlgorithm.RSA.name()); + payload.keyBitSize(request.keyLength()); + break; + } + case ECDSA: { + payload.keyAlgorithm("ECC"); + payload.ellipticCurve(request.keyCurve().value()); + break; + } + } + return payload; + } + + private Collection wrapAltNames(CertificateRequest request) { + List sanItems = new ArrayList<>(); + sanItems.addAll(toSanItems(request.emailAddresses(), 1)); + sanItems.addAll(toSanItems(request.dnsNames(), 2)); + sanItems.addAll(toSanItems(request.ipAddresses(), 7)); + return sanItems; + } + + private List toSanItems(Collection collection, int type) { + return Optional.ofNullable(collection).orElse(Collections.emptyList()).stream() + .filter(Objects::nonNull) + .map(entry -> new SANItem().type(type) + .name(type == 7 ? ((InetAddress) entry).getHostAddress() : entry.toString())) + .collect(toList()); + } + + @Override + public PEMCollection retrieveCertificate(CertificateRequest request) throws VCertException { + boolean includeChain = request.chainOption() != ChainOption.ChainOptionIgnore; + boolean rootFirstOrder = + includeChain && request.chainOption() == ChainOption.ChainOptionRootFirst; + + if (isNotBlank(request.pickupId()) && isNotBlank(request.thumbprint())) { + Tpp.CertificateSearchResponse searchResult = + searchCertificatesByFingerprint(request.thumbprint()); + if (searchResult.certificates().size() == 0) { + throw new VCertException( + format("No certificate found using fingerprint %s", request.thumbprint())); + } + if (searchResult.certificates().size() > 1) { + throw new VCertException(format( + "Error: more than one CertificateRequestId was found with the same thumbprint %s", + request.thumbprint())); + } + request.pickupId(searchResult.certificates().get(0).certificateRequestId()); + } + + CertificateRetrieveRequest certReq = + new CertificateRetrieveRequest().certificateDN(request.pickupId()).format("base64") + .rootFirstOrder(rootFirstOrder).includeChain(includeChain); + + if (request.csrOrigin() == CsrOriginOption.ServiceGeneratedCSR || request.fetchPrivateKey()) { + certReq.includePrivateKey(true); + certReq.password(request.keyPassword()); + } + + // TODO move this retry logic to feign client + Instant startTime = Instant.now(); + while (true) { + Tpp.CertificateRetrieveResponse retrieveResponse = retrieveCertificateOnce(certReq); + if (isNotBlank(retrieveResponse.certificateData())) { + PEMCollection pemCollection = PEMCollection.fromResponse( + org.bouncycastle.util.Strings + .fromByteArray(Base64.getDecoder().decode(retrieveResponse.certificateData())), + request.chainOption(), request.privateKey()); + request.checkCertificate(pemCollection.certificate()); + return pemCollection; + } + + if (ZERO.equals(request.timeout())) { + throw new VCertException(format("Failed to retrieve certificate %s. Status %s", + request.pickupId(), retrieveResponse.status())); + } + + if (Instant.now().isAfter(startTime.plus(request.timeout()))) { + throw new VCertException( + format("Timeout trying to retrieve certificate %s", request.pickupId())); + } + + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + e.printStackTrace(); + throw new VCertException("Error attempting to retry", e); + } + } + } + + private Tpp.CertificateRetrieveResponse retrieveCertificateOnce( + CertificateRetrieveRequest certificateRetrieveRequest) { + return tpp.certificateRetrieve(certificateRetrieveRequest, apiKey); + } + + + private Tpp.CertificateSearchResponse searchCertificatesByFingerprint(String fingerprint) { + final String cleanFingerprint = + fingerprint.replaceAll(":", "").replaceAll("/.", "").toUpperCase(); + + final Map searchRequest = new HashMap(); + searchRequest.put("Thumbprint", fingerprint); + + return searchCertificates(searchRequest); + } + + private Tpp.CertificateSearchResponse searchCertificates(Map searchRequest) { + return tpp.searchCertificates(searchRequest, apiKey); + } + + @Override + public void revokeCertificate(RevocationRequest request) throws VCertException { + Integer reason = revocationReasons.get(request.reason()); + if (reason == null) { + throw new VCertException(format("could not parse revocation reason `%s`", request.reason())); + } + + CertificateRevokeRequest revokeRequest = new CertificateRevokeRequest() + .certificateDN(request.certificateDN()).thumbprint(request.thumbprint()).reason(reason) + .comments(request.comments()).disable(request.disable()); + + Tpp.CertificateRevokeResponse revokeResponse = revokeCertificate(revokeRequest); + if (!revokeResponse.success()) { + throw new VCertException(format("Revocation error: %s", revokeResponse.error())); + } + } + + private Tpp.CertificateRevokeResponse revokeCertificate(CertificateRevokeRequest request) { + return tpp.revokeCertificate(request, apiKey); + } + + @Override + public String renewCertificate(RenewalRequest request) throws VCertException { + String certificateDN; + + if (isNotBlank(request.thumbprint()) && isBlank(request.certificateDN())) { + Tpp.CertificateSearchResponse searchResult = + searchCertificatesByFingerprint(request.thumbprint()); + if (searchResult.certificates().isEmpty()) { + throw new VCertException( + String.format("No certificate found using fingerprint %s", request.thumbprint())); + } + if (searchResult.certificates().size() > 1) { + throw new VCertException( + String.format("More than one certificate was found with the same thumbprint")); + } + certificateDN = searchResult.certificates().get(0).certificateRequestId(); + } else { + certificateDN = request.certificateDN(); + } + + if (isNull(certificateDN)) { + throw new VCertException( + "Failed to create renewal request: CertificateDN or Thumbprint required"); + } + + final CertificateRenewalRequest renewalRequest = new CertificateRenewalRequest(); + renewalRequest.certificateDN(certificateDN); + + if (Objects.nonNull(request.request()) && request.request().csr().length > 0) { + renewalRequest.PKCS10 = org.bouncycastle.util.Strings.fromByteArray(request.request().csr()); + } + + final Tpp.CertificateRenewalResponse response = tpp.renewCertificate(renewalRequest, apiKey()); + if (!response.success()) { + throw new VCertException(String.format("Certificate renewal error: %s", response.error())); + } + + return certificateDN; + } + + + @Override + public ImportResponse importCertificate(ImportRequest request) throws VCertException { + if (isBlank(request.policyDN())) { + request.policyDN(getPolicyDN(zone)); + } + + return doImportCertificate(request); + } + + private ImportResponse doImportCertificate(ImportRequest request) { + return tpp.importCertificate(request, apiKey); + } + + @Override + public Policy readPolicyConfiguration(String zone) throws VCertException { + throw new UnsupportedOperationException("Method not yet implemented"); + } + + @VisibleForTesting + String getPolicyDN(final String zone) { + String result = zone; + Matcher candidate = policy.matcher(zone); + if (!candidate.matches()) { + if (!policy.matcher(zone).matches()) { + result = "\\" + result; + } + result = "\\VED\\Policy" + result; + } + return result; + } + + @Data + @AllArgsConstructor + static class AuthorizeRequest { + private String username; + private String password; + } + + @Data + @AllArgsConstructor + static class ReadZoneConfigurationRequest { + String policyDN; + } + + @Data + @SuppressWarnings("WeakerAccess") + public static class ReadZoneConfigurationResponse { + Object error; + ServerPolicy policy; + } + + @Data + static class CertificateRequestsPayload { + @SerializedName("PolicyDN") + private String policyDN; + @SerializedName("CADN") + private String cadn; + private String objectName; + private String subject; + private String organizationalUnit; + private String organization; + private String city; + private String state; + private String country; + @SerializedName("SubjectAltNames") + private Collection subjectAltNames; + private String contact; + @SerializedName("CASpecificAttributes") + private Collection> caSpecificAttributes; + @SerializedName("PKCS10") + private String pkcs10; + private String keyAlgorithm; + private int keyBitSize; + private String ellipticCurve; + private boolean disableAutomaticRenewal; + } + + @Data + private static class SANItem { + private int type; + private String name; + } + + @Data + private static class NameValuePair { + private K key; + private V value; + } + + @Data + class CertificateRetrieveRequest { + private String certificateDN; + private String format; + private String password; + private boolean includePrivateKey; + private boolean includeChain; + private String friendlyName; + private boolean rootFirstOrder; + } + + @Data + class CertificateRevokeRequest { + private String certificateDN; + private String thumbprint; + private Integer reason; + private String comments; + private boolean disable; + } + + @Data + class CertificateRenewalRequest { + private String certificateDN; + private String PKCS10; + } } diff --git a/src/main/java/com/venafi/vcert/sdk/connectors/tpp/ZoneConfiguration.java b/src/main/java/com/venafi/vcert/sdk/connectors/tpp/ZoneConfiguration.java index ed5f8ad..8be0bd8 100644 --- a/src/main/java/com/venafi/vcert/sdk/connectors/tpp/ZoneConfiguration.java +++ b/src/main/java/com/venafi/vcert/sdk/connectors/tpp/ZoneConfiguration.java @@ -1,5 +1,15 @@ package com.venafi.vcert.sdk.connectors.tpp; +import static org.apache.commons.lang3.StringUtils.isNotBlank; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; +import lombok.Data; import com.venafi.vcert.sdk.SignatureAlgorithm; import com.venafi.vcert.sdk.VCertException; import com.venafi.vcert.sdk.certificate.CertificateRequest; @@ -8,191 +18,200 @@ import com.venafi.vcert.sdk.connectors.Policy; import com.venafi.vcert.sdk.endpoint.AllowedKeyConfiguration; import com.venafi.vcert.sdk.utils.Is; -import lombok.Data; - -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import static org.apache.commons.lang3.StringUtils.isNotBlank; @Data // TODO move up one package public class ZoneConfiguration { - private String organization; - private List organizationalUnit; - private String country; - private String province; - private String locality; - private Policy policy = new Policy(); // Go merges the policy struct into the ZoneConfiguration one... - private SignatureAlgorithm hashAlgorithm = SignatureAlgorithm.UnknownSignatureAlgorithm; - - private Map customAttributeValues = new HashMap<>(); // Go SDK factory sets an empty map - - - /** - * UpdateCertificateRequest updates a certificate request based on the zone configuration retrieved from the remote endpoint - * @return - */ - public void updateCertificateRequest(CertificateRequest request) { - CertificateRequest.PKIXName subject = request.subject(); - subject.organization(Entity.of(subject.organization(), organization).resolve()); - if(Is.blank(subject.organizationalUnit()) && !Is.blank(organizationalUnit)) { - subject.organizationalUnit(organizationalUnit); - } - subject.country(Entity.of(subject.country(), country).resolve()); - subject.province(Entity.of(subject.province(), province).resolve()); - subject.locality(Entity.of(subject.locality(), locality).resolve()); + private String organization; + private List organizationalUnit; + private String country; + private String province; + private String locality; + private Policy policy = new Policy(); // Go merges the policy struct into the ZoneConfiguration + // one... + private SignatureAlgorithm hashAlgorithm = SignatureAlgorithm.UnknownSignatureAlgorithm; + + private Map customAttributeValues = new HashMap<>(); // Go SDK factory sets an + // empty map + + + /** + * UpdateCertificateRequest updates a certificate request based on the zone configuration + * retrieved from the remote endpoint + * + * @return + */ + public void updateCertificateRequest(CertificateRequest request) { + CertificateRequest.PKIXName subject = request.subject(); + subject.organization(Entity.of(subject.organization(), organization).resolve()); + if (Is.blank(subject.organizationalUnit()) && !Is.blank(organizationalUnit)) { + subject.organizationalUnit(organizationalUnit); + } + subject.country(Entity.of(subject.country(), country).resolve()); + subject.province(Entity.of(subject.province(), province).resolve()); + subject.locality(Entity.of(subject.locality(), locality).resolve()); - // apply defaults for settings that weren't specified and then make sure they comply with policy - if (request.keyType() == null) { - request.keyType(KeyType.defaultKeyType()); + // apply defaults for settings that weren't specified and then make sure they comply with policy + if (request.keyType() == null) { + request.keyType(KeyType.defaultKeyType()); + } + + switch (request.keyType()) { + case ECDSA: + if (request.keyCurve() == null) { + request.keyCurve(EllipticCurve.ellipticCurveDefault()); } + if (request.signatureAlgorithm() == SignatureAlgorithm.UnknownSignatureAlgorithm) { + request.signatureAlgorithm(SignatureAlgorithm.ECDSAWithSHA256); + } + break; - switch (request.keyType()) - { - case ECDSA: - if (request.keyCurve() == null) { - request.keyCurve(EllipticCurve.ellipticCurveDefault()); - } - if (request.signatureAlgorithm() == SignatureAlgorithm.UnknownSignatureAlgorithm) { - request.signatureAlgorithm(SignatureAlgorithm.ECDSAWithSHA256); - } - break; + default: + if (request.keyLength() < 2048) { + request.keyLength(2048); + } + if (request.signatureAlgorithm() == SignatureAlgorithm.UnknownSignatureAlgorithm) { + request.signatureAlgorithm(SignatureAlgorithm.SHA256WithRSA); + } + break; + } - default: - if (request.keyLength() < 2048) { - request.keyLength(2048); + if (!Is.blank(policy.allowedKeyConfigurations())) { + for (AllowedKeyConfiguration keyConf : policy.allowedKeyConfigurations()) { + if (keyConf.keyType() == request.keyType()) { + switch (request.keyType()) { + case ECDSA: { + if (!Is.blank(keyConf.keyCurves())) { + if (!keyConf.keyCurves().contains(request.keyCurve())) { + request.keyCurve(keyConf.keyCurves().get(0)); } - if (request.signatureAlgorithm() == SignatureAlgorithm.UnknownSignatureAlgorithm) { - request.signatureAlgorithm(SignatureAlgorithm.SHA256WithRSA); + } + break; + } + case RSA: { + if (!Is.blank(keyConf.keySizes())) { + boolean sizeOK = false; + for (Integer size : keyConf.keySizes()) { + if (size.equals(request.keyLength())) { + sizeOK = true; + } } - break; - } - - if(!Is.blank(policy.allowedKeyConfigurations())) { - for(AllowedKeyConfiguration keyConf : policy.allowedKeyConfigurations()) { - if(keyConf.keyType() == request.keyType()) { - switch (request.keyType()) { - case ECDSA: { - if(!Is.blank(keyConf.keyCurves())) { - if (!keyConf.keyCurves().contains(request.keyCurve())) { - request.keyCurve(keyConf.keyCurves().get(0)); - } - } - break; - } - case RSA: { - if(!Is.blank(keyConf.keySizes())) { - boolean sizeOK = false; - for(Integer size : keyConf.keySizes()) { - if(size.equals(request.keyLength())) { - sizeOK = true; - } - } - if(!sizeOK) { - request.keyLength(keyConf.keySizes().get(0)); - } - } - break; - } - } + if (!sizeOK) { + request.keyLength(keyConf.keySizes().get(0)); } + } + break; } + } } + } } + } - private static class Entity { - private List target; - private String source; + private static class Entity { + private List target; + private String source; - private Entity() { + private Entity() { - } - static Entity of(List target, String source) { - Entity entity = new Entity(); - entity.target = target; - entity.source = source; - return entity; - } - List resolve() { - if(Is.blank(target) && isNotBlank(source)) { - return Collections.singletonList(source); - } else if(!Is.blank(target) && isNotBlank(source) && !Is.equalsFold(target.get(0), source)) { - return Collections.singletonList(source); - } - return target; - } } - public boolean validateCertificateRequest(CertificateRequest request) throws VCertException { - if(!isComponentValid(policy.subjectCNRegexes(), Collections.singletonList(request.subject().commonName()))) { - throw new VCertException("The requested CN does not match any of the allowed CN regular expressions"); - } - if(!isComponentValid(policy.subjectORegexes(), request.subject().organization())) { - throw new VCertException("The requested Organization does not match any of the allowed Organization regular expressions"); - } - if(!isComponentValid(policy.subjectOURegexes(), request.subject().organizationalUnit())) { - throw new VCertException("The requested Organizational Unit does not match any of the allowed Organization Unit regular expressions"); - } - if(!isComponentValid(policy.subjectSTRegexes(), request.subject().province())) { - throw new VCertException("The requested State/Province does not match any of the allowed State/Province regular expressions"); - } - if(!isComponentValid(policy.subjectLRegexes(), request.subject().locality())) { - throw new VCertException("The requested Locality does not match any of the allowed Locality regular expressions"); - } - if(!isComponentValid(policy.subjectCRegexes(), request.subject().country())) { - throw new VCertException("The requested Country does not match any of the allowed Country regular expressions"); - } - if(!isComponentValid(policy.dnsSanRegExs(), request.dnsNames())) { - throw new VCertException("The requested Subject Alternative Name does not match any of the allowed Country regular expressions"); - } - //todo (from Go SDK): add ip, email and over checking - - List allowedKeyConfigurations = policy.allowedKeyConfigurations(); - if(allowedKeyConfigurations != null && allowedKeyConfigurations.size() > 0) { - for(AllowedKeyConfiguration keyConfiguration : allowedKeyConfigurations) { - if(keyConfiguration.keyType() == request.keyType()) { - if(request.keyLength() > 0) { - for(Integer size : keyConfiguration.keySizes()) { - if(size.equals(request.keyLength())) { - return true; - } - } - } - return true; - } - } - throw new VCertException("The requested Key Type and Size do not match any of the allowed Key Types and Sizes"); - } - - return true; + static Entity of(List target, String source) { + Entity entity = new Entity(); + entity.target = target; + entity.source = source; + return entity; } - private boolean isComponentValid(Collection regexes, Collection components) { - if(regexes.size() == 0 || components.size() == 0) { - return true; - } + List resolve() { + if (Is.blank(target) && isNotBlank(source)) { + return Collections.singletonList(source); + } else if (!Is.blank(target) && isNotBlank(source) && !Is.equalsFold(target.get(0), source)) { + return Collections.singletonList(source); + } + return target; + } + } - for(String regex : regexes) { - Pattern pattern; - try { - pattern = Pattern.compile(regex); - } catch(PatternSyntaxException e) { - // TODO log error - return false; - } - for(String component : components) { - Matcher m = pattern.matcher(component); - if(m.matches()) { - return true; // todo: that seems wrong. Check if all policy rules need to be matched, or any one? (E.g.: Policy says location is [0]:Madrid,[1]:London - does it need to match either or both?) Also, if we have locations 0:London, 1: Brussels, 2: Madrid, won't this pass? Should it? - } + public boolean validateCertificateRequest(CertificateRequest request) throws VCertException { + if (!isComponentValid(policy.subjectCNRegexes(), + Collections.singletonList(request.subject().commonName()))) { + throw new VCertException( + "The requested CN does not match any of the allowed CN regular expressions"); + } + if (!isComponentValid(policy.subjectORegexes(), request.subject().organization())) { + throw new VCertException( + "The requested Organization does not match any of the allowed Organization regular expressions"); + } + if (!isComponentValid(policy.subjectOURegexes(), request.subject().organizationalUnit())) { + throw new VCertException( + "The requested Organizational Unit does not match any of the allowed Organization Unit regular expressions"); + } + if (!isComponentValid(policy.subjectSTRegexes(), request.subject().province())) { + throw new VCertException( + "The requested State/Province does not match any of the allowed State/Province regular expressions"); + } + if (!isComponentValid(policy.subjectLRegexes(), request.subject().locality())) { + throw new VCertException( + "The requested Locality does not match any of the allowed Locality regular expressions"); + } + if (!isComponentValid(policy.subjectCRegexes(), request.subject().country())) { + throw new VCertException( + "The requested Country does not match any of the allowed Country regular expressions"); + } + if (!isComponentValid(policy.dnsSanRegExs(), request.dnsNames())) { + throw new VCertException( + "The requested Subject Alternative Name does not match any of the allowed Country regular expressions"); + } + // todo (from Go SDK): add ip, email and over checking + + List allowedKeyConfigurations = policy.allowedKeyConfigurations(); + if (allowedKeyConfigurations != null && allowedKeyConfigurations.size() > 0) { + for (AllowedKeyConfiguration keyConfiguration : allowedKeyConfigurations) { + if (keyConfiguration.keyType() == request.keyType()) { + if (request.keyLength() > 0) { + for (Integer size : keyConfiguration.keySizes()) { + if (size.equals(request.keyLength())) { + return true; + } } + } + return true; } + } + throw new VCertException( + "The requested Key Type and Size do not match any of the allowed Key Types and Sizes"); + } + + return true; + } + + private boolean isComponentValid(Collection regexes, Collection components) { + if (regexes.size() == 0 || components.size() == 0) { + return true; + } + + for (String regex : regexes) { + Pattern pattern; + try { + pattern = Pattern.compile(regex); + } catch (PatternSyntaxException e) { + // TODO log error return false; + } + for (String component : components) { + Matcher m = pattern.matcher(component); + if (m.matches()) { + return true; // todo: that seems wrong. Check if all policy rules need to be matched, or + // any one? (E.g.: Policy says location is [0]:Madrid,[1]:London - does it + // need to match either or both?) Also, if we have locations 0:London, 1: + // Brussels, 2: Madrid, won't this pass? Should it? + } + } } + return false; + } } diff --git a/src/main/java/com/venafi/vcert/sdk/endpoint/AllowedKeyConfiguration.java b/src/main/java/com/venafi/vcert/sdk/endpoint/AllowedKeyConfiguration.java index 4892a4f..59c475c 100644 --- a/src/main/java/com/venafi/vcert/sdk/endpoint/AllowedKeyConfiguration.java +++ b/src/main/java/com/venafi/vcert/sdk/endpoint/AllowedKeyConfiguration.java @@ -1,16 +1,15 @@ package com.venafi.vcert.sdk.endpoint; +import java.util.List; import com.google.gson.annotations.SerializedName; +import lombok.Data; import com.venafi.vcert.sdk.certificate.EllipticCurve; import com.venafi.vcert.sdk.certificate.KeyType; -import lombok.Data; - -import java.util.List; @Data public class AllowedKeyConfiguration { - @SerializedName("keytype") // todo: check server response for spelling - private KeyType keyType; - private List keySizes; - private List keyCurves; + @SerializedName("keytype") // todo: check server response for spelling + private KeyType keyType; + private List keySizes; + private List keyCurves; } diff --git a/src/main/java/com/venafi/vcert/sdk/endpoint/Authentication.java b/src/main/java/com/venafi/vcert/sdk/endpoint/Authentication.java index e2e67d2..2e9deb3 100644 --- a/src/main/java/com/venafi/vcert/sdk/endpoint/Authentication.java +++ b/src/main/java/com/venafi/vcert/sdk/endpoint/Authentication.java @@ -3,19 +3,19 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; -import lombok.NoArgsConstructor; @Data @AllArgsConstructor @Builder public class Authentication { - private String user; - private String password; // todo: char[] ? - private String apiKey; + private String user; + private String password; // todo: char[] ? + private String apiKey; - @Override - public String toString() { - return Authentication.class.getSimpleName() + "(user=" + user + ", apiKey=" + apiKey + ", password=" + (!password.isEmpty() ? "****" : "not set") + ")"; - } + @Override + public String toString() { + return Authentication.class.getSimpleName() + "(user=" + user + ", apiKey=" + apiKey + + ", password=" + (!password.isEmpty() ? "****" : "not set") + ")"; + } } diff --git a/src/main/java/com/venafi/vcert/sdk/endpoint/ConnectorType.java b/src/main/java/com/venafi/vcert/sdk/endpoint/ConnectorType.java index 90d8333..a5e82b0 100644 --- a/src/main/java/com/venafi/vcert/sdk/endpoint/ConnectorType.java +++ b/src/main/java/com/venafi/vcert/sdk/endpoint/ConnectorType.java @@ -1,5 +1,6 @@ package com.venafi.vcert.sdk.endpoint; public enum ConnectorType { - TPP, CLOUD + TPP, + CLOUD } diff --git a/src/main/java/com/venafi/vcert/sdk/utils/FeignUtils.java b/src/main/java/com/venafi/vcert/sdk/utils/FeignUtils.java index d4ca3c0..45b97c4 100644 --- a/src/main/java/com/venafi/vcert/sdk/utils/FeignUtils.java +++ b/src/main/java/com/venafi/vcert/sdk/utils/FeignUtils.java @@ -1,92 +1,94 @@ package com.venafi.vcert.sdk.utils; +import java.lang.reflect.Type; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.function.Supplier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import com.google.gson.FieldNamingPolicy; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; -import com.venafi.vcert.sdk.connectors.tpp.Tpp; import feign.Feign; import feign.Logger; import feign.gson.GsonDecoder; import feign.gson.GsonEncoder; import feign.slf4j.Slf4jLogger; - -import java.lang.reflect.Type; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; -import java.util.function.Supplier; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import com.venafi.vcert.sdk.connectors.tpp.Tpp; public class FeignUtils { - static Supplier gsonBuilderFactory = GsonBuilder::new; + static Supplier gsonBuilderFactory = GsonBuilder::new; - public static T client(Class clazz, String baseUrl) { - GsonBuilder builder = gsonBuilderFor(clazz); - return Feign.builder() - .encoder(encoder(builder)) - .decoder(decoder(builder)) - .logger(new Slf4jLogger()) - .logLevel(Logger.Level.BASIC) - .target(clazz, baseUrl); - } + public static T client(Class clazz, String baseUrl) { + GsonBuilder builder = gsonBuilderFor(clazz); + return Feign.builder().encoder(encoder(builder)).decoder(decoder(builder)) + .logger(new Slf4jLogger()).logLevel(Logger.Level.BASIC).target(clazz, baseUrl); + } - private static GsonBuilder gsonBuilderFor(Class clazz) { - GsonBuilder builder = gsonBuilderFactory.get(); - if (Tpp.class.equals(clazz)) { - builder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE); - } - return builder; + private static GsonBuilder gsonBuilderFor(Class clazz) { + GsonBuilder builder = gsonBuilderFactory.get(); + if (Tpp.class.equals(clazz)) { + builder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE); } + return builder; + } - private static GsonDecoder decoder(GsonBuilder builder) { - return new GsonDecoder(builder - .registerTypeAdapter(OffsetDateTime.class, new MicrosoftJsonDateFormatDeserializer()) - .create()); - } + private static GsonDecoder decoder(GsonBuilder builder) { + return new GsonDecoder( + builder.registerTypeAdapter(OffsetDateTime.class, new MicrosoftJsonDateFormatDeserializer()) + .create()); + } - private static GsonEncoder encoder(GsonBuilder builder) { - return new GsonEncoder(builder.create()); - } + private static GsonEncoder encoder(GsonBuilder builder) { + return new GsonEncoder(builder.create()); + } - /** - * @see origin story - */ - private static class MicrosoftJsonDateFormatDeserializer implements JsonDeserializer { + /** + * @see origin + * story + */ + private static class MicrosoftJsonDateFormatDeserializer + implements JsonDeserializer { - static final Pattern msDate = Pattern.compile("^/Date\\((?\\d+)(?(?:[+-]\\d+|Z))?\\)/$"); - static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + static final Pattern msDate = + Pattern.compile("^/Date\\((?\\d+)(?(?:[+-]\\d+|Z))?\\)/$"); + static final DateTimeFormatter formatter = + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); - @Override - public OffsetDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - if (json.isJsonNull() || json.getAsString().isEmpty()) { - throw new JsonParseException(String.format("Unable to parse ZonedDateTime from [ %s ].", json.toString())); - } - String dateString = json.getAsString(); - Matcher input = msDate.matcher(dateString); - if (!input.matches()) { - return OffsetDateTime.parse(dateString, formatter); - } - // There is apocryphal, anecdotal evidence that the format can have an offset, although the original blog - // post doesn't seem to mention it - and it would, indeed, be counterproductive, as the JavaScript Date() - // constructor doesn't accept epoch with offset as an argument - but we can't rule out the existence - // of such time stamps in the wild, so we support them. - if (input.group("offset") != null) { - return OffsetDateTime - .from(Instant.ofEpochMilli(Long.parseLong(input.group("epoch")))) - .withOffsetSameInstant(ZoneOffset.of(input.group("offset"))); - } - return OffsetDateTime - .from(Instant - .ofEpochMilli(Long.parseLong(input.group("epoch"))) - .atZone(ZoneOffset.UTC)); - } + @Override + public OffsetDateTime deserialize(JsonElement json, Type typeOfT, + JsonDeserializationContext context) throws JsonParseException { + if (json.isJsonNull() || json.getAsString().isEmpty()) { + throw new JsonParseException( + String.format("Unable to parse ZonedDateTime from [ %s ].", json.toString())); + } + String dateString = json.getAsString(); + Matcher input = msDate.matcher(dateString); + if (!input.matches()) { + return OffsetDateTime.parse(dateString, formatter); + } + // There is apocryphal, anecdotal evidence that the format can have an offset, although the + // original blog + // post doesn't seem to mention it - and it would, indeed, be counterproductive, as the + // JavaScript Date() + // constructor doesn't accept epoch with offset as an argument - but we can't rule out the + // existence + // of such time stamps in the wild, so we support them. + if (input.group("offset") != null) { + return OffsetDateTime.from(Instant.ofEpochMilli(Long.parseLong(input.group("epoch")))) + .withOffsetSameInstant(ZoneOffset.of(input.group("offset"))); + } + return OffsetDateTime + .from(Instant.ofEpochMilli(Long.parseLong(input.group("epoch"))).atZone(ZoneOffset.UTC)); } -} \ No newline at end of file + } +} diff --git a/src/main/java/com/venafi/vcert/sdk/utils/Is.java b/src/main/java/com/venafi/vcert/sdk/utils/Is.java index 20e1307..df91a78 100644 --- a/src/main/java/com/venafi/vcert/sdk/utils/Is.java +++ b/src/main/java/com/venafi/vcert/sdk/utils/Is.java @@ -4,25 +4,27 @@ public class Is { - public static boolean blank(Collection collection) { - return collection == null || collection.isEmpty(); - } + public static boolean blank(Collection collection) { + return collection == null || collection.isEmpty(); + } - public static boolean blank(byte[] array) { - return array == null || array.length == 0; - } + public static boolean blank(byte[] array) { + return array == null || array.length == 0; + } - /** - * - * @param left - * @param right - * @return - * @see SO - * @see explanation - * @see Go version - */ - public static boolean equalsFold(String left, String right) { - return (left != null && right != null && left.toUpperCase().equals(right.toUpperCase())) - || (left == null && right == null); - } + /** + * + * @param left + * @param right + * @return + * @see SO + * @see explanation + * @see Go version + */ + public static boolean equalsFold(String left, String right) { + return (left != null && right != null && left.toUpperCase().equals(right.toUpperCase())) + || (left == null && right == null); + } } diff --git a/src/test/java/com/venafi/vcert/sdk/ConfigTest.java b/src/test/java/com/venafi/vcert/sdk/ConfigTest.java index f6b753d..bb37cd0 100644 --- a/src/test/java/com/venafi/vcert/sdk/ConfigTest.java +++ b/src/test/java/com/venafi/vcert/sdk/ConfigTest.java @@ -1,74 +1,72 @@ package com.venafi.vcert.sdk; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.net.URISyntaxException; import java.nio.file.Path; import java.nio.file.Paths; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; class ConfigTest { - @Test - @DisplayName("Configuration file for TPP") - void loadConfigurationFileForTpp() throws URISyntaxException, VCertException { - final Config config = Config.loadConfigFromFile(getFilePath("validTPPConfig.ini")); - - assertThat(config.baseUrl()).isEqualTo("https://ha-tpp1.example.com:5008/vedsdk"); - assertThat(config.credentials().user()).isEqualTo("admin"); - assertThat(config.credentials().password()).isEqualTo("xxx"); - assertThat(config.zone()).isEqualTo("devops\\vcert"); - } - - @Test - @DisplayName("Invalid configuration missing password") - void loadConfigurationFileForTppMissingPassword() { - Throwable throwable = assertThrows(VCertException.class, - () -> Config.loadConfigFromFile(getFilePath("invalidTPPMissingPassword.ini"))); - - assertThat(throwable.getMessage()).contains("missing TTP password"); - } - - @Test - @DisplayName("Load valid cloud configuration") - void loadConfigurationFileForCloud() throws URISyntaxException, VCertException { - final Config config = Config.loadConfigFromFile(getFilePath("validCloudConfig.ini")); - - assertThat(config.baseUrl()).isEqualTo("https://api.dev12.qa.venafi.io/v1"); - assertThat(config.credentials().apiKey()).isEqualTo("xxxxxxxx-b256-4c43-a4d4-15372ce2d548"); - assertThat(config.zone()).isEqualTo("Default"); - } - - @Test - @DisplayName("Load an invalid cloud configuration") - void loadConfigurationInvalidFileForCloud() { - Throwable throwable = assertThrows(VCertException.class, - () -> Config.loadConfigFromFile(getFilePath("invalidCloudConfig.ini"))); - assertThat(throwable.getMessage()).contains("illegal key tpp_user in section"); - } - - @Test - @DisplayName("Empty config file is not accepted") - void emptyConfigFile() { - Throwable throwable = assertThrows(VCertException.class, - () -> Config.loadConfigFromFile(getFilePath("emptyConfig.ini"))); - assertThat(throwable.getMessage()).contains("The configuration file is empty"); - } - - @Test - @DisplayName("Invalid configuration file") - void invalidConfigFile() { - Throwable throwable = assertThrows(VCertException.class, - () -> Config.loadConfigFromFile(getFilePath("invalidConfig.ini"))); - assertThat(throwable.getMessage()).contains("requires 'tpp_url' or 'cloud_apikey'"); - } - - private Path getFilePath(String resourceName) throws URISyntaxException { - return Paths.get(this.getClass().getClassLoader().getResource(resourceName).toURI()); - } - -} \ No newline at end of file + @Test + @DisplayName("Configuration file for TPP") + void loadConfigurationFileForTpp() throws URISyntaxException, VCertException { + final Config config = Config.loadConfigFromFile(getFilePath("validTPPConfig.ini")); + + assertThat(config.baseUrl()).isEqualTo("https://ha-tpp1.example.com:5008/vedsdk"); + assertThat(config.credentials().user()).isEqualTo("admin"); + assertThat(config.credentials().password()).isEqualTo("xxx"); + assertThat(config.zone()).isEqualTo("devops\\vcert"); + } + + @Test + @DisplayName("Invalid configuration missing password") + void loadConfigurationFileForTppMissingPassword() { + Throwable throwable = assertThrows(VCertException.class, + () -> Config.loadConfigFromFile(getFilePath("invalidTPPMissingPassword.ini"))); + + assertThat(throwable.getMessage()).contains("missing TPP password"); + } + + @Test + @DisplayName("Load valid cloud configuration") + void loadConfigurationFileForCloud() throws URISyntaxException, VCertException { + final Config config = Config.loadConfigFromFile(getFilePath("validCloudConfig.ini")); + + assertThat(config.baseUrl()).isEqualTo("https://api.dev12.qa.venafi.io/v1"); + assertThat(config.credentials().apiKey()).isEqualTo("xxxxxxxx-b256-4c43-a4d4-15372ce2d548"); + assertThat(config.zone()).isEqualTo("Default"); + } + + @Test + @DisplayName("Load an invalid cloud configuration") + void loadConfigurationInvalidFileForCloud() { + Throwable throwable = assertThrows(VCertException.class, + () -> Config.loadConfigFromFile(getFilePath("invalidCloudConfig.ini"))); + assertThat(throwable.getMessage()).contains("illegal key tpp_user in section"); + } + + @Test + @DisplayName("Empty config file is not accepted") + void emptyConfigFile() { + Throwable throwable = assertThrows(VCertException.class, + () -> Config.loadConfigFromFile(getFilePath("emptyConfig.ini"))); + assertThat(throwable.getMessage()).contains("The configuration file is empty"); + } + + @Test + @DisplayName("Invalid configuration file") + void invalidConfigFile() { + Throwable throwable = assertThrows(VCertException.class, + () -> Config.loadConfigFromFile(getFilePath("invalidConfig.ini"))); + assertThat(throwable.getMessage()).contains("requires 'tpp_url' or 'cloud_apikey'"); + } + + private Path getFilePath(String resourceName) throws URISyntaxException { + return Paths.get(this.getClass().getClassLoader().getResource(resourceName).toURI()); + } + +} diff --git a/src/test/java/com/venafi/vcert/sdk/Examples.java b/src/test/java/com/venafi/vcert/sdk/Examples.java index 9bab2ab..f5bfa62 100644 --- a/src/test/java/com/venafi/vcert/sdk/Examples.java +++ b/src/test/java/com/venafi/vcert/sdk/Examples.java @@ -1,5 +1,10 @@ package com.venafi.vcert.sdk; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collections; +import org.apache.commons.codec.digest.DigestUtils; import com.venafi.vcert.sdk.certificate.CertificateRequest; import com.venafi.vcert.sdk.certificate.KeyType; import com.venafi.vcert.sdk.certificate.PEMCollection; @@ -7,77 +12,64 @@ import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; import com.venafi.vcert.sdk.endpoint.Authentication; import com.venafi.vcert.sdk.endpoint.ConnectorType; -import org.apache.commons.codec.digest.DigestUtils; - -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Collections; public class Examples { - public static void main(String ... args) throws VCertException, CertificateEncodingException { - final Config config = Config.builder() - .connectorType(ConnectorType.CLOUD) - .zone("Default") - .build(); - - final VCertClient client = new VCertClient(config); - - final Authentication auth = Authentication.builder() - .apiKey("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") - .build(); - - client.authenticate(auth); - final ZoneConfiguration zoneConfiguration = client.readZoneConfiguration("Default"); - - // Generate a certificate - CertificateRequest certificateRequest = new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName("cert.test") - .organization(Collections.singletonList("Venafi, Inc.")) - .organizationalUnit(Arrays.asList("Engineering")) - .country(Collections.singletonList("US")) - .locality(Collections.singletonList("SLC")) - .province(Collections.singletonList("Utah"))) - - .keyType(KeyType.RSA); - certificateRequest = client.generateRequest(zoneConfiguration, certificateRequest); - - - // Submit the certificate request - String newCertId = client.requestCertificate(certificateRequest, "Default"); - - - // Retrieve PEM collection from Venafi - final CertificateRequest pickupRequest = new CertificateRequest().pickupId(newCertId); - PEMCollection pemCollection = client.retrieveCertificate(pickupRequest); - System.out.println(pemCollection.certificate()); - - // Renew the certificate - X509Certificate cert = (X509Certificate) pemCollection.certificate(); - String thumbprint = DigestUtils.sha1Hex(cert.getEncoded()).toUpperCase(); - final CertificateRequest certificateRequestToRenew = new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName("cert.test") - .organization(Collections.singletonList("Venafi, Inc.")) - .organizationalUnit(Arrays.asList("Engineering")) - .country(Collections.singletonList("US")) - .locality(Collections.singletonList("SLC")) - .province(Collections.singletonList("Utah"))); - - client.generateRequest(zoneConfiguration, certificateRequestToRenew); - - final RenewalRequest renewalRequest = new RenewalRequest() - .thumbprint(thumbprint) - .request(certificateRequestToRenew); - final String renewedCertificate = client.renewCertificate(renewalRequest); - - // Retrieve PEM collection from Venafi - final CertificateRequest renewPickupRequest = new CertificateRequest().pickupId(renewedCertificate); - PEMCollection pemCollectionRenewed = client.retrieveCertificate(pickupRequest); - System.out.println(pemCollectionRenewed.certificate()); - - } + public static void main(String... args) throws VCertException, CertificateEncodingException { + final Config config = + Config.builder().connectorType(ConnectorType.CLOUD).zone("Default").build(); + + final VCertClient client = new VCertClient(config); + + final Authentication auth = + Authentication.builder().apiKey("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx").build(); + + client.authenticate(auth); + final ZoneConfiguration zoneConfiguration = client.readZoneConfiguration("Default"); + + // Generate a certificate + CertificateRequest certificateRequest = new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName("cert.test") + .organization(Collections.singletonList("Venafi, Inc.")) + .organizationalUnit(Arrays.asList("Engineering")) + .country(Collections.singletonList("US")).locality(Collections.singletonList("SLC")) + .province(Collections.singletonList("Utah"))) + + .keyType(KeyType.RSA); + certificateRequest = client.generateRequest(zoneConfiguration, certificateRequest); + + + // Submit the certificate request + String newCertId = client.requestCertificate(certificateRequest, "Default"); + + + // Retrieve PEM collection from Venafi + final CertificateRequest pickupRequest = new CertificateRequest().pickupId(newCertId); + PEMCollection pemCollection = client.retrieveCertificate(pickupRequest); + System.out.println(pemCollection.certificate()); + + // Renew the certificate + X509Certificate cert = (X509Certificate) pemCollection.certificate(); + String thumbprint = DigestUtils.sha1Hex(cert.getEncoded()).toUpperCase(); + final CertificateRequest certificateRequestToRenew = + new CertificateRequest().subject(new CertificateRequest.PKIXName().commonName("cert.test") + .organization(Collections.singletonList("Venafi, Inc.")) + .organizationalUnit(Arrays.asList("Engineering")) + .country(Collections.singletonList("US")).locality(Collections.singletonList("SLC")) + .province(Collections.singletonList("Utah"))); + + client.generateRequest(zoneConfiguration, certificateRequestToRenew); + + final RenewalRequest renewalRequest = + new RenewalRequest().thumbprint(thumbprint).request(certificateRequestToRenew); + final String renewedCertificate = client.renewCertificate(renewalRequest); + + // Retrieve PEM collection from Venafi + final CertificateRequest renewPickupRequest = + new CertificateRequest().pickupId(renewedCertificate); + PEMCollection pemCollectionRenewed = client.retrieveCertificate(pickupRequest); + System.out.println(pemCollectionRenewed.certificate()); + + } } diff --git a/src/test/java/com/venafi/vcert/sdk/TestUtils.java b/src/test/java/com/venafi/vcert/sdk/TestUtils.java index 716e989..0397e14 100644 --- a/src/test/java/com/venafi/vcert/sdk/TestUtils.java +++ b/src/test/java/com/venafi/vcert/sdk/TestUtils.java @@ -1,14 +1,5 @@ package com.venafi.vcert.sdk; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; -import org.bouncycastle.openssl.PEMKeyPair; -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; -import org.bouncycastle.pkcs.PKCS10CertificationRequest; -import java.util.Base64; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; @@ -18,7 +9,11 @@ import java.net.SocketException; import java.nio.file.Files; import java.nio.file.Paths; -import java.security.*; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; @@ -27,70 +22,84 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.RSAPublicKeySpec; import java.util.ArrayList; +import java.util.Base64; import java.util.Collection; import java.util.Collections; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; public class TestUtils { - private static String loadFileContents(String name) throws IOException { - ClassLoader classLoader = TestUtils.class.getClassLoader(); - return new String(Files.readAllBytes(Paths.get(classLoader.getResource(name).getPath()))); - } + private static String loadFileContents(String name) throws IOException { + ClassLoader classLoader = TestUtils.class.getClassLoader(); + return new String(Files.readAllBytes(Paths.get(classLoader.getResource(name).getPath()))); + } - public static Certificate loadCertificateFromFile(String name) throws IOException, CertificateException { - PEMParser pemParser = new PEMParser(new StringReader(loadFileContents("certificates/" + name))); - JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter(); - Object object = pemParser.readObject(); - return certificateConverter.getCertificate((X509CertificateHolder) object); - } + public static Certificate loadCertificateFromFile(String name) + throws IOException, CertificateException { + PEMParser pemParser = new PEMParser(new StringReader(loadFileContents("certificates/" + name))); + JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter(); + Object object = pemParser.readObject(); + return certificateConverter.getCertificate((X509CertificateHolder) object); + } - public static KeyPair loadPrivateKeyFromFileAndGeneratePublicKey(String name) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { - PEMParser pemParser = new PEMParser(new StringReader(loadFileContents("certificates/" + name))); - JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); - Object object = pemParser.readObject(); - PrivateKey privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object); - RSAPrivateCrtKey privk = (RSAPrivateCrtKey) privateKey; - RSAPublicKeySpec publicKeySpec = new java.security.spec.RSAPublicKeySpec(privk.getModulus(), privk.getPublicExponent()); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); - return new KeyPair(publicKey, privateKey); - } + public static KeyPair loadPrivateKeyFromFileAndGeneratePublicKey(String name) + throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { + PEMParser pemParser = new PEMParser(new StringReader(loadFileContents("certificates/" + name))); + JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); + Object object = pemParser.readObject(); + PrivateKey privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object); + RSAPrivateCrtKey privk = (RSAPrivateCrtKey) privateKey; + RSAPublicKeySpec publicKeySpec = + new java.security.spec.RSAPublicKeySpec(privk.getModulus(), privk.getPublicExponent()); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); + return new KeyPair(publicKey, privateKey); + } - public static KeyPair loadKeyPairFromFile(String name) throws IOException { - PEMParser pemParser = new PEMParser(new StringReader(loadFileContents("certificates/" + name))); - JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); - PEMKeyPair keyPair = (PEMKeyPair) pemParser.readObject(); - PrivateKey privateKey = keyConverter.getPrivateKey(keyPair.getPrivateKeyInfo()); - PublicKey publicKey = keyConverter.getPublicKey(keyPair.getPublicKeyInfo()); - return new KeyPair(publicKey, privateKey); - } + public static KeyPair loadKeyPairFromFile(String name) throws IOException { + PEMParser pemParser = new PEMParser(new StringReader(loadFileContents("certificates/" + name))); + JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); + PEMKeyPair keyPair = (PEMKeyPair) pemParser.readObject(); + PrivateKey privateKey = keyConverter.getPrivateKey(keyPair.getPrivateKeyInfo()); + PublicKey publicKey = keyConverter.getPublicKey(keyPair.getPublicKeyInfo()); + return new KeyPair(publicKey, privateKey); + } - public static byte[] getCertificateAsBytes(X509Certificate certificate) throws IOException, CertificateEncodingException { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + public static byte[] getCertificateAsBytes(X509Certificate certificate) + throws IOException, CertificateEncodingException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - outputStream.write("-----BEGIN CERTIFICATE-----".getBytes()); - outputStream.write(System.lineSeparator().getBytes()); - outputStream.write(Base64.getEncoder().encode(certificate.getEncoded())); - outputStream.write(System.lineSeparator().getBytes()); - outputStream.write("-----END CERTIFICATE-----".getBytes()); - return outputStream.toByteArray(); - } + outputStream.write("-----BEGIN CERTIFICATE-----".getBytes()); + outputStream.write(System.lineSeparator().getBytes()); + outputStream.write(Base64.getEncoder().encode(certificate.getEncoded())); + outputStream.write(System.lineSeparator().getBytes()); + outputStream.write("-----END CERTIFICATE-----".getBytes()); + return outputStream.toByteArray(); + } - public static PKCS10CertificationRequest loadCertificateSigningRequestFromFile(String name) throws IOException { - StringReader reader = new StringReader(loadFileContents("certificates/" + name)); - try(PEMParser pemParser = new PEMParser(reader)) { - return (PKCS10CertificationRequest) pemParser.readObject(); - } + public static PKCS10CertificationRequest loadCertificateSigningRequestFromFile(String name) + throws IOException { + StringReader reader = new StringReader(loadFileContents("certificates/" + name)); + try (PEMParser pemParser = new PEMParser(reader)) { + return (PKCS10CertificationRequest) pemParser.readObject(); } + } - public static Collection getTestIps() throws SocketException { - Collection ips = new ArrayList<>(); - for(NetworkInterface networkInterface : Collections.list(NetworkInterface.getNetworkInterfaces())) { - for(InetAddress inetAddress : Collections.list(networkInterface.getInetAddresses())) { - if(!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) { - ips.add(inetAddress); - } - } + public static Collection getTestIps() throws SocketException { + Collection ips = new ArrayList<>(); + for (NetworkInterface networkInterface : Collections + .list(NetworkInterface.getNetworkInterfaces())) { + for (InetAddress inetAddress : Collections.list(networkInterface.getInetAddresses())) { + if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) { + ips.add(inetAddress); } - return ips; + } } + return ips; + } } diff --git a/src/test/java/com/venafi/vcert/sdk/VCertClientTest.java b/src/test/java/com/venafi/vcert/sdk/VCertClientTest.java index 774bca7..bc2d741 100644 --- a/src/test/java/com/venafi/vcert/sdk/VCertClientTest.java +++ b/src/test/java/com/venafi/vcert/sdk/VCertClientTest.java @@ -1,5 +1,15 @@ package com.venafi.vcert.sdk; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import java.security.Security; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import feign.FeignException; import com.venafi.vcert.sdk.certificate.CertificateRequest; import com.venafi.vcert.sdk.certificate.ImportRequest; import com.venafi.vcert.sdk.certificate.RenewalRequest; @@ -8,266 +18,243 @@ import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; import com.venafi.vcert.sdk.endpoint.Authentication; import com.venafi.vcert.sdk.endpoint.ConnectorType; -import feign.FeignException; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import java.security.Security; +class VCertClientTest { -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.*; + private final Connector connector = mock(Connector.class); + private final VCertClient classUnderTest = new VCertClient(connector); + + @Test + @DisplayName("Create venafi cloud client") + void getTypeCloud() throws VCertException { + final Config config = Config.builder().connectorType(ConnectorType.CLOUD).build(); + + VCertClient client = new VCertClient(config); + + assertThat(client).isNotNull(); + assertThat(client.getType()).isEqualTo(ConnectorType.CLOUD); + assertThat(Security.getProviders()).anyMatch(p -> p instanceof BouncyCastleProvider); + } + + @Test + @DisplayName("Create venafi tpp client") + void getTypeTpp() throws VCertException { + final Config config = Config.builder().connectorType(ConnectorType.TPP) + .baseUrl("https://localhost/vesdk/").build(); + + VCertClient client = new VCertClient(config); + + assertThat(client).isNotNull(); + assertThat(client.getType()).isEqualTo(ConnectorType.TPP); + assertThat(Security.getProviders()).anyMatch(p -> p instanceof BouncyCastleProvider); + } + + @Test + @DisplayName("Set baseurl") + void setBaseUrl() throws VCertException { + classUnderTest.setBaseUrl("https://base_url_test/"); + verify(connector).setBaseUrl("https://base_url_test/"); + } + + @Test + @DisplayName("Set venafi default zone") + void setZone() { + classUnderTest.setZone("test_zone"); + verify(connector).setZone("test_zone"); + } + + @Test + @DisplayName("Ping venafi service") + void ping() throws VCertException { + classUnderTest.ping(); + verify(connector).ping(); + } + + @Test + @DisplayName("Ping venafi service with server error") + void pingWithException() throws VCertException { + doThrow(new FeignException.InternalServerError("Error", "".getBytes())).when(connector).ping(); + + assertThrows(VCertException.class, () -> classUnderTest.ping()); + } + + @Test + @DisplayName("Authenticated with venafi endpoint") + void authenticateWithException() throws VCertException { + final Authentication auth = mock(Authentication.class); + + doThrow(new FeignException.InternalServerError("Error", "".getBytes())).when(connector) + .authenticate(auth); + + assertThrows(VCertException.class, () -> classUnderTest.authenticate(auth)); + } + + @Test + @DisplayName("Authenticated with venafi endpoint with server error") + void authenticate() throws VCertException { + final Authentication auth = mock(Authentication.class); + classUnderTest.authenticate(auth); + + verify(connector).authenticate(auth); + } + + @Test + @DisplayName("Read zone configuration") + void readZoneConfiguration() throws VCertException { + classUnderTest.readZoneConfiguration("test_zone"); + + verify(connector).readZoneConfiguration("test_zone"); + } + + @Test + @DisplayName("Read zone configuration with server error") + void readZoneConfigurationWithServerError() throws VCertException { + doThrow(new FeignException.InternalServerError("Error", "".getBytes())).when(connector) + .readZoneConfiguration("test_zone"); + + assertThrows(VCertException.class, () -> classUnderTest.readZoneConfiguration("test_zone")); + } + + @Test + @DisplayName("Generate request") + void generateRequest() throws VCertException { + final ZoneConfiguration zoneConfiguration = mock(ZoneConfiguration.class); + final CertificateRequest certificateRequest = mock(CertificateRequest.class); + + classUnderTest.generateRequest(zoneConfiguration, certificateRequest); + verify(connector).generateRequest(zoneConfiguration, certificateRequest); + } + + @Test + @DisplayName("Generate request with server error") + void generateRequestWithServerError() throws VCertException { + final ZoneConfiguration zoneConfiguration = mock(ZoneConfiguration.class); + final CertificateRequest certificateRequest = mock(CertificateRequest.class); + + doThrow(new FeignException.InternalServerError("Error", "".getBytes())).when(connector) + .generateRequest(zoneConfiguration, certificateRequest); + + assertThrows(VCertException.class, + () -> classUnderTest.generateRequest(zoneConfiguration, certificateRequest)); + } + + @Test + @DisplayName("Request certificate") + void requestCertificate() throws VCertException { + final CertificateRequest certificateRequest = mock(CertificateRequest.class); + classUnderTest.requestCertificate(certificateRequest, "test_zone"); + + verify(connector).requestCertificate(certificateRequest, "test_zone"); + } + + @Test + @DisplayName("Request certificate with server error") + void requestCertificateWithServerError() throws VCertException { + final CertificateRequest certificateRequest = mock(CertificateRequest.class); + + doThrow(new FeignException.InternalServerError("Error", "".getBytes())).when(connector) + .requestCertificate(certificateRequest, "test_zone"); + + assertThrows(VCertException.class, + () -> classUnderTest.requestCertificate(certificateRequest, "test_zone")); + } + + @Test + @DisplayName("Retrieve certificate") + void retrieveCertificate() throws VCertException { + final CertificateRequest certificateRequest = mock(CertificateRequest.class); + + classUnderTest.retrieveCertificate(certificateRequest); + verify(connector).retrieveCertificate(certificateRequest); + + } + + @Test + @DisplayName("Retrieve certificate with server error") + void retrieveCertificateWithServerError() throws VCertException { + final CertificateRequest certificateRequest = mock(CertificateRequest.class); + + doThrow(new FeignException.InternalServerError("Error", "".getBytes())).when(connector) + .retrieveCertificate(certificateRequest); + + assertThrows(VCertException.class, + () -> classUnderTest.retrieveCertificate(certificateRequest)); + } + + @Test + @DisplayName("Revoke certificate") + void revokeCertificate() throws VCertException { + final RevocationRequest revocationRequest = mock(RevocationRequest.class); + + classUnderTest.revokeCertificate(revocationRequest); + verify(connector).revokeCertificate(revocationRequest); + } + + @Test + @DisplayName("Revoke certificate with server error") + void revokeCertificateWithServerError() throws VCertException { + final RevocationRequest revocationRequest = mock(RevocationRequest.class); + + doThrow(new FeignException.InternalServerError("Error", "".getBytes())).when(connector) + .revokeCertificate(revocationRequest); + + assertThrows(VCertException.class, () -> classUnderTest.revokeCertificate(revocationRequest)); + } + + + @Test + @DisplayName("Renew certificate") + void renewCertificate() throws VCertException { + final RenewalRequest renewalRequest = mock(RenewalRequest.class); + + classUnderTest.renewCertificate(renewalRequest); + verify(connector).renewCertificate(renewalRequest); + } + + @Test + @DisplayName("Renew certificate with server error") + void renewCertificateWithServerError() throws VCertException { + final RenewalRequest renewalRequest = mock(RenewalRequest.class); + + doThrow(new FeignException.InternalServerError("Error", "".getBytes())).when(connector) + .renewCertificate(renewalRequest); + + assertThrows(VCertException.class, () -> classUnderTest.renewCertificate(renewalRequest)); + } + + @Test + @DisplayName("Import certificate") + void importCertificate() throws VCertException { + final ImportRequest importRequest = mock(ImportRequest.class); + + classUnderTest.importCertificate(importRequest); + verify(connector).importCertificate(importRequest); + } -class VCertClientTest { + @Test + @DisplayName("Import certificate with server error") + void importCertificateWithServerError() throws VCertException { + final ImportRequest importRequest = mock(ImportRequest.class); + + doThrow(new FeignException.InternalServerError("Error", "".getBytes())).when(connector) + .importCertificate(importRequest); + + assertThrows(VCertException.class, () -> classUnderTest.importCertificate(importRequest)); + } + + @Test + @DisplayName("Read policy configuration") + void readPolicyConfiguration() throws VCertException { + classUnderTest.readZoneConfiguration("test_zone"); + verify(connector).readZoneConfiguration("test_zone"); + } + + @Test + @DisplayName("Read policy configuration with server error") + void readPolicyConfigurationWithServerError() throws VCertException { + doThrow(new FeignException.InternalServerError("Error", "".getBytes())).when(connector) + .readPolicyConfiguration("test_zone"); - private final Connector connector = mock(Connector.class); - private final VCertClient classUnderTest = new VCertClient(connector); - - @Test - @DisplayName("Create venafi cloud client") - void getTypeCloud() throws VCertException { - final Config config = Config.builder() - .connectorType(ConnectorType.CLOUD) - .build(); - - VCertClient client = new VCertClient(config); - - assertThat(client).isNotNull(); - assertThat(client.getType()).isEqualTo(ConnectorType.CLOUD); - assertThat(Security.getProviders()).anyMatch(p -> p instanceof BouncyCastleProvider); - } - - @Test - @DisplayName("Create venafi tpp client") - void getTypeTpp() throws VCertException { - final Config config = Config.builder() - .connectorType(ConnectorType.TPP) - .baseUrl("https://localhost/vesdk/") - .build(); - - VCertClient client = new VCertClient(config); - - assertThat(client).isNotNull(); - assertThat(client.getType()).isEqualTo(ConnectorType.TPP); - assertThat(Security.getProviders()).anyMatch(p -> p instanceof BouncyCastleProvider); - } - - @Test - @DisplayName("Set baseurl") - void setBaseUrl() throws VCertException { - classUnderTest.setBaseUrl("https://base_url_test/"); - verify(connector).setBaseUrl("https://base_url_test/"); - } - - @Test - @DisplayName("Set venafi default zone") - void setZone() { - classUnderTest.setZone("test_zone"); - verify(connector).setZone("test_zone"); - } - - @Test - @DisplayName("Ping venafi service") - void ping() throws VCertException { - classUnderTest.ping(); - verify(connector).ping(); - } - - @Test - @DisplayName("Ping venafi service with server error") - void pingWithException() throws VCertException { - doThrow(new FeignException.InternalServerError("Error", "".getBytes())) - .when(connector) - .ping(); - - assertThrows(VCertException.class, () -> classUnderTest.ping()); - } - - @Test - @DisplayName("Authenticated with venafi endpoint") - void authenticateWithException() throws VCertException { - final Authentication auth = mock(Authentication.class); - - doThrow(new FeignException.InternalServerError("Error", "".getBytes())) - .when(connector) - .authenticate(auth); - - assertThrows(VCertException.class, () -> classUnderTest.authenticate(auth)); - } - - @Test - @DisplayName("Authenticated with venafi endpoint with server error") - void authenticate() throws VCertException { - final Authentication auth = mock(Authentication.class); - classUnderTest.authenticate(auth); - - verify(connector).authenticate(auth); - } - - @Test - @DisplayName("Read zone configuration") - void readZoneConfiguration() throws VCertException { - classUnderTest.readZoneConfiguration("test_zone"); - - verify(connector).readZoneConfiguration("test_zone"); - } - - @Test - @DisplayName("Read zone configuration with server error") - void readZoneConfigurationWithServerError() throws VCertException { - doThrow(new FeignException.InternalServerError("Error", "".getBytes())) - .when(connector) - .readZoneConfiguration("test_zone"); - - assertThrows(VCertException.class, () -> classUnderTest.readZoneConfiguration("test_zone")); - } - - @Test - @DisplayName("Generate request") - void generateRequest() throws VCertException { - final ZoneConfiguration zoneConfiguration = mock(ZoneConfiguration.class); - final CertificateRequest certificateRequest = mock(CertificateRequest.class); - - classUnderTest.generateRequest(zoneConfiguration, certificateRequest); - verify(connector).generateRequest(zoneConfiguration, certificateRequest); - } - - @Test - @DisplayName("Generate request with server error") - void generateRequestWithServerError() throws VCertException { - final ZoneConfiguration zoneConfiguration = mock(ZoneConfiguration.class); - final CertificateRequest certificateRequest = mock(CertificateRequest.class); - - doThrow(new FeignException.InternalServerError("Error", "".getBytes())) - .when(connector) - .generateRequest(zoneConfiguration, certificateRequest); - - assertThrows(VCertException.class, () -> classUnderTest.generateRequest(zoneConfiguration, certificateRequest)); - } - - @Test - @DisplayName("Request certificate") - void requestCertificate() throws VCertException { - final CertificateRequest certificateRequest = mock(CertificateRequest.class); - classUnderTest.requestCertificate(certificateRequest, "test_zone"); - - verify(connector).requestCertificate(certificateRequest, "test_zone"); - } - - @Test - @DisplayName("Request certificate with server error") - void requestCertificateWithServerError() throws VCertException { - final CertificateRequest certificateRequest = mock(CertificateRequest.class); - - doThrow(new FeignException.InternalServerError("Error", "".getBytes())) - .when(connector) - .requestCertificate(certificateRequest, "test_zone"); - - assertThrows(VCertException.class, - () -> classUnderTest.requestCertificate(certificateRequest, "test_zone")); - } - - @Test - @DisplayName("Retrieve certificate") - void retrieveCertificate() throws VCertException { - final CertificateRequest certificateRequest = mock(CertificateRequest.class); - - classUnderTest.retrieveCertificate(certificateRequest); - verify(connector).retrieveCertificate(certificateRequest); - - } - - @Test - @DisplayName("Retrieve certificate with server error") - void retrieveCertificateWithServerError() throws VCertException { - final CertificateRequest certificateRequest = mock(CertificateRequest.class); - - doThrow(new FeignException.InternalServerError("Error", "".getBytes())) - .when(connector) - .retrieveCertificate(certificateRequest); - - assertThrows(VCertException.class, () -> classUnderTest.retrieveCertificate(certificateRequest)); - } - - @Test - @DisplayName("Revoke certificate") - void revokeCertificate() throws VCertException { - final RevocationRequest revocationRequest = mock(RevocationRequest.class); - - classUnderTest.revokeCertificate(revocationRequest); - verify(connector).revokeCertificate(revocationRequest); - } - - @Test - @DisplayName("Revoke certificate with server error") - void revokeCertificateWithServerError() throws VCertException { - final RevocationRequest revocationRequest = mock(RevocationRequest.class); - - doThrow(new FeignException.InternalServerError("Error", "".getBytes())) - .when(connector) - .revokeCertificate(revocationRequest); - - assertThrows(VCertException.class, () -> classUnderTest.revokeCertificate(revocationRequest)); - } - - - @Test - @DisplayName("Renew certificate") - void renewCertificate() throws VCertException { - final RenewalRequest renewalRequest = mock(RenewalRequest.class); - - classUnderTest.renewCertificate(renewalRequest); - verify(connector).renewCertificate(renewalRequest); - } - - @Test - @DisplayName("Renew certificate with server error") - void renewCertificateWithServerError() throws VCertException { - final RenewalRequest renewalRequest = mock(RenewalRequest.class); - - doThrow(new FeignException.InternalServerError("Error", "".getBytes())) - .when(connector) - .renewCertificate(renewalRequest); - - assertThrows(VCertException.class, () -> classUnderTest.renewCertificate(renewalRequest)); - } - - @Test - @DisplayName("Import certificate") - void importCertificate() throws VCertException { - final ImportRequest importRequest = mock(ImportRequest.class); - - classUnderTest.importCertificate(importRequest); - verify(connector).importCertificate(importRequest); - } - - @Test - @DisplayName("Import certificate with server error") - void importCertificateWithServerError() throws VCertException { - final ImportRequest importRequest = mock(ImportRequest.class); - - doThrow(new FeignException.InternalServerError("Error", "".getBytes())) - .when(connector) - .importCertificate(importRequest); - - assertThrows(VCertException.class, () -> classUnderTest.importCertificate(importRequest)); - } - - @Test - @DisplayName("Read policy configuration") - void readPolicyConfiguration() throws VCertException { - classUnderTest.readZoneConfiguration("test_zone"); - verify(connector).readZoneConfiguration("test_zone"); - } - - @Test - @DisplayName("Read policy configuration with server error") - void readPolicyConfigurationWithServerError() throws VCertException { - doThrow(new FeignException.InternalServerError("Error", "".getBytes())) - .when(connector) - .readPolicyConfiguration("test_zone"); - - assertThrows(VCertException.class, () -> classUnderTest.readPolicyConfiguration("test_zone")); - } -} \ No newline at end of file + assertThrows(VCertException.class, () -> classUnderTest.readPolicyConfiguration("test_zone")); + } +} diff --git a/src/test/java/com/venafi/vcert/sdk/VCertExceptionTest.java b/src/test/java/com/venafi/vcert/sdk/VCertExceptionTest.java index 65545ea..6a8b8b0 100644 --- a/src/test/java/com/venafi/vcert/sdk/VCertExceptionTest.java +++ b/src/test/java/com/venafi/vcert/sdk/VCertExceptionTest.java @@ -1,15 +1,15 @@ package com.venafi.vcert.sdk; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.Test; class VCertExceptionTest { - @Test - void throwIfNull() { - Exception exception = assertThrows(VCertException.class, () -> VCertException.throwIfNull(null, "foo cannot be null")); - assertEquals("foo cannot be null", exception.getMessage()); - } -} \ No newline at end of file + @Test + void throwIfNull() { + Exception exception = assertThrows(VCertException.class, + () -> VCertException.throwIfNull(null, "foo cannot be null")); + assertEquals("foo cannot be null", exception.getMessage()); + } +} diff --git a/src/test/java/com/venafi/vcert/sdk/certificate/CertificateRequestTest.java b/src/test/java/com/venafi/vcert/sdk/certificate/CertificateRequestTest.java index d765a95..ceda075 100644 --- a/src/test/java/com/venafi/vcert/sdk/certificate/CertificateRequestTest.java +++ b/src/test/java/com/venafi/vcert/sdk/certificate/CertificateRequestTest.java @@ -1,31 +1,27 @@ package com.venafi.vcert.sdk.certificate; -import com.venafi.vcert.sdk.SignatureAlgorithm; -import com.venafi.vcert.sdk.VCertException; - -import java.net.*; -import java.security.KeyPair; -import java.security.Security; -import java.security.Signature; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; -import org.bouncycastle.pkcs.PKCS10CertificationRequest; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import java.util.Base64; - +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.fail; +import static org.junit.platform.commons.util.StringUtils.isNotBlank; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; import java.nio.file.Files; import java.nio.file.Paths; -import java.security.*; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.Signature; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.interfaces.RSAPrivateCrtKey; @@ -33,237 +29,260 @@ import java.security.spec.RSAPublicKeySpec; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.Collection; import java.util.Collections; import java.util.concurrent.ThreadLocalRandom; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; import java.util.stream.Stream; - -import static java.lang.String.format; -import static org.assertj.core.api.Assertions.*; -import static org.junit.platform.commons.util.StringUtils.isNotBlank; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import com.venafi.vcert.sdk.SignatureAlgorithm; +import com.venafi.vcert.sdk.VCertException; class CertificateRequestTest { - @Test - void generateECDSAPrivateKey() { - Security.addProvider(new BouncyCastleProvider()); - - assertThatCode(() -> { - CertificateRequest certificateRequest = generateTestCertificateRequest(getTestIps()); - KeyPair keyPair = certificateRequest.generateECDSAKeyPair(EllipticCurve.EllipticCurveP224); - verifyKeyPair(keyPair, SignatureAlgorithm.ECDSAWithSHA256.standardName()); - }).doesNotThrowAnyException(); - } - - @Test - void generateRSAKeyPair() { - assertThatCode(() -> { - CertificateRequest certificateRequest = generateTestCertificateRequest(getTestIps()); - KeyPair keyPair = certificateRequest.generateRSAKeyPair(512); - verifyKeyPair(keyPair, SignatureAlgorithm.SHA256WithRSA.standardName()); - }).doesNotThrowAnyException(); - } - - @Test - void generateCertificateRequestWithRSAKey() throws IOException, VCertException { - Security.addProvider(new BouncyCastleProvider()); - - CertificateRequest certificateRequest = generateTestCertificateRequest(getTestIps()); - - certificateRequest.keyType(KeyType.RSA); - certificateRequest.signatureAlgorithm(SignatureAlgorithm.SHA256WithRSA); - - certificateRequest.generatePrivateKey(); - certificateRequest.generateCSR(); - - PKCS10CertificationRequest cert = getCertRequest(certificateRequest); - - String subject = cert.getSubject().toString(); - assertThat(subject).contains("CN=vcert.test.vfidev.com"); - assertThat(subject).contains("O=Venafi\\, Inc."); - assertThat(subject).contains("OU=Engineering"); - assertThat(subject).contains("OU=Automated Tests"); - assertThat(subject).contains("C=US"); - assertThat(subject).contains("L=SLC"); - assertThat(subject).contains("ST=Utah"); - - // TODO verify certificate is valid - } - - @Test - void generateCertificateRequestWithECDSAKey() throws VCertException, IOException { - Security.addProvider(new BouncyCastleProvider()); - - CertificateRequest certificateRequest = generateTestCertificateRequest(getTestIps()); - - certificateRequest.keyType(KeyType.ECDSA); - certificateRequest.keyCurve(EllipticCurve.EllipticCurveP256); - certificateRequest.signatureAlgorithm(SignatureAlgorithm.ECDSAWithSHA256); - - certificateRequest.generatePrivateKey(); - certificateRequest.generateCSR(); - - PKCS10CertificationRequest cert = getCertRequest(certificateRequest); - - String subject = cert.getSubject().toString(); - assertThat(subject).contains("CN=vcert.test.vfidev.com"); - assertThat(subject).contains("O=Venafi\\, Inc."); - assertThat(subject).contains("OU=Engineering"); - assertThat(subject).contains("OU=Automated Tests"); - assertThat(subject).contains("C=US"); - assertThat(subject).contains("L=SLC"); - assertThat(subject).contains("ST=Utah"); - - // TODO verify certificate is valid - - } - - //TODO rework - @ParameterizedTest - @MethodSource("provideCertificatedForCheckCertificate") - void checkCertificate(CertificateRequest certificateRequest, Certificate certificate, boolean isValid, String errorMessage) { - Security.addProvider(new BouncyCastleProvider()); - - boolean validCert; - try { - validCert = certificateRequest.checkCertificate(certificate); - if(!isValid && validCert) { - fail("certificate should failed but check returns that its valid"); - } - assertThat(validCert).isTrue(); - } catch(VCertException e) { - if(isValid) { - if(isNotBlank(errorMessage) && !e.getMessage().contains(errorMessage)) { - fail(format("unexpected error '%s' (should conatins %s)", e.getMessage(), errorMessage)); - } else { - fail(format("cert should be valid but checker found error: %s", e.getMessage())); - } - } + @Test + void generateECDSAPrivateKey() { + Security.addProvider(new BouncyCastleProvider()); + + assertThatCode(() -> { + CertificateRequest certificateRequest = generateTestCertificateRequest(getTestIps()); + KeyPair keyPair = certificateRequest.generateECDSAKeyPair(EllipticCurve.EllipticCurveP224); + verifyKeyPair(keyPair, SignatureAlgorithm.ECDSAWithSHA256.standardName()); + }).doesNotThrowAnyException(); + } + + @Test + void generateRSAKeyPair() { + assertThatCode(() -> { + CertificateRequest certificateRequest = generateTestCertificateRequest(getTestIps()); + KeyPair keyPair = certificateRequest.generateRSAKeyPair(512); + verifyKeyPair(keyPair, SignatureAlgorithm.SHA256WithRSA.standardName()); + }).doesNotThrowAnyException(); + } + + @Test + void generateCertificateRequestWithRSAKey() throws IOException, VCertException { + Security.addProvider(new BouncyCastleProvider()); + + CertificateRequest certificateRequest = generateTestCertificateRequest(getTestIps()); + + certificateRequest.keyType(KeyType.RSA); + certificateRequest.signatureAlgorithm(SignatureAlgorithm.SHA256WithRSA); + + certificateRequest.generatePrivateKey(); + certificateRequest.generateCSR(); + + PKCS10CertificationRequest cert = getCertRequest(certificateRequest); + + String subject = cert.getSubject().toString(); + assertThat(subject).contains("CN=vcert.test.vfidev.com"); + assertThat(subject).contains("O=Venafi\\, Inc."); + assertThat(subject).contains("OU=Engineering"); + assertThat(subject).contains("OU=Automated Tests"); + assertThat(subject).contains("C=US"); + assertThat(subject).contains("L=SLC"); + assertThat(subject).contains("ST=Utah"); + + // TODO verify certificate is valid + } + + @Test + void generateCertificateRequestWithECDSAKey() throws VCertException, IOException { + Security.addProvider(new BouncyCastleProvider()); + + CertificateRequest certificateRequest = generateTestCertificateRequest(getTestIps()); + + certificateRequest.keyType(KeyType.ECDSA); + certificateRequest.keyCurve(EllipticCurve.EllipticCurveP256); + certificateRequest.signatureAlgorithm(SignatureAlgorithm.ECDSAWithSHA256); + + certificateRequest.generatePrivateKey(); + certificateRequest.generateCSR(); + + PKCS10CertificationRequest cert = getCertRequest(certificateRequest); + + String subject = cert.getSubject().toString(); + assertThat(subject).contains("CN=vcert.test.vfidev.com"); + assertThat(subject).contains("O=Venafi\\, Inc."); + assertThat(subject).contains("OU=Engineering"); + assertThat(subject).contains("OU=Automated Tests"); + assertThat(subject).contains("C=US"); + assertThat(subject).contains("L=SLC"); + assertThat(subject).contains("ST=Utah"); + + // TODO verify certificate is valid + + } + + // TODO rework + @ParameterizedTest + @MethodSource("provideCertificatedForCheckCertificate") + void checkCertificate(CertificateRequest certificateRequest, Certificate certificate, + boolean isValid, String errorMessage) { + Security.addProvider(new BouncyCastleProvider()); + + boolean validCert; + try { + validCert = certificateRequest.checkCertificate(certificate); + if (!isValid && validCert) { + fail("certificate should failed but check returns that its valid"); + } + assertThat(validCert).isTrue(); + } catch (VCertException e) { + if (isValid) { + if (isNotBlank(errorMessage) && !e.getMessage().contains(errorMessage)) { + fail(format("unexpected error '%s' (should conatins %s)", e.getMessage(), errorMessage)); + } else { + fail(format("cert should be valid but checker found error: %s", e.getMessage())); } - + } } - private static Stream provideCertificatedForCheckCertificate() throws IOException, CertificateException, InvalidKeySpecException, NoSuchAlgorithmException { - KeyPair rsaKeyInvalid = loadKeyPairFromFile("checkCertificatePrivateKeyRSAinvalid"); - KeyPair rsaKeyValid = loadKeyPairFromFile("checkCertificatePrivateKeyRSAvalid"); - - return Stream.of( - Arguments.of(createCertFor(KeyType.RSA, rsaKeyValid), loadCertificateFromFile("checkCertificateRSACert"), true, ""), - Arguments.of(createCertFor(KeyType.ECDSA, rsaKeyValid), loadCertificateFromFile("checkCertificateRSACert"), false, "key type"), - Arguments.of(createCertFor(KeyType.RSA, rsaKeyInvalid), loadCertificateFromFile("checkCertificateRSACert"), false, "key modules"), - Arguments.of(createCertSigningRequestFor(loadCertificateSigningRequestFromFile("checkCertificateCSRRSA")), loadCertificateFromFile("checkCertificateRSACert"), true, ""), - Arguments.of(createCertSigningRequestFor(loadCertificateSigningRequestFromFile("checkCertificateCSRRSA")), loadCertificateFromFile("checkCertificateRSACert2"), false, "key modules") - ); + } + + private static Stream provideCertificatedForCheckCertificate() + throws IOException, CertificateException, InvalidKeySpecException, NoSuchAlgorithmException { + KeyPair rsaKeyInvalid = loadKeyPairFromFile("checkCertificatePrivateKeyRSAinvalid"); + KeyPair rsaKeyValid = loadKeyPairFromFile("checkCertificatePrivateKeyRSAvalid"); + + return Stream.of( + Arguments.of(createCertFor(KeyType.RSA, rsaKeyValid), + loadCertificateFromFile("checkCertificateRSACert"), true, ""), + Arguments.of(createCertFor(KeyType.ECDSA, rsaKeyValid), + loadCertificateFromFile("checkCertificateRSACert"), false, "key type"), + Arguments.of(createCertFor(KeyType.RSA, rsaKeyInvalid), + loadCertificateFromFile("checkCertificateRSACert"), false, "key modules"), + Arguments.of( + createCertSigningRequestFor( + loadCertificateSigningRequestFromFile("checkCertificateCSRRSA")), + loadCertificateFromFile("checkCertificateRSACert"), true, ""), + Arguments.of( + createCertSigningRequestFor( + loadCertificateSigningRequestFromFile("checkCertificateCSRRSA")), + loadCertificateFromFile("checkCertificateRSACert2"), false, "key modules")); + } + + private static CertificateRequest createCertFor(KeyType keyType, KeyPair keyPair) { + return new CertificateRequest().keyType(keyType).keyPair(keyPair); + } + + private static CertificateRequest createCertSigningRequestFor( + PKCS10CertificationRequest certSigningReq) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + outputStream.write("-----BEGIN CERTIFICATE REQUEST-----".getBytes()); + outputStream.write(System.lineSeparator().getBytes()); + outputStream.write(Base64.getEncoder().encode(certSigningReq.getEncoded())); + outputStream.write(System.lineSeparator().getBytes()); + outputStream.write("-----END CERTIFICATE REQUEST-----".getBytes()); + return new CertificateRequest().csr(outputStream.toByteArray()); + } + + private static KeyPair loadKeyPairFromFile(String name) + throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { + ClassLoader classLoader = CertificateRequestTest.class.getClassLoader(); + String path = classLoader.getResource("certificates/" + name).getPath(); + // windows platform: if it starts with /C: then remove the leading slash + if (path.charAt(0) == '/' && path.charAt(2) == ':') { + path = path.substring(1); } - - private static CertificateRequest createCertFor(KeyType keyType, KeyPair keyPair) { - return new CertificateRequest().keyType(keyType).keyPair(keyPair); + String body = new String(Files.readAllBytes(Paths.get(path).toAbsolutePath())); + PEMParser pemParser = new PEMParser(new StringReader(body)); + JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); + Object object = pemParser.readObject(); + PrivateKey privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object); + RSAPrivateCrtKey privk = (RSAPrivateCrtKey) privateKey; + RSAPublicKeySpec publicKeySpec = + new java.security.spec.RSAPublicKeySpec(privk.getModulus(), privk.getPublicExponent()); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); + return new KeyPair(publicKey, privateKey); + } + + private static Certificate loadCertificateFromFile(String name) + throws IOException, CertificateException { + ClassLoader classLoader = CertificateRequestTest.class.getClassLoader(); + String path = classLoader.getResource("certificates/" + name).getPath(); + // windows platform: if it starts with /C: then remove the leading slash + if (path.charAt(0) == '/' && path.charAt(2) == ':') { + path = path.substring(1); } - - private static CertificateRequest createCertSigningRequestFor(PKCS10CertificationRequest certSigningReq) throws IOException { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - outputStream.write("-----BEGIN CERTIFICATE REQUEST-----".getBytes()); - outputStream.write(System.lineSeparator().getBytes()); - outputStream.write(Base64.getEncoder().encode(certSigningReq.getEncoded())); - outputStream.write(System.lineSeparator().getBytes()); - outputStream.write("-----END CERTIFICATE REQUEST-----".getBytes()); - return new CertificateRequest().csr(outputStream.toByteArray()); + String body = new String(Files.readAllBytes(Paths.get(path).toAbsolutePath())); + PEMParser pemParser = new PEMParser(new StringReader(body)); + JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter(); + Object object = pemParser.readObject(); + return certificateConverter.getCertificate((X509CertificateHolder) object); + } + + private static PKCS10CertificationRequest loadCertificateSigningRequestFromFile(String name) + throws IOException { + ClassLoader classLoader = CertificateRequestTest.class.getClassLoader(); + String path = classLoader.getResource("certificates/" + name).getPath(); + // windows platform: if it starts with /C: then remove the leading slash + if (path.charAt(0) == '/' && path.charAt(2) == ':') { + path = path.substring(1); } - - private static KeyPair loadKeyPairFromFile(String name) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { - ClassLoader classLoader = CertificateRequestTest.class.getClassLoader(); - String path = classLoader.getResource("certificates/" + name).getPath(); - // windows platform: if it starts with /C: then remove the leading slash - if (path.charAt(0) == '/' && path.charAt(2) == ':') { - path = path.substring(1); - } - String body = new String(Files.readAllBytes( Paths.get(path).toAbsolutePath() )); - PEMParser pemParser = new PEMParser(new StringReader(body)); - JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); - Object object = pemParser.readObject(); - PrivateKey privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object); - RSAPrivateCrtKey privk = (RSAPrivateCrtKey)privateKey; - RSAPublicKeySpec publicKeySpec = new java.security.spec.RSAPublicKeySpec(privk.getModulus(), privk.getPublicExponent()); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); - return new KeyPair(publicKey, privateKey); + String body = new String(Files.readAllBytes(Paths.get(path).toAbsolutePath())); + StringReader reader = new StringReader(body); + try (PEMParser pemParser = new PEMParser(reader)) { + return (PKCS10CertificationRequest) pemParser.readObject(); } + } - private static Certificate loadCertificateFromFile(String name) throws IOException, CertificateException { - ClassLoader classLoader = CertificateRequestTest.class.getClassLoader(); - String path = classLoader.getResource("certificates/" + name).getPath(); - // windows platform: if it starts with /C: then remove the leading slash - if (path.charAt(0) == '/' && path.charAt(2) == ':') { - path = path.substring(1); - } - String body = new String(Files.readAllBytes( Paths.get(path).toAbsolutePath() )); - PEMParser pemParser = new PEMParser(new StringReader(body)); - JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter(); - Object object = pemParser.readObject(); - return certificateConverter.getCertificate((X509CertificateHolder) object); + private PKCS10CertificationRequest getCertRequest(CertificateRequest certificateRequest) + throws IOException { + StringReader reader = new StringReader(new String(certificateRequest.csr())); + try (PEMParser pemParser = new PEMParser(reader)) { + return (PKCS10CertificationRequest) pemParser.readObject(); } - - private static PKCS10CertificationRequest loadCertificateSigningRequestFromFile(String name) throws IOException { - ClassLoader classLoader = CertificateRequestTest.class.getClassLoader(); - String path = classLoader.getResource("certificates/" + name).getPath(); - // windows platform: if it starts with /C: then remove the leading slash - if (path.charAt(0) == '/' && path.charAt(2) == ':') { - path = path.substring(1); + } + + private CertificateRequest generateTestCertificateRequest(Collection ips) + throws UnknownHostException { + return new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName("vcert.test.vfidev.com") + .organization(Collections.singletonList("Venafi, Inc.")) + .organizationalUnit(Arrays.asList("Engineering", "Automated Tests")) + .country(Collections.singletonList("US")).locality(Collections.singletonList("SLC")) + .province(Collections.singletonList("Utah"))) + .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) + .ipAddresses(ips); + } + + private Collection getTestIps() throws SocketException { + Collection ips = new ArrayList<>(); + for (NetworkInterface networkInterface : Collections + .list(NetworkInterface.getNetworkInterfaces())) { + for (InetAddress inetAddress : Collections.list(networkInterface.getInetAddresses())) { + if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) { + ips.add(inetAddress); } - String body = new String(Files.readAllBytes( Paths.get(path).toAbsolutePath() )); - StringReader reader = new StringReader(body); - try(PEMParser pemParser = new PEMParser(reader)) { - return (PKCS10CertificationRequest) pemParser.readObject(); - } - } - - private PKCS10CertificationRequest getCertRequest(CertificateRequest certificateRequest) throws IOException { - StringReader reader = new StringReader(new String(certificateRequest.csr())); - try(PEMParser pemParser = new PEMParser(reader)) { - return (PKCS10CertificationRequest)pemParser.readObject(); - } - } - - private CertificateRequest generateTestCertificateRequest(Collection ips) throws UnknownHostException { - return new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName("vcert.test.vfidev.com") - .organization(Collections.singletonList("Venafi, Inc.")) - .organizationalUnit(Arrays.asList("Engineering", "Automated Tests")) - .country(Collections.singletonList("US")) - .locality(Collections.singletonList("SLC")) - .province(Collections.singletonList("Utah"))) - .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) - .ipAddresses(ips); + } } + return ips; + } - private Collection getTestIps() throws SocketException { - Collection ips = new ArrayList<>(); - for(NetworkInterface networkInterface : Collections.list(NetworkInterface.getNetworkInterfaces())) { - for(InetAddress inetAddress : Collections.list(networkInterface.getInetAddresses())) { - if(!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) { - ips.add(inetAddress); - } - } - } - return ips; - } + private void verifyKeyPair(KeyPair keyPair, String signatureName) throws Exception { + byte[] challenge = new byte[10000]; + ThreadLocalRandom.current().nextBytes(challenge); - private void verifyKeyPair(KeyPair keyPair, String signatureName) throws Exception { - byte[] challenge = new byte[10000]; - ThreadLocalRandom.current().nextBytes(challenge); + Signature sig = Signature.getInstance(signatureName, "BC"); + sig.initSign(keyPair.getPrivate()); + sig.update(challenge); + byte[] signature = sig.sign(); - Signature sig = Signature.getInstance(signatureName, "BC"); - sig.initSign(keyPair.getPrivate()); - sig.update(challenge); - byte[] signature = sig.sign(); + sig.initVerify(keyPair.getPublic()); + sig.update(challenge); - sig.initVerify(keyPair.getPublic()); - sig.update(challenge); - - assertThat(sig.verify(signature)).isTrue(); - } + assertThat(sig.verify(signature)).isTrue(); + } } diff --git a/src/test/java/com/venafi/vcert/sdk/certificate/EllipticCurveTest.java b/src/test/java/com/venafi/vcert/sdk/certificate/EllipticCurveTest.java index f6d5d60..fc492d2 100644 --- a/src/test/java/com/venafi/vcert/sdk/certificate/EllipticCurveTest.java +++ b/src/test/java/com/venafi/vcert/sdk/certificate/EllipticCurveTest.java @@ -1,38 +1,34 @@ package com.venafi.vcert.sdk.certificate; +import static org.assertj.core.api.Assertions.assertThat; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import java.util.stream.Stream; - -import static org.assertj.core.api.Assertions.assertThat; - class EllipticCurveTest { - @ParameterizedTest - @MethodSource("provideStringsForEllipiticCurveConversion") - void ellipticCurveFromString(String fromString, String bcName, EllipticCurve expected) { - assertThat(EllipticCurve.from(fromString).bcName()).isEqualTo(bcName); - assertThat(EllipticCurve.from(fromString)).isEqualTo(expected); - } + @ParameterizedTest + @MethodSource("provideStringsForEllipiticCurveConversion") + void ellipticCurveFromString(String fromString, String bcName, EllipticCurve expected) { + assertThat(EllipticCurve.from(fromString).bcName()).isEqualTo(bcName); + assertThat(EllipticCurve.from(fromString)).isEqualTo(expected); + } - @Test - void ellipticCurveFromUnknownShouldReturnDefault() { - assertThat(EllipticCurve.from("garbage")).isEqualTo(EllipticCurve.EllipticCurveP521); - } + @Test + void ellipticCurveFromUnknownShouldReturnDefault() { + assertThat(EllipticCurve.from("garbage")).isEqualTo(EllipticCurve.EllipticCurveP521); + } - private static Stream provideStringsForEllipiticCurveConversion() { - return Stream.of( - Arguments.of("P224", "P-224", EllipticCurve.EllipticCurveP224), - Arguments.of("p224", "P-224", EllipticCurve.EllipticCurveP224), - Arguments.of("P256", "P-256", EllipticCurve.EllipticCurveP256), - Arguments.of("p256", "P-256", EllipticCurve.EllipticCurveP256), - Arguments.of("P384", "P-384", EllipticCurve.EllipticCurveP384), - Arguments.of("p384", "P-384", EllipticCurve.EllipticCurveP384), - Arguments.of("P521", "P-521", EllipticCurve.EllipticCurveP521), - Arguments.of("p521", "P-521", EllipticCurve.EllipticCurveP521) - ); - } -} \ No newline at end of file + private static Stream provideStringsForEllipiticCurveConversion() { + return Stream.of(Arguments.of("P224", "P-224", EllipticCurve.EllipticCurveP224), + Arguments.of("p224", "P-224", EllipticCurve.EllipticCurveP224), + Arguments.of("P256", "P-256", EllipticCurve.EllipticCurveP256), + Arguments.of("p256", "P-256", EllipticCurve.EllipticCurveP256), + Arguments.of("P384", "P-384", EllipticCurve.EllipticCurveP384), + Arguments.of("p384", "P-384", EllipticCurve.EllipticCurveP384), + Arguments.of("P521", "P-521", EllipticCurve.EllipticCurveP521), + Arguments.of("p521", "P-521", EllipticCurve.EllipticCurveP521)); + } +} diff --git a/src/test/java/com/venafi/vcert/sdk/certificate/KeyTypeTest.java b/src/test/java/com/venafi/vcert/sdk/certificate/KeyTypeTest.java index 8b5b37d..6cac2cf 100644 --- a/src/test/java/com/venafi/vcert/sdk/certificate/KeyTypeTest.java +++ b/src/test/java/com/venafi/vcert/sdk/certificate/KeyTypeTest.java @@ -1,38 +1,35 @@ package com.venafi.vcert.sdk.certificate; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import java.util.stream.Stream; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; - class KeyTypeTest { - @ParameterizedTest - @MethodSource("provideStringsForKeyTypeConversion") - void keyTypeFromString(String fromString, KeyType expected) { - assertThat(KeyType.from(fromString)).isEqualTo(expected); - } + @ParameterizedTest + @MethodSource("provideStringsForKeyTypeConversion") + void keyTypeFromString(String fromString, KeyType expected) { + assertThat(KeyType.from(fromString)).isEqualTo(expected); + } - @Test - void keyTypeFromUnknownShouldThrowException() { - assertThrows(IllegalArgumentException.class, () -> KeyType.from("garbage")); - } + @Test + void keyTypeFromUnknownShouldThrowException() { + assertThrows(IllegalArgumentException.class, () -> KeyType.from("garbage")); + } - private static Stream provideStringsForKeyTypeConversion() { - return Stream.of( - Arguments.of("rsa", KeyType.RSA), - Arguments.of("ecdsa", KeyType.ECDSA), - Arguments.of("ec", KeyType.ECDSA), - Arguments.of("ecc", KeyType.ECDSA), - Arguments.of("RSA", KeyType.RSA), - Arguments.of("ECDSA", KeyType.ECDSA), - Arguments.of("EC", KeyType.ECDSA), - Arguments.of("ECC", KeyType.ECDSA) - ); - } -} \ No newline at end of file + private static Stream provideStringsForKeyTypeConversion() { + return Stream.of( + Arguments.of("rsa", KeyType.RSA), + Arguments.of("ecdsa", KeyType.ECDSA), + Arguments.of("ec", KeyType.ECDSA), + Arguments.of("ecc", KeyType.ECDSA), + Arguments.of("RSA", KeyType.RSA), + Arguments.of("ECDSA", KeyType.ECDSA), + Arguments.of("EC", KeyType.ECDSA), + Arguments.of("ECC", KeyType.ECDSA)); + } +} diff --git a/src/test/java/com/venafi/vcert/sdk/certificate/PEMCollectionTest.java b/src/test/java/com/venafi/vcert/sdk/certificate/PEMCollectionTest.java index cba1b95..21bccdc 100644 --- a/src/test/java/com/venafi/vcert/sdk/certificate/PEMCollectionTest.java +++ b/src/test/java/com/venafi/vcert/sdk/certificate/PEMCollectionTest.java @@ -1,28 +1,26 @@ package com.venafi.vcert.sdk.certificate; -import com.venafi.vcert.sdk.VCertException; -import org.junit.jupiter.api.Test; - +import static org.assertj.core.api.Assertions.assertThat; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; - -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Test; +import com.venafi.vcert.sdk.VCertException; class PEMCollectionTest { - @Test - void fromResponse() throws VCertException, IOException { - ClassLoader classLoader = getClass().getClassLoader(); - String path = classLoader.getResource("certificates/certWithKey.pem").getPath(); - // windows platform: if it starts with /C: then remove the leading slash - if (path.charAt(0) == '/' && path.charAt(2) == ':') { - path = path.substring(1); - } - String body = new String(Files.readAllBytes( Paths.get(path).toAbsolutePath() )); - PEMCollection pemCollection = PEMCollection.fromResponse(body, ChainOption.ChainOptionIgnore); - assertThat(pemCollection.certificate()).isNotNull(); - assertThat(pemCollection.chain()).hasSize(0); - assertThat(pemCollection.privateKey()).isNotNull(); + @Test + void fromResponse() throws VCertException, IOException { + ClassLoader classLoader = getClass().getClassLoader(); + String path = classLoader.getResource("certificates/certWithKey.pem").getPath(); + // windows platform: if it starts with /C: then remove the leading slash + if (path.charAt(0) == '/' && path.charAt(2) == ':') { + path = path.substring(1); } -} \ No newline at end of file + String body = new String(Files.readAllBytes(Paths.get(path).toAbsolutePath())); + PEMCollection pemCollection = PEMCollection.fromResponse(body, ChainOption.ChainOptionIgnore); + assertThat(pemCollection.certificate()).isNotNull(); + assertThat(pemCollection.chain()).hasSize(0); + assertThat(pemCollection.privateKey()).isNotNull(); + } +} diff --git a/src/test/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnectorAT.java b/src/test/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnectorAT.java index 18fe082..4f3b285 100644 --- a/src/test/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnectorAT.java +++ b/src/test/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnectorAT.java @@ -1,19 +1,9 @@ package com.venafi.vcert.sdk.connectors.cloud; -import com.venafi.vcert.sdk.VCertException; -import com.venafi.vcert.sdk.certificate.*; -import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; -import com.venafi.vcert.sdk.endpoint.Authentication; -import feign.FeignException; -import org.apache.commons.codec.digest.DigestUtils; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.pkcs.PKCS10CertificationRequest; -import org.bouncycastle.util.Strings; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - +import static com.venafi.vcert.sdk.TestUtils.getTestIps; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.IOException; import java.io.StringReader; import java.net.InetAddress; @@ -25,183 +15,184 @@ import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collections; - -import static com.venafi.vcert.sdk.TestUtils.getTestIps; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.junit.jupiter.api.Assertions.assertThrows; +import org.apache.commons.codec.digest.DigestUtils; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.bouncycastle.util.Strings; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import feign.FeignException; +import com.venafi.vcert.sdk.VCertException; +import com.venafi.vcert.sdk.certificate.CertificateRequest; +import com.venafi.vcert.sdk.certificate.ImportRequest; +import com.venafi.vcert.sdk.certificate.KeyType; +import com.venafi.vcert.sdk.certificate.PEMCollection; +import com.venafi.vcert.sdk.certificate.RenewalRequest; +import com.venafi.vcert.sdk.certificate.RevocationRequest; +import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; +import com.venafi.vcert.sdk.endpoint.Authentication; class CloudConnectorAT { - private CloudConnector classUnderTest; - - @BeforeEach - public void authenticate() throws VCertException { - Security.addProvider(new BouncyCastleProvider()); - Cloud cloud = Cloud.connect(System.getenv("VENAFI_CLOUD_URL")); - classUnderTest = new CloudConnector(cloud); - Authentication authentication = new Authentication(null, null, System.getenv("VENAFI_API_KEY")); - classUnderTest.authenticate(authentication); - } - - @Test - void readZoneConfiguration() throws VCertException { - try { - ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(System.getenv("VENAFI_ZONE")); - } catch(FeignException fe) { - throw VCertException.fromFeignException(fe); - } - } - - @Test - void ping() throws VCertException { - assertThatCode(() -> classUnderTest.ping()).doesNotThrowAnyException(); - } - - @Test - void generateRequest() throws VCertException, IOException { - String zone = System.getenv("VENAFI_ZONE"); - String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); - ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); - CertificateRequest certificateRequest = new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName(commonName) - .organization(Collections.singletonList("Venafi, Inc.")) - .organizationalUnit(Arrays.asList("Engineering", "Automated Tests")) - .country(Collections.singletonList("US")) - .locality(Collections.singletonList("SLC")) - .province(Collections.singletonList("Utah"))) - .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) - .ipAddresses(getTestIps()) - .keyType(KeyType.RSA); - - certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); - assertThat(certificateRequest.csr()).isNotEmpty(); - - PKCS10CertificationRequest request = (PKCS10CertificationRequest) new PEMParser(new StringReader(Strings.fromByteArray(certificateRequest.csr()))).readObject(); - - String subject = request.getSubject().toString(); - assertThat(subject).contains(String.format("CN=%s", commonName)); - assertThat(subject).contains("O=Venafi\\, Inc."); - assertThat(subject).contains("OU=Engineering"); - assertThat(subject).contains("OU=Automated Tests"); - assertThat(subject).contains("C=US"); - assertThat(subject).contains("L=SLC"); - assertThat(subject).contains("ST=Utah"); - } - - @Test - void requestCertificate() throws VCertException, SocketException, UnknownHostException { - String zone = System.getenv("VENAFI_ZONE"); - String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); - ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); - CertificateRequest certificateRequest = new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName(commonName) - .organization(Collections.singletonList("Venafi, Inc.")) - .organizationalUnit(Arrays.asList("Engineering", "Automated Tests")) - .country(Collections.singletonList("US")) - .locality(Collections.singletonList("SLC")) - .province(Collections.singletonList("Utah"))) - .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) - .ipAddresses(getTestIps()) - .keyType(KeyType.RSA); - certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); - String certificateId = classUnderTest.requestCertificate(certificateRequest, zone); - assertThat(certificateId).isNotNull(); - } - - @Test - void retrieveCertificate() throws VCertException, SocketException, UnknownHostException { - String zone = System.getenv("VENAFI_ZONE"); - String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); - ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); - CertificateRequest certificateRequest = new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName(commonName) - .organization(Collections.singletonList("Venafi, Inc.")) - .organizationalUnit(Arrays.asList("Engineering", "Automated Tests")) - .country(Collections.singletonList("US")) - .locality(Collections.singletonList("SLC")) - .province(Collections.singletonList("Utah"))) - .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) - .ipAddresses(getTestIps()) - .keyType(KeyType.RSA); - - certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); - String certificateId = classUnderTest.requestCertificate(certificateRequest, zone); - assertThat(certificateId).isNotNull(); - - certificateRequest.pickupId(certificateId); - PEMCollection pemCollection = classUnderTest.retrieveCertificate(certificateRequest); - - assertThat(pemCollection.certificate()).isNotNull(); - assertThat(pemCollection.chain()).hasSize(2); - assertThat(pemCollection.privateKey()).isNull(); - } - - @Test - void revokeCertificate() throws VCertException { - assertThrows(UnsupportedOperationException.class, () -> { - classUnderTest.revokeCertificate(new RevocationRequest()); - }); - } - - @Test - void renewCertificate() throws VCertException, UnknownHostException, SocketException, CertificateException, NoSuchAlgorithmException { - String zone = System.getenv("VENAFI_ZONE"); - String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); - ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); - CertificateRequest certificateRequest = new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName(commonName) - .organization(Collections.singletonList("Venafi, Inc.")) - .organizationalUnit(Arrays.asList("Engineering", "Automated Tests")) - .country(Collections.singletonList("US")) - .locality(Collections.singletonList("SLC")) - .province(Collections.singletonList("Utah"))) - .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) - .ipAddresses(getTestIps()) - .keyType(KeyType.RSA); - - certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); - String certificateId = classUnderTest.requestCertificate(certificateRequest, zone); - assertThat(certificateId).isNotNull(); - - certificateRequest.pickupId(certificateId); - - PEMCollection pemCollection = classUnderTest.retrieveCertificate(certificateRequest); - X509Certificate cert = (X509Certificate) pemCollection.certificate(); - - String thumbprint = DigestUtils.sha1Hex(cert.getEncoded()).toUpperCase(); - - CertificateRequest certificateRequestToRenew = new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName(commonName) - .organization(Collections.singletonList("Venafi, Inc.")) - .organizationalUnit(Arrays.asList("Engineering", "Automated Tests")) - .country(Collections.singletonList("US")) - .locality(Collections.singletonList("SLC")) - .province(Collections.singletonList("Utah"))) - .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) - .ipAddresses(getTestIps()) - .keyType(KeyType.RSA); - classUnderTest.generateRequest(zoneConfiguration, certificateRequestToRenew); - - String renewRequestId = classUnderTest.renewCertificate(new RenewalRequest() - .request(certificateRequestToRenew) - .thumbprint(thumbprint)); - - assertThat(renewRequestId).isNotNull(); - } - - @Test - void importCertificate() { - assertThrows(UnsupportedOperationException.class, () -> classUnderTest.importCertificate(new ImportRequest())); - } - - @Test - void readPolicyConfiguration() { - assertThrows(UnsupportedOperationException.class, () -> classUnderTest.readPolicyConfiguration("zone")); + private CloudConnector classUnderTest; + + @BeforeEach + public void authenticate() throws VCertException { + Security.addProvider(new BouncyCastleProvider()); + Cloud cloud = Cloud.connect(System.getenv("VENAFI_CLOUD_URL")); + classUnderTest = new CloudConnector(cloud); + Authentication authentication = new Authentication(null, null, System.getenv("VENAFI_API_KEY")); + classUnderTest.authenticate(authentication); + } + + @Test + void readZoneConfiguration() throws VCertException { + try { + ZoneConfiguration zoneConfiguration = + classUnderTest.readZoneConfiguration(System.getenv("VENAFI_ZONE")); + } catch (FeignException fe) { + throw VCertException.fromFeignException(fe); } -} \ No newline at end of file + } + + @Test + void ping() throws VCertException { + assertThatCode(() -> classUnderTest.ping()).doesNotThrowAnyException(); + } + + @Test + void generateRequest() throws VCertException, IOException { + String zone = System.getenv("VENAFI_ZONE"); + String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); + ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); + CertificateRequest certificateRequest = new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName(commonName) + .organization(Collections.singletonList("Venafi, Inc.")) + .organizationalUnit(Arrays.asList("Engineering", "Automated Tests")) + .country(Collections.singletonList("US")).locality(Collections.singletonList("SLC")) + .province(Collections.singletonList("Utah"))) + .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) + .ipAddresses(getTestIps()).keyType(KeyType.RSA); + + certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); + assertThat(certificateRequest.csr()).isNotEmpty(); + + PKCS10CertificationRequest request = (PKCS10CertificationRequest) new PEMParser( + new StringReader(Strings.fromByteArray(certificateRequest.csr()))).readObject(); + + String subject = request.getSubject().toString(); + assertThat(subject).contains(String.format("CN=%s", commonName)); + assertThat(subject).contains("O=Venafi\\, Inc."); + assertThat(subject).contains("OU=Engineering"); + assertThat(subject).contains("OU=Automated Tests"); + assertThat(subject).contains("C=US"); + assertThat(subject).contains("L=SLC"); + assertThat(subject).contains("ST=Utah"); + } + + @Test + void requestCertificate() throws VCertException, SocketException, UnknownHostException { + String zone = System.getenv("VENAFI_ZONE"); + String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); + ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); + CertificateRequest certificateRequest = new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName(commonName) + .organization(Collections.singletonList("Venafi, Inc.")) + .organizationalUnit(Arrays.asList("Engineering", "Automated Tests")) + .country(Collections.singletonList("US")).locality(Collections.singletonList("SLC")) + .province(Collections.singletonList("Utah"))) + .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) + .ipAddresses(getTestIps()).keyType(KeyType.RSA); + certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); + String certificateId = classUnderTest.requestCertificate(certificateRequest, zone); + assertThat(certificateId).isNotNull(); + } + + @Test + void retrieveCertificate() throws VCertException, SocketException, UnknownHostException { + String zone = System.getenv("VENAFI_ZONE"); + String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); + ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); + CertificateRequest certificateRequest = new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName(commonName) + .organization(Collections.singletonList("Venafi, Inc.")) + .organizationalUnit(Arrays.asList("Engineering", "Automated Tests")) + .country(Collections.singletonList("US")).locality(Collections.singletonList("SLC")) + .province(Collections.singletonList("Utah"))) + .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) + .ipAddresses(getTestIps()).keyType(KeyType.RSA); + + certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); + String certificateId = classUnderTest.requestCertificate(certificateRequest, zone); + assertThat(certificateId).isNotNull(); + + certificateRequest.pickupId(certificateId); + PEMCollection pemCollection = classUnderTest.retrieveCertificate(certificateRequest); + + assertThat(pemCollection.certificate()).isNotNull(); + assertThat(pemCollection.chain()).hasSize(2); + assertThat(pemCollection.privateKey()).isNull(); + } + + @Test + void revokeCertificate() throws VCertException { + assertThrows(UnsupportedOperationException.class, () -> { + classUnderTest.revokeCertificate(new RevocationRequest()); + }); + } + + @Test + void renewCertificate() throws VCertException, UnknownHostException, SocketException, + CertificateException, NoSuchAlgorithmException { + String zone = System.getenv("VENAFI_ZONE"); + String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); + ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); + CertificateRequest certificateRequest = new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName(commonName) + .organization(Collections.singletonList("Venafi, Inc.")) + .organizationalUnit(Arrays.asList("Engineering", "Automated Tests")) + .country(Collections.singletonList("US")).locality(Collections.singletonList("SLC")) + .province(Collections.singletonList("Utah"))) + .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) + .ipAddresses(getTestIps()).keyType(KeyType.RSA); + + certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); + String certificateId = classUnderTest.requestCertificate(certificateRequest, zone); + assertThat(certificateId).isNotNull(); + + certificateRequest.pickupId(certificateId); + + PEMCollection pemCollection = classUnderTest.retrieveCertificate(certificateRequest); + X509Certificate cert = (X509Certificate) pemCollection.certificate(); + + String thumbprint = DigestUtils.sha1Hex(cert.getEncoded()).toUpperCase(); + + CertificateRequest certificateRequestToRenew = new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName(commonName) + .organization(Collections.singletonList("Venafi, Inc.")) + .organizationalUnit(Arrays.asList("Engineering", "Automated Tests")) + .country(Collections.singletonList("US")).locality(Collections.singletonList("SLC")) + .province(Collections.singletonList("Utah"))) + .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) + .ipAddresses(getTestIps()).keyType(KeyType.RSA); + classUnderTest.generateRequest(zoneConfiguration, certificateRequestToRenew); + + String renewRequestId = classUnderTest.renewCertificate( + new RenewalRequest().request(certificateRequestToRenew).thumbprint(thumbprint)); + + assertThat(renewRequestId).isNotNull(); + } + + @Test + void importCertificate() { + assertThrows(UnsupportedOperationException.class, + () -> classUnderTest.importCertificate(new ImportRequest())); + } + + @Test + void readPolicyConfiguration() { + assertThrows(UnsupportedOperationException.class, + () -> classUnderTest.readPolicyConfiguration("zone")); + } +} diff --git a/src/test/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnectorIT.java b/src/test/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnectorIT.java index ca40491..80296fa 100644 --- a/src/test/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnectorIT.java +++ b/src/test/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnectorIT.java @@ -1,5 +1,10 @@ package com.venafi.vcert.sdk.connectors.cloud; +import static org.assertj.core.api.Assertions.assertThat; +import java.time.OffsetDateTime; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import com.github.jenspiegsa.wiremockextension.InjectServer; import com.github.jenspiegsa.wiremockextension.WireMockExtension; import com.github.tomakehurst.wiremock.WireMockServer; @@ -9,105 +14,117 @@ import com.venafi.vcert.sdk.certificate.KeyType; import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; import com.venafi.vcert.sdk.endpoint.Authentication; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import java.time.OffsetDateTime; - -import static org.assertj.core.api.Assertions.assertThat; @ExtendWith(WireMockExtension.class) class CloudConnectorIT { - @InjectServer - private WireMockServer serverMock; - - private CloudConnector classUnderTest; - - @BeforeEach - void setup() throws VCertException { - classUnderTest = new CloudConnector(Cloud.connect("http://localhost:" + serverMock.port())); // todo String.format() - Authentication authentication = new Authentication(null, null, "12345678-1234-1234-1234-123456789012"); - classUnderTest.authenticate(authentication); - } - - @Test - void authenticate() throws VCertException { - assertThat(classUnderTest.user()).describedAs("user details").isNotNull(); - - assertThat(classUnderTest.user().apiKey()).describedAs("api key details").isNotNull(); - assertThat(classUnderTest.user().apiKey().apiKeyStatus()).describedAs("api key details").isEqualTo("ACTIVE"); - assertThat(classUnderTest.user().apiKey().apiTypes()).containsExactly("foo"); - assertThat(classUnderTest.user().apiKey().apiVersion()).isEqualTo("ALL"); - assertThat(classUnderTest.user().apiKey().username()).isEqualTo("john.doe@example.com"); - assertThat(classUnderTest.user().apiKey().creationDate()).isEqualTo(OffsetDateTime.parse("2019-01-01T14:39:51.920Z")); - assertThat(classUnderTest.user().apiKey().validityStartDate()).isEqualTo(OffsetDateTime.parse("2019-01-01T14:39:51.920Z")); - assertThat(classUnderTest.user().apiKey().validityEndDate()).isEqualTo(OffsetDateTime.parse("2019-12-31T14:39:51.920Z")); - - assertThat(classUnderTest.user().company()).isNotNull(); - assertThat(classUnderTest.user().company().id()).isEqualTo("12345678-1234-1234-1234-12345678901c"); - assertThat(classUnderTest.user().company().name()).isEqualTo("example.com"); - assertThat(classUnderTest.user().company().companyType()).isEqualTo("TPP_CUSTOMER"); - assertThat(classUnderTest.user().company().active()).isTrue(); - assertThat(classUnderTest.user().company().creationDate()).isEqualTo(OffsetDateTime.parse("2019-01-01T14:32:50.612Z")); - assertThat(classUnderTest.user().company().domains()).containsExactly("example.com"); - - assertThat(classUnderTest.user().user()).isNotNull(); - assertThat(classUnderTest.user().user().username()).isEqualTo("john.doe@example.com"); - assertThat(classUnderTest.user().user().id()).isEqualTo("12345678-1234-1234-1234-12345678901u"); - assertThat(classUnderTest.user().user().companyId()).isEqualTo("12345678-1234-1234-1234-12345678901c"); - assertThat(classUnderTest.user().user().emailAddress()).isEqualTo("john.doe@example.com"); - assertThat(classUnderTest.user().user().userType()).isEqualTo("EXTERNAL"); - assertThat(classUnderTest.user().user().userAccountType()).isEqualTo("WEB_UI"); - assertThat(classUnderTest.user().user().userStatus()).isEqualTo("ACTIVE"); - assertThat(classUnderTest.user().user().creationDate()).isEqualTo(OffsetDateTime.parse("2019-01-01T14:39:51.920Z")); - } - - @Test // todo: unit test for mapping code to check whatever is null here is mapped correctly. - void readZoneConfiguration() throws VCertException { - - ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration("Default"); - - assertThat(zoneConfiguration).isNotNull(); - assertThat(zoneConfiguration.organization()).isNull(); - assertThat(zoneConfiguration.organizationalUnit()).isNull(); - assertThat(zoneConfiguration.country()).isNull(); - assertThat(zoneConfiguration.province()).isNull(); - assertThat(zoneConfiguration.locality()).isNull(); - assertThat(zoneConfiguration.policy()).isNotNull(); - assertThat(zoneConfiguration.policy().subjectCNRegexes()).containsExactly("^.*.example.com$", "^.*.example.org$", "^.*.example.net$", "^.*.invalid$", "^.*.local$", "^.*.localhost$", "^.*.test$"); - assertThat(zoneConfiguration.policy().subjectORegexes()).containsExactly("^.*$"); - assertThat(zoneConfiguration.policy().subjectOURegexes()).containsExactly("^.*$"); - assertThat(zoneConfiguration.policy().subjectSTRegexes()).containsExactly("^.*$"); - assertThat(zoneConfiguration.policy().subjectLRegexes()).containsExactly("^.*$"); - assertThat(zoneConfiguration.policy().subjectCRegexes()).containsExactly("^.*$"); - assertThat(zoneConfiguration.policy().allowedKeyConfigurations()).isNotNull(); - assertThat(zoneConfiguration.policy().allowedKeyConfigurations()).isNotNull(); - assertThat(zoneConfiguration.policy().allowedKeyConfigurations()).hasSize(1); - assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(0).keyType()).isEqualTo(KeyType.RSA); - assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(0).keySizes()).containsExactly(2048); - assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(0).keyCurves()).isNull(); - assertThat(zoneConfiguration.policy().dnsSanRegExs()).containsExactly("^.*$"); - assertThat(zoneConfiguration.policy().ipSanRegExs()).isNull(); - assertThat(zoneConfiguration.policy().emailSanRegExs()).isNull(); - assertThat(zoneConfiguration.policy().uriSanRegExs()).isNull(); - assertThat(zoneConfiguration.policy().upnSanRegExs()).isNull(); - assertThat(zoneConfiguration.policy().allowWildcards()).isTrue(); - assertThat(zoneConfiguration.policy().allowKeyReuse()).isFalse(); - assertThat(zoneConfiguration.hashAlgorithm()).isEqualTo(SignatureAlgorithm.UnknownSignatureAlgorithm); - assertThat(zoneConfiguration.customAttributeValues()).isNotNull(); - assertThat(zoneConfiguration.customAttributeValues()).isEmpty(); - } - - - @Test - void requestCertificate() throws VCertException { - CertificateRequest certificateRequest = new CertificateRequest() - // Signing request borrowed from tpp/connector-test.go#checkCertificateCSRRSA, response unrelated from tpp/connector_test.go#successRequestCertificate - .csr("-----BEGIN CERTIFICATE REQUEST-----\nMIIBrDCCARUCAQAwbDELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0YWgxEjAQBgNV\nBAcMCVNhbHQgTGFrZTEPMA0GA1UECgwGVmVuYWZpMQ8wDQYDVQQLDAZEZXZPcHMx\nGDAWBgNVBAMMD3Rlc3QudmVuZGV2LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\ngYkCgYEAqIPiGtjnxep5gQHIiDXhHpHYhr/ndwFKQ2HNGftD3AMjMDyolSQY27w7\nPScTZXcuENew0zsH4iA7UsFhEGB6AIoelBWxiWc1SYRNslIgsSxsRlksJowFcL/E\n40qkmL0TerI2vq829jF3XY6X1E3e1OXo0kbmBLwEB/xnpfuvpt0CAwEAAaAAMA0G\nCSqGSIb3DQEBCwUAA4GBAGsKm5fJ8Zm/j9XMPXhPYmOdiDj+9QlcFq7uRRqwpxo7\nC507RR5Pj2zBRZRLJcc/bNTQFqnW92kIcvJ+YvrQl/GkEMKM2wds/RyMXRHtOJvZ\nYQt6JtkAeQOMECJ7RRHrZiG+m2by2YAB2krthK2gJGSr80xWzZWzrgdwdTe2sxUG\n-----BEGIN CERTIFICATE REQUEST-----".getBytes()); - // todo: improve test: add request matcher (and add data to request to ensure it gets passed through all right) - String requestId = classUnderTest.requestCertificate(certificateRequest, "Default"); - assertThat(requestId).isEqualTo("04c051d0-f118-11e5-8b33-d96cf8021ce5"); - } -} \ No newline at end of file + @InjectServer + private WireMockServer serverMock; + + private CloudConnector classUnderTest; + + @BeforeEach + void setup() throws VCertException { + classUnderTest = new CloudConnector(Cloud.connect("http://localhost:" + serverMock.port())); // todo + // String.format() + Authentication authentication = + new Authentication(null, null, "12345678-1234-1234-1234-123456789012"); + classUnderTest.authenticate(authentication); + } + + @Test + void authenticate() throws VCertException { + assertThat(classUnderTest.user()).describedAs("user details").isNotNull(); + + assertThat(classUnderTest.user().apiKey()).describedAs("api key details").isNotNull(); + assertThat(classUnderTest.user().apiKey().apiKeyStatus()).describedAs("api key details") + .isEqualTo("ACTIVE"); + assertThat(classUnderTest.user().apiKey().apiTypes()).containsExactly("foo"); + assertThat(classUnderTest.user().apiKey().apiVersion()).isEqualTo("ALL"); + assertThat(classUnderTest.user().apiKey().username()).isEqualTo("john.doe@example.com"); + assertThat(classUnderTest.user().apiKey().creationDate()) + .isEqualTo(OffsetDateTime.parse("2019-01-01T14:39:51.920Z")); + assertThat(classUnderTest.user().apiKey().validityStartDate()) + .isEqualTo(OffsetDateTime.parse("2019-01-01T14:39:51.920Z")); + assertThat(classUnderTest.user().apiKey().validityEndDate()) + .isEqualTo(OffsetDateTime.parse("2019-12-31T14:39:51.920Z")); + + assertThat(classUnderTest.user().company()).isNotNull(); + assertThat(classUnderTest.user().company().id()) + .isEqualTo("12345678-1234-1234-1234-12345678901c"); + assertThat(classUnderTest.user().company().name()).isEqualTo("example.com"); + assertThat(classUnderTest.user().company().companyType()).isEqualTo("TPP_CUSTOMER"); + assertThat(classUnderTest.user().company().active()).isTrue(); + assertThat(classUnderTest.user().company().creationDate()) + .isEqualTo(OffsetDateTime.parse("2019-01-01T14:32:50.612Z")); + assertThat(classUnderTest.user().company().domains()).containsExactly("example.com"); + + assertThat(classUnderTest.user().user()).isNotNull(); + assertThat(classUnderTest.user().user().username()).isEqualTo("john.doe@example.com"); + assertThat(classUnderTest.user().user().id()).isEqualTo("12345678-1234-1234-1234-12345678901u"); + assertThat(classUnderTest.user().user().companyId()) + .isEqualTo("12345678-1234-1234-1234-12345678901c"); + assertThat(classUnderTest.user().user().emailAddress()).isEqualTo("john.doe@example.com"); + assertThat(classUnderTest.user().user().userType()).isEqualTo("EXTERNAL"); + assertThat(classUnderTest.user().user().userAccountType()).isEqualTo("WEB_UI"); + assertThat(classUnderTest.user().user().userStatus()).isEqualTo("ACTIVE"); + assertThat(classUnderTest.user().user().creationDate()) + .isEqualTo(OffsetDateTime.parse("2019-01-01T14:39:51.920Z")); + } + + @Test // todo: unit test for mapping code to check whatever is null here is mapped correctly. + void readZoneConfiguration() throws VCertException { + + ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration("Default"); + + assertThat(zoneConfiguration).isNotNull(); + assertThat(zoneConfiguration.organization()).isNull(); + assertThat(zoneConfiguration.organizationalUnit()).isNull(); + assertThat(zoneConfiguration.country()).isNull(); + assertThat(zoneConfiguration.province()).isNull(); + assertThat(zoneConfiguration.locality()).isNull(); + assertThat(zoneConfiguration.policy()).isNotNull(); + assertThat(zoneConfiguration.policy().subjectCNRegexes()).containsExactly("^.*.example.com$", + "^.*.example.org$", "^.*.example.net$", "^.*.invalid$", "^.*.local$", "^.*.localhost$", + "^.*.test$"); + assertThat(zoneConfiguration.policy().subjectORegexes()).containsExactly("^.*$"); + assertThat(zoneConfiguration.policy().subjectOURegexes()).containsExactly("^.*$"); + assertThat(zoneConfiguration.policy().subjectSTRegexes()).containsExactly("^.*$"); + assertThat(zoneConfiguration.policy().subjectLRegexes()).containsExactly("^.*$"); + assertThat(zoneConfiguration.policy().subjectCRegexes()).containsExactly("^.*$"); + assertThat(zoneConfiguration.policy().allowedKeyConfigurations()).isNotNull(); + assertThat(zoneConfiguration.policy().allowedKeyConfigurations()).isNotNull(); + assertThat(zoneConfiguration.policy().allowedKeyConfigurations()).hasSize(1); + assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(0).keyType()) + .isEqualTo(KeyType.RSA); + assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(0).keySizes()) + .containsExactly(2048); + assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(0).keyCurves()).isNull(); + assertThat(zoneConfiguration.policy().dnsSanRegExs()).containsExactly("^.*$"); + assertThat(zoneConfiguration.policy().ipSanRegExs()).isNull(); + assertThat(zoneConfiguration.policy().emailSanRegExs()).isNull(); + assertThat(zoneConfiguration.policy().uriSanRegExs()).isNull(); + assertThat(zoneConfiguration.policy().upnSanRegExs()).isNull(); + assertThat(zoneConfiguration.policy().allowWildcards()).isTrue(); + assertThat(zoneConfiguration.policy().allowKeyReuse()).isFalse(); + assertThat(zoneConfiguration.hashAlgorithm()) + .isEqualTo(SignatureAlgorithm.UnknownSignatureAlgorithm); + assertThat(zoneConfiguration.customAttributeValues()).isNotNull(); + assertThat(zoneConfiguration.customAttributeValues()).isEmpty(); + } + + + @Test + void requestCertificate() throws VCertException { + CertificateRequest certificateRequest = new CertificateRequest() + // Signing request borrowed from tpp/connector-test.go#checkCertificateCSRRSA, response + // unrelated from tpp/connector_test.go#successRequestCertificate + .csr( + "-----BEGIN CERTIFICATE REQUEST-----\nMIIBrDCCARUCAQAwbDELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0YWgxEjAQBgNV\nBAcMCVNhbHQgTGFrZTEPMA0GA1UECgwGVmVuYWZpMQ8wDQYDVQQLDAZEZXZPcHMx\nGDAWBgNVBAMMD3Rlc3QudmVuZGV2LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\ngYkCgYEAqIPiGtjnxep5gQHIiDXhHpHYhr/ndwFKQ2HNGftD3AMjMDyolSQY27w7\nPScTZXcuENew0zsH4iA7UsFhEGB6AIoelBWxiWc1SYRNslIgsSxsRlksJowFcL/E\n40qkmL0TerI2vq829jF3XY6X1E3e1OXo0kbmBLwEB/xnpfuvpt0CAwEAAaAAMA0G\nCSqGSIb3DQEBCwUAA4GBAGsKm5fJ8Zm/j9XMPXhPYmOdiDj+9QlcFq7uRRqwpxo7\nC507RR5Pj2zBRZRLJcc/bNTQFqnW92kIcvJ+YvrQl/GkEMKM2wds/RyMXRHtOJvZ\nYQt6JtkAeQOMECJ7RRHrZiG+m2by2YAB2krthK2gJGSr80xWzZWzrgdwdTe2sxUG\n-----BEGIN CERTIFICATE REQUEST-----" + .getBytes()); + // todo: improve test: add request matcher (and add data to request to ensure it gets passed + // through all right) + String requestId = classUnderTest.requestCertificate(certificateRequest, "Default"); + assertThat(requestId).isEqualTo("04c051d0-f118-11e5-8b33-d96cf8021ce5"); + } +} diff --git a/src/test/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnectorTest.java b/src/test/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnectorTest.java index a33ecaf..e4baa2c 100644 --- a/src/test/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnectorTest.java +++ b/src/test/java/com/venafi/vcert/sdk/connectors/cloud/CloudConnectorTest.java @@ -1,5 +1,25 @@ package com.venafi.vcert.sdk.connectors.cloud; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.security.Security; +import java.util.Arrays; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; import com.venafi.vcert.sdk.VCertException; import com.venafi.vcert.sdk.certificate.CertificateRequest; import com.venafi.vcert.sdk.certificate.CertificateStatus; @@ -10,203 +30,180 @@ import com.venafi.vcert.sdk.connectors.cloud.domain.UserDetails; import com.venafi.vcert.sdk.connectors.tpp.ZoneConfiguration; import com.venafi.vcert.sdk.endpoint.Authentication; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.security.Security; -import java.util.Arrays; - -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class CloudConnectorTest { - @Mock - private Cloud cloud; - private CloudConnector classUnderTest; - - @Captor - private ArgumentCaptor searchRequestArgumentCaptor; - - UserDetails userDetails; - - - @BeforeEach - void setUp() { - classUnderTest = new CloudConnector(cloud); - userDetails = new UserDetails().user(new User()).company(new Company()); - when(cloud.authorize(anyString())).thenReturn(userDetails); - } - - @Test - void authenticates() throws VCertException { - Authentication auth = new Authentication(null, null, "12345678-1234-1234-1234-123456789012"); - classUnderTest.authenticate(auth); - assertEquals(userDetails, classUnderTest.user()); - } - - @Test - void requestCertificate() throws VCertException { - Security.addProvider(new BouncyCastleProvider()); - - String apiKey = "12345678-1234-1234-1234-123456789012"; - Zone zone = new Zone().defaultCertificateIdentityPolicy("defaultCertificateIdentityPolicy").defaultCertificateUsePolicy("defaultCertificateUsePolicy"); - when(cloud.zoneByTag(eq("Default"), eq(apiKey))).thenReturn(zone); - when(cloud.policyById(eq("defaultCertificateIdentityPolicy"), eq(apiKey))).thenReturn(new CertificatePolicy().certificatePolicyType("CERTIFICATE_IDENTITY")); - // TODO: To add checks for policies see com.venafi.vcert.sdk.connectors.cloud.CloudConnector.getPoliciesById and adapt test - when(cloud.policyById(eq("defaultCertificateUsePolicy"), eq(apiKey))).thenReturn(new CertificatePolicy().certificatePolicyType("CERTIFICATE_USE")); - when(cloud.certificateRequest(eq(apiKey), any(CloudConnector.CertificateRequestsPayload.class))) // todo: check request payload values - .thenReturn(new CloudConnector.CertificateRequestsResponse() - .certificateRequests(singletonList(new CloudConnector.CertificateRequestsResponseData() - .id("jackpot")))); - - CertificateRequest request = new CertificateRequest() - .subject(new CertificateRequest.PKIXName() - .commonName("random name") - .organization(singletonList("Venafi, Inc.")) - .organizationalUnit(singletonList("Automated Tests"))); - - final Authentication auth = - new Authentication(null, null, apiKey); - classUnderTest.authenticate(auth); - - ZoneConfiguration zoneConfig = classUnderTest.readZoneConfiguration("Default"); - classUnderTest.generateRequest(zoneConfig, request); - - String actual = classUnderTest.requestCertificate(request, "Default"); - - assertThat(actual).isEqualTo("jackpot"); - } - - @Test - @DisplayName("Renew a certificate that do not exists in Cloud should fail") - void renewCertificateNotFound() throws VCertException { - final String apiKey = "12345678-1234-1234-1234-123456789012"; - final Authentication auth = - new Authentication(null, null, apiKey); - - final String thumbprint = "52030990E3DC44199DA11C2D73E41EF8EAD8A4E1"; - final RenewalRequest renewalRequest = new RenewalRequest(); - final Cloud.CertificateSearchResponse searchResponse = - mock(Cloud.CertificateSearchResponse.class); - - renewalRequest.thumbprint(thumbprint); - - when(cloud.searchCertificates(eq(apiKey), searchRequestArgumentCaptor.capture())) - .thenReturn(searchResponse); - - classUnderTest.authenticate(auth); - Throwable exception = assertThrows(VCertException.class, - () -> classUnderTest.renewCertificate(renewalRequest)); - assertThat(exception.getMessage()).contains(thumbprint); - } - - @Test - @DisplayName("Renew a certificate without request details in cloud should fail") - void renewCertificateEmptyRequest() throws VCertException { - final String apiKey = "12345678-1234-1234-1234-123456789012"; - final Authentication auth = - new Authentication(null, null, apiKey); - - final RenewalRequest renewalRequest = new RenewalRequest(); - final Cloud.CertificateSearchResponse searchResponse = - mock(Cloud.CertificateSearchResponse.class); - - classUnderTest.authenticate(auth); - Throwable exception = assertThrows(VCertException.class, - () -> classUnderTest.renewCertificate(renewalRequest)); - assertThat(exception.getMessage()).contains("CertificateDN or Thumbprint required"); - } - - @Test - @DisplayName("Renew a certificate with same fingerprint for multiple requests ids should fail") - void renewCertificateMultipleRequestIds() throws VCertException { - final String apiKey = "12345678-1234-1234-1234-123456789012"; - final Authentication auth = - new Authentication(null, null, apiKey); - - final String thumbprint = "52030990E3DC44199DA11C2D73E41EF8EAD8A4E1"; - final RenewalRequest renewalRequest = new RenewalRequest(); - final Cloud.CertificateSearchResponse searchResponse = - mock(Cloud.CertificateSearchResponse.class); - - renewalRequest.thumbprint(thumbprint); - - when(cloud.searchCertificates(eq(apiKey), searchRequestArgumentCaptor.capture())) - .thenReturn(searchResponse); - - final Cloud.Certificate certificate1 = new Cloud.Certificate(); - certificate1.certificateRequestId("request_1"); - - final Cloud.Certificate certificate2 = new Cloud.Certificate(); - certificate2.certificateRequestId("request_2"); - - when(searchResponse.certificates()) - .thenReturn(Arrays.asList(certificate1, certificate2)); - - classUnderTest.authenticate(auth); - Throwable exception = assertThrows(VCertException.class, - () -> classUnderTest.renewCertificate(renewalRequest)); - - assertThat(exception.getMessage()).contains("More than one CertificateRequestId was found"); - assertThat(exception.getMessage()).contains(thumbprint); - } - - @Test - @DisplayName("Renew a certificate with fingerprint") - void renewCertificate() throws VCertException { - final String apiKey = "12345678-1234-1234-1234-123456789012"; - final Authentication auth = - new Authentication(null, null, apiKey); - - final String thumbprint = "52030990E3DC44199DA11C2D73E41EF8EAD8A4E1"; - final RenewalRequest renewalRequest = new RenewalRequest(); - - final Cloud.CertificateSearchResponse searchResponse = - mock(Cloud.CertificateSearchResponse.class); - - final CertificateStatus certificateStatus = mock(CertificateStatus.class); - final ManagedCertificate managedCertificate = mock(ManagedCertificate.class); - renewalRequest.thumbprint(thumbprint); - final Cloud.Certificate certificate1 = new Cloud.Certificate(); - certificate1.certificateRequestId("request_1"); - - final CloudConnector.CertificateRequestsResponse requestsResponse = - mock(CloudConnector.CertificateRequestsResponse.class); - - final CloudConnector.CertificateRequestsResponseData requestsResponseData = - mock(CloudConnector.CertificateRequestsResponseData.class); - - when(cloud.searchCertificates(eq(apiKey), searchRequestArgumentCaptor.capture())) - .thenReturn(searchResponse); - when(searchResponse.certificates()) - .thenReturn(singletonList(certificate1)); - when(cloud.certificateStatus( "request_1", apiKey)) - .thenReturn(certificateStatus); - when(certificateStatus.managedCertificateId()).thenReturn("test_managed_certificate_id"); - when(certificateStatus.zoneId()).thenReturn("test_zone_id"); - when(cloud.managedCertificate("test_managed_certificate_id", apiKey)) - .thenReturn(managedCertificate); - when(managedCertificate.latestCertificateRequestId()).thenReturn("request_1"); - when(cloud.certificateRequest(eq(apiKey), any(CloudConnector.CertificateRequestsPayload.class))) - .thenReturn(requestsResponse); - when(requestsResponse.certificateRequests()).thenReturn(singletonList(requestsResponseData)); - when(requestsResponseData.id()).thenReturn("certificate_result"); - - classUnderTest.authenticate(auth); - assertThat(classUnderTest.renewCertificate(renewalRequest)).isEqualTo("certificate_result"); - } -} \ No newline at end of file + @Mock + private Cloud cloud; + private CloudConnector classUnderTest; + + @Captor + private ArgumentCaptor searchRequestArgumentCaptor; + + UserDetails userDetails; + + + @BeforeEach + void setUp() { + classUnderTest = new CloudConnector(cloud); + userDetails = new UserDetails().user(new User()).company(new Company()); + when(cloud.authorize(anyString())).thenReturn(userDetails); + } + + @Test + void authenticates() throws VCertException { + Authentication auth = new Authentication(null, null, "12345678-1234-1234-1234-123456789012"); + classUnderTest.authenticate(auth); + assertEquals(userDetails, classUnderTest.user()); + } + + @Test + void requestCertificate() throws VCertException { + Security.addProvider(new BouncyCastleProvider()); + + String apiKey = "12345678-1234-1234-1234-123456789012"; + Zone zone = new Zone().defaultCertificateIdentityPolicy("defaultCertificateIdentityPolicy") + .defaultCertificateUsePolicy("defaultCertificateUsePolicy"); + when(cloud.zoneByTag(eq("Default"), eq(apiKey))).thenReturn(zone); + when(cloud.policyById(eq("defaultCertificateIdentityPolicy"), eq(apiKey))) + .thenReturn(new CertificatePolicy().certificatePolicyType("CERTIFICATE_IDENTITY")); + // TODO: To add checks for policies see + // com.venafi.vcert.sdk.connectors.cloud.CloudConnector.getPoliciesById and adapt test + when(cloud.policyById(eq("defaultCertificateUsePolicy"), eq(apiKey))) + .thenReturn(new CertificatePolicy().certificatePolicyType("CERTIFICATE_USE")); + when(cloud.certificateRequest(eq(apiKey), any(CloudConnector.CertificateRequestsPayload.class))) // todo: + // check + // request + // payload + // values + .thenReturn(new CloudConnector.CertificateRequestsResponse().certificateRequests( + singletonList(new CloudConnector.CertificateRequestsResponseData().id("jackpot")))); + + CertificateRequest request = new CertificateRequest().subject(new CertificateRequest.PKIXName() + .commonName("random name").organization(singletonList("Venafi, Inc.")) + .organizationalUnit(singletonList("Automated Tests"))); + + final Authentication auth = new Authentication(null, null, apiKey); + classUnderTest.authenticate(auth); + + ZoneConfiguration zoneConfig = classUnderTest.readZoneConfiguration("Default"); + classUnderTest.generateRequest(zoneConfig, request); + + String actual = classUnderTest.requestCertificate(request, "Default"); + + assertThat(actual).isEqualTo("jackpot"); + } + + @Test + @DisplayName("Renew a certificate that do not exists in Cloud should fail") + void renewCertificateNotFound() throws VCertException { + final String apiKey = "12345678-1234-1234-1234-123456789012"; + final Authentication auth = new Authentication(null, null, apiKey); + + final String thumbprint = "52030990E3DC44199DA11C2D73E41EF8EAD8A4E1"; + final RenewalRequest renewalRequest = new RenewalRequest(); + final Cloud.CertificateSearchResponse searchResponse = + mock(Cloud.CertificateSearchResponse.class); + + renewalRequest.thumbprint(thumbprint); + + when(cloud.searchCertificates(eq(apiKey), searchRequestArgumentCaptor.capture())) + .thenReturn(searchResponse); + + classUnderTest.authenticate(auth); + Throwable exception = + assertThrows(VCertException.class, () -> classUnderTest.renewCertificate(renewalRequest)); + assertThat(exception.getMessage()).contains(thumbprint); + } + + @Test + @DisplayName("Renew a certificate without request details in cloud should fail") + void renewCertificateEmptyRequest() throws VCertException { + final String apiKey = "12345678-1234-1234-1234-123456789012"; + final Authentication auth = new Authentication(null, null, apiKey); + + final RenewalRequest renewalRequest = new RenewalRequest(); + final Cloud.CertificateSearchResponse searchResponse = + mock(Cloud.CertificateSearchResponse.class); + + classUnderTest.authenticate(auth); + Throwable exception = + assertThrows(VCertException.class, () -> classUnderTest.renewCertificate(renewalRequest)); + assertThat(exception.getMessage()).contains("CertificateDN or Thumbprint required"); + } + + @Test + @DisplayName("Renew a certificate with same fingerprint for multiple requests ids should fail") + void renewCertificateMultipleRequestIds() throws VCertException { + final String apiKey = "12345678-1234-1234-1234-123456789012"; + final Authentication auth = new Authentication(null, null, apiKey); + + final String thumbprint = "52030990E3DC44199DA11C2D73E41EF8EAD8A4E1"; + final RenewalRequest renewalRequest = new RenewalRequest(); + final Cloud.CertificateSearchResponse searchResponse = + mock(Cloud.CertificateSearchResponse.class); + + renewalRequest.thumbprint(thumbprint); + + when(cloud.searchCertificates(eq(apiKey), searchRequestArgumentCaptor.capture())) + .thenReturn(searchResponse); + + final Cloud.Certificate certificate1 = new Cloud.Certificate(); + certificate1.certificateRequestId("request_1"); + + final Cloud.Certificate certificate2 = new Cloud.Certificate(); + certificate2.certificateRequestId("request_2"); + + when(searchResponse.certificates()).thenReturn(Arrays.asList(certificate1, certificate2)); + + classUnderTest.authenticate(auth); + Throwable exception = + assertThrows(VCertException.class, () -> classUnderTest.renewCertificate(renewalRequest)); + + assertThat(exception.getMessage()).contains("More than one CertificateRequestId was found"); + assertThat(exception.getMessage()).contains(thumbprint); + } + + @Test + @DisplayName("Renew a certificate with fingerprint") + void renewCertificate() throws VCertException { + final String apiKey = "12345678-1234-1234-1234-123456789012"; + final Authentication auth = new Authentication(null, null, apiKey); + + final String thumbprint = "52030990E3DC44199DA11C2D73E41EF8EAD8A4E1"; + final RenewalRequest renewalRequest = new RenewalRequest(); + + final Cloud.CertificateSearchResponse searchResponse = + mock(Cloud.CertificateSearchResponse.class); + + final CertificateStatus certificateStatus = mock(CertificateStatus.class); + final ManagedCertificate managedCertificate = mock(ManagedCertificate.class); + renewalRequest.thumbprint(thumbprint); + final Cloud.Certificate certificate1 = new Cloud.Certificate(); + certificate1.certificateRequestId("request_1"); + + final CloudConnector.CertificateRequestsResponse requestsResponse = + mock(CloudConnector.CertificateRequestsResponse.class); + + final CloudConnector.CertificateRequestsResponseData requestsResponseData = + mock(CloudConnector.CertificateRequestsResponseData.class); + + when(cloud.searchCertificates(eq(apiKey), searchRequestArgumentCaptor.capture())) + .thenReturn(searchResponse); + when(searchResponse.certificates()).thenReturn(singletonList(certificate1)); + when(cloud.certificateStatus("request_1", apiKey)).thenReturn(certificateStatus); + when(certificateStatus.managedCertificateId()).thenReturn("test_managed_certificate_id"); + when(certificateStatus.zoneId()).thenReturn("test_zone_id"); + when(cloud.managedCertificate("test_managed_certificate_id", apiKey)) + .thenReturn(managedCertificate); + when(managedCertificate.latestCertificateRequestId()).thenReturn("request_1"); + when(cloud.certificateRequest(eq(apiKey), any(CloudConnector.CertificateRequestsPayload.class))) + .thenReturn(requestsResponse); + when(requestsResponse.certificateRequests()).thenReturn(singletonList(requestsResponseData)); + when(requestsResponseData.id()).thenReturn("certificate_result"); + + classUnderTest.authenticate(auth); + assertThat(classUnderTest.renewCertificate(renewalRequest)).isEqualTo("certificate_result"); + } +} diff --git a/src/test/java/com/venafi/vcert/sdk/connectors/tpp/TppConnectorAT.java b/src/test/java/com/venafi/vcert/sdk/connectors/tpp/TppConnectorAT.java index 2614df5..0ee9bf0 100644 --- a/src/test/java/com/venafi/vcert/sdk/connectors/tpp/TppConnectorAT.java +++ b/src/test/java/com/venafi/vcert/sdk/connectors/tpp/TppConnectorAT.java @@ -1,16 +1,10 @@ package com.venafi.vcert.sdk.connectors.tpp; -import com.venafi.vcert.sdk.VCertException; -import com.venafi.vcert.sdk.certificate.*; -import com.venafi.vcert.sdk.endpoint.Authentication; -import feign.FeignException; -import org.apache.commons.codec.digest.DigestUtils; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.pkcs.PKCS10CertificationRequest; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - +import static com.venafi.vcert.sdk.TestUtils.getTestIps; +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.IOException; import java.io.StringReader; import java.net.InetAddress; @@ -22,265 +16,260 @@ import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collections; - -import static com.venafi.vcert.sdk.TestUtils.getTestIps; -import static java.lang.String.format; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.junit.jupiter.api.Assertions.assertThrows; +import org.apache.commons.codec.digest.DigestUtils; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import feign.FeignException; +import com.venafi.vcert.sdk.VCertException; +import com.venafi.vcert.sdk.certificate.CertificateRequest; +import com.venafi.vcert.sdk.certificate.ImportRequest; +import com.venafi.vcert.sdk.certificate.ImportResponse; +import com.venafi.vcert.sdk.certificate.KeyType; +import com.venafi.vcert.sdk.certificate.PEMCollection; +import com.venafi.vcert.sdk.certificate.RenewalRequest; +import com.venafi.vcert.sdk.certificate.RevocationRequest; +import com.venafi.vcert.sdk.endpoint.Authentication; class TppConnectorAT { - private TppConnector classUnderTest = new TppConnector(Tpp.connect(System.getenv("VENAFI_TPP_URL"))); - - @BeforeEach - void authenticate() throws VCertException { - Security.addProvider(new BouncyCastleProvider()); - Authentication authentication = new Authentication(System.getenv("VENAFI_USER"), System.getenv("VENAFI_PASSWORD"), null); - classUnderTest.authenticate(authentication); - } - - @Test - void readZoneConfiguration() throws VCertException { - try { - ZoneConfiguration zoneConfig = classUnderTest.readZoneConfiguration(System.getenv("VENAFI_ZONE")); - } catch (FeignException fe) { - throw VCertException.fromFeignException(fe); - } - } - - @Test - void ping() throws VCertException { - assertThatCode(() -> classUnderTest.ping()).doesNotThrowAnyException(); - } - - @Test - void generateRequest() throws VCertException, IOException { - String zone = System.getenv("VENAFI_ZONE"); - String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); - ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); - CertificateRequest certificateRequest = new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName(commonName) - .organization(Collections.singletonList("Venafi, Inc.")) - .organizationalUnit(Arrays.asList("Engineering", "Automated Tests")) - .country(Collections.singletonList("US")) - .locality(Collections.singletonList("SLC")) - .province(Collections.singletonList("Utah"))) - .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) - .ipAddresses(getTestIps()) - .keyType(KeyType.RSA) - .keyLength(2048); - - certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); - - assertThat(certificateRequest.csr()).isNotEmpty(); - - PKCS10CertificationRequest request = (PKCS10CertificationRequest) new PEMParser(new StringReader(new String(certificateRequest.csr()))).readObject(); - - // Values overridden by policy which is why they don't match the above values - String subject = request.getSubject().toString(); - - assertThat(subject).contains(format("CN=%s", commonName)); - } - - @Test - void requestCertificate() throws VCertException, SocketException, UnknownHostException { - String zone = System.getenv("VENAFI_ZONE"); - String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); - ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); - CertificateRequest certificateRequest = new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName(commonName) - .organization(Collections.singletonList("Venafi")) - .organizationalUnit(Collections.singletonList("Demo")) - .country(Collections.singletonList("GB")) - .locality(Collections.singletonList("Bracknell")) - .province(Collections.singletonList("Berkshire"))) - .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) - .ipAddresses(getTestIps()) - .keyType(KeyType.RSA) - .keyLength(2048); - - certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); - String certificateId = classUnderTest.requestCertificate(certificateRequest, zone); - assertThat(certificateId).isNotNull(); - } - - @Test - void retrieveCertificate() throws VCertException, SocketException, UnknownHostException { - String zone = System.getenv("VENAFI_ZONE"); - String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); - ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); - CertificateRequest certificateRequest = new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName(commonName) - .organization(Collections.singletonList("Venafi")) - .organizationalUnit(Collections.singletonList("Demo")) - .country(Collections.singletonList("GB")) - .locality(Collections.singletonList("Bracknell")) - .province(Collections.singletonList("Berkshire"))) - .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) - .ipAddresses(getTestIps()) - .keyType(KeyType.RSA) - .keyLength(2048); - - certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); - String certificateId = classUnderTest.requestCertificate(certificateRequest, zone); - assertThat(certificateId).isNotNull(); - - PEMCollection pemCollection = classUnderTest.retrieveCertificate(certificateRequest); - - assertThat(pemCollection.certificate()).isNotNull(); - assertThat(pemCollection.privateKey()).isNull(); - } - - @Test - void revokeCertificate() throws VCertException, SocketException, UnknownHostException { - String zone = System.getenv("VENAFI_ZONE"); - String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); - ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); - CertificateRequest certificateRequest = new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName(commonName) - .organization(Collections.singletonList("Venafi")) - .organizationalUnit(Collections.singletonList("Demo")) - .country(Collections.singletonList("GB")) - .locality(Collections.singletonList("Bracknell")) - .province(Collections.singletonList("Berkshire"))) - .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) - .ipAddresses(getTestIps()) - .keyType(KeyType.RSA) - .keyLength(2048); - - certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); - String certificateId = classUnderTest.requestCertificate(certificateRequest, zone); - assertThat(certificateId).isNotNull(); - - RevocationRequest revocationRequest = new RevocationRequest(); - revocationRequest.reason("key-compromise"); - revocationRequest.certificateDN(certificateRequest.pickupId()); - - classUnderTest.revokeCertificate(revocationRequest); - } - - @Test - void renewCertificate() throws VCertException, UnknownHostException, SocketException, CertificateException, NoSuchAlgorithmException { - String zone = System.getenv("VENAFI_ZONE"); - String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); - ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); - CertificateRequest certificateRequest = new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName(commonName) - .organization(Collections.singletonList("Venafi")) - .organizationalUnit(Collections.singletonList("Demo")) - .country(Collections.singletonList("GB")) - .locality(Collections.singletonList("Bracknell")) - .province(Collections.singletonList("Berkshire"))) - .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) - .ipAddresses(getTestIps()) - .keyType(KeyType.RSA) - .keyLength(2048); - - certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); - String certificateId = classUnderTest.requestCertificate(certificateRequest, zone); - assertThat(certificateId).isNotNull(); - - PEMCollection pemCollection = classUnderTest.retrieveCertificate(certificateRequest); - X509Certificate cert = (X509Certificate) pemCollection.certificate(); - - String thumbprint = DigestUtils.sha1Hex(cert.getEncoded()).toUpperCase(); - - CertificateRequest certificateRequestToRenew = new CertificateRequest().subject( - new CertificateRequest.PKIXName() - .commonName(commonName) - .organization(Collections.singletonList("Venafi")) - .organizationalUnit(Collections.singletonList("Demo")) - .country(Collections.singletonList("GB")) - .locality(Collections.singletonList("Bracknell")) - .province(Collections.singletonList("Berkshire"))) - .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) - .ipAddresses(getTestIps()) - .keyType(KeyType.RSA) - .keyLength(2048); - classUnderTest.generateRequest(zoneConfiguration, certificateRequestToRenew); - - String renewRequestId = classUnderTest.renewCertificate(new RenewalRequest() - .request(certificateRequestToRenew) - .thumbprint(thumbprint)); - - assertThat(renewRequestId).isNotNull(); - } - - @Test - void importCertificate() throws VCertException { - final String cert = "-----BEGIN CERTIFICATE-----\n" + - "MIIDdjCCAl6gAwIBAgIRAPqSZQ04IjWgO2rwIDRcOY8wDQYJKoZIhvcNAQENBQAw\n" + - "gYAxCzAJBgNVBAYTAlVTMQ0wCwYDVQQIDARVdGFoMRcwFQYDVQQHDA5TYWx0IExh\n" + - "a2UgQ2l0eTEPMA0GA1UECgwGVmVuYWZpMRswGQYDVQQLDBJOT1QgRk9SIFBST0RV\n" + - "Q1RJT04xGzAZBgNVBAMMElZDZXJ0IFRlc3QgTW9kZSBDQTAeFw0xODA5MTIxMzUw\n" + - "MzNaFw0xODEyMTExMzUwMzNaMCQxIjAgBgNVBAMTGWltcG9ydC52ZW5hZmkuZXhh\n" + - "bXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQChjQk0jSE5\n" + - "ktVdH8bAM0QCpGs1rOOVMmRkMc7d4hQ6bTlFlIypMq9t+1O2Z8i4fiKDS7vSBmBo\n" + - "WBgN9e0fbAnKEvBIcNLBS4lmwzRDxDCrNV3Dr5s+yJtUw9V2XBwiXbtW7qs5+c0O\n" + - "y7a2S/5HudXUlAuXf7SF4MboMMpHRg+UkyA4j0peir8PtmlJjlYBt3lZdaeLlD6F\n" + - "EIlIVQFZ6ulUF/kULhxhTUl2yNUUzJ/bqJlhFU6pkL+GoW1lnaZ8FYXwA1EKYyRk\n" + - "DYL581eqvIBJY9tCNWbOdU1r+5wR4OOKe/WWWhcDC6nL/M8ZYhfQg1nHoD58A8Dk\n" + - "H4AAt8A3EZpdAgMBAAGjRjBEMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB\n" + - "/wQCMAAwHwYDVR0jBBgwFoAUzqRFDvLX0mz4AjPb45tLGavm8AcwDQYJKoZIhvcN\n" + - "AQENBQADggEBABa4wqh+A63O5PHrdUCBSmQs9ve/oIXj561VBmqXkTHLrtKtbtcA\n" + - "yvsMi8RD8BibBAsUCljkCmLoQD/XeQFtsPlMAxisSMYhChh58008CIYDR8Nf/qoe\n" + - "YfzdMB/3VWCqTn9KGF8aMKeQvbFvuqmbtdCv//eYe6mNe2fa/x6PSdGMi4BPmjUC\n" + - "PmBT4p1iwMtu8LnL4UM4awjmmExR4X4rafcyGEbf0D/CRfhDLSwxvrrVcWd6TMMY\n" + - "HPZ/pw//+UrVLgEEsyM2zwf+LokbszPBvPAtHMJtr7Pnq2MQtEEkLfPqOWG3ol1H\n" + - "t+4v2LIW1q4GkwOUjPqgyIaJC5jj5pH9/g8=\n" + - "-----END CERTIFICATE-----"; - - final String pk = "-----BEGIN RSA PRIVATE KEY-----\n" + - "MIIEpAIBAAKCAQEAoY0JNI0hOZLVXR/GwDNEAqRrNazjlTJkZDHO3eIUOm05RZSM\n" + - "qTKvbftTtmfIuH4ig0u70gZgaFgYDfXtH2wJyhLwSHDSwUuJZsM0Q8QwqzVdw6+b\n" + - "PsibVMPVdlwcIl27Vu6rOfnNDsu2tkv+R7nV1JQLl3+0heDG6DDKR0YPlJMgOI9K\n" + - "Xoq/D7ZpSY5WAbd5WXWni5Q+hRCJSFUBWerpVBf5FC4cYU1JdsjVFMyf26iZYRVO\n" + - "qZC/hqFtZZ2mfBWF8ANRCmMkZA2C+fNXqryASWPbQjVmznVNa/ucEeDjinv1lloX\n" + - "Awupy/zPGWIX0INZx6A+fAPA5B+AALfANxGaXQIDAQABAoIBAE7of6WOhbsEcHkz\n" + - "CzZYFBEiVEd8chEu8wBJn9ybD/xV21KUM3x1iGC1EPeYi98ppRvygwQcHzz4Qo+X\n" + - "HsJpWAK+62TGzvqhNbTfBglPq+IEiA8MGE07WTu3B+3vIcLbe6UDoNkJndJrSIyU\n" + - "Y9iO+dYClgLi2r9FwoIpSrQzkWqlB3edle4Nq1WABtWTOSDYysz1gk0KrLmQQfXP\n" + - "CPiwkL0SjB+sfbOiVX0B2liV2oxJ5VZWNo/250wFcvrcYrgTNtEVNMXtpN0tnRMH\n" + - "NPwnY+B9WGu/NVhtvOcOTPHq9xQhbmBCS1axikizCaIqEOyegdeDJ4ASJnVybfCA\n" + - "KzjoCpUCgYEAwOmeEvzSP8hCKtLPU8QDBA1y+mEvZMwBY4qr3hfqv3qa0QmFvxkk\n" + - "7Ubmy2oFOoUnVgnhRzAf/bajbkz4ScUgd2JrUdIEhNNVwDn/llnS/UHBlZY++BtW\n" + - "mvyon9ObXgPNPoHcJqzrqARu8PPJQEsZ+xjxM/gyif3prn6Uct6R8B8CgYEA1mHd\n" + - "Astwht39z16FoX9rQRGgx64Z0nesfTjl+4mkypz6ukkcfU1GjobqEG3k666+OJk1\n" + - "SRs8s20Pahrh21LO5x/QtvChhZ+nIedqlhBlNH9uUJI9ChbUN0luetiSPT8F5aqg\n" + - "gZMY13K5icAQ+98EcNwl7ZhVPq0BvLlbqTWi9gMCgYEAjtVqoQxob6lKtIJZ19+t\n" + - "i/aZRyFmAe+6p4UpM8vpl9SjhFrUmGV5neV9ROc+79FfCqlOD3NmfGgaIbUDsTsv\n" + - "irVoWLBzgBUpzKYkw6HGQpXJS4RvIyy6tw6Tm6MFylpuQPXNlyU5ZrHBos4eGGiC\n" + - "2BPjo2MFqH5D41r9dv+sdmkCgYEAtSJYx3y2pe04/xYhGFP9fivzyeMrRC4DWoZR\n" + - "oxcoWl0KZ41QefppzBDoAVuo2Q17AX1JjWxq/DsAlCkEffhYguXZxkhIYQuE/lt2\n" + - "LjbKG/IzdfYphrXFNrVfmIIWBZOTWvqwxOpRSfBQHbhfYUCMkwMfNMHJ/LvWxOtk\n" + - "K/L6rpsCgYB6p9RU2kXexAh9kUpbGqVeJBoIh6ArXHgepESE/7dPw26D0DM0mef0\n" + - "X1MasxN3JF7ZsSGfcCLXnICSJHuNTy9WztqF3hUbQwYd9vmZxtzAo5/fK4DVAaXS\n" + - "ZtIVl/CH/az0xqLKWIlmWOip9SfUVlZdgege+PlQtRqoFVOsH8+MEg==\n" + - "-----END RSA PRIVATE KEY-----"; - - String zone = System.getenv("VENAFI_ZONE"); - ImportRequest importRequest = new ImportRequest(); - importRequest.certificateData(cert); - importRequest.privateKeyData(pk); - importRequest.policyDN(classUnderTest.getPolicyDN(zone)); - - - ImportResponse response = classUnderTest.importCertificate(importRequest); - assertThat(response).isNotNull(); - assertThat(response.certificateDN()).isNotNull(); - assertThat(response.certificateVaultId()).isNotNull(); - assertThat(response.privateKeyVaultId()).isNotNull(); - - } - - @Test - void readPolicyConfiguration() { - assertThrows(UnsupportedOperationException.class, () -> classUnderTest.readPolicyConfiguration("zone")); + private TppConnector classUnderTest = + new TppConnector(Tpp.connect(System.getenv("VENAFI_TPP_URL"))); + + @BeforeEach + void authenticate() throws VCertException { + Security.addProvider(new BouncyCastleProvider()); + Authentication authentication = + new Authentication(System.getenv("VENAFI_USER"), System.getenv("VENAFI_PASSWORD"), null); + classUnderTest.authenticate(authentication); + } + + @Test + void readZoneConfiguration() throws VCertException { + try { + ZoneConfiguration zoneConfig = + classUnderTest.readZoneConfiguration(System.getenv("VENAFI_ZONE")); + } catch (FeignException fe) { + throw VCertException.fromFeignException(fe); } -} \ No newline at end of file + } + + @Test + void ping() throws VCertException { + assertThatCode(() -> classUnderTest.ping()).doesNotThrowAnyException(); + } + + @Test + void generateRequest() throws VCertException, IOException { + String zone = System.getenv("VENAFI_ZONE"); + String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); + ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); + CertificateRequest certificateRequest = new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName(commonName) + .organization(Collections.singletonList("Venafi, Inc.")) + .organizationalUnit(Arrays.asList("Engineering", "Automated Tests")) + .country(Collections.singletonList("US")).locality(Collections.singletonList("SLC")) + .province(Collections.singletonList("Utah"))) + .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) + .ipAddresses(getTestIps()).keyType(KeyType.RSA).keyLength(2048); + + certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); + + assertThat(certificateRequest.csr()).isNotEmpty(); + + PKCS10CertificationRequest request = (PKCS10CertificationRequest) new PEMParser( + new StringReader(new String(certificateRequest.csr()))).readObject(); + + // Values overridden by policy which is why they don't match the above values + String subject = request.getSubject().toString(); + + assertThat(subject).contains(format("CN=%s", commonName)); + } + + @Test + void requestCertificate() throws VCertException, SocketException, UnknownHostException { + String zone = System.getenv("VENAFI_ZONE"); + String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); + ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); + CertificateRequest certificateRequest = new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName(commonName) + .organization(Collections.singletonList("Venafi")) + .organizationalUnit(Collections.singletonList("Demo")) + .country(Collections.singletonList("GB")) + .locality(Collections.singletonList("Bracknell")) + .province(Collections.singletonList("Berkshire"))) + .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) + .ipAddresses(getTestIps()).keyType(KeyType.RSA).keyLength(2048); + + certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); + String certificateId = classUnderTest.requestCertificate(certificateRequest, zone); + assertThat(certificateId).isNotNull(); + } + + @Test + void retrieveCertificate() throws VCertException, SocketException, UnknownHostException { + String zone = System.getenv("VENAFI_ZONE"); + String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); + ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); + CertificateRequest certificateRequest = new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName(commonName) + .organization(Collections.singletonList("Venafi")) + .organizationalUnit(Collections.singletonList("Demo")) + .country(Collections.singletonList("GB")) + .locality(Collections.singletonList("Bracknell")) + .province(Collections.singletonList("Berkshire"))) + .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) + .ipAddresses(getTestIps()).keyType(KeyType.RSA).keyLength(2048); + + certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); + String certificateId = classUnderTest.requestCertificate(certificateRequest, zone); + assertThat(certificateId).isNotNull(); + + PEMCollection pemCollection = classUnderTest.retrieveCertificate(certificateRequest); + + assertThat(pemCollection.certificate()).isNotNull(); + assertThat(pemCollection.privateKey()).isNull(); + } + + @Test + void revokeCertificate() throws VCertException, SocketException, UnknownHostException { + String zone = System.getenv("VENAFI_ZONE"); + String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); + ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); + CertificateRequest certificateRequest = new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName(commonName) + .organization(Collections.singletonList("Venafi")) + .organizationalUnit(Collections.singletonList("Demo")) + .country(Collections.singletonList("GB")) + .locality(Collections.singletonList("Bracknell")) + .province(Collections.singletonList("Berkshire"))) + .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) + .ipAddresses(getTestIps()).keyType(KeyType.RSA).keyLength(2048); + + certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); + String certificateId = classUnderTest.requestCertificate(certificateRequest, zone); + assertThat(certificateId).isNotNull(); + + RevocationRequest revocationRequest = new RevocationRequest(); + revocationRequest.reason("key-compromise"); + revocationRequest.certificateDN(certificateRequest.pickupId()); + + classUnderTest.revokeCertificate(revocationRequest); + } + + @Test + void renewCertificate() throws VCertException, UnknownHostException, SocketException, + CertificateException, NoSuchAlgorithmException { + String zone = System.getenv("VENAFI_ZONE"); + String commonName = System.getenv("VENAFI_CERT_COMMON_NAME"); + ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration(zone); + CertificateRequest certificateRequest = new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName(commonName) + .organization(Collections.singletonList("Venafi")) + .organizationalUnit(Collections.singletonList("Demo")) + .country(Collections.singletonList("GB")) + .locality(Collections.singletonList("Bracknell")) + .province(Collections.singletonList("Berkshire"))) + .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) + .ipAddresses(getTestIps()).keyType(KeyType.RSA).keyLength(2048); + + certificateRequest = classUnderTest.generateRequest(zoneConfiguration, certificateRequest); + String certificateId = classUnderTest.requestCertificate(certificateRequest, zone); + assertThat(certificateId).isNotNull(); + + PEMCollection pemCollection = classUnderTest.retrieveCertificate(certificateRequest); + X509Certificate cert = (X509Certificate) pemCollection.certificate(); + + String thumbprint = DigestUtils.sha1Hex(cert.getEncoded()).toUpperCase(); + + CertificateRequest certificateRequestToRenew = new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName(commonName) + .organization(Collections.singletonList("Venafi")) + .organizationalUnit(Collections.singletonList("Demo")) + .country(Collections.singletonList("GB")) + .locality(Collections.singletonList("Bracknell")) + .province(Collections.singletonList("Berkshire"))) + .dnsNames(Collections.singletonList(InetAddress.getLocalHost().getHostName())) + .ipAddresses(getTestIps()).keyType(KeyType.RSA).keyLength(2048); + classUnderTest.generateRequest(zoneConfiguration, certificateRequestToRenew); + + String renewRequestId = classUnderTest.renewCertificate( + new RenewalRequest().request(certificateRequestToRenew).thumbprint(thumbprint)); + + assertThat(renewRequestId).isNotNull(); + } + + @Test + void importCertificate() throws VCertException { + final String cert = "-----BEGIN CERTIFICATE-----\n" + + "MIIDdjCCAl6gAwIBAgIRAPqSZQ04IjWgO2rwIDRcOY8wDQYJKoZIhvcNAQENBQAw\n" + + "gYAxCzAJBgNVBAYTAlVTMQ0wCwYDVQQIDARVdGFoMRcwFQYDVQQHDA5TYWx0IExh\n" + + "a2UgQ2l0eTEPMA0GA1UECgwGVmVuYWZpMRswGQYDVQQLDBJOT1QgRk9SIFBST0RV\n" + + "Q1RJT04xGzAZBgNVBAMMElZDZXJ0IFRlc3QgTW9kZSBDQTAeFw0xODA5MTIxMzUw\n" + + "MzNaFw0xODEyMTExMzUwMzNaMCQxIjAgBgNVBAMTGWltcG9ydC52ZW5hZmkuZXhh\n" + + "bXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQChjQk0jSE5\n" + + "ktVdH8bAM0QCpGs1rOOVMmRkMc7d4hQ6bTlFlIypMq9t+1O2Z8i4fiKDS7vSBmBo\n" + + "WBgN9e0fbAnKEvBIcNLBS4lmwzRDxDCrNV3Dr5s+yJtUw9V2XBwiXbtW7qs5+c0O\n" + + "y7a2S/5HudXUlAuXf7SF4MboMMpHRg+UkyA4j0peir8PtmlJjlYBt3lZdaeLlD6F\n" + + "EIlIVQFZ6ulUF/kULhxhTUl2yNUUzJ/bqJlhFU6pkL+GoW1lnaZ8FYXwA1EKYyRk\n" + + "DYL581eqvIBJY9tCNWbOdU1r+5wR4OOKe/WWWhcDC6nL/M8ZYhfQg1nHoD58A8Dk\n" + + "H4AAt8A3EZpdAgMBAAGjRjBEMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB\n" + + "/wQCMAAwHwYDVR0jBBgwFoAUzqRFDvLX0mz4AjPb45tLGavm8AcwDQYJKoZIhvcN\n" + + "AQENBQADggEBABa4wqh+A63O5PHrdUCBSmQs9ve/oIXj561VBmqXkTHLrtKtbtcA\n" + + "yvsMi8RD8BibBAsUCljkCmLoQD/XeQFtsPlMAxisSMYhChh58008CIYDR8Nf/qoe\n" + + "YfzdMB/3VWCqTn9KGF8aMKeQvbFvuqmbtdCv//eYe6mNe2fa/x6PSdGMi4BPmjUC\n" + + "PmBT4p1iwMtu8LnL4UM4awjmmExR4X4rafcyGEbf0D/CRfhDLSwxvrrVcWd6TMMY\n" + + "HPZ/pw//+UrVLgEEsyM2zwf+LokbszPBvPAtHMJtr7Pnq2MQtEEkLfPqOWG3ol1H\n" + + "t+4v2LIW1q4GkwOUjPqgyIaJC5jj5pH9/g8=\n" + "-----END CERTIFICATE-----"; + + final String pk = "-----BEGIN RSA PRIVATE KEY-----\n" + + "MIIEpAIBAAKCAQEAoY0JNI0hOZLVXR/GwDNEAqRrNazjlTJkZDHO3eIUOm05RZSM\n" + + "qTKvbftTtmfIuH4ig0u70gZgaFgYDfXtH2wJyhLwSHDSwUuJZsM0Q8QwqzVdw6+b\n" + + "PsibVMPVdlwcIl27Vu6rOfnNDsu2tkv+R7nV1JQLl3+0heDG6DDKR0YPlJMgOI9K\n" + + "Xoq/D7ZpSY5WAbd5WXWni5Q+hRCJSFUBWerpVBf5FC4cYU1JdsjVFMyf26iZYRVO\n" + + "qZC/hqFtZZ2mfBWF8ANRCmMkZA2C+fNXqryASWPbQjVmznVNa/ucEeDjinv1lloX\n" + + "Awupy/zPGWIX0INZx6A+fAPA5B+AALfANxGaXQIDAQABAoIBAE7of6WOhbsEcHkz\n" + + "CzZYFBEiVEd8chEu8wBJn9ybD/xV21KUM3x1iGC1EPeYi98ppRvygwQcHzz4Qo+X\n" + + "HsJpWAK+62TGzvqhNbTfBglPq+IEiA8MGE07WTu3B+3vIcLbe6UDoNkJndJrSIyU\n" + + "Y9iO+dYClgLi2r9FwoIpSrQzkWqlB3edle4Nq1WABtWTOSDYysz1gk0KrLmQQfXP\n" + + "CPiwkL0SjB+sfbOiVX0B2liV2oxJ5VZWNo/250wFcvrcYrgTNtEVNMXtpN0tnRMH\n" + + "NPwnY+B9WGu/NVhtvOcOTPHq9xQhbmBCS1axikizCaIqEOyegdeDJ4ASJnVybfCA\n" + + "KzjoCpUCgYEAwOmeEvzSP8hCKtLPU8QDBA1y+mEvZMwBY4qr3hfqv3qa0QmFvxkk\n" + + "7Ubmy2oFOoUnVgnhRzAf/bajbkz4ScUgd2JrUdIEhNNVwDn/llnS/UHBlZY++BtW\n" + + "mvyon9ObXgPNPoHcJqzrqARu8PPJQEsZ+xjxM/gyif3prn6Uct6R8B8CgYEA1mHd\n" + + "Astwht39z16FoX9rQRGgx64Z0nesfTjl+4mkypz6ukkcfU1GjobqEG3k666+OJk1\n" + + "SRs8s20Pahrh21LO5x/QtvChhZ+nIedqlhBlNH9uUJI9ChbUN0luetiSPT8F5aqg\n" + + "gZMY13K5icAQ+98EcNwl7ZhVPq0BvLlbqTWi9gMCgYEAjtVqoQxob6lKtIJZ19+t\n" + + "i/aZRyFmAe+6p4UpM8vpl9SjhFrUmGV5neV9ROc+79FfCqlOD3NmfGgaIbUDsTsv\n" + + "irVoWLBzgBUpzKYkw6HGQpXJS4RvIyy6tw6Tm6MFylpuQPXNlyU5ZrHBos4eGGiC\n" + + "2BPjo2MFqH5D41r9dv+sdmkCgYEAtSJYx3y2pe04/xYhGFP9fivzyeMrRC4DWoZR\n" + + "oxcoWl0KZ41QefppzBDoAVuo2Q17AX1JjWxq/DsAlCkEffhYguXZxkhIYQuE/lt2\n" + + "LjbKG/IzdfYphrXFNrVfmIIWBZOTWvqwxOpRSfBQHbhfYUCMkwMfNMHJ/LvWxOtk\n" + + "K/L6rpsCgYB6p9RU2kXexAh9kUpbGqVeJBoIh6ArXHgepESE/7dPw26D0DM0mef0\n" + + "X1MasxN3JF7ZsSGfcCLXnICSJHuNTy9WztqF3hUbQwYd9vmZxtzAo5/fK4DVAaXS\n" + + "ZtIVl/CH/az0xqLKWIlmWOip9SfUVlZdgege+PlQtRqoFVOsH8+MEg==\n" + + "-----END RSA PRIVATE KEY-----"; + + String zone = System.getenv("VENAFI_ZONE"); + ImportRequest importRequest = new ImportRequest(); + importRequest.certificateData(cert); + importRequest.privateKeyData(pk); + importRequest.policyDN(classUnderTest.getPolicyDN(zone)); + + + ImportResponse response = classUnderTest.importCertificate(importRequest); + assertThat(response).isNotNull(); + assertThat(response.certificateDN()).isNotNull(); + assertThat(response.certificateVaultId()).isNotNull(); + assertThat(response.privateKeyVaultId()).isNotNull(); + + } + + @Test + void readPolicyConfiguration() { + assertThrows(UnsupportedOperationException.class, + () -> classUnderTest.readPolicyConfiguration("zone")); + } +} diff --git a/src/test/java/com/venafi/vcert/sdk/connectors/tpp/TppConnectorIT.java b/src/test/java/com/venafi/vcert/sdk/connectors/tpp/TppConnectorIT.java index 506afbc..b04a818 100644 --- a/src/test/java/com/venafi/vcert/sdk/connectors/tpp/TppConnectorIT.java +++ b/src/test/java/com/venafi/vcert/sdk/connectors/tpp/TppConnectorIT.java @@ -1,88 +1,96 @@ package com.venafi.vcert.sdk.connectors.tpp; +import static com.venafi.vcert.sdk.SignatureAlgorithm.SHA256WithRSA; +import static com.venafi.vcert.sdk.certificate.EllipticCurve.EllipticCurveP224; +import static com.venafi.vcert.sdk.certificate.EllipticCurve.EllipticCurveP256; +import static com.venafi.vcert.sdk.certificate.EllipticCurve.EllipticCurveP384; +import static com.venafi.vcert.sdk.certificate.EllipticCurve.EllipticCurveP521; +import static com.venafi.vcert.sdk.certificate.KeyType.ECDSA; +import static com.venafi.vcert.sdk.certificate.KeyType.RSA; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import com.github.jenspiegsa.wiremockextension.InjectServer; import com.github.jenspiegsa.wiremockextension.WireMockExtension; import com.github.tomakehurst.wiremock.WireMockServer; import com.venafi.vcert.sdk.VCertException; import com.venafi.vcert.sdk.endpoint.Authentication; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static com.venafi.vcert.sdk.SignatureAlgorithm.*; -import static com.venafi.vcert.sdk.certificate.EllipticCurve.*; -import static com.venafi.vcert.sdk.certificate.KeyType.ECDSA; -import static com.venafi.vcert.sdk.certificate.KeyType.RSA; -import static org.assertj.core.api.Assertions.assertThat; @ExtendWith(WireMockExtension.class) class TppConnectorIT { - @InjectServer - private WireMockServer serverMock; + @InjectServer + private WireMockServer serverMock; - private TppConnector classUnderTest; + private TppConnector classUnderTest; - @BeforeEach - void setup() throws VCertException { - classUnderTest = new TppConnector(Tpp.connect("http://localhost:" + serverMock.port() + "/vedsdk/")); // todo String.format() - Authentication auth = new Authentication("user", "pass", null); - classUnderTest.authenticate(auth); - } + @BeforeEach + void setup() throws VCertException { + classUnderTest = + new TppConnector(Tpp.connect("http://localhost:" + serverMock.port() + "/vedsdk/")); // todo + // String.format() + Authentication auth = new Authentication("user", "pass", null); + classUnderTest.authenticate(auth); + } - @Test - @DisplayName("should start and inject server.") - void shouldInjectServer() { - assertThat(serverMock).isNotNull(); - assertThat(serverMock.isRunning()).describedAs("server expected to be running.").isTrue(); - } + @Test + @DisplayName("should start and inject server.") + void shouldInjectServer() { + assertThat(serverMock).isNotNull(); + assertThat(serverMock.isRunning()).describedAs("server expected to be running.").isTrue(); + } - @Test - void authenticate() throws VCertException { - // call in @BeforeEach - assertThat(classUnderTest.bestBeforeEnd).isEqualTo("2019-03-27T19:06:19.479Z"); - assertThat(classUnderTest.apiKey()).isEqualTo("12345678-1234-1234-1234-123456789012"); - } + @Test + void authenticate() throws VCertException { + // call in @BeforeEach + assertThat(classUnderTest.bestBeforeEnd).isEqualTo("2019-03-27T19:06:19.479Z"); + assertThat(classUnderTest.apiKey()).isEqualTo("12345678-1234-1234-1234-123456789012"); + } - @Test - void readZoneConfiguration() throws VCertException { - ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration("tag"); + @Test + void readZoneConfiguration() throws VCertException { + ZoneConfiguration zoneConfiguration = classUnderTest.readZoneConfiguration("tag"); - assertThat(zoneConfiguration).isNotNull(); - assertThat(zoneConfiguration.organization()).isNull(); - assertThat(zoneConfiguration.organizationalUnit()).isNotNull(); - assertThat(zoneConfiguration.organizationalUnit()).isEmpty(); - assertThat(zoneConfiguration.country()).isNull(); - assertThat(zoneConfiguration.province()).isNull(); - assertThat(zoneConfiguration.locality()).isNull(); - assertThat(zoneConfiguration.policy()).isNotNull(); - assertThat(zoneConfiguration.policy().subjectCNRegexes()).containsExactly(".*"); - assertThat(zoneConfiguration.policy().subjectORegexes()).containsExactly(".*"); - assertThat(zoneConfiguration.policy().subjectOURegexes()).containsExactly(".*"); - assertThat(zoneConfiguration.policy().subjectSTRegexes()).containsExactly(".*"); - assertThat(zoneConfiguration.policy().subjectLRegexes()).containsExactly(".*"); - assertThat(zoneConfiguration.policy().subjectCRegexes()).containsExactly(".*"); - assertThat(zoneConfiguration.policy().allowedKeyConfigurations()).isNotNull(); - assertThat(zoneConfiguration.policy().allowedKeyConfigurations()).isNotNull(); - assertThat(zoneConfiguration.policy().allowedKeyConfigurations()).hasSize(2);// - assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(0).keyType()).isEqualTo(RSA); - assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(0).keySizes()).containsExactly(512, 1024, 2048, 4096, 8192); - assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(0).keyCurves()).isNull(); - assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(1).keyType()).isEqualTo(ECDSA); - assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(1).keySizes()).isNull(); - assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(1).keyCurves()).containsExactly(EllipticCurveP224, EllipticCurveP256, EllipticCurveP384, EllipticCurveP521); - assertThat(zoneConfiguration.policy().dnsSanRegExs()).containsExactly(".*"); - assertThat(zoneConfiguration.policy().ipSanRegExs()).containsExactly(".*"); - assertThat(zoneConfiguration.policy().emailSanRegExs()).containsExactly(".*"); - assertThat(zoneConfiguration.policy().uriSanRegExs()).containsExactly(".*"); - assertThat(zoneConfiguration.policy().upnSanRegExs()).containsExactly(".*"); - assertThat(zoneConfiguration.policy().allowWildcards()).isTrue(); - assertThat(zoneConfiguration.policy().allowKeyReuse()).isFalse(); - assertThat(zoneConfiguration.hashAlgorithm()).isEqualTo(SHA256WithRSA); - assertThat(zoneConfiguration.customAttributeValues()).isNotNull(); - assertThat(zoneConfiguration.customAttributeValues()).isEmpty(); - } + assertThat(zoneConfiguration).isNotNull(); + assertThat(zoneConfiguration.organization()).isNull(); + assertThat(zoneConfiguration.organizationalUnit()).isNotNull(); + assertThat(zoneConfiguration.organizationalUnit()).isEmpty(); + assertThat(zoneConfiguration.country()).isNull(); + assertThat(zoneConfiguration.province()).isNull(); + assertThat(zoneConfiguration.locality()).isNull(); + assertThat(zoneConfiguration.policy()).isNotNull(); + assertThat(zoneConfiguration.policy().subjectCNRegexes()).containsExactly(".*"); + assertThat(zoneConfiguration.policy().subjectORegexes()).containsExactly(".*"); + assertThat(zoneConfiguration.policy().subjectOURegexes()).containsExactly(".*"); + assertThat(zoneConfiguration.policy().subjectSTRegexes()).containsExactly(".*"); + assertThat(zoneConfiguration.policy().subjectLRegexes()).containsExactly(".*"); + assertThat(zoneConfiguration.policy().subjectCRegexes()).containsExactly(".*"); + assertThat(zoneConfiguration.policy().allowedKeyConfigurations()).isNotNull(); + assertThat(zoneConfiguration.policy().allowedKeyConfigurations()).hasSize(2);// + assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(0).keyType()) + .isEqualTo(RSA); + assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(0).keySizes()) + .containsExactly(512, 1024, 2048, 4096, 8192); + assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(0).keyCurves()).isNull(); + assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(1).keyType()) + .isEqualTo(ECDSA); + assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(1).keySizes()).isNull(); + assertThat(zoneConfiguration.policy().allowedKeyConfigurations().get(1).keyCurves()) + .containsExactly(EllipticCurveP224, EllipticCurveP256, EllipticCurveP384, + EllipticCurveP521); + assertThat(zoneConfiguration.policy().dnsSanRegExs()).containsExactly(".*"); + assertThat(zoneConfiguration.policy().ipSanRegExs()).containsExactly(".*"); + assertThat(zoneConfiguration.policy().emailSanRegExs()).containsExactly(".*"); + assertThat(zoneConfiguration.policy().uriSanRegExs()).containsExactly(".*"); + assertThat(zoneConfiguration.policy().upnSanRegExs()).containsExactly(".*"); + assertThat(zoneConfiguration.policy().allowWildcards()).isTrue(); + assertThat(zoneConfiguration.policy().allowKeyReuse()).isFalse(); + assertThat(zoneConfiguration.hashAlgorithm()).isEqualTo(SHA256WithRSA); + assertThat(zoneConfiguration.customAttributeValues()).isNotNull(); + assertThat(zoneConfiguration.customAttributeValues()).isEmpty(); + } } diff --git a/src/test/java/com/venafi/vcert/sdk/connectors/tpp/TppConnectorTest.java b/src/test/java/com/venafi/vcert/sdk/connectors/tpp/TppConnectorTest.java index 0aee1d4..55e2255 100644 --- a/src/test/java/com/venafi/vcert/sdk/connectors/tpp/TppConnectorTest.java +++ b/src/test/java/com/venafi/vcert/sdk/connectors/tpp/TppConnectorTest.java @@ -1,12 +1,18 @@ package com.venafi.vcert.sdk.connectors.tpp; -import com.venafi.vcert.sdk.VCertException; -import com.venafi.vcert.sdk.certificate.CertificateRequest; -import com.venafi.vcert.sdk.certificate.RenewalRequest; -import com.venafi.vcert.sdk.connectors.LockableValue; -import com.venafi.vcert.sdk.connectors.LockableValues; -import com.venafi.vcert.sdk.connectors.ServerPolicy; -import com.venafi.vcert.sdk.endpoint.Authentication; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.security.Security; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.util.Arrays; +import java.util.Collections; import org.apache.commons.lang3.RandomStringUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.jupiter.api.BeforeEach; @@ -19,165 +25,167 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import java.security.Security; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.util.Arrays; -import java.util.Collections; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import com.venafi.vcert.sdk.VCertException; +import com.venafi.vcert.sdk.certificate.CertificateRequest; +import com.venafi.vcert.sdk.certificate.RenewalRequest; +import com.venafi.vcert.sdk.connectors.LockableValue; +import com.venafi.vcert.sdk.connectors.LockableValues; +import com.venafi.vcert.sdk.connectors.ServerPolicy; +import com.venafi.vcert.sdk.endpoint.Authentication; @ExtendWith(MockitoExtension.class) class TppConnectorTest { - private static final Logger logger = LoggerFactory.getLogger(TppConnectorTest.class); - private static final String API_KEY = "12345678-1234-1234-1234-123456789012"; - - @Mock - private Tpp tpp; - private TppConnector classUnderTest; - - @Captor - private ArgumentCaptor certificateRenewalRequestArgumentCaptor; - - @BeforeEach - void setUp() throws VCertException { - this.classUnderTest = new TppConnector(tpp); - - AuthorizeResponse response = new AuthorizeResponse().apiKey(API_KEY).validUntil(OffsetDateTime.now()); - when(tpp.authorize(any(TppConnector.AuthorizeRequest.class))).thenReturn(response); - - Authentication authentication = new Authentication("user", "pass", null); - classUnderTest.authenticate(authentication); - } - - @Test - void canGetAuthToken() throws VCertException { - assertNotNull(classUnderTest.apiKey()); - } - - @Test - @DisplayName("Request a certificate from TPP") - void requestCertificate() throws VCertException { - Security.addProvider(new BouncyCastleProvider()); - - TppConnector.ReadZoneConfigurationRequest expectedRZCRequest = new TppConnector.ReadZoneConfigurationRequest("\\VED\\Policy\\\\VED\\Policy\\myZone"); - when(tpp.readZoneConfiguration(eq(expectedRZCRequest), eq(API_KEY))) - .thenReturn(new TppConnector.ReadZoneConfigurationResponse() - .policy(new ServerPolicy() + private static final Logger logger = LoggerFactory.getLogger(TppConnectorTest.class); + private static final String API_KEY = "12345678-1234-1234-1234-123456789012"; + + @Mock + private Tpp tpp; + private TppConnector classUnderTest; + + @Captor + private ArgumentCaptor certificateRenewalRequestArgumentCaptor; + + @BeforeEach + void setUp() throws VCertException { + this.classUnderTest = new TppConnector(tpp); + + AuthorizeResponse response = + new AuthorizeResponse().apiKey(API_KEY).validUntil(OffsetDateTime.now()); + when(tpp.authorize(any(TppConnector.AuthorizeRequest.class))).thenReturn(response); + + Authentication authentication = new Authentication("user", "pass", null); + classUnderTest.authenticate(authentication); + } + + @Test + void canGetAuthToken() throws VCertException { + assertNotNull(classUnderTest.apiKey()); + } + + @Test + @DisplayName("Request a certificate from TPP") + void requestCertificate() throws VCertException { + Security.addProvider(new BouncyCastleProvider()); + + TppConnector.ReadZoneConfigurationRequest expectedRZCRequest = + new TppConnector.ReadZoneConfigurationRequest("\\VED\\Policy\\\\VED\\Policy\\myZone"); + when( + tpp.readZoneConfiguration(eq(expectedRZCRequest), eq(API_KEY))) + .thenReturn( + new TppConnector.ReadZoneConfigurationResponse() + .policy( + new ServerPolicy() .subject(new ServerPolicy.Subject() - .organizationalUnit(new LockableValues(false, Collections.singletonList("OU"))) - .state(new LockableValue<>(false, "state")) - .city(new LockableValue<>(false, "city")) - .country(new LockableValue<>(false, "country")) - .organization(new LockableValue<>(false, "organization"))) - - - .keyPair( - new ServerPolicy.KeyPair(new LockableValue<>(false, "keyAlgo"), - new LockableValue<>(false, 1024), - null)))); - when(tpp.requestCertificate(any(TppConnector.CertificateRequestsPayload.class), eq(API_KEY))).thenReturn(new Tpp.CertificateRequestResponse().certificateDN("reqId")); - String zoneTag = "myZone"; - ZoneConfiguration zoneConfig = classUnderTest.readZoneConfiguration(classUnderTest.getPolicyDN(zoneTag)); - String cn = String.format("t%d-%s.venafi.xample.com", Instant.now().getEpochSecond(), RandomStringUtils.randomAlphabetic(4).toLowerCase()); - CertificateRequest request = new CertificateRequest() - .subject(new CertificateRequest.PKIXName() - .commonName(cn) - .organization(Collections.singletonList("Venafi, Inc.")) - .organizationalUnit(Collections.singletonList("Automated Tests")) - .locality(Collections.singletonList("Las Vegas")) - .province(Collections.singletonList("Nevada")) - .country(Collections.singletonList("US"))) - .friendlyName(cn) - .keyLength(512); - classUnderTest.generateRequest(zoneConfig, request); - logger.info("getPolicyDN(ZoneTag) = %s", classUnderTest.getPolicyDN(zoneTag)); - String requestId = classUnderTest.requestCertificate(request, classUnderTest.getPolicyDN(zoneTag)); - assertEquals("reqId", requestId); - } - - - @Test - @DisplayName("Renew Certificate with an empty request") - void renewCertificateWithEmptyRequest() throws VCertException { - final RenewalRequest renewalRequest = mock(RenewalRequest.class); - final Throwable throwable = assertThrows(VCertException.class, () -> classUnderTest.renewCertificate(renewalRequest)); - - assertThat(throwable.getMessage()).contains("CertificateDN or Thumbprint required"); - } - - @Test - @DisplayName("Renew Certificate with fingerprint not found") - void renewCertificateWithFingeprintNoSearchResults() throws VCertException { - final RenewalRequest renewalRequest = mock(RenewalRequest.class); - final Tpp.CertificateSearchResponse certificateSearchResponse = - mock(Tpp.CertificateSearchResponse.class); - - when(renewalRequest.thumbprint()).thenReturn("1111:1111:1111:1111"); - when(tpp.searchCertificates(any(), eq(API_KEY))).thenReturn(certificateSearchResponse); - - final Throwable throwable = assertThrows(VCertException.class, () -> classUnderTest.renewCertificate(renewalRequest)); - assertThat(throwable.getMessage()).contains("No certificate found using fingerprint"); - } - - @Test - @DisplayName("Renew Certificate multiple certificates for the fingerprint") - void renewCertificateWithFingerPrintMultipleCertificates() throws VCertException { - final RenewalRequest renewalRequest = mock(RenewalRequest.class); - final Tpp.CertificateSearchResponse certificateSearchResponse = - mock(Tpp.CertificateSearchResponse.class); - - when(renewalRequest.thumbprint()).thenReturn("1111:1111:1111:1111"); - when(tpp.searchCertificates(any(), eq(API_KEY))).thenReturn(certificateSearchResponse); - when(certificateSearchResponse.certificates()).thenReturn(Arrays.asList(new Tpp.Certificate(), new Tpp.Certificate())); - - final Throwable throwable = assertThrows(VCertException.class, () -> classUnderTest.renewCertificate(renewalRequest)); - assertThat(throwable.getMessage()).contains("More than one certificate was found"); - } - - @Test - @DisplayName("Renew Certificate with fingerprint") - void renewCertificateWithFingerPrint() throws VCertException { - final RenewalRequest renewalRequest = mock(RenewalRequest.class); - final Tpp.CertificateSearchResponse certificateSearchResponse = - mock(Tpp.CertificateSearchResponse.class); - final Tpp.Certificate certificate = mock(Tpp.Certificate.class); - final Tpp.CertificateRenewalResponse certificateRenewalResponse = - mock(Tpp.CertificateRenewalResponse.class); - - when(renewalRequest.thumbprint()).thenReturn("1111:1111:1111:1111"); - when(tpp.searchCertificates(any(), eq(API_KEY))).thenReturn(certificateSearchResponse); - when(certificateSearchResponse.certificates()).thenReturn(Arrays.asList(certificate)); - when(certificate.certificateRequestId()).thenReturn("test_certificate_requestid"); - when(tpp.renewCertificate(certificateRenewalRequestArgumentCaptor.capture(), any())) - .thenReturn(certificateRenewalResponse); - when(certificateRenewalResponse.success()).thenReturn(true); - - String result = classUnderTest.renewCertificate(renewalRequest); - assertThat(result).isEqualTo("test_certificate_requestid"); - } - - @Test - @DisplayName("Renew Certificate with DN") - void renewCertificateWithDN() throws VCertException { - final RenewalRequest renewalRequest = mock(RenewalRequest.class); - final Tpp.CertificateRenewalResponse certificateRenewalResponse = - mock(Tpp.CertificateRenewalResponse.class); - - when(renewalRequest.certificateDN()).thenReturn("certificateDN"); - when(tpp.renewCertificate(certificateRenewalRequestArgumentCaptor.capture(), any())) - .thenReturn(certificateRenewalResponse); - when(certificateRenewalResponse.success()).thenReturn(true); - - String result = classUnderTest.renewCertificate(renewalRequest); - assertThat(result).isEqualTo("certificateDN"); - } -} \ No newline at end of file + .organizationalUnit(new LockableValues(false, + Collections.singletonList("OU"))) + .state(new LockableValue<>(false, "state")) + .city(new LockableValue<>(false, "city")) + .country(new LockableValue<>(false, "country")) + .organization(new LockableValue<>(false, "organization"))) + + + .keyPair(new ServerPolicy.KeyPair(new LockableValue<>(false, "keyAlgo"), + new LockableValue<>(false, 1024), null)))); + when(tpp.requestCertificate(any(TppConnector.CertificateRequestsPayload.class), eq(API_KEY))) + .thenReturn(new Tpp.CertificateRequestResponse().certificateDN("reqId")); + String zoneTag = "myZone"; + ZoneConfiguration zoneConfig = + classUnderTest.readZoneConfiguration(classUnderTest.getPolicyDN(zoneTag)); + String cn = String.format("t%d-%s.venafi.xample.com", Instant.now().getEpochSecond(), + RandomStringUtils.randomAlphabetic(4).toLowerCase()); + CertificateRequest request = new CertificateRequest() + .subject(new CertificateRequest.PKIXName().commonName(cn) + .organization(Collections.singletonList("Venafi, Inc.")) + .organizationalUnit(Collections.singletonList("Automated Tests")) + .locality(Collections.singletonList("Las Vegas")) + .province(Collections.singletonList("Nevada")).country(Collections.singletonList("US"))) + .friendlyName(cn).keyLength(512); + classUnderTest.generateRequest(zoneConfig, request); + logger.info("getPolicyDN(ZoneTag) = %s", classUnderTest.getPolicyDN(zoneTag)); + String requestId = + classUnderTest.requestCertificate(request, classUnderTest.getPolicyDN(zoneTag)); + assertEquals("reqId", requestId); + } + + + @Test + @DisplayName("Renew Certificate with an empty request") + void renewCertificateWithEmptyRequest() throws VCertException { + final RenewalRequest renewalRequest = mock(RenewalRequest.class); + final Throwable throwable = + assertThrows(VCertException.class, () -> classUnderTest.renewCertificate(renewalRequest)); + + assertThat(throwable.getMessage()).contains("CertificateDN or Thumbprint required"); + } + + @Test + @DisplayName("Renew Certificate with fingerprint not found") + void renewCertificateWithFingeprintNoSearchResults() throws VCertException { + final RenewalRequest renewalRequest = mock(RenewalRequest.class); + final Tpp.CertificateSearchResponse certificateSearchResponse = + mock(Tpp.CertificateSearchResponse.class); + + when(renewalRequest.thumbprint()).thenReturn("1111:1111:1111:1111"); + when(tpp.searchCertificates(any(), eq(API_KEY))).thenReturn(certificateSearchResponse); + + final Throwable throwable = + assertThrows(VCertException.class, () -> classUnderTest.renewCertificate(renewalRequest)); + assertThat(throwable.getMessage()).contains("No certificate found using fingerprint"); + } + + @Test + @DisplayName("Renew Certificate multiple certificates for the fingerprint") + void renewCertificateWithFingerPrintMultipleCertificates() throws VCertException { + final RenewalRequest renewalRequest = mock(RenewalRequest.class); + final Tpp.CertificateSearchResponse certificateSearchResponse = + mock(Tpp.CertificateSearchResponse.class); + + when(renewalRequest.thumbprint()).thenReturn("1111:1111:1111:1111"); + when(tpp.searchCertificates(any(), eq(API_KEY))).thenReturn(certificateSearchResponse); + when(certificateSearchResponse.certificates()) + .thenReturn(Arrays.asList(new Tpp.Certificate(), new Tpp.Certificate())); + + final Throwable throwable = + assertThrows(VCertException.class, () -> classUnderTest.renewCertificate(renewalRequest)); + assertThat(throwable.getMessage()).contains("More than one certificate was found"); + } + + @Test + @DisplayName("Renew Certificate with fingerprint") + void renewCertificateWithFingerPrint() throws VCertException { + final RenewalRequest renewalRequest = mock(RenewalRequest.class); + final Tpp.CertificateSearchResponse certificateSearchResponse = + mock(Tpp.CertificateSearchResponse.class); + final Tpp.Certificate certificate = mock(Tpp.Certificate.class); + final Tpp.CertificateRenewalResponse certificateRenewalResponse = + mock(Tpp.CertificateRenewalResponse.class); + + when(renewalRequest.thumbprint()).thenReturn("1111:1111:1111:1111"); + when(tpp.searchCertificates(any(), eq(API_KEY))).thenReturn(certificateSearchResponse); + when(certificateSearchResponse.certificates()).thenReturn(Arrays.asList(certificate)); + when(certificate.certificateRequestId()).thenReturn("test_certificate_requestid"); + when(tpp.renewCertificate(certificateRenewalRequestArgumentCaptor.capture(), any())) + .thenReturn(certificateRenewalResponse); + when(certificateRenewalResponse.success()).thenReturn(true); + + String result = classUnderTest.renewCertificate(renewalRequest); + assertThat(result).isEqualTo("test_certificate_requestid"); + } + + @Test + @DisplayName("Renew Certificate with DN") + void renewCertificateWithDN() throws VCertException { + final RenewalRequest renewalRequest = mock(RenewalRequest.class); + final Tpp.CertificateRenewalResponse certificateRenewalResponse = + mock(Tpp.CertificateRenewalResponse.class); + + when(renewalRequest.certificateDN()).thenReturn("certificateDN"); + when(tpp.renewCertificate(certificateRenewalRequestArgumentCaptor.capture(), any())) + .thenReturn(certificateRenewalResponse); + when(certificateRenewalResponse.success()).thenReturn(true); + + String result = classUnderTest.renewCertificate(renewalRequest); + assertThat(result).isEqualTo("certificateDN"); + } +} diff --git a/src/test/java/com/venafi/vcert/sdk/connectors/tpp/ZoneConfigurationTest.java b/src/test/java/com/venafi/vcert/sdk/connectors/tpp/ZoneConfigurationTest.java index dba08ab..9afb417 100644 --- a/src/test/java/com/venafi/vcert/sdk/connectors/tpp/ZoneConfigurationTest.java +++ b/src/test/java/com/venafi/vcert/sdk/connectors/tpp/ZoneConfigurationTest.java @@ -1,111 +1,109 @@ package com.venafi.vcert.sdk.connectors.tpp; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import java.util.Arrays; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import com.venafi.vcert.sdk.VCertException; import com.venafi.vcert.sdk.certificate.CertificateRequest; import com.venafi.vcert.sdk.certificate.KeyType; import com.venafi.vcert.sdk.connectors.Policy; import com.venafi.vcert.sdk.endpoint.AllowedKeyConfiguration; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.util.Arrays; - -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; class ZoneConfigurationTest { - @Test - @DisplayName("Validate a policy match") - void validateCertificateRequest() throws VCertException { - final ZoneConfiguration zoneConfiguration = getBaseZoneConfiguration(); - - zoneConfiguration.validateCertificateRequest(getDefaultCertificateRequest()); - } - - @Test - @DisplayName("Expect CN not to match with a termination") - void invalidCNMatch() throws VCertException { - final ZoneConfiguration zoneConfiguration = getBaseZoneConfiguration(); - final CertificateRequest certificateRequest = getDefaultCertificateRequest(); - certificateRequest.subject().commonName("vcert.text.vfidev.com.example"); - - final Throwable exception = assertThrows(VCertException.class, - () -> zoneConfiguration.validateCertificateRequest(certificateRequest)); - - assertThat(exception.getMessage()).contains("CN does not match any of the allowed CN"); - } - - @Test - @DisplayName("Invalid match in the state province") - void invalidProvince() throws VCertException { - final ZoneConfiguration zoneConfiguration = getBaseZoneConfiguration(); - final CertificateRequest certificateRequest = getDefaultCertificateRequest(); - certificateRequest.subject().province(Arrays.asList("Test")); - - final Throwable exception = assertThrows(VCertException.class, - () -> zoneConfiguration.validateCertificateRequest(certificateRequest)); - - assertThat(exception.getMessage()).contains("does not match any of the allowed State/Province"); - } - - - @Test - @DisplayName("Key Policies should fail if do not match") - void invalidKeyPolices() throws VCertException { - final ZoneConfiguration zoneConfiguration = getBaseZoneConfiguration(); - final CertificateRequest certificateRequest = getDefaultCertificateRequest(); - certificateRequest.keyType(KeyType.ECDSA); - - final Throwable exception = assertThrows(VCertException.class, - () -> zoneConfiguration.validateCertificateRequest(certificateRequest)); - - assertThat(exception.getMessage()).contains("Key Type and Size do not match"); - } - - private CertificateRequest getDefaultCertificateRequest() { - final ZoneConfiguration zoneConfiguration = getBaseZoneConfiguration(); - final CertificateRequest request = new CertificateRequest(); - final CertificateRequest.PKIXName subject = new CertificateRequest.PKIXName(); - subject.commonName("vcert.text.vfidev.com"); - subject.organization(singletonList("Venafi, Inc.")); - subject.organizationalUnit(Arrays.asList("Engineering")); - subject.locality(singletonList("Las Vegas")); - subject.province(singletonList("Nevada")); - subject.country(singletonList("US")); - - request.subject(subject); - request.dnsNames(emptyList()); - return request; - } - - private ZoneConfiguration getBaseZoneConfiguration() { - final ZoneConfiguration defaultZoneConf = new ZoneConfiguration(); - final Policy policy = new Policy(); - final AllowedKeyConfiguration allowedKeyConfiguration = new AllowedKeyConfiguration(); - - defaultZoneConf.organization("Venafi"); - defaultZoneConf.organizationalUnit(Arrays.asList("Engineering", "Automated Test")); - defaultZoneConf.country("US"); - defaultZoneConf.province("Utah"); - defaultZoneConf.locality("SLC"); - - allowedKeyConfiguration.keyType(KeyType.RSA); - allowedKeyConfiguration.keySizes(singletonList(4096)); - - policy.allowedKeyConfigurations(Arrays.asList(allowedKeyConfiguration)); - policy.subjectCNRegexes(singletonList(".*vfidev.com")); - policy.subjectORegexes(singletonList("Venafi, Inc.")); - policy.subjectOURegexes(singletonList("Engineering")); - policy.subjectSTRegexes(singletonList("Nevada")); - policy.subjectLRegexes(singletonList("Las Vegas")); - policy.subjectCRegexes(singletonList("US")); - policy.dnsSanRegExs(singletonList(".*")); - - defaultZoneConf.policy(policy); - return defaultZoneConf; - } - -} \ No newline at end of file + @Test + @DisplayName("Validate a policy match") + void validateCertificateRequest() throws VCertException { + final ZoneConfiguration zoneConfiguration = getBaseZoneConfiguration(); + + zoneConfiguration.validateCertificateRequest(getDefaultCertificateRequest()); + } + + @Test + @DisplayName("Expect CN not to match with a termination") + void invalidCNMatch() throws VCertException { + final ZoneConfiguration zoneConfiguration = getBaseZoneConfiguration(); + final CertificateRequest certificateRequest = getDefaultCertificateRequest(); + certificateRequest.subject().commonName("vcert.text.vfidev.com.example"); + + final Throwable exception = assertThrows(VCertException.class, + () -> zoneConfiguration.validateCertificateRequest(certificateRequest)); + + assertThat(exception.getMessage()).contains("CN does not match any of the allowed CN"); + } + + @Test + @DisplayName("Invalid match in the state province") + void invalidProvince() throws VCertException { + final ZoneConfiguration zoneConfiguration = getBaseZoneConfiguration(); + final CertificateRequest certificateRequest = getDefaultCertificateRequest(); + certificateRequest.subject().province(Arrays.asList("Test")); + + final Throwable exception = assertThrows(VCertException.class, + () -> zoneConfiguration.validateCertificateRequest(certificateRequest)); + + assertThat(exception.getMessage()).contains("does not match any of the allowed State/Province"); + } + + + @Test + @DisplayName("Key Policies should fail if do not match") + void invalidKeyPolices() throws VCertException { + final ZoneConfiguration zoneConfiguration = getBaseZoneConfiguration(); + final CertificateRequest certificateRequest = getDefaultCertificateRequest(); + certificateRequest.keyType(KeyType.ECDSA); + + final Throwable exception = assertThrows(VCertException.class, + () -> zoneConfiguration.validateCertificateRequest(certificateRequest)); + + assertThat(exception.getMessage()).contains("Key Type and Size do not match"); + } + + private CertificateRequest getDefaultCertificateRequest() { + final ZoneConfiguration zoneConfiguration = getBaseZoneConfiguration(); + final CertificateRequest request = new CertificateRequest(); + final CertificateRequest.PKIXName subject = new CertificateRequest.PKIXName(); + subject.commonName("vcert.text.vfidev.com"); + subject.organization(singletonList("Venafi, Inc.")); + subject.organizationalUnit(Arrays.asList("Engineering")); + subject.locality(singletonList("Las Vegas")); + subject.province(singletonList("Nevada")); + subject.country(singletonList("US")); + + request.subject(subject); + request.dnsNames(emptyList()); + return request; + } + + private ZoneConfiguration getBaseZoneConfiguration() { + final ZoneConfiguration defaultZoneConf = new ZoneConfiguration(); + final Policy policy = new Policy(); + final AllowedKeyConfiguration allowedKeyConfiguration = new AllowedKeyConfiguration(); + + defaultZoneConf.organization("Venafi"); + defaultZoneConf.organizationalUnit(Arrays.asList("Engineering", "Automated Test")); + defaultZoneConf.country("US"); + defaultZoneConf.province("Utah"); + defaultZoneConf.locality("SLC"); + + allowedKeyConfiguration.keyType(KeyType.RSA); + allowedKeyConfiguration.keySizes(singletonList(4096)); + + policy.allowedKeyConfigurations(Arrays.asList(allowedKeyConfiguration)); + policy.subjectCNRegexes(singletonList(".*vfidev.com")); + policy.subjectORegexes(singletonList("Venafi, Inc.")); + policy.subjectOURegexes(singletonList("Engineering")); + policy.subjectSTRegexes(singletonList("Nevada")); + policy.subjectLRegexes(singletonList("Las Vegas")); + policy.subjectCRegexes(singletonList("US")); + policy.dnsSanRegExs(singletonList(".*")); + + defaultZoneConf.policy(policy); + return defaultZoneConf; + } + +}