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
130
131
132
133
134
|
# This class is basically a hidden class that knows how to act
# on the CA. It's only used by the 'puppetca' executable, and its
# job is to provide a CLI-like interface to the CA class.
module Puppet
module SSL
class CertificateAuthority
class Interface
INTERFACE_METHODS = [:destroy, :list, :revoke, :generate, :sign, :print, :verify, :fingerprint]
class InterfaceError < ArgumentError; end
attr_reader :method, :subjects, :digest
# Actually perform the work.
def apply(ca)
unless subjects or method == :list
raise ArgumentError, "You must provide hosts or :all when using #{method}"
end
begin
return send(method, ca) if respond_to?(method)
(subjects == :all ? ca.list : subjects).each do |host|
ca.send(method, host)
end
rescue InterfaceError
raise
rescue => detail
puts detail.backtrace if Puppet[:trace]
Puppet.err "Could not call #{method}: #{detail}"
end
end
def generate(ca)
raise InterfaceError, "It makes no sense to generate all hosts; you must specify a list" if subjects == :all
subjects.each do |host|
ca.generate(host)
end
end
def initialize(method, options)
self.method = method
self.subjects = options[:to]
@digest = options[:digest] || :MD5
end
# List the hosts.
def list(ca)
unless subjects
puts ca.waiting?.join("\n")
return nil
end
signed = ca.list
requests = ca.waiting?
if subjects == :all
hosts = [signed, requests].flatten
elsif subjects == :signed
hosts = signed.flatten
else
hosts = subjects
end
hosts.uniq.sort.each do |host|
invalid = false
begin
ca.verify(host) unless requests.include?(host)
rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => details
invalid = details.to_s
end
if not invalid and signed.include?(host)
puts "+ #{host} (#{ca.fingerprint(host, @digest)})"
elsif invalid
puts "- #{host} (#{ca.fingerprint(host, @digest)}) (#{invalid})"
else
puts "#{host} (#{ca.fingerprint(host, @digest)})"
end
end
end
# Set the method to apply.
def method=(method)
raise ArgumentError, "Invalid method #{method} to apply" unless INTERFACE_METHODS.include?(method)
@method = method
end
# Print certificate information.
def print(ca)
(subjects == :all ? ca.list : subjects).each do |host|
if value = ca.print(host)
puts value
else
Puppet.err "Could not find certificate for #{host}"
end
end
end
# Print certificate information.
def fingerprint(ca)
(subjects == :all ? ca.list + ca.waiting?: subjects).each do |host|
if value = ca.fingerprint(host, @digest)
puts "#{host} #{value}"
else
Puppet.err "Could not find certificate for #{host}"
end
end
end
# Sign a given certificate.
def sign(ca)
list = subjects == :all ? ca.waiting? : subjects
raise InterfaceError, "No waiting certificate requests to sign" if list.empty?
list.each do |host|
ca.sign(host)
end
end
# Set the list of hosts we're operating on. Also supports keywords.
def subjects=(value)
unless value == :all or value == :signed or value.is_a?(Array)
raise ArgumentError, "Subjects must be an array or :all; not #{value}"
end
value = nil if value.is_a?(Array) and value.empty?
@subjects = value
end
end
end
end
end
|