All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.venafi.vcert.sdk.connectors.ZoneConfiguration Maven / Gradle / Ivy

Go to download

VCert is a Java library, SDK, designed to simplify key generation and enrollment of machine identities (also known as SSL/TLS certificates and keys) that comply with enterprise security policy by using the Venafi Platform or Venafi Cloud.

There is a newer version: 0.9.3
Show newest version
package com.venafi.vcert.sdk.connectors;

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;
import com.venafi.vcert.sdk.certificate.EllipticCurve;
import com.venafi.vcert.sdk.certificate.KeyType;
import com.venafi.vcert.sdk.endpoint.AllowedKeyConfiguration;
import com.venafi.vcert.sdk.utils.Is;

@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

  private String zoneId;
  private AllowedKeyConfiguration keyConfig;
  private String applicationId;
  private String certificateIssuingTemplateId;

  /**
   * UpdateCertificateRequest updates a certificate request based on the zone configuration
   * retrieved from the remote endpoint
   * 
   */
  public void applyCertificateRequestDefaultSettingsIfNeeded(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(keyConfig != null && keyConfig.keyType() != null ? keyConfig.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;

      default:
        if (request.keyLength() < KeyType.defaultRsaLength()) {
          request.keyLength(keyConfig != null && !Is.blank(keyConfig.keySizes())
              && keyConfig.keySizes().get(0) >= KeyType.defaultRsaLength() ? keyConfig.keySizes().get(0)
                  : KeyType.defaultRsaLength());
        }
        if (request.signatureAlgorithm() == SignatureAlgorithm.UnknownSignatureAlgorithm) {
          request.signatureAlgorithm(SignatureAlgorithm.SHA256WithRSA);
        }
        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;
            }
          }
        }
      }
    }
  }

  private static class Entity {
    private List target;
    private String source;

    private Entity() {

    }

    static Entity of(List target, String source) {
      Entity entity = new Entity();
      entity.target = target;
      entity.source = (source != null)? source : "";
      return entity;
    }

    List resolve() {
      //Adding  empty string validation. When Certificate Issuing Template uses .* as regex, it means any string is
      // valid, even empty or null strings
      return Is.blank(target)? Collections.singletonList(source) : target;
    }
  }

  public boolean validateCertificateRequest(CertificateRequest request) throws VCertException {
    if (!isComponentValid(policy.subjectCNRegexes(),
        Collections.singletonList(request.subject().commonName()), false)) {
      throw new VCertException(
          "The requested CN does not match any of the allowed CN regular expressions");
    }
    if (!isComponentValid(policy.subjectORegexes(), request.subject().organization(), false)) {
      throw new VCertException(
          "The requested Organization does not match any of the allowed Organization regular expressions");
    }
    if (!isComponentValid(policy.subjectOURegexes(), request.subject().organizationalUnit(), false)) {
      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(), false)) {
      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(), false)) {
      throw new VCertException(
          "The requested Locality does not match any of the allowed Locality regular expressions");
    }
    if (!isComponentValid(policy.subjectCRegexes(), request.subject().country(), false)) {
      throw new VCertException(
          "The requested Country does not match any of the allowed Country regular expressions");
    }
    if (!isComponentValid(policy.dnsSanRegExs(), request.dnsNames(), true)) {
      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, boolean optional) {
    if (regexes.isEmpty() || (optional && Is.blank(components))) {
      return true;
    }

    if (components != null) {
      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;
  }
}






© 2015 - 2024 Weber Informatics LLC | Privacy Policy