diff --git a/CHANGELOG.md b/CHANGELOG.md index b82dd2ff..908d406a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org). +## [v7.12.0](https://github.com/treydock/puppet-module-keycloak/tree/v7.12.0) (2021-11-24) + +[Full Changelog](https://github.com/treydock/puppet-module-keycloak/compare/v7.11.1...v7.12.0) + +### Added + +- Add Realm properties and allow custom properties [\#228](https://github.com/treydock/puppet-module-keycloak/pull/228) ([treydock](https://github.com/treydock)) + ## [v7.11.1](https://github.com/treydock/puppet-module-keycloak/tree/v7.11.1) (2021-11-24) [Full Changelog](https://github.com/treydock/puppet-module-keycloak/compare/v7.11.0...v7.11.1) diff --git a/REFERENCE.md b/REFERENCE.md index 0977c6c5..c3bd53c9 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -3236,6 +3236,10 @@ contentSecurityPolicy Default value: `frame-src 'self'; frame-ancestors 'self'; object-src 'none';` +##### `custom_properties` + +custom properties to pass as realm configurations + ##### `default_client_scopes` Default Client Scopes @@ -3260,6 +3264,14 @@ dockerAuthenticationFlow Default value: `docker auth` +##### `edit_username_allowed` + +Valid values: ``true``, ``false`` + +editUsernameAllowed + +Default value: `false` + ##### `email_theme` emailTheme @@ -3438,6 +3450,14 @@ smtpServer starttls smtpServer user +##### `ssl_required` + +Valid values: `none`, `all`, `external` + +sslRequired + +Default value: `external` + ##### `sso_session_idle_timeout` ssoSessionIdleTimeout diff --git a/lib/puppet/provider/keycloak_api.rb b/lib/puppet/provider/keycloak_api.rb index 8b2b839b..3d8346b7 100644 --- a/lib/puppet/provider/keycloak_api.rb +++ b/lib/puppet/provider/keycloak_api.rb @@ -25,7 +25,7 @@ class << self end def self.type_properties - resource_type.validproperties.reject { |p| p.to_sym == :ensure } + resource_type.validproperties.reject { |p| [:ensure, :custom_properties].include? p.to_sym } end def type_properties diff --git a/lib/puppet/provider/keycloak_realm/kcadm.rb b/lib/puppet/provider/keycloak_realm/kcadm.rb index b685cc12..67128db5 100644 --- a/lib/puppet/provider/keycloak_realm/kcadm.rb +++ b/lib/puppet/provider/keycloak_realm/kcadm.rb @@ -136,6 +136,10 @@ def self.instances optional_scopes = get_client_scopes(realm[:name], 'optional') realm[:optional_client_scopes] = optional_scopes.keys.map { |k| k.to_s } realm[:roles] = get_realm_roles(realm[:name]) + realm[:custom_properties] = {} + d.each_pair do |k, v| + realm[:custom_properties][k] = v unless type_properties.include?(k.to_sym) + end realms << new(realm) end realms @@ -156,6 +160,9 @@ def create events_config = {} data[:id] = resource[:id] data[:realm] = resource[:name] + (resource[:custom_properties] || {}).each_pair do |k, v| + data[k] = v unless type_properties.include?(k.to_sym) + end type_properties.each do |property| next if flow_properties.include?(property) next if [:default_client_scopes, :optional_client_scopes, :roles].include?(property) @@ -316,6 +323,9 @@ def flush unless @property_flush.empty? data = {} events_config = {} + (@property_flush[:custom_properties] || resource[:custom_properties] || {}).each_pair do |k, v| + data[k] = v unless type_properties.include?(k.to_sym) + end type_properties.each do |property| next if [:default_client_scopes, :optional_client_scopes, :roles].include?(property) if flow_properties.include?(property) && !available_flows(resource[:name]).include?(resource[property.to_sym]) diff --git a/lib/puppet/type/keycloak_realm.rb b/lib/puppet/type/keycloak_realm.rb index ea0bf943..491f2cc6 100644 --- a/lib/puppet/type/keycloak_realm.rb +++ b/lib/puppet/type/keycloak_realm.rb @@ -164,6 +164,18 @@ defaultto :false end + newproperty(:ssl_required) do + desc 'sslRequired' + newvalues('none', 'all', 'external') + defaultto 'external' + end + + newproperty(:edit_username_allowed, boolean: true) do + desc 'editUsernameAllowed' + newvalues(:true, :false) + defaultto :false + end + newproperty(:browser_flow) do desc 'browserFlow' defaultto('browser') @@ -331,4 +343,44 @@ def insync?(is) super(is) end end + + newproperty(:custom_properties) do + desc 'custom properties to pass as realm configurations' + defaultto {} + + validate do |value| + # rubocop:disable Style/SignalException + fail 'custom_properties should be a Hash' unless value.is_a? ::Hash + value.each_pair do |_k, v| + fail 'custom_properties does not allow Hash values' if v.is_a? ::Hash + end + # rubocop:enable Style/SignalException + end + + def insync?(is) + should = @should + should = should[0] if should.is_a?(Array) + should.each_pair do |k, v| + return false unless is.key?(k) + case v + when String, TrueClass, FalseClass + return false if is[k].to_s != v.to_s + when Array + return false if is[k].sort != v.sort + end + end + true + end + + def change_to_s(currentvalue, newvalue) + currentvalue = currentvalue.to_s if currentvalue != :absent + newvalue = newvalue.to_s + super(currentvalue, newvalue) + end + + def is_to_s(currentvalue) # rubocop:disable Style/PredicateName + currentvalue.to_s + end + alias_method :should_to_s, :is_to_s + end end diff --git a/metadata.json b/metadata.json index 0e550702..43890587 100644 --- a/metadata.json +++ b/metadata.json @@ -1,6 +1,6 @@ { "name": "treydock-keycloak", - "version": "7.11.1", + "version": "7.12.0", "author": "treydock", "summary": "Keycloak Puppet module", "license": "Apache-2.0", diff --git a/spec/acceptance/2_realm_spec.rb b/spec/acceptance/2_realm_spec.rb index 5332f2db..a72cfc55 100644 --- a/spec/acceptance/2_realm_spec.rb +++ b/spec/acceptance/2_realm_spec.rb @@ -52,6 +52,8 @@ class { 'keycloak': expect(data['registrationAllowed']).to eq(false) expect(data['resetPasswordAllowed']).to eq(false) expect(data['verifyEmail']).to eq(false) + expect(data['sslRequired']).to eq('external') + expect(data['editUsernameAllowed']).to eq(false) end end @@ -182,6 +184,10 @@ class { 'keycloak': smtp_server_reply_to_display_name => 'Hostmaster', brute_force_protected => true, roles => ['uma_authorization', 'new_role', 'other_new_role'], + custom_properties => { + 'failureFactor' => 60, + 'revokeRefreshToken' => true, + }, } EOS @@ -221,6 +227,8 @@ class { 'keycloak': expect(data['smtpServer']['replyTo']).to eq('webmaster@example.org') expect(data['smtpServer']['replyToDisplayName']).to eq('Hostmaster') expect(data['bruteForceProtected']).to eq(true) + expect(data['failureFactor']).to eq(60) + expect(data['revokeRefreshToken']).to eq(true) end end diff --git a/spec/unit/puppet/type/keycloak_realm_spec.rb b/spec/unit/puppet/type/keycloak_realm_spec.rb index 29736ece..a9141a77 100644 --- a/spec/unit/puppet/type/keycloak_realm_spec.rb +++ b/spec/unit/puppet/type/keycloak_realm_spec.rb @@ -39,6 +39,9 @@ enabled: :true, remember_me: :false, login_with_email_allowed: :true, + ssl_required: 'external', + registration_allowed: :false, + edit_username_allowed: :false, browser_flow: 'browser', registration_flow: 'registration', direct_grant_flow: 'direct grant', @@ -128,6 +131,7 @@ :reset_password_allowed, :verify_email, :login_with_email_allowed, + :edit_username_allowed, :internationalization_enabled, :manage_roles, :events_enabled, @@ -188,6 +192,23 @@ end end + describe 'custom_properties' do + it 'allow custom properties' do + config[:custom_properties] = { 'foo' => 'bar' } + expect(resource[:custom_properties]).to eq('foo' => 'bar') + end + + it 'is in sync with default' do + config[:custom_properties] = {} + expect(resource.property(:custom_properties).insync?('foo' => 'bar')).to eq(true) + end + + it 'is in sync with defined properties' do + config[:custom_properties] = { 'foo' => 'bar' } + expect(resource.property(:custom_properties).insync?('foo' => 'bar', 'bar' => 'baz')).to eq(true) + end + end + it 'autorequires keycloak_conn_validator' do keycloak_conn_validator = Puppet::Type.type(:keycloak_conn_validator).new(name: 'keycloak') catalog = Puppet::Resource::Catalog.new