diff options
author | Jacob Helwig <jacob@technosorcery.net> | 2018-06-04 11:30:09 -0700 |
---|---|---|
committer | Jacob Helwig <jacob@technosorcery.net> | 2018-06-21 14:27:04 -0700 |
commit | d1719de1d77b9c139b1b5f5832330807c0fe11fe (patch) | |
tree | 69c541233bc64c5d47746e062e0efcba0c5436b5 /spec/unit | |
download | puppet-sshkeys_core-d1719de1d77b9c139b1b5f5832330807c0fe11fe.tar.gz puppet-sshkeys_core-d1719de1d77b9c139b1b5f5832330807c0fe11fe.tar.bz2 |
Initial sshkey type import from Puppet repository
Imported from dbf5a8964af9b87446542d24f46534cf90f11f59 in the Puppet repo.
Diffstat (limited to 'spec/unit')
-rw-r--r-- | spec/unit/provider/sshkey/parsed_spec.rb | 93 | ||||
-rw-r--r-- | spec/unit/type/ssh_authorized_key_spec.rb | 258 | ||||
-rw-r--r-- | spec/unit/type/sshkey_spec.rb | 77 |
3 files changed, 428 insertions, 0 deletions
diff --git a/spec/unit/provider/sshkey/parsed_spec.rb b/spec/unit/provider/sshkey/parsed_spec.rb new file mode 100644 index 0000000..38aa7f7 --- /dev/null +++ b/spec/unit/provider/sshkey/parsed_spec.rb @@ -0,0 +1,93 @@ +#! /usr/bin/env ruby +require 'spec_helper' + +describe "sshkey parsed provider" do + let :type do Puppet::Type.type(:sshkey) end + let :provider do type.provider(:parsed) end + subject { provider } + + after :each do + subject.clear + end + + def key + 'AAAAB3NzaC1yc2EAAAABIwAAAQEAzwHhxXvIrtfIwrudFqc8yQcIfMudrgpnuh1F3AV6d2BrLgu/yQE7W5UyJMUjfj427sQudRwKW45O0Jsnr33F4mUw+GIMlAAmp9g24/OcrTiB8ZUKIjoPy/cO4coxGi8/NECtRzpD/ZUPFh6OEpyOwJPMb7/EC2Az6Otw4StHdXUYw22zHazBcPFnv6zCgPx1hA7QlQDWTu4YcL0WmTYQCtMUb3FUqrcFtzGDD0ytosgwSd+JyN5vj5UwIABjnNOHPZ62EY1OFixnfqX/+dUwrFSs5tPgBF/KkC6R7tmbUfnBON6RrGEmu+ajOTOLy23qUZB4CQ53V7nyAWhzqSK+hw==' + end + + it "should parse the name from the first field" do + expect(subject.parse_line('test ssh-rsa '+key)[:name]).to eq("test") + end + + it "should parse the first component of the first field as the name" do + expect(subject.parse_line('test,alias ssh-rsa '+key)[:name]).to eq("test") + end + + it "should parse host_aliases from the remaining components of the first field" do + expect(subject.parse_line('test,alias ssh-rsa '+key)[:host_aliases]).to eq(["alias"]) + end + + it "should parse multiple host_aliases" do + expect(subject.parse_line('test,alias1,alias2,alias3 ssh-rsa '+key)[:host_aliases]).to eq(["alias1","alias2","alias3"]) + end + + it "should not drop an empty host_alias" do + expect(subject.parse_line('test,alias, ssh-rsa '+key)[:host_aliases]).to eq(["alias",""]) + end + + it "should recognise when there are no host aliases" do + expect(subject.parse_line('test ssh-rsa '+key)[:host_aliases]).to eq([]) + end + + context "with the sample file" do + ['sample', 'sample_with_blank_lines'].each do |sample_file| + let :fixture do my_fixture(sample_file) end + before :each do subject.stubs(:default_target).returns(fixture) end + + it "should parse to records on prefetch" do + expect(subject.target_records(fixture)).to be_empty + subject.prefetch + + records = subject.target_records(fixture) + expect(records).to be_an Array + expect(records).to be_all {|x| expect(x).to be_an Hash } + end + + it "should reconstitute the file from records" do + subject.prefetch + records = subject.target_records(fixture) + text = subject.to_file(records).gsub(/^# HEADER.+\n/, '') + + oldlines = File.readlines(fixture).map(&:chomp) + newlines = text.chomp.split("\n") + expect(oldlines.length).to eq(newlines.length) + + oldlines.zip(newlines).each do |old, new| + expect(old.gsub(/\s+/, '')).to eq(new.gsub(/\s+/, '')) + end + end + end + end + + context 'default ssh_known_hosts target path' do + ['9.10', '9.11', '10.10'].each do |version| + it 'should be `/etc/ssh_known_hosts` when OSX version 10.10 or older`' do + Facter.expects(:value).with(:operatingsystem).returns('Darwin') + Facter.expects(:value).with(:macosx_productversion_major).returns(version) + expect(subject.default_target).to eq('/etc/ssh_known_hosts') + end + end + + ['10.11', '10.13', '11.0', '11.11'].each do |version| + it 'should be `/etc/ssh/ssh_known_hosts` when OSX version 10.11 or newer`' do + Facter.expects(:value).with(:operatingsystem).returns('Darwin') + Facter.expects(:value).with(:macosx_productversion_major).returns(version) + expect(subject.default_target).to eq('/etc/ssh/ssh_known_hosts') + end + end + + it 'should be `/etc/ssh/ssh_known_hosts` on other operating systems' do + Facter.expects(:value).with(:operatingsystem).returns('RedHat') + expect(subject.default_target).to eq('/etc/ssh/ssh_known_hosts') + end + end +end diff --git a/spec/unit/type/ssh_authorized_key_spec.rb b/spec/unit/type/ssh_authorized_key_spec.rb new file mode 100644 index 0000000..ae93667 --- /dev/null +++ b/spec/unit/type/ssh_authorized_key_spec.rb @@ -0,0 +1,258 @@ +#! /usr/bin/env ruby +require 'spec_helper' + + +describe Puppet::Type.type(:ssh_authorized_key), :unless => Puppet.features.microsoft_windows? do + include PuppetSpec::Files + + before do + provider_class = stub 'provider_class', :name => "fake", :suitable? => true, :supports_parameter? => true + described_class.stubs(:defaultprovider).returns(provider_class) + described_class.stubs(:provider).returns(provider_class) + + provider = stub 'provider', :class => provider_class, :file_path => make_absolute("/tmp/whatever"), :clear => nil + provider_class.stubs(:new).returns(provider) + end + + it "has :name as its namevar" do + expect(described_class.key_attributes).to eq [:name] + end + + describe "when validating attributes" do + + [:name, :provider].each do |param| + it "has a #{param} parameter" do + expect(described_class.attrtype(param)).to eq :param + end + end + + [:type, :key, :user, :target, :options, :ensure].each do |property| + it "has a #{property} property" do + expect(described_class.attrtype(property)).to eq :property + end + end + + end + + describe "when validating values" do + + describe "for name" do + + it "supports valid names" do + described_class.new(:name => "username", :ensure => :present, :user => "nobody") + described_class.new(:name => "username@hostname", :ensure => :present, :user => "nobody") + end + + it "supports whitespace" do + described_class.new(:name => "my test", :ensure => :present, :user => "nobody") + end + + end + + describe "for ensure" do + + it "supports :present" do + described_class.new(:name => "whev", :ensure => :present, :user => "nobody") + end + + it "supports :absent" do + described_class.new(:name => "whev", :ensure => :absent, :user => "nobody") + end + + it "nots support other values" do + expect { described_class.new(:name => "whev", :ensure => :foo, :user => "nobody") }.to raise_error(Puppet::Error, /Invalid value/) + end + + end + + describe "for type" do + + [ + :'ssh-dss', :dsa, + :'ssh-rsa', :rsa, + :'ecdsa-sha2-nistp256', + :'ecdsa-sha2-nistp384', + :'ecdsa-sha2-nistp521', + :ed25519, :'ssh-ed25519', + ].each do |keytype| + it "supports #{keytype}" do + described_class.new(:name => "whev", :type => keytype, :user => "nobody") + end + end + + it "aliases :rsa to :ssh-rsa" do + key = described_class.new(:name => "whev", :type => :rsa, :user => "nobody") + expect(key.should(:type)).to eq :'ssh-rsa' + end + + it "aliases :dsa to :ssh-dss" do + key = described_class.new(:name => "whev", :type => :dsa, :user => "nobody") + expect(key.should(:type)).to eq :'ssh-dss' + end + + it "doesn't support values other than ssh-dss, ssh-rsa, dsa, rsa" do + expect { described_class.new(:name => "whev", :type => :something) }.to raise_error(Puppet::Error,/Invalid value/) + end + + end + + describe "for key" do + + it "supports a valid key like a 1024 bit rsa key" do + expect { described_class.new(:name => "whev", :type => :rsa, :user => "nobody", :key => 'AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCPfzW2ry7XvMc6E5Kj2e5fF/YofhKEvsNMUogR3PGL/HCIcBlsEjKisrY0aYgD8Ikp7ZidpXLbz5dBsmPy8hJiBWs5px9ZQrB/EOQAwXljvj69EyhEoGawmxQMtYw+OAIKHLJYRuk1QiHAMHLp5piqem8ZCV2mLb9AsJ6f7zUVw==')}.to_not raise_error + end + + it "supports a valid key like a 4096 bit rsa key" do + expect { described_class.new(:name => "whev", :type => :rsa, :user => "nobody", :key => 'AAAAB3NzaC1yc2EAAAADAQABAAACAQDEY4pZFyzSfRc9wVWI3DfkgT/EL033UZm/7x1M+d+lBD00qcpkZ6CPT7lD3Z+vylQlJ5S8Wcw6C5Smt6okZWY2WXA9RCjNJMIHQbJAzwuQwgnwU/1VMy9YPp0tNVslg0sUUgpXb13WW4mYhwxyGmIVLJnUrjrQmIFhtfHsJAH8ZVqCWaxKgzUoC/YIu1u1ScH93lEdoBPLlwm6J0aiM7KWXRb7Oq1nEDZtug1zpX5lhgkQWrs0BwceqpUbY+n9sqeHU5e7DCyX/yEIzoPRW2fe2Gx1Iq6JKM/5NNlFfaW8rGxh3Z3S1NpzPHTRjw8js3IeGiV+OPFoaTtM1LsWgPDSBlzIdyTbSQR7gKh0qWYCNV/7qILEfa0yIFB5wIo4667iSPZw2pNgESVtenm8uXyoJdk8iWQ4mecdoposV/znknNb2GPgH+n/2vme4btZ0Sl1A6rev22GQjVgbWOn8zaDglJ2vgCN1UAwmq41RXprPxENGeLnWQppTnibhsngu0VFllZR5kvSIMlekLRSOFLFt92vfd+tk9hZIiKm9exxcbVCGGQPsf6dZ27rTOmg0xM2Sm4J6RRKuz79HQgA4Eg18+bqRP7j/itb89DmtXEtoZFAsEJw8IgIfeGGDtHTkfAlAC92mtK8byeaxGq57XCTKbO/r5gcOMElZHy1AcB8kw==')}.to_not raise_error + end + + it "supports a valid key like a 1024 bit dsa key" do + expect { described_class.new(:name => "whev", :type => :dsa, :user => "nobody", :key => 'AAAAB3NzaC1kc3MAAACBAI80iR78QCgpO4WabVqHHdEDigOjUEHwIjYHIubR/7u7DYrXY+e+TUmZ0CVGkiwB/0yLHK5dix3Y/bpj8ZiWCIhFeunnXccOdE4rq5sT2V3l1p6WP33RpyVYbLmeuHHl5VQ1CecMlca24nHhKpfh6TO/FIwkMjghHBfJIhXK+0w/AAAAFQDYzLupuMY5uz+GVrcP+Kgd8YqMmwAAAIB3SVN71whLWjFPNTqGyyIlMy50624UfNOaH4REwO+Of3wm/cE6eP8n75vzTwQGBpJX3BPaBGW1S1Zp/DpTOxhCSAwZzAwyf4WgW7YyAOdxN3EwTDJZeyiyjWMAOjW9/AOWt9gtKg0kqaylbMHD4kfiIhBzo31ZY81twUzAfN7angAAAIBfva8sTSDUGKsWWIXkdbVdvM4X14K4gFdy0ZJVzaVOtZ6alysW6UQypnsl6jfnbKvsZ0tFgvcX/CPyqNY/gMR9lyh/TCZ4XQcbqeqYPuceGehz+jL5vArfqsW2fJYFzgCcklmr/VxtP5h6J/T0c9YcDgc/xIfWdZAlznOnphI/FA==')}.to_not raise_error + end + + it "doesn't support whitespaces" do + expect { described_class.new(:name => "whev", :type => :rsa, :user => "nobody", :key => 'AAA FA==')}.to raise_error(Puppet::Error,/Key must not contain whitespace/) + end + + end + + describe "for options" do + + it "supports flags as options" do + expect { described_class.new(:name => "whev", :type => :rsa, :user => "nobody", :options => 'cert-authority')}.to_not raise_error + expect { described_class.new(:name => "whev", :type => :rsa, :user => "nobody", :options => 'no-port-forwarding')}.to_not raise_error + end + + it "supports key-value pairs as options" do + expect { described_class.new(:name => "whev", :type => :rsa, :user => "nobody", :options => 'command="command"')}.to_not raise_error + end + + it "supports key-value pairs where value consist of multiple items" do + expect { described_class.new(:name => "whev", :type => :rsa, :user => "nobody", :options => 'from="*.domain1,host1.domain2"')}.to_not raise_error + end + + it "supports environments as options" do + expect { described_class.new(:name => "whev", :type => :rsa, :user => "nobody", :options => 'environment="NAME=value"')}.to_not raise_error + end + + it "supports multiple options as an array" do + expect { described_class.new(:name => "whev", :type => :rsa, :user => "nobody", :options => ['cert-authority','environment="NAME=value"'])}.to_not raise_error + end + + it "doesn't support a comma separated list" do + expect { described_class.new(:name => "whev", :type => :rsa, :user => "nobody", :options => 'cert-authority,no-port-forwarding')}.to raise_error(Puppet::Error, /must be provided as an array/) + end + + it "uses :absent as a default value" do + expect(described_class.new(:name => "whev", :type => :rsa, :user => "nobody").should(:options)).to eq [:absent] + end + + it "property should return well formed string of arrays from is_to_s" do + resource = described_class.new(:name => "whev", :type => :rsa, :user => "nobody", :options => ["a","b","c"]) + expect(resource.property(:options).is_to_s(["a","b","c"])).to eq "['a', 'b', 'c']" + end + + it "property should return well formed string of arrays from should_to_s" do + resource = described_class.new(:name => "whev", :type => :rsa, :user => "nobody", :options => ["a","b","c"]) + expect(resource.property(:options).should_to_s(["a","b","c"])).to eq "['a', 'b', 'c']" + end + + end + + describe "for user" do + + it "supports present users" do + described_class.new(:name => "whev", :type => :rsa, :user => "root") + end + + it "supports absent users" do + described_class.new(:name => "whev", :type => :rsa, :user => "ihopeimabsent") + end + + end + + describe "for target" do + + it "supports absolute paths" do + described_class.new(:name => "whev", :type => :rsa, :target => "/tmp/here") + end + + it "uses the user's path if not explicitly specified" do + expect(described_class.new(:name => "whev", :user => 'root').should(:target)).to eq File.expand_path("~root/.ssh/authorized_keys") + end + + it "doesn't consider the user's path if explicitly specified" do + expect(described_class.new(:name => "whev", :user => 'root', :target => '/tmp/here').should(:target)).to eq '/tmp/here' + end + + it "informs about an absent user" do + Puppet::Log.level = :debug + described_class.new(:name => "whev", :user => 'idontexist').should(:target) + expect(@logs.map(&:message)).to include("The required user is not yet present on the system") + end + + end + + end + + describe "when neither user nor target is specified" do + + it "raises an error" do + expect do + described_class.new( + :name => "Test", + :key => "AAA", + :type => "ssh-rsa", + :ensure => :present) + end.to raise_error(Puppet::Error,/user.*or.*target.*mandatory/) + end + + end + + describe "when both target and user are specified" do + + it "uses target" do + resource = described_class.new( + :name => "Test", + :user => "root", + :target => "/tmp/blah" + ) + expect(resource.should(:target)).to eq "/tmp/blah" + end + + end + + + describe "when user is specified" do + + it "determines target" do + resource = described_class.new( + :name => "Test", + :user => "root" + ) + target = File.expand_path("~root/.ssh/authorized_keys") + expect(resource.should(:target)).to eq target + end + + # Bug #2124 - ssh_authorized_key always changes target if target is not defined + it "doesn't raise spurious change events" do + resource = described_class.new(:name => "Test", :user => "root") + target = File.expand_path("~root/.ssh/authorized_keys") + expect(resource.property(:target).safe_insync?(target)).to eq true + end + + end + + describe "when calling validate" do + + it "doesn't crash on a non-existent user" do + resource = described_class.new( + :name => "Test", + :user => "ihopesuchuserdoesnotexist" + ) + resource.validate + end + + end + +end diff --git a/spec/unit/type/sshkey_spec.rb b/spec/unit/type/sshkey_spec.rb new file mode 100644 index 0000000..d16e595 --- /dev/null +++ b/spec/unit/type/sshkey_spec.rb @@ -0,0 +1,77 @@ +#! /usr/bin/env ruby +require 'spec_helper' + + +describe Puppet::Type.type(:sshkey) do + + it "uses :name as its namevar" do + expect(described_class.key_attributes).to eq [:name] + end + + describe "when validating attributes" do + [:name, :provider].each do |param| + it "has a #{param} parameter" do + expect(described_class.attrtype(param)).to eq :param + end + end + + [:host_aliases, :ensure, :key, :type].each do |property| + it "has a #{property} property" do + expect(described_class.attrtype(property)).to eq :property + end + end + end + + describe "when validating values" do + + [ + :'ssh-dss', :dsa, + :'ssh-rsa', :rsa, + :'ecdsa-sha2-nistp256', + :'ecdsa-sha2-nistp384', + :'ecdsa-sha2-nistp521', + :'ssh-ed25519', :ed25519, + ].each do |keytype| + it "supports #{keytype} as a type value" do + described_class.new(:name => "foo", :type => keytype) + end + end + + it "aliases :rsa to :ssh-rsa" do + key = described_class.new(:name => "foo", :type => :rsa) + expect(key.should(:type)).to eq :'ssh-rsa' + end + + it "aliases :dsa to :ssh-dss" do + key = described_class.new(:name => "foo", :type => :dsa) + expect(key.should(:type)).to eq :'ssh-dss' + end + + it "doesn't support values other than ssh-dss, ssh-rsa, dsa, rsa for type" do + expect { + described_class.new(:name => "whev", :type => :'ssh-dsa') + }.to raise_error(Puppet::Error, /Invalid value.*ssh-dsa/) + end + + it "accepts one host_alias" do + described_class.new(:name => "foo", :host_aliases => 'foo.bar.tld') + end + + it "accepts multiple host_aliases as an array" do + described_class.new(:name => "foo", :host_aliases => ['foo.bar.tld','10.0.9.9']) + end + + it "doesn't accept spaces in any host_alias" do + expect { + described_class.new(:name => "foo", :host_aliases => ['foo.bar.tld','foo bar']) + }.to raise_error(Puppet::Error, /cannot include whitespace/) + end + + it "doesn't accept aliases in the resourcename" do + expect { + described_class.new(:name => 'host,host.domain,ip') + }.to raise_error(Puppet::Error, /No comma in resourcename/) + end + + end +end |