Skip to content

Commit

Permalink
Merge pull request #193 from cyberark/170-improve-unit-tests
Browse files Browse the repository at this point in the history
170 improve unit tests
  • Loading branch information
sgnn7 authored Aug 24, 2020
2 parents 6bbb7aa + 1927bd2 commit 75094e8
Show file tree
Hide file tree
Showing 15 changed files with 663 additions and 485 deletions.
56 changes: 0 additions & 56 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

### Functions

* [`conjur::client`](#conjurclient): This function is a representation of a Conjur / DAP client with majority of the functionality that allows us to authenticate against a server
* [`conjur::secret`](#conjursecret): Function to retrieve a Conjur / DAP secret

## Resource types
Expand Down Expand Up @@ -54,61 +53,6 @@ Conjur / DAP URL

## Functions

### `conjur::client`

Type: Ruby 4.x API

This function is a representation of a Conjur / DAP client with majority
of the functionality that allows us to authenticate against a server.

#### `conjur::client(String $uri, Integer $version, String $cert)`

The conjur::client function.

Returns: `Class` Conjur client instance

##### `uri`

Data type: `String`

The URL of the Conjur or DAP instance.

##### `version`

Data type: `Integer`

Conjur API version.

##### `cert`

Data type: `String`

The _raw_ PEM-encoded x509 CA certificate chain for the DAP instance

#### `conjur::client(String $uri, Integer $version, Optional[Undef] $cert)`

The conjur::client function.

Returns: `Class` Conjur client instance

##### `uri`

Data type: `String`

The URL of the Conjur or DAP instance.

##### `version`

Data type: `Integer`

Conjur API version.

##### `cert`

Data type: `Optional[Undef]`

The _raw_ PEM-encoded x509 CA certificate chain for the DAP instance

### `conjur::secret`

Type: Ruby 4.x API
Expand Down
55 changes: 55 additions & 0 deletions lib/conjur/puppet_module/http.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

require 'conjur/puppet_module/ssl'

module Conjur
module PuppetModule
# This module is in charge of interacting with the Conjur endpoints
module HTTP
class << self
def directory_uri(url)
url += '/' unless url.end_with? '/'
URI url
end

def get(host_url, path, ssl_certificate, token)
uri = directory_uri(host_url) + path
use_ssl = uri.scheme == 'https'
certs = Conjur::PuppetModule::SSL.load(ssl_certificate)

headers = {}
if token
encoded_token = Base64.urlsafe_encode64(token)
headers['Authorization'] = "Token token=\"#{encoded_token}\""
end

Net::HTTP.start uri.host, uri.port, use_ssl: use_ssl, cert_store: certs do |http|
response = http.get(uri.request_uri, headers)

raise Net::HTTPError.new response.message, response unless response.code.match?(%r{^2})

response.body
end
end

def post(host_url, path, ssl_certificate, data)
uri = directory_uri(host_url) + path

raise(ArgumentError, "POST data to #{uri} must not be empty!") \
if data.nil? || data.empty?

use_ssl = uri.scheme == 'https'
certs = Conjur::PuppetModule::SSL.load(ssl_certificate)

Net::HTTP.start uri.host, uri.port, use_ssl: use_ssl, cert_store: certs do |http|
response = http.post(uri.request_uri, data)

raise Net::HTTPError.new response.message, response unless response.code.match?(%r{^2})

response.body
end
end
end
end
end
end
37 changes: 37 additions & 0 deletions lib/conjur/puppet_module/ssl.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

module Conjur
module PuppetModule
# This module is a bundle of helper methods for handling the SSL and certificate
# logic
module SSL
class << self
def load(ssl_certificate)
if ssl_certificate.nil? || ssl_certificate.empty?
Puppet.warning('No Conjur SSL certificate - YOU ARE VULNERABLE TO MITM ATTACKS!')
return []
end

cert_store = OpenSSL::X509::Store.new
parsed_certs = parse_certs(ssl_certificate)

Puppet.info("Parsed #{parsed_certs.length} certificate(s) from SSL cert chain")

parsed_certs.each do |x509_cert|
cert_store.add_cert x509_cert
end

cert_store
end

def parse_certs(certs)
cert_header = '-----BEGIN CERTIFICATE-----'
cert_footer = '-----END CERTIFICATE-----'
cert_re = %r{#{cert_header}\r?\n.*?\r?\n#{cert_footer}}m

certs.scan(cert_re).map(&OpenSSL::X509::Certificate.method(:new))
end
end
end
end
end
121 changes: 0 additions & 121 deletions lib/puppet/functions/conjur/client.rb

This file was deleted.

63 changes: 27 additions & 36 deletions lib/puppet/functions/conjur/secret.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'conjur/puppet_module/config'
require 'conjur/puppet_module/http'
require 'conjur/puppet_module/identity'

# Function to retrieve a Conjur / DAP secret
Expand Down Expand Up @@ -38,44 +39,36 @@
return_type 'Sensitive'
end

def find_certs(certs)
cert_header = '-----BEGIN CERTIFICATE-----'
cert_footer = '-----END CERTIFICATE-----'
cert_re = %r{#{cert_header}\r?\n.*?\r?\n#{cert_footer}}m

certs.scan(cert_re).map(&OpenSSL::X509::Certificate.method(:new))
end

def cert_store(certs)
certs && OpenSSL::X509::Store.new.tap do |store|
find_certs(certs).each(&store.method(:add_cert))
end
end

def authentication_path(account, login)
['authn', account, login, 'authenticate']
.map(&URI.method(:encode_www_form_component)).join('/')
end

def directory_uri(url)
url += '/' unless url.end_with? '/'
URI url
end

# Authenticates against a Conjur / DAP server returning the API token
def authenticate(url, account, authn_login, authn_api_key, ssl_certificate)
uri = directory_uri(url) + authentication_path(account, authn_login)
use_ssl = uri.scheme == 'https'

Net::HTTP.start uri.host, uri.port, use_ssl: use_ssl, cert_store: cert_store(ssl_certificate) do |http|
response = http.post uri.request_uri, authn_api_key.unwrap
raise Net::HTTPError.new response.message, response unless response.code.match?(%r{^2})
response.body
end
def authenticate(url, ssl_certificate, account, authn_login, authn_api_key)
Conjur::PuppetModule::HTTP.post(
url,
authentication_path(account, authn_login),
ssl_certificate,
authn_api_key.unwrap,
)
end

def get_token(appliance_url, account, authn_login, authn_api_key, ssl_certificate)
authenticate(appliance_url, account, authn_login, authn_api_key, ssl_certificate)
# Fetches a variable from Conjur / DAP
def get_variable(url, ssl_certificate, account, variable_id, token)
secrets_path = [
'secrets',
URI.encode_www_form_component(account),
'variable',
ERB::Util.url_encode(variable_id),
].join('/')

Conjur::PuppetModule::HTTP.get(
url,
secrets_path,
ssl_certificate,
token,
)
end

def with_credentials(id, options = {})
Expand Down Expand Up @@ -106,16 +99,14 @@ def with_credentials(id, options = {})
# Ideally we would be able to support `cert_file` here too

Puppet.debug('Instantiating Conjur client...')
client = call_function('conjur::client', opts['appliance_url'], opts['version'],
opts['ssl_certificate'])

Puppet.debug('Fetching Conjur token')
token = get_token(opts['appliance_url'], opts['account'], opts['authn_login'],
opts['authn_api_key'], opts['ssl_certificate'])
token = authenticate(opts['appliance_url'], opts['ssl_certificate'], opts['account'],
opts['authn_login'], opts['authn_api_key'])
Puppet.info('Conjur token retrieved')

Puppet.debug("Fetching Conjur secret '#{id}'...")
secret = client.variable_value(opts['account'], id, token)
secret = get_variable(opts['appliance_url'], opts['ssl_certificate'], opts['account'],
id, token)
Puppet.info("Conjur secret #{id} retrieved")

Puppet::Pops::Types::PSensitiveType::Sensitive.new(secret)
Expand Down
Loading

0 comments on commit 75094e8

Please sign in to comment.