summaryrefslogtreecommitdiffstats
path: root/lib/puppet/ssl/host.rb
blob: 0e65d30b16cc6197cfbdd178bcb1382702db3673 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
require 'puppet/ssl'
require 'puppet/ssl/key'
require 'puppet/ssl/certificate'
require 'puppet/ssl/certificate_request'
require 'puppet/util/constant_inflector'

# The class that manages all aspects of our SSL certificates --
# private keys, public keys, requests, etc.
class Puppet::SSL::Host
    # Yay, ruby's strange constant lookups.
    Key = Puppet::SSL::Key
    CertificateRequest = Puppet::SSL::CertificateRequest
    Certificate = Puppet::SSL::Certificate

    extend Puppet::Util::ConstantInflector

    attr_reader :name
    attr_accessor :ca

    # A bit of metaprogramming that we use to define all of
    # the methods for managing our ssl-related files.
    def self.manage_file(name, &block)
        var = "@%s" % name

        maker = "generate_%s" % name
        reader = "read_%s" % name

        classname = file2constant(name.to_s)

        begin
            klass = const_get(classname)
        rescue
            raise Puppet::DevError, "Cannot map %s to a valid constant" % name
        end

        # Define the method that creates it.
        define_method(maker, &block)

        # Define the reading method.
        define_method(reader) do
            klass.find(self.name)
        end

        # Define the overall method, which just calls the reader and maker
        # as appropriate.
        define_method(name) do
            unless cert = instance_variable_get(var)
                return nil unless cert = send(reader)
                instance_variable_set(var, cert)
            end
            cert.content
        end
    end

    # This is the private key; we can create it from scratch
    # with no inputs.
    manage_file :key do
        @key = Key.new(name)
        @key.generate
        @key.save :in => :file
        true
    end

    # Our certificate request requires the key but that's all.
    manage_file :certificate_request do
        generate_key unless key
        @certificate_request = CertificateRequest.new(name)
        @certificate_request.generate(key)
        @certificate_request.save :in => :file
        return true
    end

    # Our certificate itself might not successfully "generate", since
    # that generation is actually accomplished by a CA signing the
    # stored CSR.
    manage_file :certificate do
        generate_certificate_request unless certificate_request

        @certificate = Certificate.new(name)
        if @certificate.generate(certificate_request)
            @certificate.save :in => :file
            return true
        else
            return false
        end
    end

    # Is this a ca host, meaning that all of its files go in the CA collections?
    def ca?
        ca
    end

    # Remove all traces of this ssl host
    def destroy
        [key, certificate, certificate_request].each do |instance|
            instance.class.destroy(instance) if instance
        end
    end

    def initialize(name)
        @name = name
        @key = @certificate = @certificate_request = nil
        @ca = false
    end

    # Extract the public key from the private key.
    def public_key
        key.public_key
    end

    # Try to get our signed certificate.
    def retrieve_signed_certificate(source = :ca_file)
        if cert = Puppet::SSL::Certificate.find(name, :in => source)
            @certificate = cert
            @certificate.save :in => :file
            return true
        else
            return false
        end
    end

    # Send our CSR to the server, defaulting to the
    # local CA.
    def send_certificate_request(dest = :ca_file)
        raise ArgumentError, "Must generate CSR before sending to server" unless certificate_request

        @certificate_request.save :in => dest
    end
end