Skip to content
Permalink
main
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
require_relative '../../puppet/trusted_external'
# @api private
class Puppet::Context::TrustedInformation
# one of 'remote', 'local', or false, where 'remote' is authenticated via cert,
# 'local' is trusted by virtue of running on the same machine (not a remote
# request), and false is an unauthenticated remote request.
#
# @return [String, Boolean]
attr_reader :authenticated
# The validated certificate name used for the request
#
# @return [String]
attr_reader :certname
# Extra information that comes from the trusted certificate's extensions.
#
# @return [Hash{Object => Object}]
attr_reader :extensions
# The domain name derived from the validated certificate name
#
# @return [String]
attr_reader :domain
# The hostname derived from the validated certificate name
#
# @return [String]
attr_reader :hostname
def initialize(authenticated, certname, extensions, external = {})
@authenticated = authenticated.freeze
@certname = certname.freeze
@extensions = extensions.freeze
if @certname
hostname, domain = @certname.split('.', 2)
else
hostname = nil
domain = nil
end
@hostname = hostname.freeze
@domain = domain.freeze
@external = external.is_a?(Proc) ? external : external.freeze
end
def self.remote(authenticated, node_name, certificate)
external = proc { retrieve_trusted_external(node_name) }
if authenticated
extensions = {}
if certificate.nil?
Puppet.info(_('TrustedInformation expected a certificate, but none was given.'))
else
extensions = Hash[certificate.custom_extensions.collect do |ext|
[ext['oid'].freeze, ext['value'].freeze]
end]
end
new('remote', node_name, extensions, external)
else
new(false, nil, {}, external)
end
end
def self.local(node)
# Always trust local data by picking up the available parameters.
client_cert = node ? node.parameters['clientcert'] : nil
external = proc { retrieve_trusted_external(client_cert) }
new('local', client_cert, {}, external)
end
# Additional external facts loaded through `trusted_external_command`.
#
# @return [Hash]
def external
if @external.is_a?(Proc)
@external = @external.call.freeze
end
@external
end
def self.retrieve_trusted_external(certname)
deep_freeze(Puppet::TrustedExternal.retrieve(certname) || {})
end
private_class_method :retrieve_trusted_external
# Deeply freezes the given object. The object and its content must be of the types:
# Array, Hash, Numeric, Boolean, Regexp, NilClass, or String. All other types raises an Error.
# (i.e. if they are assignable to Puppet::Pops::Types::Data type).
def self.deep_freeze(object)
case object
when Array
object.each {|v| deep_freeze(v) }
object.freeze
when Hash
object.each {|k, v| deep_freeze(k); deep_freeze(v) }
object.freeze
when NilClass, Numeric, TrueClass, FalseClass
# do nothing
when String
object.freeze
else
raise Puppet::Error, _("Unsupported data type: '%{klass}'") % { klass: object.class }
end
object
end
private_class_method :deep_freeze
def to_h
{
'authenticated'.freeze => authenticated,
'certname'.freeze => certname,
'extensions'.freeze => extensions,
'hostname'.freeze => hostname,
'domain'.freeze => domain,
'external'.freeze => external,
}.freeze
end
end