class Conjur::Configuration

Stores a configuration for the Conjur API client. This class provides global and *thread local* storage for common options used by the Conjur API. Most importantly, it specifies the

* REST endpoints, derived from the {Conjur::Configuration#appliance_url} and {Conjur::Configuration#account} options
* The certificate used for secure connections to the Conjur appliance ({Conjur::Configuration#cert_file})

### Environment Variables

Option values used by Conjur can be given by environment variables, using a standard naming scheme. Specifically, an environment variable named ‘CONJUR_ACCOUNT` will be used to provide a default value for the {Conjur::Configuration#account} option.

### Required Options

The {Conjur::Configuration#account} and {Conjur::Configuration#appliance_url} are always required. Except in special cases, the {Conjur::Configuration#cert_file} is also required, but you may omit it if your Conjur root certificate is in the OpenSSl default certificate store.

### Thread Local Configuration

While using a globally available configuration is convenient for most applications, sometimes you will need to use different configurations in different threads. This is supported by returning a thread local version from {Conjur.configuration} if one has been set by {Conjur.with_configuration}.

@see Conjur.configuration @see Conjur.configure @see Conjur.with_configuration

@example Basic Configuration

Conjur.configure do |c|
  c.account = 'the-account'
  c.cert_file = find_conjur_cert_file
end

@example Setting the appliance_url from an environment variable

ENV['CONJUR_APPLIANCE_URL'] = 'https://some-host.com/api'
Conjur::Configuration.new.appliance_url # => 'https://some-host.com/api'

@example Using thread local configuration in a web application request handler

# Assume that we're in a request handler thread in a multithreaded web server.

requested_appliance_url = request.header 'X-Conjur-Appliance-Url'

with_configuration Conjur.config.clone(appliance_url: requested_appliance_url) do
  # `api` is an instance attribute.  Note that we can use an api that was created
  # before we modified the thread local configuration.

  # 404 if the user doesn't exist

  user = api.user request.header('X-Conjur-Login')
  raise HttpError, 404, "User #{user.login} does not exist" unless user.exists?
  # ... finish the request
end

Attributes

computed[R]

@api private

explicit[R]

@api private

supplied[R]

@api private

Public Class Methods

accepted_options() click to toggle source

@api private

# File lib/conjur/configuration.rb, line 196
def accepted_options
  require 'set'
  @options ||= Set.new
end
add_option(name, options = {}) click to toggle source

@param [Symbol] name @param [Hash] options @option options [Boolean] :boolean (false) whether this option should have a ‘?’ accessor @option options [Boolean, String] :env Environment variable for this option. Set to false

to disallow environment based configuration.  Default is CONJUR_<OPTION_NAME>.

@option options [Proc, *] :default Default value or proc to provide it @option options [Boolean] :required (false) when true, raise an exception if the option is

not set

@option options [Proc, to_proc] :convert proc-ish to convert environment

values to appropriate types

@param [Proc] def_proc block to provide default values @api private

# File lib/conjur/configuration.rb, line 213
def add_option name, options = {}, &def_proc
  accepted_options << name
  allow_env = options[:env].nil? || options[:env]
  env_var = options[:env] || "CONJUR_#{name.to_s.upcase}"
  def_val = options[:default]
  opt_name = name

  def_proc ||= if def_val.respond_to?(:call)
    def_val
  elsif options[:required]
    proc { raise "Missing required option #{opt_name}" }
  else
    proc { def_val }
  end

  convert = options[:convert] || ->(x){ x }
  # Allow a Symbol, for example
  convert = convert.to_proc if convert.respond_to?(:to_proc)

  define_method("#{name}=") do |value|
    set name, value
  end

  define_method("#{name}_env_var") do
    allow_env ? env_var : nil
  end

  define_method(name) do
    value = computed[name]
    return value unless value.nil?

    if supplied.member?(name)
      supplied[name]
    elsif allow_env && ENV.member?(env_var)
      instance_exec(ENV[env_var], &convert)
    else
      instance_eval(&def_proc)
    end.tap do |value|
      computed[name] = value
    end
  end

  alias_method("#{name}?", name) if options[:boolean]
end
new(options = {}) click to toggle source

Create a new {Conjur::Configuration}, setting initial values from ‘options`.

@note ‘options` must use symbols for keys.

@example

Conjur.config = Conjur::Configuration.new account: 'companyname'
Conjur.config.account # => 'companyname'

@param [Hash] options hash of options to set on the new instance.

# File lib/conjur/configuration.rb, line 188
def initialize options = {}
  @explicit = options.dup
  @supplied = options.dup
  @computed = Hash.new
end

Public Instance Methods

apply_cert_config!(store=OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE) click to toggle source

Add the certificate configured by the {#ssl_certificate} and {#cert_file} options to the certificate store used by Conjur clients.

NOTE: If you specify a non-default ‘store` value, you must manually set the `ssl_cert_store` value on {#rest_client_options} to the same value.

@param [OpenSSL::X509::Store] store the certificate store that the certificate will be installed in. @return [Boolean] whether a certificate was added to the store.

# File lib/conjur/configuration.rb, line 431
def apply_cert_config! store=OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE
  if ssl_certificate
    CertUtils.add_chained_cert(store, ssl_certificate)
  elsif cert_file
    ensure_cert_readable!(cert_file)
    store.add_file cert_file
  else
    return false
  end
  true
end
clone(override_options = {}) click to toggle source

Return a copy of this {Conjur::Configuration} instance, optionally updating the copy with options from the ‘override_options` hash.

@example

original = Conjur.configuration
original.account  # => 'conjur'
copy = original.clone account: 'some-other-account'
copy.account    # => 'some-other-account'
original.account # => 'conjur'

@param [Hash] override_options options to set on the new instance @return [Conjur::Configuration] a copy of this configuration

# File lib/conjur/configuration.rb, line 271
def clone override_options = {}
  self.class.new self.explicit.dup.merge(override_options)
end
create_rest_client_options(options) click to toggle source

Create rest_client_options by merging the input with the rest_client_options present on the configuration object.

# File lib/conjur/configuration.rb, line 407
def create_rest_client_options options
  rest_client_options.merge(options || {})
end
set(key, value) click to toggle source

Manually set an option. Note that setting an option not present in {Conjur::Configuration.accepted_options} is a no op. @api private @param [Symbol, String] key the name of the option to set @param [Object] value the option value.

# File lib/conjur/configuration.rb, line 280
def set(key, value)
  if self.class.accepted_options.include?(key.to_sym)
    explicit[key.to_sym] = value
    supplied[key.to_sym] = value
    computed.clear
  end
end
version_logic(v4_logic, v5_logic) click to toggle source

Calls a major-version-specific function.

# File lib/conjur/configuration.rb, line 412
def version_logic v4_logic, v5_logic
  case version.to_s
  when "4"
    v4_logic.call
  when "5"
    v5_logic.call
  else
    raise "Unsupported major version #{version}"
  end
end

Private Instance Methods

ensure_cert_readable!(path) click to toggle source
# File lib/conjur/configuration.rb, line 453
def ensure_cert_readable!(path)
  # Try to open the file to make sure it exists and that it's
  # readable. Don't rescue exceptions from it, just let them
  # propagate.
  File.open(path) {}
end
global_service_url(service_port_offset, service_name: nil) click to toggle source
# File lib/conjur/configuration.rb, line 445
def global_service_url service_port_offset, service_name: nil
  if appliance_url
    URI.join([appliance_url, service_name].compact.join('/')).to_s
  else
    "http://localhost:#{service_base_port + service_port_offset}"
  end
end