aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2026-04-15 21:41:19 +0000
committerGerrit Code Review <review@openstack.org>2026-04-15 21:41:19 +0000
commit88aecb6009d2ef6e543849cd9930d1bd80cfca2f (patch)
treef5046b005ae3bdd767049e37005ce5e4bfb9ee39 /tests
parentfb5f1b5c8be8cad9f8e165f9cbb83a3b7ed177a0 (diff)
parent1264c46c67690abb900d74552d100746fcfa921e (diff)
downloadkolla-ansible-88aecb6009d2ef6e543849cd9930d1bd80cfca2f.tar.gz
kolla-ansible-88aecb6009d2ef6e543849cd9930d1bd80cfca2f.zip
Merge "Fix keystone with IDP configured."
Diffstat (limited to 'tests')
-rw-r--r--tests/run.yml15
-rw-r--r--tests/templates/globals-default.j211
-rw-r--r--tests/templates/keystone-federation/attribute_mapping.json42
-rw-r--r--tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.client.j24
-rw-r--r--tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.conf.j21
-rw-r--r--tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.provider.j2324
-rw-r--r--tests/testinfra/test_horizon.py51
7 files changed, 448 insertions, 0 deletions
diff --git a/tests/run.yml b/tests/run.yml
index b7c8fc702..78d34d8eb 100644
--- a/tests/run.yml
+++ b/tests/run.yml
@@ -164,6 +164,8 @@
- neutron
- nova
- bifrost
+ - keystone-httpd/federation/oidc/metadata
+ - keystone-httpd/federation/oidc/attribute_maps
- name: Generate configuration files
template:
@@ -210,6 +212,19 @@
- src: "tests/templates/tenks-deploy-config.yml.j2"
dest: "{{ ansible_env.HOME }}/tenks.yml"
when: "{{ scenario == 'ironic' }}"
+ # keystone-federation config
+ - src: "tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.conf.j2"
+ dest: "/etc/kolla/config/keystone-httpd/federation/oidc/metadata/idp.example.org%2Frealms%2Fexample.conf"
+ when: "{{ scenario == 'federation' }}"
+ - src: "tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.provider.j2"
+ dest: "/etc/kolla/config/keystone-httpd/federation/oidc/metadata/idp.example.org%2Frealms%2Fexample.provider"
+ when: "{{ scenario == 'federation' }}"
+ - src: "tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.client.j2"
+ dest: "/etc/kolla/config/keystone-httpd/federation/oidc/metadata/idp.example.org%2Frealms%2Fexample.client"
+ when: "{{ scenario == 'federation' }}"
+ - src: "tests/templates/keystone-federation/attribute_mapping.json"
+ dest: "/etc/kolla/config/keystone-httpd/federation/oidc/attribute_maps/attribute_mapping.json"
+ when: "{{ scenario == 'federation' }}"
when: item.when | default(true)
- block:
diff --git a/tests/templates/globals-default.j2 b/tests/templates/globals-default.j2
index 80f34b0aa..313e7d5cf 100644
--- a/tests/templates/globals-default.j2
+++ b/tests/templates/globals-default.j2
@@ -282,6 +282,17 @@ enable_valkey: "yes"
{% if scenario == "federation" %}
enable_keystone_federation: true
+keystone_identity_providers:
+ - name: "example_provider"
+ openstack_domain: "Default"
+ protocol: "openid"
+ identifier: "https://idp.example.org/realms/example"
+ public_name: "Example Provider"
+ attribute_mapping: "sso_oidc_mapping"
+ metadata_folder: "/etc/kolla/config/keystone-httpd/federation/oidc/metadata"
+keystone_identity_mappings:
+ - name: "sso_oidc_mapping"
+ file: "/etc/kolla/config/keystone-httpd/federation/oidc/attribute_maps/attribute_mapping.json"
{% endif %}
mariadb_monitor_read_only_interval: "30000"
diff --git a/tests/templates/keystone-federation/attribute_mapping.json b/tests/templates/keystone-federation/attribute_mapping.json
new file mode 100644
index 000000000..022cbafd2
--- /dev/null
+++ b/tests/templates/keystone-federation/attribute_mapping.json
@@ -0,0 +1,42 @@
+[
+ {
+ "local": [
+ {
+ "user": {
+ "name": "{0}",
+ "email": "{1}",
+ "domain": {
+ "name": "{2}"
+ }
+ },
+ "domain": {
+ "name": "{2}"
+ },
+ "projects": [
+ {
+ "name": "{3}",
+ "roles": [
+ {
+ "name": "member"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "remote": [
+ {
+ "type": "OIDC-preferred_username"
+ },
+ {
+ "type": "OIDC-email"
+ },
+ {
+ "type": "OIDC-openstack-user-domain"
+ },
+ {
+ "type": "OIDC-openstack-default-project"
+ }
+ ]
+ }
+]
diff --git a/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.client.j2 b/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.client.j2
new file mode 100644
index 000000000..253898f3a
--- /dev/null
+++ b/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.client.j2
@@ -0,0 +1,4 @@
+{
+ "client_id":"keystone",
+ "client_secret":"example_secret"
+}
diff --git a/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.conf.j2 b/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.conf.j2
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.conf.j2
@@ -0,0 +1 @@
+{}
diff --git a/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.provider.j2 b/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.provider.j2
new file mode 100644
index 000000000..c45eb26f9
--- /dev/null
+++ b/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.provider.j2
@@ -0,0 +1,324 @@
+{
+ "issuer": "https://idp.example.org/realms/example",
+ "authorization_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/auth",
+ "token_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/token",
+ "introspection_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/token/introspect",
+ "userinfo_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/userinfo",
+ "end_session_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/logout",
+ "frontchannel_logout_session_supported": true,
+ "frontchannel_logout_supported": true,
+ "jwks_uri": "https://idp.example.org/realms/example/protocol/openid-connect/certs",
+ "check_session_iframe": "https://idp.example.org/realms/example/protocol/openid-connect/login-status-iframe.html",
+ "grant_types_supported": [
+ "authorization_code",
+ "implicit",
+ "refresh_token",
+ "password",
+ "client_credentials",
+ "urn:openid:params:grant-type:ciba",
+ "urn:ietf:params:oauth:grant-type:device_code"
+ ],
+ "acr_values_supported": [
+ "0",
+ "1"
+ ],
+ "response_types_supported": [
+ "code",
+ "none",
+ "id_token",
+ "token",
+ "id_token token",
+ "code id_token",
+ "code token",
+ "code id_token token"
+ ],
+ "subject_types_supported": [
+ "public",
+ "pairwise"
+ ],
+ "prompt_values_supported": [
+ "none",
+ "login",
+ "consent"
+ ],
+ "id_token_signing_alg_values_supported": [
+ "PS384",
+ "RS384",
+ "EdDSA",
+ "ES384",
+ "HS256",
+ "HS512",
+ "ES256",
+ "RS256",
+ "HS384",
+ "ES512",
+ "PS256",
+ "PS512",
+ "RS512"
+ ],
+ "id_token_encryption_alg_values_supported": [
+ "ECDH-ES+A256KW",
+ "ECDH-ES+A192KW",
+ "ECDH-ES+A128KW",
+ "RSA-OAEP",
+ "RSA-OAEP-256",
+ "RSA1_5",
+ "ECDH-ES"
+ ],
+ "id_token_encryption_enc_values_supported": [
+ "A256GCM",
+ "A192GCM",
+ "A128GCM",
+ "A128CBC-HS256",
+ "A192CBC-HS384",
+ "A256CBC-HS512"
+ ],
+ "userinfo_signing_alg_values_supported": [
+ "PS384",
+ "RS384",
+ "EdDSA",
+ "ES384",
+ "HS256",
+ "HS512",
+ "ES256",
+ "RS256",
+ "HS384",
+ "ES512",
+ "PS256",
+ "PS512",
+ "RS512",
+ "none"
+ ],
+ "userinfo_encryption_alg_values_supported": [
+ "ECDH-ES+A256KW",
+ "ECDH-ES+A192KW",
+ "ECDH-ES+A128KW",
+ "RSA-OAEP",
+ "RSA-OAEP-256",
+ "RSA1_5",
+ "ECDH-ES"
+ ],
+ "userinfo_encryption_enc_values_supported": [
+ "A256GCM",
+ "A192GCM",
+ "A128GCM",
+ "A128CBC-HS256",
+ "A192CBC-HS384",
+ "A256CBC-HS512"
+ ],
+ "request_object_signing_alg_values_supported": [
+ "PS384",
+ "RS384",
+ "EdDSA",
+ "ES384",
+ "HS256",
+ "HS512",
+ "ES256",
+ "RS256",
+ "HS384",
+ "ES512",
+ "PS256",
+ "PS512",
+ "RS512",
+ "none"
+ ],
+ "request_object_encryption_alg_values_supported": [
+ "ECDH-ES+A256KW",
+ "ECDH-ES+A192KW",
+ "ECDH-ES+A128KW",
+ "RSA-OAEP",
+ "RSA-OAEP-256",
+ "RSA1_5",
+ "ECDH-ES"
+ ],
+ "request_object_encryption_enc_values_supported": [
+ "A256GCM",
+ "A192GCM",
+ "A128GCM",
+ "A128CBC-HS256",
+ "A192CBC-HS384",
+ "A256CBC-HS512"
+ ],
+ "response_modes_supported": [
+ "query",
+ "fragment",
+ "form_post",
+ "query.jwt",
+ "fragment.jwt",
+ "form_post.jwt",
+ "jwt"
+ ],
+ "registration_endpoint": "https://idp.example.org/realms/example/clients-registrations/openid-connect",
+ "token_endpoint_auth_methods_supported": [
+ "private_key_jwt",
+ "client_secret_basic",
+ "client_secret_post",
+ "tls_client_auth",
+ "client_secret_jwt"
+ ],
+ "token_endpoint_auth_signing_alg_values_supported": [
+ "PS384",
+ "RS384",
+ "EdDSA",
+ "ES384",
+ "HS256",
+ "HS512",
+ "ES256",
+ "RS256",
+ "HS384",
+ "ES512",
+ "PS256",
+ "PS512",
+ "RS512"
+ ],
+ "introspection_endpoint_auth_methods_supported": [
+ "private_key_jwt",
+ "client_secret_basic",
+ "client_secret_post",
+ "tls_client_auth",
+ "client_secret_jwt"
+ ],
+ "introspection_endpoint_auth_signing_alg_values_supported": [
+ "PS384",
+ "RS384",
+ "EdDSA",
+ "ES384",
+ "HS256",
+ "HS512",
+ "ES256",
+ "RS256",
+ "HS384",
+ "ES512",
+ "PS256",
+ "PS512",
+ "RS512"
+ ],
+ "authorization_signing_alg_values_supported": [
+ "PS384",
+ "RS384",
+ "EdDSA",
+ "ES384",
+ "HS256",
+ "HS512",
+ "ES256",
+ "RS256",
+ "HS384",
+ "ES512",
+ "PS256",
+ "PS512",
+ "RS512"
+ ],
+ "authorization_encryption_alg_values_supported": [
+ "ECDH-ES+A256KW",
+ "ECDH-ES+A192KW",
+ "ECDH-ES+A128KW",
+ "RSA-OAEP",
+ "RSA-OAEP-256",
+ "RSA1_5",
+ "ECDH-ES"
+ ],
+ "authorization_encryption_enc_values_supported": [
+ "A256GCM",
+ "A192GCM",
+ "A128GCM",
+ "A128CBC-HS256",
+ "A192CBC-HS384",
+ "A256CBC-HS512"
+ ],
+ "claims_supported": [
+ "aud",
+ "sub",
+ "iss",
+ "auth_time",
+ "name",
+ "given_name",
+ "family_name",
+ "preferred_username",
+ "email",
+ "acr"
+ ],
+ "claim_types_supported": [
+ "normal"
+ ],
+ "claims_parameter_supported": true,
+ "scopes_supported": [
+ "openid",
+ "roles",
+ "acr",
+ "profile",
+ "address",
+ "basic",
+ "offline_access",
+ "groups",
+ "email",
+ "phone",
+ "service_account",
+ "web-origins",
+ "microprofile-jwt"
+ ],
+ "request_parameter_supported": true,
+ "request_uri_parameter_supported": true,
+ "require_request_uri_registration": true,
+ "code_challenge_methods_supported": [
+ "plain",
+ "S256"
+ ],
+ "tls_client_certificate_bound_access_tokens": true,
+ "revocation_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/revoke",
+ "revocation_endpoint_auth_methods_supported": [
+ "private_key_jwt",
+ "client_secret_basic",
+ "client_secret_post",
+ "tls_client_auth",
+ "client_secret_jwt"
+ ],
+ "revocation_endpoint_auth_signing_alg_values_supported": [
+ "PS384",
+ "RS384",
+ "EdDSA",
+ "ES384",
+ "HS256",
+ "HS512",
+ "ES256",
+ "RS256",
+ "HS384",
+ "ES512",
+ "PS256",
+ "PS512",
+ "RS512"
+ ],
+ "backchannel_logout_supported": true,
+ "backchannel_logout_session_supported": true,
+ "device_authorization_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/auth/device",
+ "backchannel_token_delivery_modes_supported": [
+ "poll",
+ "ping"
+ ],
+ "backchannel_authentication_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/ext/ciba/auth",
+ "backchannel_authentication_request_signing_alg_values_supported": [
+ "PS384",
+ "RS384",
+ "EdDSA",
+ "ES384",
+ "ES256",
+ "RS256",
+ "ES512",
+ "PS256",
+ "PS512",
+ "RS512"
+ ],
+ "require_pushed_authorization_requests": false,
+ "pushed_authorization_request_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/ext/par/request",
+ "mtls_endpoint_aliases": {
+ "token_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/token",
+ "revocation_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/revoke",
+ "introspection_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/token/introspect",
+ "device_authorization_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/auth/device",
+ "registration_endpoint": "https://idp.example.org/realms/example/clients-registrations/openid-connect",
+ "userinfo_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/userinfo",
+ "pushed_authorization_request_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/ext/par/request",
+ "backchannel_authentication_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/ext/ciba/auth"
+ },
+ "authorization_response_iss_parameter_supported": true
+}
+
diff --git a/tests/testinfra/test_horizon.py b/tests/testinfra/test_horizon.py
index 9b27e4700..0c1527a9d 100644
--- a/tests/testinfra/test_horizon.py
+++ b/tests/testinfra/test_horizon.py
@@ -12,13 +12,17 @@
# License for the specific language governing permissions and limitations
# under the License.
+import os
+import pytest
import time
import yaml
from pathlib import Path
from selenium.common.exceptions import TimeoutException
+from selenium.common.exceptions import WebDriverException
from selenium import webdriver
from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.ui import WebDriverWait
home = Path.home()
@@ -122,3 +126,50 @@ def test_horizon_login(host):
raise e
finally:
driver.quit()
+
+
+@pytest.mark.skipif(
+ os.getenv("SCENARIO") != "federation",
+ reason=(
+ "Current scenario is not federation. "
+ "Not running test."
+ )
+)
+def test_horizon_login_federation(host):
+
+ firefox_options = webdriver.FirefoxOptions()
+ selenium_url = host.environment().get(
+ 'SELENIUM_REMOTE_URL', 'http://localhost:4500/wd/hub')
+
+ driver = webdriver.Remote(
+ command_executor=selenium_url,
+ options=firefox_options)
+
+ horizon_proto = host.environment().get('HORIZON_PROTO')
+ horizon_url = horizon_proto + "://192.0.2.10"
+ login_url = '/'.join((
+ horizon_url,
+ 'auth',
+ 'login'))
+
+ try:
+ driver.get(login_url)
+ auth_type_field = driver.find_element(By.ID, 'id_auth_type')
+ select = Select(auth_type_field)
+ select.select_by_value('example_provider_openid')
+ button = driver.find_element(By.CSS_SELECTOR, '.btn-primary')
+
+ try:
+ button.click()
+ except WebDriverException as e:
+ if "Reached error page" in str(e) or "dnsNotFound" in str(e):
+ pass # This is expected behavior, so we ignore the exception
+ else:
+ raise # Re-raise if it failed for an unexpected reason
+
+ assert "idp.example.org" in driver.current_url # nosec B101
+
+ except TimeoutException as e:
+ raise e
+ finally:
+ driver.quit()