Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.0.0 #17

Merged
merged 9 commits into from Feb 13, 2013
2 changes: 1 addition & 1 deletion Modulefile
@@ -1,5 +1,5 @@
name 'puppetlabs-java_ks'
version '0.0.6'
version '1.0.0'
source 'https://github.com/puppetlabs/puppetlabs-java_ks.git'
author 'puppetlabs'
license 'ASL 2.0'
Expand Down
97 changes: 54 additions & 43 deletions lib/puppet/provider/java_ks/keytool.rb
Expand Up @@ -20,13 +20,21 @@ def to_pkcs12
tmpfile = Tempfile.new("#{@resource[:name]}.")
tmpfile.write(@resource[:password])
tmpfile.flush
output = Puppet::Util.execute(
cmd,
:stdinfile => tmpfile.path,
:failonfail => true,
:combine => true
)

# To maintain backwards compatibility with Puppet 2.7.x, resort to ugly
# code to make sure RANDFILE is passed as an environment variable to the
# openssl command but not retained in the Puppet process environment.
randfile = Tempfile.new("#{@resource[:name]}.")
if Puppet::Util::Execution.respond_to?(:withenv)
withenv = Puppet::Util::Execution.method(:withenv)
else
withenv = Puppet::Util.method(:withenv)
end
output = withenv.call('RANDFILE' => randfile.path) do
run_command(cmd, false, tmpfile)
end
tmpfile.close!
randfile.close!
return output
end

Expand All @@ -50,7 +58,7 @@ def import_ks
tmpfile.write("#{@resource[:password]}\n#{@resource[:password]}\n#{@resource[:password]}")
end
tmpfile.flush
run_keystore_command(cmd, @resource[:target], tmpfile)
run_command(cmd, @resource[:target], tmpfile)
tmppk12.close!
tmpfile.close!
end
Expand All @@ -66,12 +74,7 @@ def exists?
tmpfile = Tempfile.new("#{@resource[:name]}.")
tmpfile.write(@resource[:password])
tmpfile.flush
Puppet::Util.execute(
cmd,
:stdinfile => tmpfile.path,
:failonfail => true,
:combine => true
)
run_command(cmd, false, tmpfile)
tmpfile.close!
return true
rescue
Expand All @@ -86,7 +89,7 @@ def latest
'x509', '-fingerprint', '-md5', '-noout',
'-in', @resource[:certificate]
]
output = Puppet::Util.execute(cmd)
output = run_command(cmd)
latest = output.scan(/MD5 Fingerprint=(.*)/)[0][0]
return latest
end
Expand All @@ -96,21 +99,16 @@ def current
output = ''
cmd = [
command(:keytool),
'-list',
'-list', '-v',
'-keystore', @resource[:target],
'-alias', @resource[:name]
]
tmpfile = Tempfile.new("#{@resource[:name]}.")
tmpfile.write(@resource[:password])
tmpfile.flush
output = Puppet::Util.execute(
cmd,
:stdinfile => tmpfile.path,
:failonfail => true,
:combine => true
)
output = run_command(cmd, false, tmpfile)
tmpfile.close!
current = output.scan(/Certificate fingerprint \(MD5\): (.*)/)[0][0]
current = output.scan(/Certificate fingerprints:\n\s+MD5: (.*)/)[0][0]
return current
end

Expand All @@ -137,7 +135,7 @@ def create
tmpfile.write("#{@resource[:password]}\n#{@resource[:password]}")
end
tmpfile.flush
run_keystore_command(cmd, @resource[:target], tmpfile)
run_command(cmd, @resource[:target], tmpfile)
tmpfile.close!
end
end
Expand All @@ -152,12 +150,7 @@ def destroy
tmpfile = Tempfile.new("#{@resource[:name]}.")
tmpfile.write(@resource[:password])
tmpfile.flush
Puppet::Util.execute(
cmd,
:stdinfile => tmpfile.path,
:failonfail => true,
:combine => true
)
run_command(cmd, false, tmpfile)
tmpfile.close!
end

Expand All @@ -167,38 +160,56 @@ def update
create
end

def run_keystore_command(cmd, target, stdinfile)
def run_command(cmd, target=false, stdinfile=false)

# The Puppet::Util::Execution.execute method is deparcated in Puppet 3.x
# but we need this to work on 2.7.x too.
if Puppet::Util::Execution.respond_to?(:execute)
exec_method = Puppet::Util::Execution.method(:execute)
else
exec_method = Puppet::Util.method(:execute)
end

# the java keytool will not correctly deal with an empty target keystore
# file. If we encounter an empty keystore target file, preserve the mode,
# owner and group, and delete the empty file.
if File.exists?(target) and File.zero?(target)
if target and (File.exists?(target) and File.zero?(target))
stat = File.stat(target)
File.delete(target)
end

# There's a problem in IBM java wherein stdin cannot be used (trivially)
# pass in the keystore passwords. This makes the provider work on SLES
# with minimal effort.
# There's a problem in IBM java keytool wherein stdin cannot be used
# (trivially) to pass in the keystore passwords. The below hack makes the
# provider work on SLES with minimal effort at the cost of letting the
# passphrase to the keystore show up in the process list as an argument.
# From a best practice standpoint the keystore should be protected by file
# permissions and not just the passphrase so "making it work on SLES"
# trumps.
if Facter.value('osfamily') == 'Suse' and @resource[:password]
cmd << '-srcstorepass' << @resource[:password]
cmd << '-deststorepass' << @resource[:password]
cmd_to_run = cmd.is_a?(String) ? cmd.split(/\s/).first : cmd.first
if cmd_to_run == command(:keytool)
cmd << '-srcstorepass' << @resource[:password]
cmd << '-deststorepass' << @resource[:password]
end
end

# Now run the command
Puppet::Util.execute(
cmd,
:stdinfile => stdinfile.path,
:failonfail => true,
:combine => true
)
options = { :failonfail => true, :combine => true }
output = if stdinfile
exec_method.call(cmd, options.merge(:stdinfile => stdinfile.path))
else
exec_method.call(cmd, options)
end

# for previously empty files, restore the mode, owner and group. The funky
# double-take check is because on Suse defined? doesn't seem to behave
# quite the same as on Debian, RedHat
if defined? stat and stat
if target and (defined? stat and stat)
File.chmod(stat.mode, target)
File.chown(stat.uid, stat.gid, target)
end

return output
end

end
19 changes: 1 addition & 18 deletions spec/spec_helper.rb
@@ -1,18 +1 @@
require 'pathname'
dir = Pathname.new(__FILE__).parent
$LOAD_PATH.unshift(dir, dir + 'lib', dir + '../lib')

require 'mocha'
require 'puppet'
gem 'rspec', '>=2.0.0'
require 'rspec/expectations'

RSpec.configure do |config|
config.mock_with :mocha
end

# We need this because the RAL uses 'should' as a method. This
# allows us the same behaviour but with a different method name.
class Object
alias :must :should
end
require 'puppetlabs_spec_helper/module_spec_helper'
Expand Up @@ -47,15 +47,15 @@

describe 'when importing a private key and certifcate' do
it 'should execute openssl and keytool with specific options' do
Puppet::Util.expects(:execute).with do |args|
provider.expects(:run_command).with do |*args|
args[0] == [
'myopenssl', 'pkcs12', '-export', '-passout', 'stdin',
'-in', resource[:certificate],
'-inkey', resource[:private_key],
'-name', resource[:name]
]
end
Puppet::Util.expects(:execute).with do |args|
provider.expects(:run_command).with do |*args|
args[0] == [
'mykeytool', '-importkeystore', '-srcstoretype', 'PKCS12',
'-destkeystore', resource[:target],
Expand All @@ -76,7 +76,7 @@
it 'should call keytool with specific options if only certificate is provided' do
no_pk = resource.dup
no_pk.delete(:private_key)
Puppet::Util.expects(:execute).with do |args|
provider.expects(:run_command).with do |*args|
args[0] == [
'mykeytool', '-importcert', '-noprompt',
'-alias', no_pk[:name],
Expand All @@ -91,7 +91,7 @@

describe 'when removing entries from keytool' do
it 'should execute keytool with a specific set of options' do
Puppet::Util.expects(:execute).with do |args|
provider.expects(:run_command).with do |*args|
args[0] == [
'mykeytool', '-delete',
'-alias', resource[:name],
Expand Down
File renamed without changes.