From ea468990763fa7ad0a6191750e9e912a65c05c14 Mon Sep 17 00:00:00 2001 From: Angel Moo <67758421+angelmoo@users.noreply.github.com> Date: Wed, 3 Feb 2021 18:16:47 -0600 Subject: [PATCH] Transition from DevOpsACCELERATE to OutagePREVENT (#19) * add changes for transition from DevOpsACCELERATE to OutagePREVENT * modifying cloud url * adding minor version for addressable on vcert --- lib/cloud/cloud.rb | 111 ++++++++++++++++++++++++++--------------- lib/objects/objects.rb | 3 +- lib/utils/utils.rb | 11 ++++ vcert.gemspec | 3 +- 4 files changed, 87 insertions(+), 41 deletions(-) diff --git a/lib/cloud/cloud.rb b/lib/cloud/cloud.rb index d91b1be..4bf6c82 100644 --- a/lib/cloud/cloud.rb +++ b/lib/cloud/cloud.rb @@ -1,12 +1,13 @@ require 'json' require 'utils/utils' +require 'addressable/uri' class Vcert::CloudConnection CLOUD_PREFIX = ''.freeze def initialize(url, apikey) @url = if url.nil? - 'https://api.venafi.cloud/v1'.freeze + 'https://api.venafi.cloud'.freeze else url end @@ -15,8 +16,12 @@ def initialize(url, apikey) def request(zone_tag, request) - zone_id = get_zoneId_by_tag(zone_tag) - _, data = post(URL_CERTIFICATE_REQUESTS, {:zoneId => zone_id, :certificateSigningRequest => request.csr}) + zone_config = zone_configuration(zone_tag) + _, data = post(URL_CERTIFICATE_REQUESTS, {:applicationId => zone_config.app_id, + :certificateIssuingTemplateId=>zone_config.cit_id, + :certificateSigningRequest => request.csr, + :apiClientInformation => getApiClientInformation + }) LOG.debug("Raw response to certificate request:") LOG.debug(JSON.pretty_generate(data)) request.id = data['certificateRequests'][0]["id"] @@ -34,7 +39,8 @@ def retrieve(request) when CERT_STATUS_FAILED raise Vcert::ServerUnexpectedBehaviorError, "Certificate issue status is FAILED" when CERT_STATUS_ISSUED - status, full_chain = get(URL_CERTIFICATE_RETRIEVE % request.id + "?chainOrder=#{CHAIN_OPTION_ROOT_LAST}&format=PEM") + cert_arr = data["certificateIds"] + status, full_chain = get(URL_CERTIFICATE_RETRIEVE % cert_arr[0] + "?chainOrder=#{CHAIN_OPTION_ROOT_LAST}&format=PEM") if status == 200 cert = parse_full_chain full_chain if cert.private_key == nil @@ -57,30 +63,38 @@ def renew(request, generate_new_key: true) raise Vcert::ClientBadDataError, "Either request ID or certificate thumbprint is required to renew the certificate" end if request.thumbprint != nil - manage_id = search_by_thumbprint(request.thumbprint) + cert_id, request_id = search_by_thumbprint(request.thumbprint) end if request.id != nil prev_request = get_cert_status(request) - manage_id = prev_request[:manage_id] + request_id = request.id zone = prev_request[:zoneId] end - if manage_id == nil - raise Vcert::VcertError, "Can't find the existing certificate" + if request_id == nil + raise Vcert::VcertError, "Can't find the existing certificate request id" end - status, data = get(URL_MANAGED_CERTIFICATE_BY_ID % manage_id) + status, data = get(URL_CERTIFICATE_STATUS % request_id) + if status == 200 - request.id = data['latestCertificateRequestId'] + request.id = data['id'] + cert_id = data['certificateIds'][0] else raise Vcert::ServerUnexpectedBehaviorError, "Status #{status}" end - if zone == nil + + if prev_request == nil prev_request = get_cert_status(request) - zone = prev_request[:zoneId] end - d = {existingManagedCertificateId: manage_id, zoneId: zone} + + d = {existingCertificateId: cert_id, + applicationId: data["applicationId"], + certificateIssuingTemplateId: data["certificateIssuingTemplateId"], + apiClientInformation: getApiClientInformation + + } if request.csr? d.merge!(certificateSigningRequest: request.csr) d.merge!(reuseCSR: false) @@ -96,7 +110,8 @@ def renew(request, generate_new_key: true) organizational_unit: parsed_csr[:OU]) d.merge!(certificateSigningRequest: renew_request.csr) else - d.merge!(reuseCSR: true) + raise Vcert::VcertError, "This operation is not yet supported" + #d.merge!(reuseCSR: true) end status, data = post(URL_CERTIFICATE_REQUESTS, data = d) @@ -118,9 +133,23 @@ def zone_configuration(tag) raise Vcert::ClientBadDataError, "Zone should not be empty" end LOG.info("Getting configuration for zone #{tag}") - _, data = get(URL_ZONE_BY_TAG % tag) - template_id = data['certificateIssuingTemplateId'] - _, data = get(URL_TEMPLATE_BY_ID % template_id) + arr = tag.split("\\", 2) + + app_name = arr[0] + cit_alias = arr[1] + + if app_name.to_s.strip.empty? || cit_alias.to_s.strip.empty? + raise Vcert::ClientBadDataError, "The parameters: app_name, cit_alias or both are empty" + end + app_name = Addressable::URI.encode_component(app_name, Addressable::URI::CharacterClasses::QUERY) + cit_alias = Addressable::URI.encode_component(cit_alias, Addressable::URI::CharacterClasses::QUERY) + + #get cit + _, data = get(URL_CIT_BY_APP_NAME_CIT_ALIAS % [app_name, cit_alias]) + + #get app info + _, app = get(URL_APPLICATION_BY_NAME % app_name) + kt = Vcert::KeyType.new data['keyTypes'][0]["keyType"], data['keyTypes'][0]["keyLengths"][0].to_i z = Vcert::ZoneConfiguration.new( country: Vcert::CertField.new(""), @@ -130,6 +159,9 @@ def zone_configuration(tag) organizational_unit: Vcert::CertField.new(""), key_type: Vcert::CertField.new(kt, locked: true), ) + z.app_id = app["id"] + z.cit_id = data["id"] + return z end @@ -137,14 +169,21 @@ def policy(zone_id) unless zone_id raise Vcert::ClientBadDataError, "Zone should be not nil" end - status, data = get(URL_PROJECT_ZONE_DETAILS % zone_id) - if status != 200 - raise Vcert::ServerUnexpectedBehaviorError, "Invalid status getting issuing template: %s for zone %s" % status, zone_id + arr = zone_id.split("\\", 2) + + app_name = arr[0] + cit_alias = arr[1] + + if app_name.to_s.strip.empty? || cit_alias.to_s.strip.empty? + raise Vcert::ClientBadDataError, "The parameters: app_name, cit_alias or both are empty" end - template_id = data['certificateIssuingTemplateId'] - status, data = get(URL_TEMPLATE_BY_ID % template_id) + + app_name = Addressable::URI.encode_component(app_name, Addressable::URI::CharacterClasses::QUERY) + cit_alias = Addressable::URI.encode_component(cit_alias, Addressable::URI::CharacterClasses::QUERY) + status, data = get(URL_CIT_BY_APP_NAME_CIT_ALIAS % [app_name, cit_alias]) + puts data if status != 200 - raise Vcert::ServerUnexpectedBehaviorError, "Invalid status getting policy: %s for issuing template %s" % status, template_id + raise Vcert::ServerUnexpectedBehaviorError, "Invalid status getting issuing template: %s for zone %s" % status, zone_id end parse_policy_responce_to_object(data) end @@ -158,20 +197,13 @@ def policy(zone_id) CERT_STATUS_PENDING = 'PENDING' CERT_STATUS_FAILED = 'FAILED' CERT_STATUS_ISSUED = 'ISSUED' - URL_ZONE_BY_TAG = "zones/tag/%s" - URL_PROJECT_ZONE_DETAILS = "projectzones/%s" - URL_TEMPLATE_BY_ID = "certificateissuingtemplates/%s" - URL_CERTIFICATE_REQUESTS = "certificaterequests" + URL_CIT_BY_APP_NAME_CIT_ALIAS = "outagedetection/v1/applications/%s/certificateissuingtemplates/%s" + URL_APPLICATION_BY_NAME = "outagedetection/v1/applications/name/%s" + URL_CERTIFICATE_REQUESTS = "outagedetection/v1/certificaterequests" URL_CERTIFICATE_STATUS = URL_CERTIFICATE_REQUESTS + "/%s" - URL_CERTIFICATE_RETRIEVE = URL_CERTIFICATE_REQUESTS + "/%s/certificate" - URL_CERTIFICATE_SEARCH = "certificatesearch" - URL_MANAGED_CERTIFICATES = "managedcertificates" - URL_MANAGED_CERTIFICATE_BY_ID = URL_MANAGED_CERTIFICATES + "/%s" - - def get_zoneId_by_tag(tag) - _, data = get(URL_ZONE_BY_TAG % tag) - data['id'] - end + URL_CERTIFICATE_RETRIEVE = "outagedetection/v1/certificates/%s/contents" + URL_CERTIFICATE_SEARCH = "outagedetection/v1/certificatesearch" + def get(url) uri = URI.parse(@url) @@ -262,9 +294,10 @@ def search_by_thumbprint(thumbprint) raise Vcert::ServerUnexpectedBehaviorError, "Status: #{status}. Message: #{data.body.to_s}" end # TODO: check data - manageId = data['certificates'][0]['managedCertificateId'] - LOG.info("Found existing certificate with ID #{manageId}") - return manageId + certId = data['certificates'][0]['id'] + certReqId = data['certificates'][0]['certificateRequestId'] + LOG.info("Found existing certificate with ID #{certId}") + return certId, certReqId end def get_cert_status(request) diff --git a/lib/objects/objects.rb b/lib/objects/objects.rb index 1c7696c..8a65195 100644 --- a/lib/objects/objects.rb +++ b/lib/objects/objects.rb @@ -300,7 +300,8 @@ def match_regexps?(s, regexps) end class ZoneConfiguration - attr_reader :country, :province, :locality, :organization, :organizational_unit, :key_type + attr_reader :country, :province, :locality, :organization, :organizational_unit, :key_type, :app_id, :cit_id; + attr_accessor :app_id, :cit_id # @param [CertField] country # @param [CertField] province diff --git a/lib/utils/utils.rb b/lib/utils/utils.rb index 439827d..17b1154 100644 --- a/lib/utils/utils.rb +++ b/lib/utils/utils.rb @@ -1,3 +1,5 @@ +require 'socket' + def parse_pem_list(multiline) pems = [] buf = "" @@ -144,3 +146,12 @@ def initialize (access_token, expires, identity, refresh_token, refresh_until, s end end +def getApiClientInformation() + ip = Socket.ip_address_list.detect{|intf| intf.ipv4_private?} + ip_addres = ip.ip_address + data = { + type: CLIENT_ID, + identifier: ip_addres + } + return data +end \ No newline at end of file diff --git a/vcert.gemspec b/vcert.gemspec index e2e72d6..6987e9f 100644 --- a/vcert.gemspec +++ b/vcert.gemspec @@ -10,4 +10,5 @@ Gem::Specification.new do |s| s.homepage = 'https://rubygems.org/gems/vcert' s.license = 'Apache-2.0' -end + s.add_runtime_dependency 'addressable', '~> 2.7', '>= 2.7.0' +end \ No newline at end of file