aboutsummaryrefslogtreecommitdiff
path: root/spec/integration
diff options
context:
space:
mode:
Diffstat (limited to 'spec/integration')
-rw-r--r--spec/integration/provider/ssh_authorized_key_spec.rb219
-rw-r--r--spec/integration/provider/sshkey_spec.rb159
2 files changed, 378 insertions, 0 deletions
diff --git a/spec/integration/provider/ssh_authorized_key_spec.rb b/spec/integration/provider/ssh_authorized_key_spec.rb
new file mode 100644
index 0000000..14af2de
--- /dev/null
+++ b/spec/integration/provider/ssh_authorized_key_spec.rb
@@ -0,0 +1,219 @@
+#! /usr/bin/env ruby
+
+require 'spec_helper'
+require 'puppet/file_bucket/dipper'
+
+describe Puppet::Type.type(:ssh_authorized_key).provider(:parsed), '(integration)', :unless => Puppet.features.microsoft_windows? do
+ include PuppetSpec::Files
+
+ let :fake_userfile do
+ tmpfile('authorized_keys.user')
+ end
+
+ let :fake_rootfile do
+ tmpfile('authorized_keys.root')
+ end
+
+ let :sample_rsa_keys do
+ [
+ 'AAAAB3NzaC1yc2EAAAADAQABAAAAgQCi18JBZOq10X3w4f67nVhO0O3s5Y1vHH4UgMSM3ZnQwbC5hjGyYSi9UULOoQQoQynI/a0I9NL423/Xk/XJVIKCHcS8q6V2Wmjd+fLNelOjxxoW6mbIytEt9rDvwgq3Mof3/m21L3t2byvegR00a+ikKbmInPmKwjeWZpexCIsHzQ==', # 1024 bit
+ 'AAAAB3NzaC1yc2EAAAADAQABAAAAgQDLClyvi3CsJw5Id6khZs2/+s11qOH4Gdp6iDioDsrIp0m8kSiPr71VGyQYAfPzzvHemHS7Xg0NkG1Kc8u9tRqBQfTvz7ubq0AT/g01+4P2hQ/soFkuwlUG/HVnnaYb6N0Qp5SHWvD5vBE2nFFQVpP5GrSctPtHSjzJq/i+6LYhmQ==', # 1024 bit
+ 'AAAAB3NzaC1yc2EAAAADAQABAAABAQDLygAO6txXkh9FNV8xSsBkATeqLbHzS7sFjGI3gt0Dx6q3LjyKwbhQ1RLf28kd5G6VWiXmClU/RtiPdUz8nrGuun++2mrxzrXrvpR9dq1lygLQ2wn2cI35dN5bjRMtXy3decs6HUhFo9MoNwX250rUWfdCyNPhGIp6OOfmjdy+UeLGNxq9wDx6i4bT5tVVSqVRtsEfw9+ICXchzl85QudjneVVpP+thriPZXfXA5eaGwAo/dmoKOIhUwF96gpdLqzNtrGQuxPbV80PTbGv9ZtAtTictxaDz8muXO7he9pXmchUpxUKtMFjHkL0FAZ9tRPmv3RA30sEr2fZ8+LKvnE50w0' #2048 Bit
+ ]
+ end
+
+ let :sample_dsa_keys do
+ [
+ 'AAAAB3NzaC1kc3MAAACBAOPck2O8MIDSqxPSnvENt6tzRrKJ5oOhB6Nc6oEcWm+VEH1gvuxdiRqwoMgRwyEf1yUd+UAcLw3a6Jn+EtFyEBN/5WF+4Tt4xTxZ0Pfik2Wc5uqHbQ2dkmOoXiAOYPiD3JUQ1Xwm/J0CgetjitoLfzAGdCNhMqguqAuHcVJ78ZZbAAAAFQCIBKFYZ+I18I+dtgteirXh+VVEEwAAAIEAs1yvQ/wnLLrRCM660pF4kBiw3D6dJfMdCXWQpn0hZmkBQSIzZv4Wuk3giei5luxscDxNc+y3CTXtnyG4Kt1Yi2sOdvhRI3rX8tD+ejn8GHazM05l5VIo9uu4AQPIE32iV63IqgApSBbJ6vDJW91oDH0J492WdLCar4BS/KE3cRwAAACBAN0uSDyJqYLRsfYcFn4HyVf6TJxQm1IcwEt6GcJVzgjri9VtW7FqY5iBqa9B9Zdh5XXAYJ0XLsWQCcrmMHM2XGHGpA4gL9VlCJ/0QvOcXxD2uK7IXwAVUA7g4V4bw8EVnFv2Flufozhsp+4soo1xiYc5jiFVHwVlk21sMhAtKAeF' # 1024 Bit
+ ]
+ end
+
+ let :sample_lines do
+ [
+ "ssh-rsa #{sample_rsa_keys[1]} root@someotherhost",
+ "ssh-dss #{sample_dsa_keys[0]} root@anywhere",
+ "ssh-rsa #{sample_rsa_keys[2]} paul",
+ "ssh-rsa #{sample_rsa_keys[2]} dummy"
+ ]
+ end
+
+ let :dummy do
+ Puppet::Type.type(:ssh_authorized_key).new(
+ :name => 'dummy',
+ :target => fake_userfile,
+ :user => 'nobody',
+ :ensure => :absent
+ )
+ end
+
+ before :each do
+ File.stubs(:chown)
+ File.stubs(:chmod)
+ Puppet::Util::SUIDManager.stubs(:asuser).yields
+ end
+
+ after :each do
+ described_class.clear # Work around bug #6628
+ end
+
+ def create_fake_key(username, content)
+ filename = (username == :root ? fake_rootfile : fake_userfile )
+ File.open(filename, 'w') do |f|
+ content.each do |line|
+ f.puts line
+ end
+ end
+ end
+
+ def check_fake_key(username, expected_content)
+ filename = (username == :root ? fake_rootfile : fake_userfile )
+ content = File.readlines(filename).map(&:chomp).sort.reject{ |x| x =~ /^# HEADER:/ }
+ expect(content.join("\n")).to eq(expected_content.sort.join("\n"))
+ end
+
+ def run_in_catalog(*resources)
+ Puppet::FileBucket::Dipper.any_instance.stubs(:backup) # Don't backup to the filebucket
+ catalog = Puppet::Resource::Catalog.new
+ catalog.host_config = false
+ resources.each do |resource|
+ resource.expects(:err).never
+ catalog.add_resource(resource)
+ end
+ catalog.apply
+ end
+
+ it "should not complain about empty lines and comments" do
+ described_class.expects(:flush).never
+ sample = ['',sample_lines[0],' ',sample_lines[1],'# just a comment','#and another']
+ create_fake_key(:user,sample)
+ run_in_catalog(dummy)
+ check_fake_key(:user, sample)
+ end
+
+ it "should keep empty lines and comments when modifying a file" do
+ create_fake_key(:user, ['',sample_lines[0],' ',sample_lines[3],'# just a comment','#and another'])
+ run_in_catalog(dummy)
+ check_fake_key(:user, ['',sample_lines[0],' ','# just a comment','#and another'])
+ end
+
+ describe "when managing one resource" do
+
+ describe "with ensure set to absent" do
+ let :resource do
+ Puppet::Type.type(:ssh_authorized_key).new(
+ :name => 'root@hostname',
+ :type => :rsa,
+ :key => sample_rsa_keys[0],
+ :target => fake_rootfile,
+ :user => 'root',
+ :ensure => :absent
+ )
+ end
+
+ it "should not modify root's keyfile if resource is currently not present" do
+ create_fake_key(:root, sample_lines)
+ run_in_catalog(resource)
+ check_fake_key(:root, sample_lines)
+ end
+
+ it "remove the key from root's keyfile if resource is currently present" do
+ create_fake_key(:root, sample_lines + ["ssh-rsa #{sample_rsa_keys[0]} root@hostname"])
+ run_in_catalog(resource)
+ check_fake_key(:root, sample_lines)
+ end
+ end
+
+ describe "when ensure is present" do
+ let :resource do
+ Puppet::Type.type(:ssh_authorized_key).new(
+ :name => 'root@hostname',
+ :type => :rsa,
+ :key => sample_rsa_keys[0],
+ :target => fake_rootfile,
+ :user => 'root',
+ :ensure => :present
+ )
+ end
+
+ # just a dummy so the parsedfile provider is aware
+ # of the user's authorized_keys file
+
+ it "should add the key if it is not present" do
+ create_fake_key(:root, sample_lines)
+ run_in_catalog(resource)
+ check_fake_key(:root, sample_lines + ["ssh-rsa #{sample_rsa_keys[0]} root@hostname" ])
+ end
+
+ it "should modify the type if type is out of sync" do
+ create_fake_key(:root,sample_lines + [ "ssh-dss #{sample_rsa_keys[0]} root@hostname" ])
+ run_in_catalog(resource)
+ check_fake_key(:root, sample_lines + [ "ssh-rsa #{sample_rsa_keys[0]} root@hostname" ])
+ end
+
+ it "should modify the key if key is out of sync" do
+ create_fake_key(:root,sample_lines + [ "ssh-rsa #{sample_rsa_keys[1]} root@hostname" ])
+ run_in_catalog(resource)
+ check_fake_key(:root, sample_lines + [ "ssh-rsa #{sample_rsa_keys[0]} root@hostname" ])
+ end
+
+ it "should remove the key from old file if target is out of sync" do
+ create_fake_key(:user, [ sample_lines[0], "ssh-rsa #{sample_rsa_keys[0]} root@hostname" ])
+ create_fake_key(:root, [ sample_lines[1], sample_lines[2] ])
+ run_in_catalog(resource, dummy)
+ check_fake_key(:user, [ sample_lines[0] ])
+ #check_fake_key(:root, [ sample_lines[1], sample_lines[2], "ssh-rsa #{sample_rsa_keys[0]} root@hostname" ])
+ end
+
+ it "should add the key to new file if target is out of sync" do
+ create_fake_key(:user, [ sample_lines[0], "ssh-rsa #{sample_rsa_keys[0]} root@hostname" ])
+ create_fake_key(:root, [ sample_lines[1], sample_lines[2] ])
+ run_in_catalog(resource, dummy)
+ #check_fake_key(:user, [ sample_lines[0] ])
+ check_fake_key(:root, [ sample_lines[1], sample_lines[2], "ssh-rsa #{sample_rsa_keys[0]} root@hostname" ])
+ end
+
+ it "should modify options if options are out of sync" do
+ resource[:options]=[ 'from="*.domain1,host1.domain2"', 'no-port-forwarding', 'no-pty' ]
+ create_fake_key(:root, sample_lines + [ "from=\"*.false,*.false2\",no-port-forwarding,no-pty ssh-rsa #{sample_rsa_keys[0]} root@hostname"])
+ run_in_catalog(resource)
+ check_fake_key(:root, sample_lines + [ "from=\"*.domain1,host1.domain2\",no-port-forwarding,no-pty ssh-rsa #{sample_rsa_keys[0]} root@hostname"] )
+ end
+ end
+ end
+
+ describe "when managing two resource" do
+ let :examples do
+ resources = []
+ resources << Puppet::Type.type(:ssh_authorized_key).new(
+ :name => 'root@hostname',
+ :type => :rsa,
+ :key => sample_rsa_keys[0],
+ :target => fake_rootfile,
+ :user => 'root',
+ :ensure => :present
+ )
+ resources << Puppet::Type.type(:ssh_authorized_key).new(
+ :name => 'user@hostname',
+ :key => sample_rsa_keys[1],
+ :type => :rsa,
+ :target => fake_userfile,
+ :user => 'nobody',
+ :ensure => :present
+ )
+ resources
+ end
+
+ describe "and both keys are absent" do
+ before :each do
+ create_fake_key(:root, sample_lines)
+ create_fake_key(:user, sample_lines)
+ end
+
+ it "should add both keys" do
+ run_in_catalog(*examples)
+ check_fake_key(:root, sample_lines + [ "ssh-rsa #{sample_rsa_keys[0]} root@hostname" ])
+ check_fake_key(:user, sample_lines + [ "ssh-rsa #{sample_rsa_keys[1]} user@hostname" ])
+ end
+ end
+ end
+end
diff --git a/spec/integration/provider/sshkey_spec.rb b/spec/integration/provider/sshkey_spec.rb
new file mode 100644
index 0000000..f461460
--- /dev/null
+++ b/spec/integration/provider/sshkey_spec.rb
@@ -0,0 +1,159 @@
+#!/usr/bin/env ruby
+
+require 'spec_helper'
+require 'puppet/file_bucket/dipper'
+require 'puppet_spec/files'
+require 'puppet_spec/compiler'
+
+describe Puppet::Type.type(:sshkey).provider(:parsed), '(integration)',
+ :unless => Puppet.features.microsoft_windows? do
+ include PuppetSpec::Files
+ include PuppetSpec::Compiler
+
+ before :each do
+ # Don't backup to filebucket
+ Puppet::FileBucket::Dipper.any_instance.stubs(:backup)
+ # We don't want to execute anything
+ described_class.stubs(:filetype).
+ returns Puppet::Util::FileType::FileTypeFlat
+
+ @sshkey_file = tmpfile('sshkey_integration_specs')
+ FileUtils.cp(my_fixture('sample'), @sshkey_file)
+ end
+
+ after :each do
+ # sshkey provider class
+ described_class.clear
+ end
+
+ let(:type_under_test) { 'sshkey' }
+
+ describe "when managing a ssh known hosts file it..." do
+
+ let(:super_unique) { "my.super.unique.host" }
+ it "should create a new known_hosts file with mode 0644" do
+ target = tmpfile('ssh_known_hosts')
+ manifest = "#{type_under_test} { '#{super_unique}':
+ ensure => 'present',
+ type => 'rsa',
+ key => 'TESTKEY',
+ target => '#{target}' }"
+ apply_with_error_check(manifest)
+ expect_file_mode(target, "644")
+ end
+
+ it "should create an SSH host key entry (ensure present)" do
+ manifest = "#{type_under_test} { '#{super_unique}':
+ ensure => 'present',
+ type => 'rsa',
+ key => 'mykey',
+ target => '#{@sshkey_file}' }"
+ apply_with_error_check(manifest)
+ expect(File.read(@sshkey_file)).to match(/#{super_unique}.*mykey/)
+ end
+
+ let(:sshkey_name) { 'kirby.madstop.com' }
+ it "should delete an entry for an SSH host key" do
+ manifest = "#{type_under_test} { '#{sshkey_name}':
+ ensure => 'absent',
+ target => '#{@sshkey_file}' }"
+ apply_with_error_check(manifest)
+ expect(File.read(@sshkey_file)).not_to match(/#{sshkey_name}.*Yqk0=/)
+ end
+
+ it "should update an entry for an SSH host key" do
+ manifest = "#{type_under_test} { '#{sshkey_name}':
+ ensure => 'present',
+ type => 'rsa',
+ key => 'mynewshinykey',
+ target => '#{@sshkey_file}' }"
+ apply_with_error_check(manifest)
+ expect(File.read(@sshkey_file)).to match(/#{sshkey_name}.*mynewshinykey/)
+ expect(File.read(@sshkey_file)).not_to match(/#{sshkey_name}.*Yqk0=/)
+ end
+
+ # test all key types
+ types = ["ssh-dss", "dsa",
+ "ssh-ed25519", "ed25519",
+ "ssh-rsa", "rsa",
+ "ecdsa-sha2-nistp256",
+ "ecdsa-sha2-nistp384",
+ "ecdsa-sha2-nistp521"]
+ # these types are treated as aliases for sshkey <ahem> type
+ # so they are populated as the *values* below
+ aliases = {"dsa" => "ssh-dss",
+ "ed25519" => "ssh-ed25519",
+ "rsa" => "ssh-rsa"}
+ types.each do |type|
+ it "should update an entry with #{type} type" do
+ manifest = "#{type_under_test} { '#{sshkey_name}':
+ ensure => 'present',
+ type => '#{type}',
+ key => 'mynewshinykey',
+ target => '#{@sshkey_file}' }"
+
+ apply_with_error_check(manifest)
+ if aliases.has_key?(type)
+ full_type = aliases[type]
+ expect(File.read(@sshkey_file)).
+ to match(/#{sshkey_name}.*#{full_type}.*mynew/)
+ else
+ expect(File.read(@sshkey_file)).
+ to match(/#{sshkey_name}.*#{type}.*mynew/)
+ end
+ end
+ end
+
+ # test unknown key type fails
+ let(:invalid_type) { 'ssh-er0ck' }
+ it "should raise an error with an unknown type" do
+ manifest = "#{type_under_test} { '#{sshkey_name}':
+ ensure => 'present',
+ type => '#{invalid_type}',
+ key => 'mynewshinykey',
+ target => '#{@sshkey_file}' }"
+ expect {
+ apply_compiled_manifest(manifest)
+ }.to raise_error(Puppet::ResourceError, /Invalid value "#{invalid_type}"/)
+ end
+
+ #single host_alias
+ let(:host_alias) { 'r0ckdata.com' }
+ it "should update an entry with new host_alias" do
+ manifest = "#{type_under_test} { '#{sshkey_name}':
+ ensure => 'present',
+ host_aliases => '#{host_alias}',
+ target => '#{@sshkey_file}' }"
+ apply_with_error_check(manifest)
+ expect(File.read(@sshkey_file)).to match(/#{sshkey_name},#{host_alias}\s/)
+ expect(File.read(@sshkey_file)).not_to match(/#{sshkey_name}\s/)
+ end
+
+ #array host_alias
+ let(:host_aliases) { "r0ckdata.com,erict.net" }
+ it "should update an entry with new host_alias" do
+ manifest = "#{type_under_test} { '#{sshkey_name}':
+ ensure => 'present',
+ host_aliases => '#{host_alias}',
+ target => '#{@sshkey_file}' }"
+ apply_with_error_check(manifest)
+ expect(File.read(@sshkey_file)).to match(/#{sshkey_name},#{host_alias}\s/)
+ expect(File.read(@sshkey_file)).not_to match(/#{sshkey_name}\s/)
+ end
+
+ #puppet resource sshkey
+ it "should fetch an entry from resources" do
+ @resource_app = Puppet::Application[:resource]
+ @resource_app.preinit
+ @resource_app.command_line.stubs(:args).
+ returns([type_under_test, sshkey_name, "target=#{@sshkey_file}"])
+
+ @resource_app.expects(:puts).with do |args|
+ expect(args).to match(/#{sshkey_name}/)
+ end
+ @resource_app.main
+ end
+
+ end
+
+end