Skip to content

Commit

Permalink
Adjust keycloak_required_action resource to not use metaparameter alias
Browse files Browse the repository at this point in the history
  • Loading branch information
TuningYourCode committed Sep 24, 2024
1 parent 078b5cc commit 36a277c
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 24 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -603,9 +603,9 @@ The path for `install_dir` will be joined with `bin/kcadm.sh` to produce the ful
The keycloak_required_action type can be used to define actions a user must perform during the authentication process.
A user will not be able to complete the authentication process until these actions are complete. For instance, change a one-time password, accept T&C, etc.

The name for an action is `$alias on $realm`.
The name for an action is `$provider_id on $realm`.

**Important**: actions from puppet config and from a server are matched based on a combination of alias and realm, so edition of aliases is not supported.
**Important**: The keycloak rest api documentation uses the term `alias` which will be filled with the value of `provider_id` in this module.

```puppet
# Minimal example
Expand Down
16 changes: 6 additions & 10 deletions lib/puppet/provider/keycloak_required_action/kcadm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def self.prefetch(resources)
action_providers = instances
resources.each_key do |name|
provider = action_providers.find do |c|
c.alias == resources[name][:alias] && c.realm == resources[name][:realm]
c.provider_id == resources[name][:provider_id] && c.realm == resources[name][:realm]
end
if provider
resources[name].provider = provider
Expand All @@ -34,7 +34,6 @@ def self.instances
required_actions.each do |a|
action = {
ensure: :present,
alias: a['alias'],
display_name: a['name'],
realm: realm,
enabled: a['enabled'],
Expand All @@ -61,7 +60,6 @@ def self.instances
unregistered_actions.each do |a|
action = {
ensure: :absent,
alias: a['providerId'],
display_name: a['name'],
realm: realm,
enabled: false,
Expand Down Expand Up @@ -105,18 +103,17 @@ def create
# Asigning property_flush to is needed to make the flush method to
# configure properties of the required action after the registration.
@property_flush = resource.to_hash
@property_hash[:alias] = resource[:provider_id] # Initially it's equal to the provider id until configuration is applied to it
@property_hash[:ensure] = :present
end

def destroy
Puppet.debug('Keycloak required action: destroy')
begin
kcadm('delete', "authentication/required-actions/#{@property_hash[:alias]}", resource[:realm])
kcadm('delete', "authentication/required-actions/#{@property_hash[:provider_id]}", resource[:realm])
rescue StandardError => e
raise Puppet::Error, "kcadm deletion of required action failed\nError message: #{e.message}"
end
Puppet.info("Keycloak: deregistered required action #{@property_hash[:alias]} for #{resource[:realm]}")
Puppet.info("Keycloak: deregistered required action #{@property_hash[:provider_id]} for #{resource[:realm]}")
@property_hash.clear
end

Expand All @@ -130,16 +127,16 @@ def flush

begin
t = Tempfile.new('keycloak_required_action_configure')
t.write(JSON.pretty_generate(alias: resource[:alias],
t.write(JSON.pretty_generate(alias: resource[:provider_id],
name: resource[:display_name] || @property_hash[:display_name],
enabled: resource[:enabled],
priority: resource[:priority],
config: resource[:config] || {},
defaultAction: resource[:default]))
t.close
Puppet.debug(IO.read(t.path))
kcadm('update', "authentication/required-actions/#{@property_hash[:alias]}", resource[:realm], t.path)
Puppet.info("Keycloak: configured required action #{@property_hash[:alias]} (provider #{resource[:provider_id]}) for #{resource[:realm]}")
kcadm('update', "authentication/required-actions/#{@property_hash[:provider_id]}", resource[:realm], t.path)
Puppet.info("Keycloak: configured required action #{@property_hash[:display_name]} (provider #{resource[:provider_id]}) for #{resource[:realm]}")
rescue StandardError => e
raise Puppet::Error, "kcadm configuration of required action failed\nError message: #{e.message}"
end
Expand All @@ -150,7 +147,6 @@ def flush

def to_keycloak_representation(resource)
{
alias: resource[:alias],
name: resource[:display_name],
realm: resource[:realm],
providerId: resource[:provider_id],
Expand Down
16 changes: 4 additions & 12 deletions lib/puppet/type/keycloak_required_action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
@example Enable Webauthn Register and make it default
keycloak_required_action { 'webauthn-register on master':
ensure => present,
alias => 'webauthn-register',
provider_id => 'webauthn-register',
display_name => 'Webauthn Register',
default => true,
Expand Down Expand Up @@ -40,16 +39,9 @@
desc 'realm'
end

newparam(:alias, namevar: true) do
desc 'Alias.'
end

newparam(:provider_id) do
desc 'providerId of the required action. Default to `alias`'
newparam(:provider_id, namevar: true) do
desc 'providerId of the required action.'
munge { |v| v.to_s }
defaultto do
@resource[:alias]
end
end

newproperty(:display_name) do
Expand Down Expand Up @@ -107,7 +99,7 @@ def self.title_patterns
%r{^((\S+) on (\S+))$},
[
[:name],
[:alias],
[:provider_id],
[:realm]
]
],
Expand All @@ -122,7 +114,7 @@ def self.title_patterns

validate do
required_properties = [
:alias,
:provider_id,
:realm
]
required_properties.each do |property|
Expand Down
27 changes: 27 additions & 0 deletions spec/acceptance/10_required_action_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,31 @@ class { 'keycloak': }
end
end
end

context 'manage required action with multiple realms' do

Check failure on line 91 in spec/acceptance/10_required_action_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet 7 (Ruby 2.7.8 fixtures=.fixtures.yml)

RSpec/ContextWording: Context description should match /^when\b/, /^with\b/, or /^without\b/. (https://rspec.rubystyle.guide/#context-descriptions, https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording)

Check failure on line 91 in spec/acceptance/10_required_action_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet 8 (Ruby 3.2.3 fixtures=.fixtures.yml)

RSpec/ContextWording: Context description should match /^when\b/, /^with\b/, or /^without\b/. (https://rspec.rubystyle.guide/#context-descriptions, https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording)

Check failure on line 91 in spec/acceptance/10_required_action_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet 7 (Ruby 2.7.7 fixtures=.fixtures-latest.yml)

RSpec/ContextWording: Context description should match /^when\b/, /^with\b/, or /^without\b/. (https://rspec.rubystyle.guide/#context-descriptions, https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording)

Check failure on line 91 in spec/acceptance/10_required_action_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet 8 (Ruby 3.2.2 fixtures=.fixtures-latest.yml)

RSpec/ContextWording: Context description should match /^when\b/, /^with\b/, or /^without\b/. (https://rspec.rubystyle.guide/#context-descriptions, https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording)
it 'runs successfully' do
pp = <<-PUPPET_PP
class { 'keycloak': }
keycloak_realm { 'test': ensure => 'present' }
keycloak_realm { 'test2': ensure => 'present' }
keycloak_required_action { 'webauthn-register on test':
ensure => 'present',
display_name => 'Webauthn Register',
default => true,
enabled => true,
priority => 200,
}
keycloak_required_action { 'webauthn-register on test2':
ensure => 'present',
display_name => 'Webauthn Register',
default => true,
enabled => true,
priority => 200,
}
PUPPET_PP

apply_manifest(pp, catch_failures: true)
apply_manifest(pp, catch_changes: true)
end
end
end

0 comments on commit 36a277c

Please sign in to comment.