Skip to content

Commit

Permalink
Implement realm otp, webauthn, webauthn passwordless and bruteforce p…
Browse files Browse the repository at this point in the history
…roperties (#312)

* Implement bruteforce properties

* Add tests for bruteforce properties

* Implement webauthn policy properties

* Add tests for webauthn policy properties

* Add unit tests for bruteforce and webauthn properties

* Implement webauthn passwordless policy properties

* Add tests for webauthn passwordless policy properties

* Implement otp policy properties

* Add tests for otp policy properties
  • Loading branch information
TuningYourCode authored Jun 19, 2024
1 parent 739f8ae commit a627fa4
Show file tree
Hide file tree
Showing 3 changed files with 410 additions and 6 deletions.
186 changes: 186 additions & 0 deletions lib/puppet/type/keycloak_realm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -338,12 +338,88 @@ def should_to_s(_newvalue)
newvalues(:true, :false)
end

newproperty(:permanent_lockout, boolean: true) do
desc 'permanentLockout'
newvalues(:true, :false)
defaultto :false
end

newproperty(:max_failure_wait_seconds, parent: PuppetX::Keycloak::IntegerProperty) do
desc 'maxFailureWaitSeconds'
defaultto 900
end

newproperty(:minimum_quick_login_wait_seconds, parent: PuppetX::Keycloak::IntegerProperty) do
desc 'minimumQuickLoginWaitSeconds'
defaultto 60
end

newproperty(:wait_increment_seconds, parent: PuppetX::Keycloak::IntegerProperty) do
desc 'waitIncrementSeconds'
defaultto 60
end

newproperty(:quick_login_check_milli_seconds, parent: PuppetX::Keycloak::IntegerProperty) do
desc 'quickLoginCheckMilliSeconds'
defaultto 1_000
end

newproperty(:max_delta_time_seconds, parent: PuppetX::Keycloak::IntegerProperty) do
desc 'maxDeltaTimeSeconds'
defaultto 43_200
end

newproperty(:failure_factor, parent: PuppetX::Keycloak::IntegerProperty) do
desc 'failureFactor'
defaultto 30
end

newparam(:manage_roles, boolean: true) do
desc 'Manage realm roles'
newvalues(:true, :false)
defaultto(:true)
end

newproperty(:otp_policy_type) do
desc 'otpPolicyType'
newvalues('totp', 'hotp')
defaultto 'totp'
end

newproperty(:otp_policy_algorithm) do
desc 'otpPolicyAlgorithm'
newvalues('HmacSHA1', 'HmacSHA256', 'HmacSHA512')
defaultto 'HmacSHA1'
end

newproperty(:otp_policy_initial_counter, parent: PuppetX::Keycloak::IntegerProperty) do
desc 'otpPolicyInitialCounter'
defaultto 0
end

newproperty(:otp_policy_digits) do
desc 'otpPolicyDigits'
newvalues(6, 8)
defaultto 6
munge { |v| v.to_i }
end

newproperty(:otp_policy_look_ahead_window, parent: PuppetX::Keycloak::IntegerProperty) do
desc 'otpPolicyLookAheadWindow'
defaultto 1
end

newproperty(:otp_policy_period, parent: PuppetX::Keycloak::IntegerProperty) do
desc 'otpPolicyPeriod'
defaultto 30
end

newproperty(:otp_policy_code_reusable, boolean: true) do
desc 'otpPolicyCodeReusable'
newvalues(:true, :false)
defaultto :false
end

newproperty(:roles, array_matching: :all, parent: PuppetX::Keycloak::ArrayProperty) do
desc 'roles'
defaultto ['offline_access', 'uma_authorization']
Expand All @@ -357,6 +433,116 @@ def insync?(is)
end
end

newproperty(:web_authn_policy_rp_entity_name) do
desc 'webAuthnPolicyRpEntityName'
defaultto 'keycloak'
end

newproperty(:web_authn_policy_signature_algorithms, array_matching: :all, parent: PuppetX::Keycloak::ArrayProperty) do
desc 'webAuthnPolicySignatureAlgorithms'
defaultto ['ES256']
end

newproperty(:web_authn_policy_rp_id) do
desc 'webAuthnPolicyRpId'
defaultto ''
end

newproperty(:web_authn_policy_attestation_conveyance_preference) do
desc 'webAuthnPolicyAttestationConveyancePreference'
newvalues('none', 'direct', 'indirect', 'not specified')
defaultto 'not specified'
end

newproperty(:web_authn_policy_authenticator_attachment) do
desc 'webAuthnPolicyAuthenticatorAttachment'
newvalues('platform', 'cross-platform', 'not specified')
defaultto 'not specified'
end

newproperty(:web_authn_policy_require_resident_key) do
desc 'webAuthnPolicyRequireResidentKey'
newvalues('No', 'Yes', 'not specified')
defaultto 'not specified'
end

newproperty(:web_authn_policy_user_verification_requirement) do
desc 'webAuthnPolicyUserVerificationRequirement'
newvalues('required', 'preferred', 'discouraged', 'not specified')
defaultto 'not specified'
end

newproperty(:web_authn_policy_create_timeout, parent: PuppetX::Keycloak::IntegerProperty) do
desc 'webAuthnPolicyCreateTimeout'
defaultto 0
end

newproperty(:web_authn_policy_avoid_same_authenticator_register, boolean: true) do
desc 'webAuthnPolicyAvoidSameAuthenticatorRegister'
newvalues(:true, :false)
defaultto :false
end

newproperty(:web_authn_policy_acceptable_aaguids, array_matching: :all, parent: PuppetX::Keycloak::ArrayProperty) do
desc 'webAuthnPolicyAcceptableAaguids'
defaultto []
end

newproperty(:web_authn_policy_passwordless_rp_entity_name) do
desc 'webAuthnPolicyPasswordlessRpEntityName'
defaultto 'keycloak'
end

newproperty(:web_authn_policy_passwordless_signature_algorithms, array_matching: :all, parent: PuppetX::Keycloak::ArrayProperty) do
desc 'webAuthnPolicyPasswordlessSignatureAlgorithms'
defaultto ['ES256']
end

newproperty(:web_authn_policy_passwordless_rp_id) do
desc 'webAuthnPolicyPasswordlessRpId'
defaultto ''
end

newproperty(:web_authn_policy_passwordless_attestation_conveyance_preference) do
desc 'webAuthnPolicyPasswordlessAttestationConveyancePreference'
newvalues('none', 'direct', 'indirect', 'not specified')
defaultto 'not specified'
end

newproperty(:web_authn_policy_passwordless_authenticator_attachment) do
desc 'webAuthnPolicyPasswordlessAuthenticatorAttachment'
newvalues('platform', 'cross-platform', 'not specified')
defaultto 'not specified'
end

newproperty(:web_authn_policy_passwordless_require_resident_key) do
desc 'webAuthnPolicyPasswordlessRequireResidentKey'
newvalues('No', 'Yes', 'not specified')
defaultto 'not specified'
end

newproperty(:web_authn_policy_passwordless_user_verification_requirement) do
desc 'webAuthnPolicyPasswordlessUserVerificationRequirement'
newvalues('required', 'preferred', 'discouraged', 'not specified')
defaultto 'not specified'
end

newproperty(:web_authn_policy_passwordless_create_timeout, parent: PuppetX::Keycloak::IntegerProperty) do
desc 'webAuthnPolicyPasswordlessCreateTimeout'
defaultto 0
end

newproperty(:web_authn_policy_passwordless_avoid_same_authenticator_register, boolean: true) do
desc 'webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister'
newvalues(:true, :false)
defaultto :false
end

newproperty(:web_authn_policy_passwordless_acceptable_aaguids, array_matching: :all, parent: PuppetX::Keycloak::ArrayProperty) do
desc 'webAuthnPolicyPasswordlessAcceptableAaguids'
defaultto []
end

newproperty(:custom_properties) do
desc 'custom properties to pass as realm configurations'
defaultto {}
Expand Down
66 changes: 65 additions & 1 deletion spec/acceptance/2_realm_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,41 @@ class { 'keycloak': }
default_locale => 'en',
supported_locales => ['en','de'],
custom_properties => {
'failureFactor' => 60,
'revokeRefreshToken' => true,
},
failure_factor => 60,
permanent_lockout => true,
max_failure_wait_seconds => 999,
minimum_quick_login_wait_seconds => 40,
wait_increment_seconds => 10,
quick_login_check_milli_seconds => 10,
max_delta_time_seconds => 3600,
otp_policy_type => 'totp',
otp_policy_algorithm => 'HmacSHA512',
otp_policy_initial_counter => 1,
otp_policy_digits => 8,
otp_policy_period => 30,
otp_policy_code_reusable => true,
web_authn_policy_rp_entity_name => 'Keycloak',
web_authn_policy_signature_algorithms => ['ES256', 'ES384', 'ES512', 'RS256', 'RS384', 'RS512'],
web_authn_policy_rp_id => 'https://example.com',
web_authn_policy_attestation_conveyance_preference => 'direct',
web_authn_policy_authenticator_attachment => 'cross-platform',
web_authn_policy_require_resident_key => 'No',
web_authn_policy_user_verification_requirement => 'required',
web_authn_policy_create_timeout => 600,
web_authn_policy_avoid_same_authenticator_register => true,
web_authn_policy_acceptable_aaguids => ['d1d1d1d1-d1d1-d1d1-d1d1-d1d1d1d1d1d1'],
web_authn_policy_passwordless_rp_entity_name => 'Keycloak',
web_authn_policy_passwordless_signature_algorithms => ['ES256', 'ES384', 'ES512', 'RS256', 'RS384', 'RS512'],
web_authn_policy_passwordless_rp_id => 'https://example.com',
web_authn_policy_passwordless_attestation_conveyance_preference => 'direct',
web_authn_policy_passwordless_authenticator_attachment => 'cross-platform',
web_authn_policy_passwordless_require_resident_key => 'No',
web_authn_policy_passwordless_user_verification_requirement => 'required',
web_authn_policy_passwordless_create_timeout => 600,
web_authn_policy_passwordless_avoid_same_authenticator_register => true,
web_authn_policy_passwordless_acceptable_aaguids => ['d1d1d1d1-d1d1-d1d1-d1d1-d1d1d1d1d1d1'],
}
PUPPET_PP

Expand Down Expand Up @@ -263,10 +295,42 @@ class { 'keycloak': }
expect(data['adminTheme']).to eq('keycloak.v2')
expect(data['emailTheme']).to eq('keycloak.v2')
expect(data['failureFactor']).to eq(60)
expect(data['permanentLockout']).to eq(true)
expect(data['maxFailureWaitSeconds']).to eq(999)
expect(data['minimumQuickLoginWaitSeconds']).to eq(40)
expect(data['waitIncrementSeconds']).to eq(10)
expect(data['quickLoginCheckMilliSeconds']).to eq(10)
expect(data['maxDeltaTimeSeconds']).to eq(3600)
expect(data['revokeRefreshToken']).to eq(true)
expect(data['internationalizationEnabled']).to eq(true)
expect(data['defaultLocale']).to eq('en')
expect(data['supportedLocales']).to eq(['de', 'en'])
expect(data['otpPolicyType']).to eq('totp')
expect(data['otpPolicyAlgorithm']).to eq('HmacSHA512')
expect(data['otpPolicyInitialCounter']).to eq(1)
expect(data['otpPolicyDigits']).to eq(8)
expect(data['otpPolicyPeriod']).to eq(30)
expect(data['otpPolicyCodeReusable']).to eq(true)
expect(data['webAuthnPolicyRpEntityName']).to eq('Keycloak')
expect(data['webAuthnPolicySignatureAlgorithms']).to eq(['ES256', 'ES384', 'ES512', 'RS256', 'RS384', 'RS512'])
expect(data['webAuthnPolicyRpId']).to eq('https://example.com')
expect(data['webAuthnPolicyAttestationConveyancePreference']).to eq('direct')
expect(data['webAuthnPolicyAuthenticatorAttachment']).to eq('cross-platform')
expect(data['webAuthnPolicyRequireResidentKey']).to eq('No')
expect(data['webAuthnPolicyUserVerificationRequirement']).to eq('required')
expect(data['webAuthnPolicyCreateTimeout']).to eq(600)
expect(data['webAuthnPolicyAvoidSameAuthenticatorRegister']).to eq(true)
expect(data['webAuthnPolicyAcceptableAaguids']).to eq(['d1d1d1d1-d1d1-d1d1-d1d1-d1d1d1d1d1d1'])
expect(data['webAuthnPolicyPasswordlessRpEntityName']).to eq('Keycloak')
expect(data['webAuthnPolicyPasswordlessSignatureAlgorithms']).to eq(['ES256', 'ES384', 'ES512', 'RS256', 'RS384', 'RS512'])
expect(data['webAuthnPolicyPasswordlessRpId']).to eq('https://example.com')
expect(data['webAuthnPolicyPasswordlessAttestationConveyancePreference']).to eq('direct')
expect(data['webAuthnPolicyPasswordlessAuthenticatorAttachment']).to eq('cross-platform')
expect(data['webAuthnPolicyPasswordlessRequireResidentKey']).to eq('No')
expect(data['webAuthnPolicyPasswordlessUserVerificationRequirement']).to eq('required')
expect(data['webAuthnPolicyPasswordlessCreateTimeout']).to eq(600)
expect(data['webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister']).to eq(true)
expect(data['webAuthnPolicyPasswordlessAcceptableAaguids']).to eq(['d1d1d1d1-d1d1-d1d1-d1d1-d1d1d1d1d1d1'])
end
end

Expand Down
Loading

0 comments on commit a627fa4

Please sign in to comment.