Skip to content

Commit

Permalink
Grub2 grub_user fix (#32)
Browse files Browse the repository at this point in the history
The user generation script was incorrectly outputting additional
erronous information
  • Loading branch information
trevor-vaughan committed May 9, 2018
1 parent ce7389d commit e773a9a
Show file tree
Hide file tree
Showing 15 changed files with 493 additions and 400 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 3.0.1
- Fix generation of grub2 user entries
- Add support for OEL

## 3.0.0

- Added code to fix the EFI stack on Linux hosts
Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ group :development, :unit_tests do
gem 'puppet-lint-file_ensure-check', :require => false
gem 'puppet-lint-version_comparison-check', :require => false
gem 'rspec-puppet-facts', :require => false
gem 'beaker-rspec', :require => false
gem 'simp-beaker-helpers', :require => false

gem 'coveralls', :require => false unless RUBY_VERSION =~ /^1\.8/
gem 'simplecov', '~> 0.7.0', :require => false
Expand Down
65 changes: 35 additions & 30 deletions lib/puppet/provider/grub_user/grub2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,26 @@ def self.mkconfig_path

mk_resource_methods

def self.grub2_cfg
require 'puppetx/augeasproviders_grub/menuentry'

PuppetX::AugeasprovidersGrub::Util.grub2_cfg
end

def grub2_cfg
self.class.grub2_cfg
end

def self.grub2_cfg_path
require 'puppetx/augeasproviders_grub/menuentry'

PuppetX::AugeasprovidersGrub::Util.grub2_cfg_path
end

def grub2_cfg_path
self.class.grub2_cfg_path
end

def self.extract_users(content)
superusers = nil
users = {}
Expand Down Expand Up @@ -56,11 +76,7 @@ def self.instances
# Short circuit if we've already gathered this information
return @instance_array if @instance_array

require 'puppetx/augeasproviders_grub/menuentry'

grub2_config = PuppetX::AugeasprovidersGrub::Util.grub2_cfg

all_users = extract_users(grub2_config)
all_users = extract_users(grub2_cfg)

@instance_array = all_users.collect{|x| x = new(x)}

Expand Down Expand Up @@ -98,6 +114,10 @@ def self.post_resource_eval
@already_reported = nil
end

def initialize(args)
super
end

def exists?
# Make sure that we don't have any issues with the file.
if File.exist?(resource[:target])
Expand Down Expand Up @@ -203,6 +223,13 @@ def purge
end

def flush
# This is to clean up the legacy file that was put in place incorrectly
# prior to the standard 01_users configuration file
legacy_file = '/etc/grub.d/01_puppet_managed_users'
unless resource[:target] == legacy_file
File.unlink(legacy_file) if File.exist?(legacy_file)
end

output = []

output << <<-EOM
Expand All @@ -211,7 +238,7 @@ def flush
# This file managed by Puppet
# Manual changes will be erased!
########
exec tail -n +3 $0
cat << USER_LIST
EOM

# Build the password file
Expand Down Expand Up @@ -241,6 +268,7 @@ def flush
end

output += users
output << 'USER_LIST'

output = output.join("\n")

Expand All @@ -256,30 +284,7 @@ def flush
FileUtils.chmod(0755, resource[:target])
end

os_info = Facter.value(:os)
if os_info
os_name = Facter.value(:os)['name']
else
# Support for old versions of Facter
unless os_name
os_name = Facter.value(:operatingsystem)
end
end

cfg = nil
[
"/etc/grub2-efi.cfg",
# Handle the standard EFI naming convention
"/boot/efi/EFI/#{os_name.downcase}/grub.cfg",
"/etc/grub2.cfg",
"/boot/grub/grub.cfg",
"/boot/grub2/grub.cfg"
].each {|c|
cfg = c if FileTest.file? c
}
fail("Cannot find grub.cfg location to use with #{command(:mkconfig)}") unless cfg

mkconfig "-o", cfg
mkconfig "-o", grub2_cfg_path
end

private
Expand Down
6 changes: 2 additions & 4 deletions lib/puppet/type/grub_user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,17 @@
EOM

newvalues(:true, :false)

defaultto(:false)
end

newparam(:target) do
newparam(:target, :parent => Puppet::Parameter::Path) do
desc <<-EOM
The file to which to write the user information.
Must be an absolute path.
EOM

newvalues(/^\/.+/)
defaultto('/etc/grub.d/01_puppet_managed_users')
defaultto('/etc/grub.d/02_puppet_managed_users')
end

newparam(:report_unmanaged, :boolean => true) do
Expand Down
36 changes: 30 additions & 6 deletions lib/puppetx/augeasproviders_grub/menuentry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,21 +125,45 @@ def self.munge_grubby_value(value, flavor, grubby_info)
# Raise an error if not found.
#
# @return (String) The full path to the GRUB2 configuration file.
def self.grub2_cfg
def self.grub2_cfg_path
paths = [
'/boot/grub2/grub.cfg',
'/boot/grub/grub.cfg',
'/etc/grub2-efi.cfg',
'/etc/grub2.cfg'
'/etc/grub2.cfg',
'/boot/grub2/grub.cfg'
]

if File.exist?('/sys/firmware/efi')
os_info = Facter.value(:os)
if os_info
os_name = Facter.value(:os)['name']
else
# Support for old versions of Facter
unless os_name
os_name = Facter.value(:operatingsystem)
end
end

paths = [
'/etc/grub2-efi.cfg',
# Handle the standard EFI naming convention
"/boot/efi/EFI/#{os_name.downcase}/grub.cfg"
] + paths
end

paths.each do |path|
return File.read(path) if (File.readable?(path) && !File.directory?(path))
return path if (File.readable?(path) && !File.directory?(path))
end

raise Puppet::Error, 'Could not find a GRUB2 configuration on the system'
end

# Return the contents of the GRUB2 configuration on the system.
# Raise an error if not found.
#
# @return (String) The contents of the GRUB2 configuration on the system.
def self.grub2_cfg
return File.read(grub2_cfg_path)
end

# Return a list of options that have the kernel path prepended and are
# formatted with all processing arguments handled.
#
Expand Down
9 changes: 8 additions & 1 deletion metadata.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "herculesteam-augeasproviders_grub",
"version": "3.0.0",
"version": "3.0.1",
"author": "Dominic Cleal, Raphael Pinson, Trevor Vaughan",
"summary": "Augeas-based grub types and providers for Puppet",
"license": "Apache-2.0",
Expand Down Expand Up @@ -48,6 +48,13 @@
"6",
"7"
]
},
{
"operatingsystem": "OracleLinux",
"operatingsystemrelease": [
"6",
"7"
]
}
],
"requirements": [
Expand Down
File renamed without changes.
153 changes: 153 additions & 0 deletions spec/acceptance/05_grub2_users_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
require 'spec_helper_acceptance'

test_name 'Augeasproviders Grub'

describe 'GRUB2 User Tests' do
hosts_with_role(hosts, 'grub2').each do |host|
let(:target_files) {
[
'/etc/grub.d/02_puppet_managed_users',
'/etc/grub2.cfg'
]
}

let(:password_info) {{
:plain_password => 'really bad password',
:hashed_password => 'grub.pbkdf2.sha512.10000.3ED7C861BA4107282E3A55FC80B549995D105324F2CB494BBF34DE86517DFCB8DCFCA3E0C3550C64F9A259B516BFDD928C0FAC4E66CFDA351A957D702EE32C3D.C589ED8757DB23957A5F946470A58CF216A7507634647E532BC68085AAA52622AB4E6E151CF60CD8409166F6581FC166CE4D4845D61353A4C439C2170CC25747',
:hashed_password_20k => 'grub.pbkdf2.sha512.20000.4CD886B13634E03CF533C3F4C27E59E8F67D9C62915C04E03B019651FFB1DE8BE9EBB09B0D5759CF94A502566D748C28E9AF2150E81BFF1202E66D3C417A28A1.62E1AE32B4746DCBF222EB22FA670D35E7FAAD438677D67A0A1275E79430CF4E0F31EBF2186E645E922109B973CFF9A71BD53DCA77D9E749BDEC302022FD00BE'
}}

context 'set a user on the system with a plain text password' do
let(:manifest) { %(
grub_user { 'test_user1':
password => '#{password_info[:plain_password]}'
}
)}

let(:legacy_file) { '/etc/grub.d/01_puppet_managed_users' }

# With a legacy file to be removed
it 'should have a legacy file' do
create_remote_file(host, legacy_file , '# Legacy File')
end

# Using puppet_apply as a helper
it 'should work with no errors' do
apply_manifest_on(host, manifest, :catch_failures => true)
end

it 'should have removed the legacy file' do
expect(host.file_exist?(legacy_file)).to be false
end

it 'should be idempotent' do
apply_manifest_on(host, manifest, {:catch_changes => true})
end

it 'should set an encrypted password' do
target_files.each do |target_file|
result = on(host, %(grep 'password_pbkdf2 test_user1' #{target_file})).stdout

password_identifier, user, password_hash = result.split(/\s+/)
expect(user).to eql('test_user1')
expect(password_hash).to match(/grub\.pbkdf2\.sha512\.10000\..*/)
end
end
end

context 'set a user on the system with a hashed password' do
let(:manifest) { %(
grub_user { 'test_user1':
password => '#{password_info[:hashed_password]}'
}
)}

# Using puppet_apply as a helper
it 'should work with no errors' do
apply_manifest_on(host, manifest, :catch_failures => true)
end

it 'should be idempotent' do
apply_manifest_on(host, manifest, :catch_changes => true)
end

it 'should set an encrypted password' do
target_files.each do |target_file|
result = on(host, %(grep 'password_pbkdf2 test_user1' #{target_file})).stdout

password_identifier, user, password_hash = result.split(/\s+/)
expect(user).to eql('test_user1')
expect(password_hash).to eql(password_info[:hashed_password])
end
end
end

context 'set a user on the system with a hashed password with 20000 rounds' do
let(:manifest) { %(
grub_user { 'test_user1':
password => '#{password_info[:hashed_password_20k]}',
rounds => '20000'
}
)}

# Using puppet_apply as a helper
it 'should work with no errors' do
apply_manifest_on(host, manifest, :catch_failures => true)
end

it 'should be idempotent' do
apply_manifest_on(host, manifest, {:catch_changes => true})
end

it 'should set an encrypted password' do
target_files.each do |target_file|
result = on(host, %(grep 'password_pbkdf2 test_user1' #{target_file})).stdout

password_identifier, user, password_hash = result.split(/\s+/)
expect(user).to eql('test_user1')
expect(password_hash).to eql(password_info[:hashed_password_20k])
end
end
end

context 'should purge any users when purge is set' do
let(:manifest) { %(
grub_user { 'test_user1':
password => '#{password_info[:hashed_password]}',
purge => true
}
)}

# Using puppet_apply as a helper
it 'should work with no errors' do
apply_manifest_on(host, manifest, :catch_failures => true)
end

it 'should be idempotent' do
apply_manifest_on(host, manifest, {:catch_changes => true})
end

it 'should purge unmanaged users' do
on(host, %(puppet resource grub_user bad_user password='some password'))

result = apply_manifest_on(host, manifest, :catch_failures => true).stdout
expect(result).to match(/Purged.*bad_user/)

target_files.each do |target_file|
result = on(host, %(grep 'password_pbkdf2 test_user1' #{target_file})).stdout

password_identifier, user, password_hash = result.split(/\s+/)
expect(user).to eql('test_user1')
expect(password_hash).to eql(password_info[:hashed_password])

result = on(
host,
%(grep 'password_pbkdf2 bad_user' #{target_file}),
:acceptable_exit_codes => [1]
).stdout
expect(result).to be_empty
end
end
end
end
end
Loading

0 comments on commit e773a9a

Please sign in to comment.