diff --git a/spec/acceptance/2_realm_spec.rb b/spec/acceptance/2_realm_spec.rb index 9ff8470..18d9616 100644 --- a/spec/acceptance/2_realm_spec.rb +++ b/spec/acceptance/2_realm_spec.rb @@ -1,191 +1,194 @@ require 'spec_helper_acceptance' describe 'keycloak_realm:', if: RSpec.configuration.keycloak_full do context 'creates realm' do it 'runs successfully' do pp = <<-EOS include mysql::server class { 'keycloak': datasource_driver => 'mysql', } keycloak_realm { 'test': ensure => 'present', smtp_server_host => 'smtp.example.org', smtp_server_port => 587, smtp_server_starttls => false, smtp_server_auth => false, smtp_server_user => 'john', smtp_server_password => 'secret', smtp_server_envelope_from => 'keycloak@id.example.org', smtp_server_from => 'keycloak@id.example.org', smtp_server_from_display_name => 'Keycloak', smtp_server_reply_to => 'webmaster@example.org', smtp_server_reply_to_display_name => 'Webmaster', + brute_force_protected => false, } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has created a realm' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get realms/test' do data = JSON.parse(stdout) expect(data['id']).to eq('test') + expect(data['bruteForceProtected']).to eq(false) end end it 'has left default-client-scopes' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get realms/test/default-default-client-scopes' do data = JSON.parse(stdout) names = data.map { |d| d['name'] }.sort expect(names).to include('email') expect(names).to include('profile') expect(names).to include('role_list') end end it 'has left optional-client-scopes' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get realms/test/default-optional-client-scopes' do data = JSON.parse(stdout) names = data.map { |d| d['name'] }.sort expect(names).to include('address') expect(names).to include('offline_access') expect(names).to include('phone') end end it 'has default events config' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get events/config -r test' do data = JSON.parse(stdout) expect(data['eventsEnabled']).to eq(false) expect(data['eventsExpiration']).to be_nil expect(data['eventsListeners']).to eq(['jboss-logging']) expect(data['adminEventsEnabled']).to eq(false) expect(data['adminEventsDetailsEnabled']).to eq(false) end end it 'has correct smtp settings' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get realms/test' do data = JSON.parse(stdout) expect(data['smtpServer']['host']).to eq('smtp.example.org') expect(data['smtpServer']['port']).to eq('587') expect(data['smtpServer']['starttls']).to eq('false') expect(data['smtpServer']['auth']).to eq('false') expect(data['smtpServer']['user']).to eq('john') expect(data['smtpServer']['envelopeFrom']).to eq('keycloak@id.example.org') expect(data['smtpServer']['from']).to eq('keycloak@id.example.org') expect(data['smtpServer']['fromDisplayName']).to eq('Keycloak') expect(data['smtpServer']['replyTo']).to eq('webmaster@example.org') expect(data['smtpServer']['replyToDisplayName']).to eq('Webmaster') end end end context 'updates realm' do it 'runs successfully' do pp = <<-EOS include mysql::server class { 'keycloak': datasource_driver => 'mysql', } keycloak_realm { 'test': ensure => 'present', remember_me => true, access_code_lifespan => 3600, access_token_lifespan => 3600, sso_session_idle_timeout => 3600, sso_session_max_lifespan => 72000, default_client_scopes => ['profile'], content_security_policy => "frame-src https://*.duosecurity.com/ 'self'; frame-src 'self'; frame-ancestors 'self'; object-src 'none';", events_enabled => true, events_expiration => 2678400, admin_events_enabled => true, admin_events_details_enabled => true, smtp_server_host => 'smtp.example.org', smtp_server_port => 587, smtp_server_starttls => false, smtp_server_auth => true, smtp_server_user => 'jane', smtp_server_password => 'secret', smtp_server_envelope_from => 'keycloak@id.example.org', smtp_server_from => 'keycloak@id.example.org', smtp_server_from_display_name => 'Keycloak', smtp_server_reply_to => 'webmaster@example.org', smtp_server_reply_to_display_name => 'Hostmaster', - + brute_force_protected => true, } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has updated the realm' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get realms/test' do data = JSON.parse(stdout) expect(data['rememberMe']).to eq(true) expect(data['accessCodeLifespan']).to eq(3600) expect(data['accessTokenLifespan']).to eq(3600) expect(data['ssoSessionIdleTimeout']).to eq(3600) expect(data['ssoSessionMaxLifespan']).to eq(72_000) expect(data['browserSecurityHeaders']['contentSecurityPolicy']).to eq("frame-src https://*.duosecurity.com/ 'self'; frame-src 'self'; frame-ancestors 'self'; object-src 'none';") expect(data['smtpServer']['host']).to eq('smtp.example.org') expect(data['smtpServer']['port']).to eq('587') expect(data['smtpServer']['starttls']).to eq('false') expect(data['smtpServer']['auth']).to eq('true') expect(data['smtpServer']['user']).to eq('jane') expect(data['smtpServer']['envelopeFrom']).to eq('keycloak@id.example.org') expect(data['smtpServer']['from']).to eq('keycloak@id.example.org') expect(data['smtpServer']['fromDisplayName']).to eq('Keycloak') expect(data['smtpServer']['replyTo']).to eq('webmaster@example.org') expect(data['smtpServer']['replyToDisplayName']).to eq('Hostmaster') + expect(data['bruteForceProtected']).to eq(true) end end it 'has updated the realm default-client-scopes' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get realms/test/default-default-client-scopes' do data = JSON.parse(stdout) names = data.map { |d| d['name'] } expect(names).to eq(['profile']) end end it 'has updated events config' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get events/config -r test' do data = JSON.parse(stdout) expect(data['eventsEnabled']).to eq(true) expect(data['eventsExpiration']).to eq(2_678_400) expect(data['eventsListeners']).to eq(['jboss-logging']) expect(data['adminEventsEnabled']).to eq(true) expect(data['adminEventsDetailsEnabled']).to eq(true) end end end context 'creates realm with invalid browser flow' do it 'runs successfully' do pp = <<-EOS include mysql::server class { 'keycloak': datasource_driver => 'mysql', } keycloak_realm { 'test2': ensure => 'present', browser_flow => 'Copy of browser', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, expect_changes: true) end it 'has created a realm' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get realms/test2' do data = JSON.parse(stdout) expect(data['browserFlow']).to eq('browser') end end end end diff --git a/spec/acceptance/3_ldap_spec.rb b/spec/acceptance/3_ldap_spec.rb index b91a91e..78c79a9 100644 --- a/spec/acceptance/3_ldap_spec.rb +++ b/spec/acceptance/3_ldap_spec.rb @@ -1,275 +1,284 @@ require 'spec_helper_acceptance' describe 'keycloak_ldap_user_provider:', if: RSpec.configuration.keycloak_full do context 'creates ldap' do it 'runs successfully' do pp = <<-EOS include mysql::server class { 'keycloak': datasource_driver => 'mysql', } keycloak_realm { 'test': ensure => 'present' } keycloak_ldap_user_provider { 'LDAP': realm => 'test', users_dn => 'ou=People,dc=test', connection_url => 'ldap://localhost:389', custom_user_search_filter => '(objectClass=posixAccount)', } keycloak_ldap_mapper { 'full-name': realm => 'test', ldap => 'LDAP-test', type => 'full-name-ldap-mapper', ldap_attribute => 'foo', } keycloak_ldap_mapper { "first name for LDAP-test on test": ensure => 'present', type => 'user-attribute-ldap-mapper', user_model_attribute => 'firstName', ldap_attribute => 'givenName', } keycloak_ldap_mapper { 'group-role for LDAP-test on test': type => 'role-ldap-mapper', roles_dn => 'ou=Groups,dc=example,dc=com', roles_ldap_filter => '(!(cn=P*))', } keycloak_ldap_mapper { 'group for LDAP-test on test': type => 'group-ldap-mapper', groups_dn => 'ou=Groups,dc=example,dc=com', groups_ldap_filter => '(cn=P*)', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has created a LDAP user provider' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get components/LDAP-test -r test' do data = JSON.parse(stdout) expect(data['config']['usersDn']).to eq(['ou=People,dc=test']) expect(data['config']['connectionUrl']).to eq(['ldap://localhost:389']) expect(data['config']['customUserSearchFilter']).to eq(['(objectClass=posixAccount)']) + expect(data['config']['trustEmail']).to eq(['false']) + expect(data['config']['fullSyncPeriod']).to eq(['-1']) + expect(data['config']['changedSyncPeriod']).to eq(['-1']) end end it 'has created a LDAP mapper' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get components -r test' do data = JSON.parse(stdout) d = data.select { |o| o['name'] == 'full-name' }[0] expect(d['providerId']).to eq('full-name-ldap-mapper') expect(d['config']['ldap.full.name.attribute']).to eq(['foo']) end end it 'has set firstName LDAP mapper' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get components -r test' do data = JSON.parse(stdout) d = data.select { |o| o['name'] == 'first name' }[0] expect(d['providerId']).to eq('user-attribute-ldap-mapper') expect(d['config']['user.model.attribute']).to eq(['firstName']) expect(d['config']['ldap.attribute']).to eq(['givenName']) end end it 'has set group-role LDAP mapper' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get components -r test' do data = JSON.parse(stdout) d = data.select { |o| o['name'] == 'group-role' }[0] expect(d['providerId']).to eq('role-ldap-mapper') expect(d['config']['roles.dn']).to eq(['ou=Groups,dc=example,dc=com']) expect(d['config']['roles.ldap.filter']).to eq(['(!(cn=P*))']) end end it 'has set group LDAP mapper' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get components -r test' do data = JSON.parse(stdout) d = data.select { |o| o['name'] == 'group' }[0] expect(d['providerId']).to eq('group-ldap-mapper') expect(d['config']['groups.dn']).to eq(['ou=Groups,dc=example,dc=com']) expect(d['config']['groups.ldap.filter']).to eq(['(cn=P*)']) end end end context 'updates ldap' do it 'runs successfully' do pp = <<-EOS include mysql::server class { 'keycloak': datasource_driver => 'mysql', } keycloak_realm { 'test': ensure => 'present' } keycloak_ldap_user_provider { 'LDAP': realm => 'test', users_dn => 'ou=People,dc=test', connection_url => 'ldap://localhost:389', user_object_classes => ['posixAccount'], + trust_email => true, + full_sync_period => 60, + changed_sync_period => 30, } keycloak_ldap_mapper { 'full-name': realm => 'test', ldap => 'LDAP-test', type => 'full-name-ldap-mapper', ldap_attribute => 'bar', } keycloak_ldap_mapper { 'group-role for LDAP-test on test': type => 'role-ldap-mapper', roles_dn => 'ou=Groups,dc=example,dc=com', roles_ldap_filter => '(!(cn=P0*))', } keycloak_ldap_mapper { 'group for LDAP-test on test': type => 'group-ldap-mapper', groups_dn => 'ou=Groups,dc=example,dc=com', groups_ldap_filter => '(cn=P0*)', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has updated a LDAP user provider' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get components/LDAP-test -r test' do data = JSON.parse(stdout) expect(data['config']['usersDn']).to eq(['ou=People,dc=test']) expect(data['config']['connectionUrl']).to eq(['ldap://localhost:389']) expect(data['config']['userObjectClasses']).to eq(['posixAccount']) expect(data['config'].key?('customUserSearchFilter')).to eq(false) + expect(data['config']['trustEmail']).to eq(['true']) + expect(data['config']['fullSyncPeriod']).to eq(['60']) + expect(data['config']['changedSyncPeriod']).to eq(['30']) end end it 'has updated a LDAP mapper' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get components -r test' do data = JSON.parse(stdout) d = data.select { |o| o['name'] == 'full-name' }[0] expect(d['providerId']).to eq('full-name-ldap-mapper') expect(d['config']['ldap.full.name.attribute']).to eq(['bar']) end end it 'has updated group-role LDAP mapper' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get components -r test' do data = JSON.parse(stdout) d = data.select { |o| o['name'] == 'group-role' }[0] expect(d['providerId']).to eq('role-ldap-mapper') expect(d['config']['roles.dn']).to eq(['ou=Groups,dc=example,dc=com']) expect(d['config']['roles.ldap.filter']).to eq(['(!(cn=P0*))']) end end it 'has updated group LDAP mapper' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get components -r test' do data = JSON.parse(stdout) d = data.select { |o| o['name'] == 'group' }[0] expect(d['providerId']).to eq('group-ldap-mapper') expect(d['config']['groups.dn']).to eq(['ou=Groups,dc=example,dc=com']) expect(d['config']['groups.ldap.filter']).to eq(['(cn=P0*)']) end end end context 'creates ldap with simple auth' do it 'runs successfully' do pp = <<-EOS include mysql::server class { 'keycloak': datasource_driver => 'mysql', } keycloak_realm { 'test': ensure => 'present' } keycloak_ldap_user_provider { 'LDAP2': realm => 'test', users_dn => 'ou=People,dc=test', connection_url => 'ldap://localhost:389', custom_user_search_filter => '(objectClass=posixAccount)', auth_type => 'simple', bind_dn => 'cn=read,ou=People,dc=test', bind_credential => 'test', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has created a LDAP user provider' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get components/LDAP2-test -r test' do data = JSON.parse(stdout) expect(data['config']['authType']).to eq(['simple']) expect(data['config']['bindDn']).to eq(['cn=read,ou=People,dc=test']) expect(data['config']['bindCredential'][0]).to match(%r{^[\*]+$}) end end it 'has set bindCredential' do on hosts, "mysql keycloak -BN -e 'SELECT VALUE FROM COMPONENT_CONFIG WHERE NAME=\"bindCredential\" AND COMPONENT_ID=\"LDAP2-test\"'" do expect(stdout).to match(%r{^test$}) end end end context 'updates ldap auth' do it 'runs successfully' do pp = <<-EOS include mysql::server class { 'keycloak': datasource_driver => 'mysql', } keycloak_realm { 'test': ensure => 'present' } keycloak_ldap_user_provider { 'LDAP': realm => 'test', users_dn => 'ou=People,dc=test', connection_url => 'ldap://localhost:389', user_object_classes => ['posixAccount'], auth_type => 'simple', bind_dn => 'cn=read,ou=People,dc=test', bind_credential => 'test', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has updated a LDAP user provider' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get components/LDAP-test -r test' do data = JSON.parse(stdout) expect(data['config']['authType']).to eq(['simple']) expect(data['config']['bindDn']).to eq(['cn=read,ou=People,dc=test']) expect(data['config']['bindCredential'][0]).to match(%r{^[\*]+$}) end end it 'has set bindCredential' do on hosts, "mysql keycloak -BN -e 'SELECT VALUE FROM COMPONENT_CONFIG WHERE NAME=\"bindCredential\" AND COMPONENT_ID=\"LDAP-test\"'" do expect(stdout).to match(%r{^test$}) end end end context 'ensure => absent' do it 'runs successfully' do pp = <<-EOS include mysql::server class { 'keycloak': datasource_driver => 'mysql', } keycloak_ldap_mapper { 'full-name': ensure => 'absent', realm => 'test', ldap => 'LDAP-test', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has deleted ldap mapper' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get components -r test' do data = JSON.parse(stdout) d = data.select { |o| o['name'] == 'full-name' }[0] expect(d).to be_nil end end end end diff --git a/spec/acceptance/8_identity_provider_spec.rb b/spec/acceptance/8_identity_provider_spec.rb index 03bffa0..2d9fffd 100644 --- a/spec/acceptance/8_identity_provider_spec.rb +++ b/spec/acceptance/8_identity_provider_spec.rb @@ -1,96 +1,160 @@ require 'spec_helper_acceptance' describe 'keycloak_identity_provider type:', if: RSpec.configuration.keycloak_full do context 'creates identity provider' do it 'runs successfully' do pp = <<-EOS include mysql::server class { 'keycloak': datasource_driver => 'mysql', } keycloak_realm { 'test': ensure => 'present' } keycloak_identity_provider { 'cilogon on test': ensure => 'present', display_name => 'CILogon', provider_id => 'oidc', first_broker_login_flow_alias => 'browser', client_id => 'cilogon:/client_id/foobar', client_secret => 'supersecret', user_info_url => 'https://cilogon.org/oauth2/userinfo', token_url => 'https://cilogon.org/oauth2/token', authorization_url => 'https://cilogon.org/authorize', + jwks_url => 'https://cilogon.org/jwks', + gui_order => 1, + } + keycloak_identity_provider { 'foo on test': + ensure => 'present', + display_name => 'foo', + provider_id => 'keycloak-oidc', + first_broker_login_flow_alias => 'browser', + client_id => 'foobar', + client_secret => 'supersecret', + user_info_url => 'https://foo/oauth2/userinfo', + token_url => 'https://foo/oauth2/token', + authorization_url => 'https://foo/authorize', + gui_order => 2, } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has created identity provider' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get identity-provider/instances/cilogon -r test' do data = JSON.parse(stdout) expect(data['enabled']).to eq(true) expect(data['displayName']).to eq('CILogon') + expect(data['providerId']).to eq('oidc') + expect(data['config']['jwksUrl']).to eq('https://cilogon.org/jwks') + expect(data['config']['guiOrder']).to eq('1') + expect(data['config']['syncMode']).to eq('IMPORT') + end + end + + it 'has created keycloak-oidc identity provider' do + on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get identity-provider/instances/foo -r test' do + data = JSON.parse(stdout) + expect(data['enabled']).to eq(true) + expect(data['displayName']).to eq('foo') + expect(data['providerId']).to eq('keycloak-oidc') + expect(data['config']['userInfoUrl']).to eq('https://foo/oauth2/userinfo') + expect(data['config']['tokenUrl']).to eq('https://foo/oauth2/token') + expect(data['config']['authorizationUrl']).to eq('https://foo/authorize') + expect(data['config']['guiOrder']).to eq('2') end end end context 'updates identity provider' do it 'runs successfully' do pp = <<-EOS include mysql::server class { 'keycloak': datasource_driver => 'mysql', } keycloak_realm { 'test': ensure => 'present' } keycloak_identity_provider { 'cilogon on test': ensure => 'present', display_name => 'CILogon', provider_id => 'oidc', first_broker_login_flow_alias => 'first broker login', client_id => 'cilogon:/client_id/foobar', client_secret => 'supersecret', user_info_url => 'https://cilogon.org/oauth2/userinfo', token_url => 'https://cilogon.org/oauth2/token', authorization_url => 'https://cilogon.org/authorize', + jwks_url => 'https://cilogon.org/jwks', + gui_order => 3, + sync_mode => 'FORCE', + } + keycloak_identity_provider { 'foo on test': + ensure => 'present', + display_name => 'foo', + provider_id => 'keycloak-oidc', + first_broker_login_flow_alias => 'browser', + client_id => 'foobar', + client_secret => 'supersecret', + user_info_url => 'https://foo/userinfo', + token_url => 'https://foo/token', + authorization_url => 'https://foo/authorize', + gui_order => 4, } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has created identity provider' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get identity-provider/instances/cilogon -r test' do data = JSON.parse(stdout) expect(data['enabled']).to eq(true) + expect(data['displayName']).to eq('CILogon') + expect(data['providerId']).to eq('oidc') + expect(data['config']['jwksUrl']).to eq('https://cilogon.org/jwks') expect(data['firstBrokerLoginFlowAlias']).to eq('first broker login') + expect(data['config']['guiOrder']).to eq('3') + expect(data['config']['syncMode']).to eq('FORCE') + end + end + + it 'has created keycloak-oidc identity provider' do + on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get identity-provider/instances/foo -r test' do + data = JSON.parse(stdout) + expect(data['enabled']).to eq(true) + expect(data['displayName']).to eq('foo') + expect(data['providerId']).to eq('keycloak-oidc') + expect(data['config']['userInfoUrl']).to eq('https://foo/userinfo') + expect(data['config']['tokenUrl']).to eq('https://foo/token') + expect(data['config']['authorizationUrl']).to eq('https://foo/authorize') + expect(data['config']['guiOrder']).to eq('4') end end end context 'ensure => absent' do it 'runs successfully' do pp = <<-EOS include mysql::server class { 'keycloak': datasource_driver => 'mysql', } keycloak_identity_provider { 'cilogon on test': ensure => 'absent', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has deleted identity provider' do on hosts, '/opt/keycloak/bin/kcadm-wrapper.sh get identity-provider/instances -r test' do data = JSON.parse(stdout) d = data.select { |o| o['alias'] == 'cilogon' }[0] expect(d).to be_nil end end end end diff --git a/spec/unit/puppet/type/keycloak_identity_provider_spec.rb b/spec/unit/puppet/type/keycloak_identity_provider_spec.rb index afcef15..6066991 100644 --- a/spec/unit/puppet/type/keycloak_identity_provider_spec.rb +++ b/spec/unit/puppet/type/keycloak_identity_provider_spec.rb @@ -1,265 +1,303 @@ require 'spec_helper' describe Puppet::Type.type(:keycloak_identity_provider) do let(:default_config) do { name: 'foo', realm: 'test', authorization_url: 'http://authorization', token_url: 'http://token', client_id: 'foobar', client_secret: 'secret', } end let(:config) do default_config end let(:resource) do described_class.new(config) end it 'adds to catalog without raising an error' do catalog = Puppet::Resource::Catalog.new expect { catalog.add_resource resource }.not_to raise_error end it 'has a name' do expect(resource[:name]).to eq('foo') end it 'has alias default to name' do expect(resource[:alias]).to eq('foo') end it 'has internal_id default to resource_name-realm' do expect(resource[:internal_id]).to eq('foo-test') end it 'has realm' do expect(resource[:realm]).to eq('test') end it 'handles componsite name' do component = described_class.new(name: 'foo on test') expect(component[:name]).to eq('foo on test') expect(component[:alias]).to eq('foo') expect(component[:realm]).to eq('test') end it 'defaults to provider_id=oidc' do expect(resource[:provider_id]).to eq('oidc') end + it 'allows keycloak-oidc' do + config[:provider_id] = 'keycloak-oidc' + expect(resource[:provider_id]).to eq('keycloak-oidc') + end + it 'does not allow invalid provider_id' do config[:provider_id] = 'foo' expect { resource }.to raise_error(%r{foo}) end it 'defaults to update_profile_first_login_mode=on' do expect(resource[:update_profile_first_login_mode]).to eq('on') end it 'does not allow invalid update_profile_first_login_mode' do config[:update_profile_first_login_mode] = 'foo' expect { resource }.to raise_error(%r{foo}) end it 'defaults to prompt undefined' do expect(resource[:prompt]).to be_nil end it 'does not allow invalid prompt' do config[:prompt] = 'foo' expect { resource }.to raise_error(%r{foo}) end defaults = { enabled: :true, trust_email: :false, store_token: :false, add_read_token_role_on_create: :false, authenticate_by_default: :false, link_only: :false, first_broker_login_flow_alias: 'first broker login', hide_on_login_page: :false, validate_signature: :false, ui_locales: :false, backchannel_supported: :false, use_jwks_url: :true, login_hint: :false, disable_user_info: :false, } describe 'basic properties' do # Test basic properties [ :display_name, :first_broker_login_flow_alias, :post_broker_login_flow_alias, :user_info_url, :client_id, :token_url, :authorization_url, :logout_url, :issuer, :default_scope, :allowed_clock_skew, :forward_parameters, + :jwks_url, ].each do |p| it "should accept a #{p}" do config[p] = 'foo' expect(resource[p]).to eq('foo') end next unless defaults[p] it "should have default for #{p}" do expect(resource[p]).to eq(defaults[p]) end end end + describe 'integer properties' do + # Test integer properties + [ + :gui_order, + ].each do |p| + it "should accept a #{p}" do + config[p] = 100 + expect(resource[p]).to eq('100') + end + next unless defaults[p] + it "should have default for #{p}" do + expect(resource[p]).to eq(defaults[p]) + end + end + end + describe 'boolean properties' do # Test boolean properties [ :enabled, :trust_email, :store_token, :add_read_token_role_on_create, :authenticate_by_default, :link_only, :hide_on_login_page, :validate_signature, :ui_locales, :backchannel_supported, :use_jwks_url, :login_hint, :disable_user_info, ].each do |p| it "should accept true for #{p}" do config[p] = true expect(resource[p]).to eq(:true) config[p] = 'true' expect(resource[p]).to eq(:true) end it "should accept false for #{p}" do config[p] = false expect(resource[p]).to eq(:false) config[p] = 'false' expect(resource[p]).to eq(:false) end it "should not accept strings for #{p}" do config[p] = 'foo' expect { resource }.to raise_error(%r{foo}) end next unless defaults[p] it "should have default for #{p}" do expect(resource[p]).to eq(defaults[p]) end end end describe 'array properties' do # Array properties [ ].each do |p| it 'accepts array' do config[p] = ['foo', 'bar'] expect(resource[p]).to eq(['foo', 'bar']) end next unless defaults[p] it "should have default for #{p}" do expect(resource[p]).to eq(defaults[p]) end end end describe 'client_auth_method' do [ 'client_secret_post', 'client_secret_basic', 'client_secret_jwt', 'private_key_jwt' ].each do |v| it "accepts #{v}" do config[:client_auth_method] = v expect(resource[:client_auth_method]).to eq(v) end end it 'does not accept invalid values' do config[:client_auth_method] = 'foo' expect { resource }.to raise_error(%r{Invalid}) end end + describe 'sync_mode' do + [ + 'IMPORT', 'LEGACY', 'FORCE' + ].each do |v| + it "accepts #{v}" do + config[:sync_mode] = v + expect(resource[:sync_mode]).to eq(v) + end + end + + it 'does not accept invalid values' do + config[:sync_mode] = 'foo' + expect { resource }.to raise_error(%r{Invalid}) + 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 catalog.add_resource resource catalog.add_resource keycloak_conn_validator rel = resource.autorequire[0] expect(rel.source.ref).to eq(keycloak_conn_validator.ref) expect(rel.target.ref).to eq(resource.ref) end it 'autorequires kcadm-wrapper.sh' do file = Puppet::Type.type(:file).new(name: 'kcadm-wrapper.sh', path: '/opt/keycloak/bin/kcadm-wrapper.sh') catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource file rel = resource.autorequire[0] expect(rel.source.ref).to eq(file.ref) expect(rel.target.ref).to eq(resource.ref) end it 'autorequires keycloak_realm' do keycloak_realm = Puppet::Type.type(:keycloak_realm).new(name: 'test') catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource keycloak_realm rel = resource.autorequire[0] expect(rel.source.ref).to eq(keycloak_realm.ref) expect(rel.target.ref).to eq(resource.ref) end it 'requires realm' do config[:ensure] = :present config[:provider_id] = 'oidc' config.delete(:realm) expect { resource }.to raise_error(Puppet::Error, %r{realm is required}) end it 'requires authorization_url' do config[:ensure] = :present config[:provider_id] = 'oidc' config.delete(:authorization_url) expect { resource }.to raise_error(Puppet::Error, %r{authorization_url is required}) end it 'requires token_url' do config[:ensure] = :present config[:provider_id] = 'oidc' config.delete(:token_url) expect { resource }.to raise_error(Puppet::Error, %r{token_url is required}) end it 'requires client_id' do config[:ensure] = :present config[:provider_id] = 'oidc' config.delete(:client_id) expect { resource }.to raise_error(Puppet::Error, %r{client_id is required}) end it 'requires client_secret' do config[:ensure] = :present config[:provider_id] = 'oidc' config.delete(:client_secret) expect { resource }.to raise_error(Puppet::Error, %r{client_secret is required}) end end diff --git a/spec/unit/puppet/type/keycloak_ldap_user_provider_spec.rb b/spec/unit/puppet/type/keycloak_ldap_user_provider_spec.rb index 6dc836b..d860dce 100644 --- a/spec/unit/puppet/type/keycloak_ldap_user_provider_spec.rb +++ b/spec/unit/puppet/type/keycloak_ldap_user_provider_spec.rb @@ -1,298 +1,319 @@ require 'spec_helper' describe Puppet::Type.type(:keycloak_ldap_user_provider) do let(:default_config) do { name: 'foo', realm: 'test', } end let(:config) do default_config end let(:resource) do described_class.new(config) end it 'adds to catalog without raising an error' do catalog = Puppet::Resource::Catalog.new expect { catalog.add_resource resource }.not_to raise_error end it 'has a name' do expect(resource[:name]).to eq('foo') end it 'has resource_name default to name' do expect(resource[:resource_name]).to eq('foo') end it 'has id default to resource_name-realm' do expect(resource[:id]).to eq('foo-test') end it 'has realm' do expect(resource[:realm]).to eq('test') end it 'handles componsite name' do component = described_class.new(name: 'foo on test') expect(component[:name]).to eq('foo on test') expect(component[:resource_name]).to eq('foo') expect(component[:realm]).to eq('test') end it 'defaults to auth_type=none' do expect(resource[:auth_type]).to eq('none') end it 'does not allow invalid auth_type' do config[:auth_type] = 'foo' expect { resource }.to raise_error(%r{foo}) end it 'defaults to edit_mode=READ_ONLY' do expect(resource[:edit_mode]).to eq('READ_ONLY') end it 'does not allow invalid edit_mode' do config[:edit_mode] = 'foo' expect { resource }.to raise_error(%r{foo}) end it 'defaults to vendor=other' do expect(resource[:vendor]).to eq('other') end it 'does not allow invalid vendor' do config[:vendor] = 'foo' expect { resource }.to raise_error(%r{foo}) end it 'defaults to use_truststore_spi=ldapsOnly' do expect(resource[:use_truststore_spi]).to eq('ldapsOnly') end it 'does not allow invalid use_truststore_spi' do config[:use_truststore_spi] = 'foo' expect { resource }.to raise_error(%r{foo}) end it 'allows bind_dn' do config[:auth_type] = 'simple' config[:bind_dn] = 'foo' expect(resource[:bind_dn]).to eq('foo') end it 'allows bind_credential' do config[:auth_type] = 'simple' config[:bind_credential] = 'foo' expect(resource[:bind_credential]).to eq('foo') end it 'allows use_kerberos_for_password_authentication' do config[:auth_type] = 'simple' config[:use_kerberos_for_password_authentication] = true expect(resource[:use_kerberos_for_password_authentication]).to eq(:true) end it 'does not allow invalid bind_credential' do config[:auth_type] = 'simple' config[:use_kerberos_for_password_authentication] = 'foo' expect { resource }.to raise_error(%r{foo}) end it 'allows string one for search_scope' do config[:search_scope] = 'one' expect(resource[:search_scope]).to eq('1') end it 'allows string one_level for search_scope' do config[:search_scope] = 'one_level' expect(resource[:search_scope]).to eq('1') end it 'allows string 1 for search_scope' do config[:search_scope] = '1' expect(resource[:search_scope]).to eq('1') end it 'allows 1 for search_scope' do config[:search_scope] = 1 expect(resource[:search_scope]).to eq('1') end it 'allows string subtree for search_scope' do config[:search_scope] = 'subtree' expect(resource[:search_scope]).to eq('2') end it 'allows string 2 for search_scope' do config[:search_scope] = '2' expect(resource[:search_scope]).to eq('2') end it 'allows 2 for search_scope' do config[:search_scope] = 2 expect(resource[:search_scope]).to eq('2') end it 'does not allow invalid search_scope' do config[:search_scope] = 'foo' expect { resource }.to raise_error(%r{foo}) end it 'defaults custom_user_search_filter' do expect(resource[:custom_user_search_filter]).to eq(:absent) end it 'accepts valid custom_user_search_filter' do config[:custom_user_search_filter] = '(foo=bar)' expect(resource[:custom_user_search_filter]).to eq('(foo=bar)') end it 'does not allow invalid custom_user_search_filter' do config[:custom_user_search_filter] = 'foo=bar' expect { resource }.to raise_error(Puppet::Error, %r{must start with "\(" and end with "\)"}) end defaults = { enabled: :true, priority: '0', batch_size_for_sync: '1000', username_ldap_attribute: 'uid', rdn_ldap_attribute: 'uid', uuid_ldap_attribute: 'entryUUID', import_enabled: :true, user_object_classes: ['inetOrgPerson', 'organizationalPerson'], + trust_email: :false, + full_sync_period: '-1', + changed_sync_period: '-1', } describe 'basic properties' do # Test basic properties [ :users_dn, :connection_url, :priority, :batch_size_for_sync, :username_ldap_attribute, :rdn_ldap_attribute, :uuid_ldap_attribute, ].each do |p| it "should accept a #{p}" do config[p] = 'foo' expect(resource[p]).to eq('foo') end next unless defaults[p] it "should have default for #{p}" do expect(resource[p]).to eq(defaults[p]) end end end + describe 'integer properties' do + # Test integer properties + [ + :full_sync_period, + :changed_sync_period, + ].each do |p| + it "should accept a #{p}" do + config[p] = 100 + expect(resource[p]).to eq('100') + end + next unless defaults[p] + it "should have default for #{p}" do + expect(resource[p]).to eq(defaults[p]) + end + end + end + describe 'boolean properties' do # Test boolean properties [ :enabled, :import_enabled, + :trust_email, ].each do |p| it "should accept true for #{p}" do config[p] = true expect(resource[p]).to eq(:true) config[p] = 'true' expect(resource[p]).to eq(:true) end it "should accept false for #{p}" do config[p] = false expect(resource[p]).to eq(:false) config[p] = 'false' expect(resource[p]).to eq(:false) end it "should not accept strings for #{p}" do config[p] = 'foo' expect { resource }.to raise_error(%r{foo}) end next unless defaults[p] it "should have default for #{p}" do expect(resource[p]).to eq(defaults[p]) end end end describe 'array properties' do # Array properties [ :user_object_classes, ].each do |p| it 'accepts array' do config[p] = ['foo', 'bar'] expect(resource[p]).to eq(['foo', 'bar']) end next unless defaults[p] it "should have default for #{p}" do expect(resource[p]).to eq(defaults[p]) end 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 catalog.add_resource resource catalog.add_resource keycloak_conn_validator rel = resource.autorequire[0] expect(rel.source.ref).to eq(keycloak_conn_validator.ref) expect(rel.target.ref).to eq(resource.ref) end it 'autorequires kcadm-wrapper.sh' do file = Puppet::Type.type(:file).new(name: 'kcadm-wrapper.sh', path: '/opt/keycloak/bin/kcadm-wrapper.sh') catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource file rel = resource.autorequire[0] expect(rel.source.ref).to eq(file.ref) expect(rel.target.ref).to eq(resource.ref) end it 'autorequires keycloak_realm' do keycloak_realm = Puppet::Type.type(:keycloak_realm).new(name: 'test') catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource keycloak_realm rel = resource.autorequire[0] expect(rel.source.ref).to eq(keycloak_realm.ref) expect(rel.target.ref).to eq(resource.ref) end it 'does not allow use_kerberos_for_password_authentication with auth_type=none' do config[:auth_type] = 'none' config[:use_kerberos_for_password_authentication] = true expect { resource }.to raise_error(Puppet::Error, %r{use_kerberos_for_password_authentication is not valid for auth_type none}) end it 'does not allow bind_credential with auth_type=none' do config[:auth_type] = 'none' config[:bind_credential] = true expect { resource }.to raise_error(Puppet::Error, %r{bind_credential is not valid for auth_type none}) end it 'does not allow bind_dn with auth_type=none' do config[:auth_type] = 'none' config[:bind_dn] = true expect { resource }.to raise_error(Puppet::Error, %r{bind_dn is not valid for auth_type none}) end end diff --git a/spec/unit/puppet/type/keycloak_realm_spec.rb b/spec/unit/puppet/type/keycloak_realm_spec.rb index 2d89aa6..b5030e0 100644 --- a/spec/unit/puppet/type/keycloak_realm_spec.rb +++ b/spec/unit/puppet/type/keycloak_realm_spec.rb @@ -1,193 +1,194 @@ require 'spec_helper' describe Puppet::Type.type(:keycloak_realm) do let(:default_config) do { name: 'test', } end let(:config) do default_config end let(:resource) do described_class.new(config) end it 'adds to catalog without raising an error' do catalog = Puppet::Resource::Catalog.new expect { catalog.add_resource resource }.not_to raise_error end it 'has a name' do expect(resource[:name]).to eq('test') end it 'has id default to name' do expect(resource[:id]).to eq('test') end defaults = { login_theme: 'keycloak', account_theme: 'keycloak', admin_theme: 'keycloak', email_theme: 'keycloak', access_code_lifespan_user_action: nil, access_token_lifespan_for_implicit_flow: nil, enabled: :true, remember_me: :false, login_with_email_allowed: :true, browser_flow: 'browser', registration_flow: 'registration', direct_grant_flow: 'direct grant', reset_credentials_flow: 'reset credentials', client_authentication_flow: 'clients', docker_authentication_flow: 'docker auth', content_security_policy: "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", events_enabled: :false, events_listeners: ['jboss-logging'], admin_events_enabled: :false, admin_events_details_enabled: :false, } describe 'basic properties' do # Test basic properties [ :display_name, :display_name_html, :login_theme, :account_theme, :admin_theme, :email_theme, :events_expiration, :browser_flow, :registration_flow, :direct_grant_flow, :reset_credentials_flow, :client_authentication_flow, :docker_authentication_flow, :content_security_policy, :smtp_server_user, :smtp_server_password, :smtp_server_host, :smtp_server_envelope_from, :smtp_server_from, :smtp_server_from_display_name, :smtp_server_reply_to, :smtp_server_reply_to_display_name, ].each do |p| it "should accept a #{p}" do config[p] = 'foo' expect(resource[p]).to eq('foo') end next unless defaults[p] it "should have default for #{p}" do expect(resource[p]).to eq(defaults[p]) end end end describe 'integer properties' do # Test integer properties [ :sso_session_idle_timeout, :sso_session_max_lifespan, :access_code_lifespan, :access_code_lifespan_user_action, :access_token_lifespan, :access_token_lifespan_for_implicit_flow, :smtp_server_port, ].each do |p| it "should accept a #{p}" do config[p] = 100 expect(resource[p]).to eq(100) end next unless defaults[p] it "should have default for #{p}" do expect(resource[p]).to eq(defaults[p]) end end end describe 'boolean properties' do # Test boolean properties [ :remember_me, :login_with_email_allowed, :internationalization_enabled, :events_enabled, :admin_events_enabled, :admin_events_details_enabled, :smtp_server_auth, :smtp_server_starttls, :smtp_server_ssl, + :brute_force_protected, ].each do |p| it "should accept true for #{p}" do config[p] = true expect(resource[p]).to eq(:true) end it "should accept true for #{p} string" do config[p] = 'true' expect(resource[p]).to eq(:true) end it "should accept false for #{p}" do config[p] = false expect(resource[p]).to eq(:false) end it "should accept false for #{p} string" do config[p] = 'false' expect(resource[p]).to eq(:false) end it "should not accept strings for #{p}" do config[p] = 'foo' expect { resource }.to raise_error(%r{foo}) end next unless defaults[p] it "should have default for #{p}" do expect(resource[p]).to eq(defaults[p]) end end end describe 'array properties' do # Array properties [ :default_client_scopes, :optional_client_scopes, :events_listeners, :supported_locales, ].each do |p| it "should accept array for #{p}" do config[p] = ['foo', 'bar'] expect(resource[p]).to eq(['foo', 'bar']) end next unless defaults[p] it "should have default for #{p}" do expect(resource[p]).to eq(defaults[p]) end 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 catalog.add_resource resource catalog.add_resource keycloak_conn_validator rel = resource.autorequire[0] expect(rel.source.ref).to eq(keycloak_conn_validator.ref) expect(rel.target.ref).to eq(resource.ref) end it 'autorequires kcadm-wrapper.sh' do file = Puppet::Type.type(:file).new(name: 'kcadm-wrapper.sh', path: '/opt/keycloak/bin/kcadm-wrapper.sh') catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource file rel = resource.autorequire[0] expect(rel.source.ref).to eq(file.ref) expect(rel.target.ref).to eq(resource.ref) end end