Add oidc federation test setup
Add devstack testing setup for OIDC using an instance of keycloak which is instantiated from a keycloak image. This is largely taken from Kristi's work in https://github.com/knikolla/devstack-plugin-oidc This configuration is triggered by enabling the devstack service keystone-oidc-federation. The expectation is that either SAML2 or OIDC is enabled, but not both. Depends-On: https://review.opendev.org/c/openstack/keystone-tempest-plugin/+/864571 Co-Authored-By: David Wilde <dwilde@redhat.com> Change-Id: I1ff4d48c05cef1022dc510df03104f36cdd7a953
This commit is contained in:
parent
420f4ff46d
commit
d293315eec
17
.zuul.yaml
17
.zuul.yaml
@ -202,6 +202,21 @@
|
|||||||
name: keystone-dsvm-py35-functional-federation
|
name: keystone-dsvm-py35-functional-federation
|
||||||
parent: keystone-dsvm-py35-functional-federation-ubuntu-xenial
|
parent: keystone-dsvm-py35-functional-federation-ubuntu-xenial
|
||||||
|
|
||||||
|
# Experimental
|
||||||
|
- job:
|
||||||
|
name: keystone-dsvm-functional-oidc-federation
|
||||||
|
parent: keystone-dsvm-functional
|
||||||
|
vars:
|
||||||
|
devstack_localrc:
|
||||||
|
TEMPEST_PLUGINS: '/opt/stack/keystone-tempest-plugin'
|
||||||
|
USE_PYTHON3: True
|
||||||
|
OS_CACERT: '/opt/stack/data/ca_bundle.pem'
|
||||||
|
devstack_services:
|
||||||
|
tls-proxy: true
|
||||||
|
keystone-oidc-federation: true
|
||||||
|
devstack_plugins:
|
||||||
|
keystone: https://opendev.org/openstack/keystone
|
||||||
|
|
||||||
- project:
|
- project:
|
||||||
templates:
|
templates:
|
||||||
- openstack-cover-jobs
|
- openstack-cover-jobs
|
||||||
@ -279,3 +294,5 @@
|
|||||||
irrelevant-files: *irrelevant-files
|
irrelevant-files: *irrelevant-files
|
||||||
- keystone-dsvm-py35-functional-federation-ubuntu-xenial:
|
- keystone-dsvm-py35-functional-federation-ubuntu-xenial:
|
||||||
irrelevant-files: *irrelevant-files
|
irrelevant-files: *irrelevant-files
|
||||||
|
- keystone-dsvm-functional-oidc-federation:
|
||||||
|
irrelevant-files: *irrelevant-files
|
||||||
|
47
devstack/files/oidc/apache_oidc.conf
Normal file
47
devstack/files/oidc/apache_oidc.conf
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# DO NOT USE THIS IN PRODUCTION ENVIRONMENTS!
|
||||||
|
OIDCSSLValidateServer Off
|
||||||
|
OIDCOAuthSSLValidateServer Off
|
||||||
|
OIDCCookieSameSite On
|
||||||
|
|
||||||
|
OIDCClaimPrefix "OIDC-"
|
||||||
|
OIDCResponseType "id_token"
|
||||||
|
OIDCScope "openid email profile"
|
||||||
|
OIDCProviderMetadataURL "%OIDC_METADATA_URL%"
|
||||||
|
OIDCClientID "%OIDC_CLIENT_ID%"
|
||||||
|
OIDCClientSecret "%OIDC_CLIENT_SECRET%"
|
||||||
|
OIDCPKCEMethod "S256"
|
||||||
|
OIDCCryptoPassphrase "openstack"
|
||||||
|
|
||||||
|
OIDCRedirectURI "https://%HOST_IP%/identity/v3/auth/OS-FEDERATION/identity_providers/%IDP_ID%/protocols/openid/websso"
|
||||||
|
OIDCRedirectURI "https://%HOST_IP%/identity/v3/auth/OS-FEDERATION/websso/openid"
|
||||||
|
|
||||||
|
<LocationMatch "/v3/auth/OS-FEDERATION/websso/openid">
|
||||||
|
AuthType "openid-connect"
|
||||||
|
Require valid-user
|
||||||
|
LogLevel debug
|
||||||
|
</LocationMatch>
|
||||||
|
|
||||||
|
<LocationMatch "/v3/auth/OS-FEDERATION/identity_providers/%IDP_ID%/protocols/openid/websso">
|
||||||
|
AuthType "openid-connect"
|
||||||
|
Require valid-user
|
||||||
|
LogLevel debug
|
||||||
|
</LocationMatch>
|
||||||
|
|
||||||
|
<LocationMatch "/v3/auth/OS-FEDERATION/identity_providers/%IDP_ID%/protocols/openid/auth">
|
||||||
|
AuthType "openid-connect"
|
||||||
|
Require valid-user
|
||||||
|
LogLevel debug
|
||||||
|
</LocationMatch>
|
||||||
|
|
||||||
|
<Location ~ "/v3/OS-FEDERATION/identity_providers/%IDP_ID%/protocols/openid/auth">
|
||||||
|
AuthType oauth20
|
||||||
|
Require valid-user
|
||||||
|
</Location>
|
||||||
|
|
||||||
|
OIDCOAuthClientID "%OIDC_CLIENT_ID%"
|
||||||
|
OIDCOAuthClientSecret "%OIDC_CLIENT_SECRET%"
|
||||||
|
OIDCOAuthIntrospectionEndpoint "%OIDC_INTROSPECTION_URL%"
|
||||||
|
|
||||||
|
# Horizon favors the referrer to the Keystone URL that is set.
|
||||||
|
# https://github.com/openstack/horizon/blob/5e4ca1a9fdec04db08552e9e93fe372b8b8b45ae/openstack_auth/views.py#L192
|
||||||
|
Header always set Referrer-Policy "no-referrer"
|
160
devstack/lib/oidc.sh
Normal file
160
devstack/lib/oidc.sh
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
DOMAIN_NAME=${DOMAIN_NAME:-federated_domain}
|
||||||
|
PROJECT_NAME=${PROJECT_NAME:-federated_project}
|
||||||
|
GROUP_NAME=${GROUP_NAME:-federated_users}
|
||||||
|
|
||||||
|
OIDC_CLIENT_ID=${CLIENT_ID:-devstack}
|
||||||
|
OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET:-nomoresecret}
|
||||||
|
|
||||||
|
OIDC_ISSUER=${OIDC_ISSUER:-"https://$HOST_IP:8443"}
|
||||||
|
OIDC_ISSUER_BASE="${OIDC_ISSUER}/realms/master"
|
||||||
|
|
||||||
|
OIDC_METADATA_URL=${OIDC_METADATA_URL:-"https://$HOST_IP:8443/realms/master/.well-known/openid-configuration"}
|
||||||
|
OIDC_INTROSPECTION_URL=${OIDC_INTROSPECTION_URL:-"https://$HOST_IP:8443/realms/master/protocol/openid-connect/token/introspect"}
|
||||||
|
|
||||||
|
IDP_ID=${IDP_ID:-sso}
|
||||||
|
IDP_USERNAME=${IDP_USERNAME:-admin}
|
||||||
|
IDP_PASSWORD=${IDP_PASSWORD:-nomoresecret}
|
||||||
|
|
||||||
|
MAPPING_REMOTE_TYPE=${MAPPING_REMOTE_TYPE:-OIDC-preferred_username}
|
||||||
|
MAPPING_USER_NAME=${MAPPING_USER_NAME:-"{0}"}
|
||||||
|
PROTOCOL_ID=${PROTOCOL_ID:-openid}
|
||||||
|
|
||||||
|
REDIRECT_URI="https://$HOST_IP/identity/v3/auth/OS-FEDERATION/identity_providers/$IDP_ID/protocols/openid/websso"
|
||||||
|
|
||||||
|
OIDC_PLUGIN="$DEST/keystone/devstack"
|
||||||
|
|
||||||
|
function install_federation {
|
||||||
|
if is_ubuntu; then
|
||||||
|
install_package libapache2-mod-auth-openidc
|
||||||
|
sudo a2enmod headers
|
||||||
|
install_package docker.io
|
||||||
|
install_package docker-compose
|
||||||
|
elif is_fedora; then
|
||||||
|
install_package mod_auth_openidc
|
||||||
|
install_package podman
|
||||||
|
install_package podman-docker
|
||||||
|
install_package docker-compose
|
||||||
|
sudo systemctl start podman.socket
|
||||||
|
else
|
||||||
|
echo "Skipping installation. Only supported on Ubuntu and RHEL based."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function configure_federation {
|
||||||
|
# Specify the header that contains information about the identity provider
|
||||||
|
iniset $KEYSTONE_CONF openid remote_id_attribute "HTTP_OIDC_ISS"
|
||||||
|
iniset $KEYSTONE_CONF auth methods "password,token,openid,application_credential"
|
||||||
|
iniset $KEYSTONE_CONF federation trusted_dashboard "https://$HOST_IP/auth/websso/"
|
||||||
|
|
||||||
|
cp $DEST/keystone/etc/sso_callback_template.html /etc/keystone/
|
||||||
|
|
||||||
|
if [[ "$WSGI_MODE" == "uwsgi" ]]; then
|
||||||
|
restart_service "devstack@keystone"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$OIDC_ISSUER_BASE" == "https://$HOST_IP:8443/realms/master" ]]; then
|
||||||
|
# Assuming we want to setup a local keycloak here.
|
||||||
|
sed -i "s#DEVSTACK_DEST#${DATA_DIR}#" ${OIDC_PLUGIN}/tools/oidc/docker-compose.yaml
|
||||||
|
sudo docker-compose --file ${OIDC_PLUGIN}/tools/oidc/docker-compose.yaml up -d
|
||||||
|
|
||||||
|
# wait for the server to be up
|
||||||
|
attempt_counter=0
|
||||||
|
max_attempts=100
|
||||||
|
until $(curl --output /dev/null --silent --fail $OIDC_METADATA_URL); do
|
||||||
|
if [ ${attempt_counter} -eq ${max_attempts} ];then
|
||||||
|
echo "Keycloak server failed to come up in time"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
attempt_counter=$(($attempt_counter+1))
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
KEYCLOAK_URL="https://$HOST_IP:8443" \
|
||||||
|
KEYCLOAK_USERNAME="admin" \
|
||||||
|
KEYCLOAK_PASSWORD="nomoresecret" \
|
||||||
|
HOST_IP="$HOST_IP" \
|
||||||
|
python3 $OIDC_PLUGIN/tools/oidc/setup_keycloak_client.py
|
||||||
|
fi
|
||||||
|
|
||||||
|
local keystone_apache_conf=$(apache_site_config_for keystone-wsgi-public)
|
||||||
|
cat $OIDC_PLUGIN/files/oidc/apache_oidc.conf | sudo tee -a $keystone_apache_conf
|
||||||
|
sudo sed -i -e "
|
||||||
|
s|%OIDC_CLIENT_ID%|$OIDC_CLIENT_ID|g;
|
||||||
|
s|%OIDC_CLIENT_SECRET%|$OIDC_CLIENT_SECRET|g;
|
||||||
|
s|%OIDC_METADATA_URL%|$OIDC_METADATA_URL|g;
|
||||||
|
s|%OIDC_INTROSPECTION_URL%|$OIDC_INTROSPECTION_URL|g;
|
||||||
|
s|%HOST_IP%|$HOST_IP|g;
|
||||||
|
s|%IDP_ID%|$IDP_ID|g;
|
||||||
|
" $keystone_apache_conf
|
||||||
|
|
||||||
|
restart_apache_server
|
||||||
|
}
|
||||||
|
|
||||||
|
function register_federation {
|
||||||
|
local federated_domain=$(get_or_create_domain $DOMAIN_NAME)
|
||||||
|
local federated_project=$(get_or_create_project $PROJECT_NAME $DOMAIN_NAME)
|
||||||
|
local federated_users=$(get_or_create_group $GROUP_NAME $DOMAIN_NAME)
|
||||||
|
local member_role=$(get_or_create_role Member)
|
||||||
|
|
||||||
|
openstack role add --group $federated_users --domain $federated_domain $member_role
|
||||||
|
openstack role add --group $federated_users --project $federated_project $member_role
|
||||||
|
|
||||||
|
openstack identity provider create \
|
||||||
|
--remote-id $OIDC_ISSUER_BASE \
|
||||||
|
--domain $DOMAIN_NAME $IDP_ID
|
||||||
|
}
|
||||||
|
|
||||||
|
function configure_tests_settings {
|
||||||
|
# Here we set any settings that might be need by the fed_scenario set of tests
|
||||||
|
iniset $TEMPEST_CONFIG identity-feature-enabled federation True
|
||||||
|
|
||||||
|
# we probably need an oidc version of this flag based on local oidc
|
||||||
|
iniset $TEMPEST_CONFIG identity-feature-enabled external_idp True
|
||||||
|
|
||||||
|
# Identity provider settings
|
||||||
|
iniset $TEMPEST_CONFIG fed_scenario idp_id $IDP_ID
|
||||||
|
iniset $TEMPEST_CONFIG fed_scenario idp_remote_ids $OIDC_ISSUER_BASE
|
||||||
|
iniset $TEMPEST_CONFIG fed_scenario idp_username $IDP_USERNAME
|
||||||
|
iniset $TEMPEST_CONFIG fed_scenario idp_password $IDP_PASSWORD
|
||||||
|
iniset $TEMPEST_CONFIG fed_scenario idp_oidc_url $OIDC_ISSUER
|
||||||
|
iniset $TEMPEST_CONFIG fed_scenario idp_client_id $OIDC_CLIENT_ID
|
||||||
|
iniset $TEMPEST_CONFIG fed_scenario idp_client_secret $OIDC_CLIENT_SECRET
|
||||||
|
|
||||||
|
# Mapping rules settings
|
||||||
|
iniset $TEMPEST_CONFIG fed_scenario mapping_remote_type $MAPPING_REMOTE_TYPE
|
||||||
|
iniset $TEMPEST_CONFIG fed_scenario mapping_user_name $MAPPING_USER_NAME
|
||||||
|
iniset $TEMPEST_CONFIG fed_scenario mapping_group_name $GROUP_NAME
|
||||||
|
iniset $TEMPEST_CONFIG fed_scenario mapping_group_domain_name $DOMAIN_NAME
|
||||||
|
iniset $TEMPEST_CONFIG fed_scenario enable_k2k_groups_mapping False
|
||||||
|
|
||||||
|
# Protocol settings
|
||||||
|
iniset $TEMPEST_CONFIG fed_scenario protocol_id $PROTOCOL_ID
|
||||||
|
}
|
||||||
|
|
||||||
|
function uninstall_federation {
|
||||||
|
# Ensure Keycloak is stopped and the containers are cleaned up
|
||||||
|
sudo docker-compose --file ${OIDC_PLUGIN}/tools/oidc/docker-compose.yaml down
|
||||||
|
if is_ubuntu; then
|
||||||
|
sudo docker rmi $(sudo docker images -a -q)
|
||||||
|
uninstall_package docker-compose
|
||||||
|
elif is_fedora; then
|
||||||
|
sudo podman rmi $(sudo podman images -a -q)
|
||||||
|
uninstall_package podman
|
||||||
|
else
|
||||||
|
echo "Skipping uninstallation of OIDC federation for non ubuntu nor fedora nor suse host"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,13 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
KEYSTONE_PLUGIN=$DEST/keystone/devstack
|
KEYSTONE_PLUGIN=$DEST/keystone/devstack
|
||||||
source $KEYSTONE_PLUGIN/lib/federation.sh
|
|
||||||
|
if is_service_enabled keystone-saml2-federation; then
|
||||||
|
source $KEYSTONE_PLUGIN/lib/federation.sh
|
||||||
|
elif is_service_enabled keystone-oidc-federation; then
|
||||||
|
source $KEYSTONE_PLUGIN/lib/oidc.sh
|
||||||
|
fi
|
||||||
|
|
||||||
source $KEYSTONE_PLUGIN/lib/scope.sh
|
source $KEYSTONE_PLUGIN/lib/scope.sh
|
||||||
|
|
||||||
# For more information on Devstack plugins, including a more detailed
|
# For more information on Devstack plugins, including a more detailed
|
||||||
@ -25,6 +31,10 @@ if [[ "$1" == "stack" && "$2" == "install" ]]; then
|
|||||||
# This phase is executed after the projects have been installed
|
# This phase is executed after the projects have been installed
|
||||||
echo "Keystone plugin - Install phase"
|
echo "Keystone plugin - Install phase"
|
||||||
if is_service_enabled keystone-saml2-federation; then
|
if is_service_enabled keystone-saml2-federation; then
|
||||||
|
echo "installing saml2 federation"
|
||||||
|
install_federation
|
||||||
|
elif is_service_enabled keystone-oidc-federation; then
|
||||||
|
echo "installing oidc federation"
|
||||||
install_federation
|
install_federation
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -33,6 +43,10 @@ elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
|
|||||||
# before they are started
|
# before they are started
|
||||||
echo "Keystone plugin - Post-config phase"
|
echo "Keystone plugin - Post-config phase"
|
||||||
if is_service_enabled keystone-saml2-federation; then
|
if is_service_enabled keystone-saml2-federation; then
|
||||||
|
echo "configuring saml2 federation"
|
||||||
|
configure_federation
|
||||||
|
elif is_service_enabled keystone-oidc-federation; then
|
||||||
|
echo "configuring oidc federation"
|
||||||
configure_federation
|
configure_federation
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -40,12 +54,21 @@ elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
|
|||||||
# This phase is executed after the projects have been started
|
# This phase is executed after the projects have been started
|
||||||
echo "Keystone plugin - Extra phase"
|
echo "Keystone plugin - Extra phase"
|
||||||
if is_service_enabled keystone-saml2-federation; then
|
if is_service_enabled keystone-saml2-federation; then
|
||||||
|
echo "registering saml2 federation"
|
||||||
|
register_federation
|
||||||
|
elif is_service_enabled keystone-oidc-federation; then
|
||||||
|
echo "registering oidc federation"
|
||||||
register_federation
|
register_federation
|
||||||
fi
|
fi
|
||||||
|
|
||||||
elif [[ "$1" == "stack" && "$2" == "test-config" ]]; then
|
elif [[ "$1" == "stack" && "$2" == "test-config" ]]; then
|
||||||
# This phase is executed after Tempest was configured
|
# This phase is executed after Tempest was configured
|
||||||
echo "Keystone plugin - Test-config phase"
|
echo "Keystone plugin - Test-config phase"
|
||||||
if is_service_enabled keystone-saml2-federation; then
|
if is_service_enabled keystone-saml2-federation; then
|
||||||
|
echo "config tests settings for saml"
|
||||||
|
configure_tests_settings
|
||||||
|
elif is_service_enabled keystone-oidc-federation; then
|
||||||
|
echo "config tests settings for oidc"
|
||||||
configure_tests_settings
|
configure_tests_settings
|
||||||
fi
|
fi
|
||||||
if [[ "$(trueorfalse False KEYSTONE_ENFORCE_SCOPE)" == "True" ]] ; then
|
if [[ "$(trueorfalse False KEYSTONE_ENFORCE_SCOPE)" == "True" ]] ; then
|
||||||
@ -66,6 +89,10 @@ if [[ "$1" == "clean" ]]; then
|
|||||||
# Called by clean.sh after the "unstack" phase
|
# Called by clean.sh after the "unstack" phase
|
||||||
# Undo what was performed during the "install" phase
|
# Undo what was performed during the "install" phase
|
||||||
if is_service_enabled keystone-saml2-federation; then
|
if is_service_enabled keystone-saml2-federation; then
|
||||||
|
echo "uninstalling saml"
|
||||||
|
uninstall_federation
|
||||||
|
elif is_service_enabled keystone-oidc-federation; then
|
||||||
|
echo "uninstalling oidc"
|
||||||
uninstall_federation
|
uninstall_federation
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
0
devstack/tools/oidc/__init__.py
Normal file
0
devstack/tools/oidc/__init__.py
Normal file
33
devstack/tools/oidc/docker-compose.yaml
Normal file
33
devstack/tools/oidc/docker-compose.yaml
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
keycloak:
|
||||||
|
image: quay.io/keycloak/keycloak:latest
|
||||||
|
command: start-dev --log-level debug --log=console,file --https-certificate-file=/etc/certs/devstack-cert.pem --https-certificate-key-file=/etc/certs/devstack-cert.pem
|
||||||
|
container_name: oidc_keycloak_1
|
||||||
|
environment:
|
||||||
|
KEYCLOAK_ADMIN: admin
|
||||||
|
KEYCLOAK_ADMIN_PASSWORD: nomoresecret
|
||||||
|
KEYCLOAK_USER: admin
|
||||||
|
KEYCLOAK_PASSWORD: nomoresecret
|
||||||
|
KEYCLOAK_LOG_LEVEL: DEBUG
|
||||||
|
DB_VENDOR: mariadb
|
||||||
|
DB_DATABASE: keycloak
|
||||||
|
DB_USER: keycloak
|
||||||
|
DB_PASSWORD: "nomoresecret"
|
||||||
|
DB_ADDR: "keycloak-database"
|
||||||
|
DB_PORT: "3306"
|
||||||
|
JAVA_OPTS: "-server -Xms128m -Xmx1024m -XX:MetaspaceSize=128M -XX:MaxMetaspaceSize=512m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true"
|
||||||
|
ports:
|
||||||
|
- "8088:8080" # host:container
|
||||||
|
- "8443:8443"
|
||||||
|
volumes:
|
||||||
|
- DEVSTACK_DEST:/etc/certs:rw
|
||||||
|
|
||||||
|
keycloak-database:
|
||||||
|
image: quay.io/metal3-io/mariadb:latest
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: nomoresecret
|
||||||
|
MYSQL_DATABASE: keycloak
|
||||||
|
MYSQL_USER: keycloak
|
||||||
|
MYSQL_PASSWORD: nomoresecret
|
61
devstack/tools/oidc/setup_keycloak_client.py
Normal file
61
devstack/tools/oidc/setup_keycloak_client.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import os
|
||||||
|
import requests
|
||||||
|
|
||||||
|
KEYCLOAK_USERNAME = os.environ.get('KEYCLOAK_USERNAME')
|
||||||
|
KEYCLOAK_PASSWORD = os.environ.get('KEYCLOAK_PASSWORD')
|
||||||
|
KEYCLOAK_URL = os.environ.get('KEYCLOAK_URL')
|
||||||
|
HOST_IP = os.environ.get('HOST_IP', 'localhost')
|
||||||
|
|
||||||
|
class KeycloakClient(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.session = requests.session()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def construct_url(realm, path):
|
||||||
|
return f'{KEYCLOAK_URL}/admin/realms/{realm}/{path}'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def token_endpoint(realm):
|
||||||
|
return f'{KEYCLOAK_URL}/realms/{realm}/protocol/openid-connect/token'
|
||||||
|
|
||||||
|
def _admin_auth(self, realm):
|
||||||
|
params = {
|
||||||
|
'grant_type': 'password',
|
||||||
|
'client_id': 'admin-cli',
|
||||||
|
'username': KEYCLOAK_USERNAME,
|
||||||
|
'password': KEYCLOAK_PASSWORD,
|
||||||
|
'scope': 'openid',
|
||||||
|
}
|
||||||
|
r = requests.post(self.token_endpoint(realm), data=params).json()
|
||||||
|
headers = {
|
||||||
|
'Authorization': ("Bearer %s" % r['access_token']),
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
self.session.headers.update(headers)
|
||||||
|
return r
|
||||||
|
|
||||||
|
def create_client(self, realm, client_id, client_secret, redirect_uris):
|
||||||
|
self._admin_auth(realm)
|
||||||
|
data = {
|
||||||
|
'clientId': client_id,
|
||||||
|
'secret': client_secret,
|
||||||
|
'redirectUris': redirect_uris,
|
||||||
|
'implicitFlowEnabled': True,
|
||||||
|
'directAccessGrantsEnabled': True,
|
||||||
|
}
|
||||||
|
return self.session.post(self.construct_url(realm, 'clients'), json=data)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
c = KeycloakClient()
|
||||||
|
|
||||||
|
redirect_uris = [
|
||||||
|
f'http://{HOST_IP}/identity/v3/auth/OS-FEDERATION/identity_providers/sso/protocols/openid/websso',
|
||||||
|
f'http://{HOST_IP}/identity/v3/auth/OS-FEDERATION/websso/openid'
|
||||||
|
]
|
||||||
|
|
||||||
|
c.create_client('master', 'devstack', 'nomoresecret', redirect_uris)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user