From ebaf6020e2a1b1f8f37661047b6da5371618fe39 Mon Sep 17 00:00:00 2001 From: Leo Arnold Date: Sun, 2 Sep 2018 02:51:09 +0200 Subject: [PATCH] WIP --- manifests/init.pp | 3 +- spec/classes/init_spec.rb | 99 +++++++++++++- spec/fixtures/files/cupsd.conf.default | 122 ++++++++++++++++++ spec/spec_helper.rb | 6 + templates/cupsd.conf.erb | 170 ++++++++++++++++--------- 5 files changed, 337 insertions(+), 63 deletions(-) create mode 100644 spec/fixtures/files/cupsd.conf.default diff --git a/manifests/init.pp b/manifests/init.pp index 05899cb0..919d6f39 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -50,13 +50,14 @@ Boolean $package_manage = true, Variant[String, Array[String]] $package_names = $::cups::params::package_names, Optional[String] $papersize = undef, + Hash $policies = {}, Boolean $purge_unmanaged_queues = false, Optional[Hash] $resources = undef, Boolean $service_enable = true, String $service_ensure = 'running', Boolean $service_manage = true, Variant[String, Array[String]] $service_names = 'cups', - Optional[Boolean] $web_interface = undef, + Optional[Boolean] $web_interface = true, ) inherits cups::params { contain cups::packages diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb index 254122bb..b77c1584 100644 --- a/spec/classes/init_spec.rb +++ b/spec/classes/init_spec.rb @@ -11,11 +11,13 @@ listen: ['localhost:631', '/var/run/cups/cups.sock'], package_ensure: 'present', package_manage: 'true', + policies: {}, purge_unmanaged_queues: 'false', service_enable: 'true', service_ensure: 'running', service_manage: 'true', - service_names: 'cups' + service_names: 'cups', + web_interface: true } end @@ -24,10 +26,11 @@ default_queue papersize resources - web_interface ] end + let(:content) { file_fixture('cupsd.conf.default').read } + it { is_expected.to contain_class('cups::params') } it { is_expected.to contain_class('cups').with(defaults) } @@ -46,7 +49,7 @@ it { is_expected.to contain_file('/etc/cups/cupsd.conf').with(mode: '0640') } - it { is_expected.to contain_file('/etc/cups/cupsd.conf').with(content: /\A#.*DO NOT/) } + it { is_expected.to contain_file('/etc/cups/cupsd.conf').with(content: content) } it { is_expected.to contain_class('cups::server').that_requires('Class[cups::packages]') } @@ -232,6 +235,96 @@ end end + describe 'policies' do + let(:facts) { any_supported_os } + + context 'when modifying the default policy' do + context 'when setting JobPrivateAccess to all' do + let(:params) { { policies: { 'default' => { 'JobPrivateAccess' => 'all' } } } } + let(:content) { %r{.*?^\s*JobPrivateAccess all$.*?}m } + + it { is_expected.to contain_file('/etc/cups/cupsd.conf').with(content: content) } + end + + context 'when setting JobPrivateValues to none' do + let(:params) { { policies: { 'default' => { 'JobPrivateValues' => 'none' } } } } + let(:content) { %r{.*?^\s*JobPrivateValues none$.*?}m } + + it { is_expected.to contain_file('/etc/cups/cupsd.conf').with(content: content) } + end + + context 'when setting SubscriptionPrivateAccess to all' do + let(:params) { { policies: { 'default' => { 'SubscriptionPrivateAccess' => 'all' } } } } + let(:content) { %r{.*?^\s*SubscriptionPrivateAccess all$.*?}m } + + it { is_expected.to contain_file('/etc/cups/cupsd.conf').with(content: content) } + end + + context 'when setting SubscriptionPrivateValues to none' do + let(:params) { { policies: { 'default' => { 'SubscriptionPrivateValues' => 'none' } } } } + let(:content) { %r{.*?^\s*SubscriptionPrivateValues none$.*?}m } + + it { is_expected.to contain_file('/etc/cups/cupsd.conf').with(content: content) } + end + + context 'when modifying a Limit' do + let(:params) do + { + policies: { + 'default' => { + 'Limit' => { + 'Create-Job' => { + 'AuthType' => 'Negotiate', + 'Order' => 'deny,allow' + } + } + } + } + } + end + let(:content) { %r{.*?]*Create-Job[^>]*>\s*AuthType Negotiate\s*Order deny,allow\s*.*?}m } + + it { is_expected.to contain_file('/etc/cups/cupsd.conf').with(content: content) } + end + end + + context 'when adding a custom policy' do + context 'with an empty hash as value' do + let(:params) { { policies: { 'lab999' => {} } } } + + it { is_expected.to contain_file('/etc/cups/cupsd.conf').with(content: %r{^.*$}m) } + end + + context 'when setting JobPrivateAccess to all' do + let(:params) { { policies: { 'lab999' => { 'JobPrivateAccess' => 'all' } } } } + let(:content) { %r{.*?^\s*JobPrivateAccess all$.*?}m } + + it { is_expected.to contain_file('/etc/cups/cupsd.conf').with(content: content) } + end + + context 'when setting JobPrivateValues to none' do + let(:params) { { policies: { 'lab999' => { 'JobPrivateValues' => 'none' } } } } + let(:content) { %r{.*?^\s*JobPrivateValues none$.*?}m } + + it { is_expected.to contain_file('/etc/cups/cupsd.conf').with(content: content) } + end + + context 'when setting SubscriptionPrivateAccess to all' do + let(:params) { { policies: { 'lab999' => { 'SubscriptionPrivateAccess' => 'all' } } } } + let(:content) { %r{.*?^\s*SubscriptionPrivateAccess all$.*?}m } + + it { is_expected.to contain_file('/etc/cups/cupsd.conf').with(content: content) } + end + + context 'when setting SubscriptionPrivateValues to none' do + let(:params) { { policies: { 'lab999' => { 'SubscriptionPrivateValues' => 'none' } } } } + let(:content) { %r{.*?^\s*SubscriptionPrivateValues none$.*?}m } + + it { is_expected.to contain_file('/etc/cups/cupsd.conf').with(content: content) } + end + end + end + describe 'purge_unmanaged_queues' do let(:facts) { any_supported_os } diff --git a/spec/fixtures/files/cupsd.conf.default b/spec/fixtures/files/cupsd.conf.default new file mode 100644 index 00000000..e3918f01 --- /dev/null +++ b/spec/fixtures/files/cupsd.conf.default @@ -0,0 +1,122 @@ +# This file is managed by Puppet. DO NOT EDIT. +LogLevel warn +PageLogFormat +MaxLogSize 0 +Listen localhost:631 +Listen /var/run/cups/cups.sock +Browsing Off +BrowseLocalProtocols dnssd +DefaultAuthType Basic +WebInterface Yes + + Order allow,deny + + + Order allow,deny + + + AuthType Default + Require user @SYSTEM + Order allow,deny + + + AuthType Default + Require user @SYSTEM + Order allow,deny + + + JobPrivateAccess default + JobPrivateValues default + SubscriptionPrivateAccess default + SubscriptionPrivateValues default + + Order deny,allow + + + Require user @OWNER @SYSTEM + Order deny,allow + + + AuthType Default + Require user @SYSTEM + Order deny,allow + + + AuthType Default + Require user @SYSTEM + Order deny,allow + + + Require user @OWNER @SYSTEM + Order deny,allow + + + Order deny,allow + + + + JobPrivateAccess default + JobPrivateValues default + SubscriptionPrivateAccess default + SubscriptionPrivateValues default + + AuthType Default + Order deny,allow + + + AuthType Default + Require user @OWNER @SYSTEM + Order deny,allow + + + AuthType Default + Require user @SYSTEM + Order deny,allow + + + AuthType Default + Require user @SYSTEM + Order deny,allow + + + AuthType Default + Require user @OWNER @SYSTEM + Order deny,allow + + + Order deny,allow + + + + JobPrivateAccess default + JobPrivateValues default + SubscriptionPrivateAccess default + SubscriptionPrivateValues default + + AuthType Negotiate + Order deny,allow + + + AuthType Negotiate + Require user @OWNER @SYSTEM + Order deny,allow + + + AuthType Default + Require user @SYSTEM + Order deny,allow + + + AuthType Default + Require user @SYSTEM + Order deny,allow + + + AuthType Negotiate + Require user @OWNER @SYSTEM + Order deny,allow + + + Order deny,allow + + diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 333a3af3..af9fcd4d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -62,3 +62,9 @@ def any_supported_os(morefacts = {}) Dir["#{PROJECT_ROOT}/lib/puppet_x/**/*.rb"].each do |file| require file end + +def file_fixture(*relative_path) + path = File.expand_path(File.join(__dir__, 'fixtures', 'files', *relative_path)) + + Pathname.new(path) +end diff --git a/templates/cupsd.conf.erb b/templates/cupsd.conf.erb index 36863280..29d7cc84 100644 --- a/templates/cupsd.conf.erb +++ b/templates/cupsd.conf.erb @@ -26,66 +26,118 @@ DefaultAuthType Basic Require user @SYSTEM Order allow,deny - - JobPrivateAccess default - JobPrivateValues default - SubscriptionPrivateAccess default - SubscriptionPrivateValues default - - Order deny,allow - - - Require user @OWNER @SYSTEM - Order deny,allow - - - AuthType Default - Require user @SYSTEM - Order deny,allow - - - AuthType Default - Require user @SYSTEM - Order deny,allow - - - Require user @OWNER @SYSTEM - Order deny,allow - - - Order deny,allow - - - - JobPrivateAccess default - JobPrivateValues default - SubscriptionPrivateAccess default - SubscriptionPrivateValues default - - AuthType Default - Order deny,allow - - - AuthType Default - Require user @OWNER @SYSTEM - Order deny,allow - - - AuthType Default - Require user @SYSTEM - Order deny,allow - - - AuthType Default - Require user @SYSTEM - Order deny,allow - - - AuthType Default - Require user @OWNER @SYSTEM - Order deny,allow +<% + default_policies = { + 'default' => { + 'JobPrivateAccess' => 'default', + 'JobPrivateValues' => 'default', + 'SubscriptionPrivateAccess' => 'default', + 'SubscriptionPrivateValues' => 'default', + 'Limit' => { + %w[Create-Job Print-Job Print-URI Validate-Job] => { 'Order' => 'deny,allow' }, + %w[Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document] => { 'Require' => 'user @OWNER @SYSTEM', 'Order' => 'deny,allow' }, + %w[CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default CUPS-Get-Devices] => { 'AuthType' => 'Default', 'Require' => 'user @SYSTEM', 'Order' => 'deny,allow' }, + %w[Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs] => { 'AuthType' => 'Default', 'Require' => 'user @SYSTEM', 'Order' => 'deny,allow' }, + %w[Cancel-Job CUPS-Authenticate-Job] => { 'Require' => 'user @OWNER @SYSTEM', 'Order' => 'deny,allow' }, + 'All' => { 'Order' => 'deny,allow' } + } + }, + 'authenticated' => { + 'JobPrivateAccess' => 'default', + 'JobPrivateValues' => 'default', + 'SubscriptionPrivateAccess' => 'default', + 'SubscriptionPrivateValues' => 'default', + 'Limit' => { + %w[Create-Job Print-Job Print-URI Validate-Job] => { 'AuthType' => 'Default', 'Order' => 'deny,allow' }, + %w[Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document] => { 'AuthType' => 'Default', 'Require' => 'user @OWNER @SYSTEM', 'Order' => 'deny,allow' }, + %w[CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default] => { 'AuthType' => 'Default', 'Require' => 'user @SYSTEM', 'Order' => 'deny,allow' }, + %w[Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs] => { 'AuthType' => 'Default', 'Require' => 'user @SYSTEM', 'Order' => 'deny,allow' }, + %w[Cancel-Job CUPS-Authenticate-Job] => { 'AuthType' => 'Default', 'Require' => 'user @OWNER @SYSTEM', 'Order' => 'deny,allow' }, + 'All' => { 'Order' => 'deny,allow' } + } + }, + 'kerberos' => { + 'JobPrivateAccess' => 'default', + 'JobPrivateValues' => 'default', + 'SubscriptionPrivateAccess' => 'default', + 'SubscriptionPrivateValues' => 'default', + 'Limit' => { + %w[Create-Job Print-Job Print-URI Validate-Job] => { 'AuthType' => 'Negotiate', 'Order' => 'deny,allow' }, + %w[Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document] => { 'AuthType' => 'Negotiate', 'Require' => 'user @OWNER @SYSTEM', 'Order' => 'deny,allow' }, + %w[CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default] => { 'AuthType' => 'Default', 'Require' => 'user @SYSTEM', 'Order' => 'deny,allow' }, + %w[Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs] => { 'AuthType' => 'Default', 'Require' => 'user @SYSTEM', 'Order' => 'deny,allow' }, + %w[Cancel-Job CUPS-Authenticate-Job] => { 'AuthType' => 'Negotiate', 'Require' => 'user @OWNER @SYSTEM', 'Order' => 'deny,allow' }, + 'All' => { 'Order' => 'deny,allow' } + } + } + } + + policies = default_policies + + overridden_policies = default_policies.keys & @policies.keys + overridden_policies.each do |policy| + if @policies[policy]['Limit'].is_a?(Hash) && !@policies[policy]['Limit'].empty? + default_limits = default_policies[policy]['Limit'] + desired_limits = @policies[policy].delete('Limit') + + actions = (default_limits.keys.flatten | desired_limits.keys.flatten) + limits = {} + actions.each do |action| + limits[action] = (desired_limits.find { |k, _v| k.include?(action) } || [])[1] || default_limits.find { |k, _v| k.include?(action) }[1] + end + + policies[policy]['Limit'] = { 'All' => limits.delete('All') } + limits.values.uniq.each do |v| + actions = limits.keys.select { |k| limits[k] == v } + policies[policy]['Limit'][actions] = v + end + end + + policies[policy].merge!(@policies[policy]) + end + + custom_policies = @policies.keys - default_policies.keys + custom_policies.each do |policy| + policies[policy] = default_policies['default'].dup + + if @policies[policy]['Limit'].is_a?(Hash) && !@policies[policy]['Limit'].empty? + default_limits = default_policies['default']['Limit'] + desired_limits = @policies[policy].delete('Limit') + + actions = (default_limits.keys.flatten | desired_limits.keys.flatten) + limits = {} + actions.each do |action| + limit[action] = (desired_limits.find { |k, _v| k.include?(action) } || [])[1] || default_limits.find { |k, _v| k.include?(action) }[1] + end + + policies[policy]['Limit'] = { 'All' => limits['All'] } + limits.values.uniq.each do |v| + actions = limits.keys.select { |k| limits[k] == v } - ['All'] + policies[policy]['Limit'][actions] = v + end + end + + policies[policy].merge!(@policies[policy]) + end +-%> +<% policies.each do |policy, config| -%> +> + JobPrivateAccess <%= config['JobPrivateAccess'] %> + JobPrivateValues <%= config['JobPrivateValues'] %> + SubscriptionPrivateAccess <%= config['SubscriptionPrivateAccess'] %> + SubscriptionPrivateValues <%= config['SubscriptionPrivateValues'] %> +<% config['Limit'].each do |actions, restrictions| -%> +<% next if actions == 'All' -%> +<%= " " %> +<% restrictions.each do |k, v| -%> +<%= " #{k} #{v}" %> +<% end -%> +<% end -%> - Order deny,allow +<% config['Limit']['All'].each do |k, v| -%> +<%= " #{k} #{v}" %> +<% end -%> +<% end -%>