feat: add openidc_metadata_dir to federation::oidc

Add optional keystone::federation::openidc::openidc_metadata_dir param
to set OIDCMetadataDir, to be configured when using multiple OIDC
providers. OIDCProviderMetadataURL is now optional and mutually
exclusive with OIDCMetadataDir.

References
https://github.com/OpenIDC/mod_auth_openidc/wiki/Multiple-Providers

Change-Id: Ife36d000c6747a14a6d9ae3bff4babc6ac8b3022
This commit is contained in:
Francesco Di Nucci 2024-07-01 10:43:50 +02:00 committed by Takashi Kajinami
parent 7558e5bfa1
commit e4acfc9f29
4 changed files with 79 additions and 31 deletions

View File

@ -17,8 +17,13 @@
# (Required) String value. # (Required) String value.
# #
# [*openidc_provider_metadata_url*] # [*openidc_provider_metadata_url*]
# The url that points to your OpenID Connect metadata provider # (Optional) The url that points to your OpenID Connect metadata provider.
# (Required) String value. # Defaults to undef
#
# [*openidc_metadata_dir*]
# (Optional) Path of OIDCMetadataDir, directory that holds metadata in case of
# usage of multiple OIDC provider.
# Defaults to undef
# #
# [*openidc_client_id*] # [*openidc_client_id*]
# The client ID to use when handshaking with your OpenID Connect provider # The client ID to use when handshaking with your OpenID Connect provider
@ -154,36 +159,36 @@ class keystone::federation::openidc (
$keystone_url, $keystone_url,
$methods, $methods,
$idp_name, $idp_name,
$openidc_provider_metadata_url,
$openidc_client_id, $openidc_client_id,
$openidc_client_secret, $openidc_client_secret,
$openidc_crypto_passphrase = 'openstack', Optional[Stdlib::HTTPUrl] $openidc_provider_metadata_url = undef,
$openidc_response_type = 'id_token', Optional[Stdlib::Unixpath] $openidc_metadata_dir = undef,
$openidc_response_mode = undef, $openidc_crypto_passphrase = 'openstack',
$openidc_cache_type = undef, $openidc_response_type = 'id_token',
$openidc_cache_shm_max = undef, $openidc_response_mode = undef,
$openidc_cache_shm_entry_size = undef, $openidc_cache_type = undef,
$openidc_cache_dir = undef, $openidc_cache_shm_max = undef,
$openidc_cache_clean_interval = undef, $openidc_cache_shm_entry_size = undef,
$openidc_claim_delimiter = undef, $openidc_cache_dir = undef,
Boolean $openidc_enable_oauth = false, $openidc_cache_clean_interval = undef,
$openidc_introspection_endpoint = undef, $openidc_claim_delimiter = undef,
$openidc_verify_jwks_uri = undef, Boolean $openidc_enable_oauth = false,
$openidc_verify_method = 'introspection', $openidc_introspection_endpoint = undef,
$openidc_pass_userinfo_as = undef, $openidc_verify_jwks_uri = undef,
$openidc_pass_claim_as = undef, $openidc_verify_method = 'introspection',
$openidc_redirect_uri = undef, $openidc_pass_userinfo_as = undef,
$memcached_servers = undef, $openidc_pass_claim_as = undef,
$redis_server = undef, $openidc_redirect_uri = undef,
$redis_password = undef, $memcached_servers = undef,
$redis_username = undef, $redis_server = undef,
$redis_database = undef, $redis_password = undef,
$redis_connect_timeout = undef, $redis_username = undef,
$redis_timeout = undef, $redis_database = undef,
$remote_id_attribute = $facts['os_service_default'], $redis_connect_timeout = undef,
$template_order = 331, $redis_timeout = undef,
$remote_id_attribute = $facts['os_service_default'],
$template_order = 331,
) { ) {
include apache include apache
include apache::mod::auth_openidc include apache::mod::auth_openidc
@ -193,6 +198,15 @@ class keystone::federation::openidc (
if ! defined(Class['keystone::wsgi::apache']) { if ! defined(Class['keystone::wsgi::apache']) {
fail('The keystone::wsgi::apache class should be included in the catalog') fail('The keystone::wsgi::apache class should be included in the catalog')
} }
# With a single provider, OIDCProviderMetadataURL should be set, with multiple
# providers OIDCMetadataDir should be used instead
if !$openidc_provider_metadata_url and !$openidc_metadata_dir {
fail('Set one openidc_provider_metadata_url or openidc_metadata_dir')
}
if $openidc_provider_metadata_url and $openidc_metadata_dir {
fail("openidc_provider_metadata_url and openidc_metadata_dir are mutually \
exclusive, set only one of the two.")
}
if !($openidc_verify_method in ['introspection', 'jwks']) { if !($openidc_verify_method in ['introspection', 'jwks']) {
fail('Unsupported token verification method. Must be one of "introspection" or "jwks"') fail('Unsupported token verification method. Must be one of "introspection" or "jwks"')

View File

@ -0,0 +1,5 @@
---
features: >
Add ``keystone::federation::openidc:openidc_metadata_dir`` parameter
to specify OIDCMetadataDir path instead of OIDCProviderMetadataURL . This may
be required when multiple OIDC providers are used for the federation.

View File

@ -50,6 +50,18 @@ describe 'keystone::federation::openidc' do
params.merge!(:openidc_enable_oauth => true) params.merge!(:openidc_enable_oauth => true)
it_raises 'a Puppet:Error', /You must set openidc_introspection_endpoint when enabling oauth support/ it_raises 'a Puppet:Error', /You must set openidc_introspection_endpoint when enabling oauth support/
end end
before do
params.merge!({
:openidc_metadata_dir => '/CUSTOM_METADATA_DIR',
})
it_raises 'a Puppet:Error', /openidc_provider_metadata_url and openidc_metadata_dir are mutually/
end
before do
params.delete(:openidc_provider_metadata_url)
it_raises 'a Puppet:Error', /Set openidc_provider_metadata_url or openidc_metadata_dir/
end
end end
on_supported_os({ on_supported_os({
@ -76,10 +88,23 @@ describe 'keystone::federation::openidc' do
it 'should contain expected config' do it 'should contain expected config' do
content = get_param('concat::fragment', 'keystone_wsgi-configure_openidc_keystone', 'content') content = get_param('concat::fragment', 'keystone_wsgi-configure_openidc_keystone', 'content')
expect(content).to match('OIDCProviderMetadataURL "https://accounts.google.com/.well-known/openid-configuration"')
expect(content).to match('OIDCClientID "openid_client_id"') expect(content).to match('OIDCClientID "openid_client_id"')
expect(content).to match('OIDCClientSecret "openid_client_secret"') expect(content).to match('OIDCClientSecret "openid_client_secret"')
expect(content).to match('OIDCRedirectURI "http://localhost:5000/v3/OS-FEDERATION/identity_providers/myidp/protocols/openid/auth"') expect(content).to match('OIDCRedirectURI "http://localhost:5000/v3/OS-FEDERATION/identity_providers/myidp/protocols/openid/auth"')
expect(content).to match('OIDCProviderMetadataURL "https://accounts.google.com/.well-known/openid-configuration"')
end
end
context 'with openidc_metadata_dir' do
before do
params.delete(:openidc_provider_metadata_url)
params.merge!({
:openidc_metadata_dir => '/CUSTOM_METADATA_DIR'
})
end
it 'should contain the expected OIDCMetadataDir' do
content = get_param('concat::fragment', 'keystone_wsgi-configure_openidc_keystone', 'content')
expect(content).to match('OIDCMetadataDir "/CUSTOM_METADATA_DIR"')
end end
end end

View File

@ -1,11 +1,15 @@
OIDCClaimPrefix "OIDC-" OIDCClaimPrefix "OIDC-"
OIDCResponseType "<%= scope['keystone::federation::openidc::openidc_response_type']-%>" OIDCResponseType "<%= scope['keystone::federation::openidc::openidc_response_type']-%>"
OIDCScope "openid email profile" OIDCScope "openid email profile"
<%- if scope['::keystone::federation::openidc::openidc_provider_metadata_url'] != nil -%>
OIDCProviderMetadataURL "<%= scope['keystone::federation::openidc::openidc_provider_metadata_url']-%>" OIDCProviderMetadataURL "<%= scope['keystone::federation::openidc::openidc_provider_metadata_url']-%>"
<%- end -%>
<%- if scope['::keystone::federation::openidc::openidc_metadata_dir'] != nil -%>
OIDCMetadataDir "<%= scope['::keystone::federation::openidc::openidc_metadata_dir'] %>"
<%- end -%>
OIDCClientID "<%= scope['keystone::federation::openidc::openidc_client_id']-%>" OIDCClientID "<%= scope['keystone::federation::openidc::openidc_client_id']-%>"
OIDCClientSecret "<%= scope['keystone::federation::openidc::openidc_client_secret']-%>" OIDCClientSecret "<%= scope['keystone::federation::openidc::openidc_client_secret']-%>"
OIDCCryptoPassphrase "<%= scope['keystone::federation::openidc::openidc_crypto_passphrase']-%>" OIDCCryptoPassphrase "<%= scope['keystone::federation::openidc::openidc_crypto_passphrase']-%>"
<%- if scope['::keystone::federation::openidc::openidc_response_mode'] != nil -%> <%- if scope['::keystone::federation::openidc::openidc_response_mode'] != nil -%>
OIDCResponseMode "<%= scope['::keystone::federation::openidc::openidc_response_mode'] %>" OIDCResponseMode "<%= scope['::keystone::federation::openidc::openidc_response_mode'] %>"
<%- end -%> <%- end -%>