diff --git a/lib/puppet/provider/f5_passwordpolicy/rest.rb b/lib/puppet/provider/f5_passwordpolicy/rest.rb new file mode 100644 index 0000000..c6bd76a --- /dev/null +++ b/lib/puppet/provider/f5_passwordpolicy/rest.rb @@ -0,0 +1,58 @@ +require File.join(File.dirname(__FILE__), '../f5') +require 'json' + +Puppet::Type.type(:f5_passwordpolicy).provide(:rest, parent: Puppet::Provider::F5) do + mk_resource_methods + + def self.instances + instances = [] + instances << new(password_policy_properties) + instances + end + + def self.prefetch(resources) + raise 'More than 1 f5_passwordpolicy resource in catalog' unless resources.size == 1 + resource = resources.values[0] + resource.provider = instances.first + end + + def self.password_policy_properties + properties = {} + policy = Puppet::Provider::F5.call('/mgmt/tm/auth/password-policy') + + properties[:name] = '/Common/password-policy' + %w[expirationWarning maxDuration maxLoginFailures minDuration minimumLength passwordMemory policyEnforcement requiredLowercase requiredNumeric requiredSpecial requiredUppercase].each do |property| + properties[property.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase.to_sym] = policy[property] + end + properties[:provider] = :rest + properties + end + + def strip_puppet_keys(hash) + # Remove puppet keys from resource hash. + hash.reject do |k, _| + [:ensure, :name, :provider, Puppet::Type.metaparams].flatten.include?(k) + end + end + + # Expects a puppet resource property_hash and returns a payload suitable for posting to the F5 API. + def message(resource) + message = strip_nil_values(resource) + message = convert_underscores(message) + message = strip_puppet_keys(message) + message = string_to_integer(message) + message.to_json + end + + def flush + begin + Puppet::Provider::F5.put('/mgmt/tm/auth/password-policy/', + message(@property_hash)) + rescue StandardError => e + # Something went wrong. + @property_hash = self.class.password_policy_properties + raise e + end + @property_hash = self.class.password_policy_properties + end +end diff --git a/lib/puppet/type/f5_passwordpolicy.rb b/lib/puppet/type/f5_passwordpolicy.rb new file mode 100644 index 0000000..a430d78 --- /dev/null +++ b/lib/puppet/type/f5_passwordpolicy.rb @@ -0,0 +1,73 @@ +Puppet::Type.newtype(:f5_passwordpolicy) do + @doc = 'Sets the password policy on the BIG-IP system.' + + apply_to_device if Facter.value(:url).nil? + + newparam(:name, namevar: true) do + end + + newproperty(:expiration_warning) do + newvalues(/^\d+$/) + munge { |value| Integer(value) } + end + + newproperty(:max_duration) do + newvalues(/^\d+$/) + munge { |value| Integer(value) } + end + + newproperty(:max_login_failures) do + newvalues(/^\d+$/) + munge { |value| Integer(value) } + end + + newproperty(:min_duration) do + newvalues(/^\d+$/) + munge { |value| Integer(value) } + end + + newproperty(:minimum_length) do + newvalues(/^\d+$/) + munge { |value| Integer(value) } + end + + newproperty(:password_memory) do + newvalues(/^\d+$/) + munge { |value| Integer(value) } + end + + newproperty(:policy_enforcement) do + munge do |value| + value = value.downcase if value.respond_to? :downcase + + case value + when true, 'true', 'enabled' + 'enabled' + when false, 'false', 'disabled' + 'disabled' + else + raise ArgumentError, 'expected a boolean value, \'enabled\' or \'disabled\'' + end + end + end + + newproperty(:required_lowercase) do + newvalues(/^\d+$/) + munge { |value| Integer(value) } + end + + newproperty(:required_numeric) do + newvalues(/^\d+$/) + munge { |value| Integer(value) } + end + + newproperty(:required_special) do + newvalues(/^\d+$/) + munge { |value| Integer(value) } + end + + newproperty(:required_uppercase) do + newvalues(/^\d+$/) + munge { |value| Integer(value) } + end +end diff --git a/spec/acceptance/f5_passwordpolicy/rest_spec.rb b/spec/acceptance/f5_passwordpolicy/rest_spec.rb new file mode 100644 index 0000000..dff3473 --- /dev/null +++ b/spec/acceptance/f5_passwordpolicy/rest_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper_acceptance' + +describe 'f5_passwordpolicy' do + it 'sets password policy' do + pp = <<-MANIFEST + f5_passwordpolicy { '/Common/password-policy': + expiration_warning => 10, + max_duration => 99998, + max_login_failures => 0, + min_duration => 0, + minimum_length => 10, + password_memory => 0, + policy_enforcement => true, + required_lowercase => 2, + required_numeric => 1, + required_special => 1, + required_uppercase => 1, + } + MANIFEST + make_site_pp(pp) + run_device(allow_changes: true) + run_device(allow_changes: false) + end +end