* Add keystone-openidc setup code.
The keystone-openidc charm requires 2 configuration steps:
1) Configure the oidc-client-id, oidc-client-secret and
oidc-provider-metadata-url, this information is tightly related to
the Identity Provider configured, which for testing purposes this is
the openidc-test-fixture charm, the setup function
zaza.openstack.charm_tests.openidc.setup.configure_keystone_openidc
takes care of setting these values once the fixture charm is ready
for service.
2) Create the OpenStack objects to correctly configure the federation,
this is made by the setup function
zaza.openstack.charm_tests.openidc.setup.keystone_federation_setup_site1
which will create and configure the following resources:
- Create a domain named 'federated_domain'.
- Create a group named 'federated_users'.
- Grant the 'Member' role to users in the 'federated_users' group.
- Create an identity provider named 'openid'.
- Create a mapping named 'openid_mapping'.
- Create a federation protocol named 'openid' that relates the mapping
and the identity provider.
* Add support for v3oidcpassword auth plugin.
get_keystone_session() uses the v3.OidcPassword class when the
OS_AUTH_TYPE is set to v3oidcpassword, this class expects the following
extra configuration options:
- OS_IDENTITY_PROVIDER
- OS_PROTOCOL
- OS_CLIENT_ID
- OS_CLIENT_SECRET
- OS_ACCESS_TOKEN_ENDPOINT (optional)
- OS_DISCOVERY_ENDPOINT (optional)
* Add test for keystone-openidc
This patch introduces a new testing class named CharmKeystoneOpenIDCTest
which interacts with keystone using users provided by
openidc-test-fixture via OpenID Connect.
* Add keystone_session argument to launch instances.
Adding the option to pass a keystone session allows callers to use
credentials different from the ones provided by
get_overcloud_keystone_session(), this is helpful when testing non
default keystone configurations (e.g. Federation).
* Add zaza.openstack.charm_tests.openidc.tests.TestLaunchInstance
This testing class configures a private network in the user's project defined by the mapping
rules during the setUpClass stage. Specifically this test performs the following steps:
- Create keypair named 'zaza' in the user's project
- Create a router for the project
- Attach the router to the external network
- Create a network
- Create a subnet attached to the previously create network
- Connect the subnet to the project's router
The testing method launches an instance using a keystone session
associated with a user backed by OpenID Connect.
175 lines
6.8 KiB
Python
175 lines
6.8 KiB
Python
# Copyright 2022 Canonical Ltd.
|
|
#
|
|
# 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.
|
|
|
|
"""Keystone OpenID Connect Testing."""
|
|
import copy
|
|
import logging
|
|
import pprint
|
|
|
|
import zaza.model
|
|
|
|
from zaza.openstack.charm_tests.glance.setup import CIRROS_IMAGE_NAME
|
|
from zaza.openstack.charm_tests.keystone import BaseKeystoneTest
|
|
from zaza.openstack.charm_tests.neutron.setup import (
|
|
OVERCLOUD_NETWORK_CONFIG,
|
|
DEFAULT_UNDERCLOUD_NETWORK_CONFIG,
|
|
)
|
|
from zaza.openstack.charm_tests.nova.setup import manage_ssh_key
|
|
from zaza.openstack.charm_tests.openidc.setup import (
|
|
FEDERATED_DOMAIN,
|
|
IDP,
|
|
PROTOCOL_NAME,
|
|
)
|
|
from zaza.openstack.utilities import (
|
|
generic as generic_utils,
|
|
openstack as openstack_utils,
|
|
)
|
|
|
|
# static users created by openidc-test-fixture charm
|
|
OIDC_TEST_USER = 'johndoe'
|
|
OIDC_TEST_USER_PASSWORD = 'f00bar'
|
|
|
|
|
|
class BaseCharmKeystoneOpenIDC(BaseKeystoneTest):
|
|
"""Charm Keystone OpenID Connect tests."""
|
|
|
|
run_resource_cleanup = True
|
|
RESOURCE_PREFIX = 'zaza-openidc'
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
"""Define openrc credentials for OIDC_TEST_USER."""
|
|
super().setUpClass()
|
|
charm_config = zaza.model.get_application_config('keystone-openidc')
|
|
client_id = charm_config['oidc-client-id']['value']
|
|
client_secret = charm_config['oidc-client-secret']['value']
|
|
metadata_url = charm_config['oidc-provider-metadata-url']['value']
|
|
cls.oidc_test_openrc = {
|
|
'API_VERSION': 3,
|
|
'OS_USERNAME': OIDC_TEST_USER,
|
|
'OS_PASSWORD': OIDC_TEST_USER_PASSWORD,
|
|
# using the first keystone ip by default, for environments with
|
|
# HA+TLS enabled this is the virtual IP, otherwise it will be one
|
|
# of the keystone units.
|
|
'OS_AUTH_URL': 'https://{}:5000/v3'.format(cls.keystone_ips[0]),
|
|
'OS_PROJECT_DOMAIN_NAME': FEDERATED_DOMAIN,
|
|
'OS_PROJECT_NAME': '{}_project'.format(OIDC_TEST_USER),
|
|
'OS_CACERT': openstack_utils.get_cacert(),
|
|
# openid specific info
|
|
'OS_AUTH_TYPE': 'v3oidcpassword',
|
|
'OS_DISCOVERY_ENDPOINT': metadata_url,
|
|
'OS_OPENID_SCOPE': 'openid email profile',
|
|
'OS_CLIENT_ID': client_id,
|
|
'OS_CLIENT_SECRET': client_secret,
|
|
'OS_IDENTITY_PROVIDER': IDP,
|
|
'OS_PROTOCOL': PROTOCOL_NAME,
|
|
}
|
|
logging.info('openrc: %s', pprint.pformat(cls.oidc_test_openrc))
|
|
|
|
|
|
class TestToken(BaseCharmKeystoneOpenIDC):
|
|
"""Test tokens for user's backed by OpenID Connect via Federation."""
|
|
|
|
def test_token_issue(self):
|
|
"""Test token issue with a federated user via openidc."""
|
|
openrc = copy.deepcopy(self.oidc_test_openrc)
|
|
with self.v3_keystone_preferred():
|
|
for ip in self.keystone_ips:
|
|
logging.info('keystone IP %s', ip)
|
|
openrc['AUTH_URL'] = 'https://{}:5000/v3'.format(ip)
|
|
keystone_session = openstack_utils.get_keystone_session(
|
|
openrc, scope='PROJECT')
|
|
logging.info('Retrieving token for federated user')
|
|
token = keystone_session.get_token()
|
|
logging.info('Token: %s', token)
|
|
self.assertIsNotNone(token)
|
|
logging.info('OK')
|
|
|
|
|
|
class TestLaunchInstance(BaseCharmKeystoneOpenIDC):
|
|
"""Test instance launching in a project defined by Federation mapping."""
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
"""Configure user's project network backed by OpenID Connect."""
|
|
super().setUpClass()
|
|
# Get network configuration settings
|
|
network_config = {"private_net_cidr": "192.168.21.0/24"}
|
|
# Declared overcloud settings
|
|
network_config.update(OVERCLOUD_NETWORK_CONFIG)
|
|
# Default undercloud settings
|
|
network_config.update(DEFAULT_UNDERCLOUD_NETWORK_CONFIG)
|
|
# Environment specific settings
|
|
network_config.update(generic_utils.get_undercloud_env_vars())
|
|
ip_version = network_config.get("ip_version") or 4
|
|
|
|
keystone_session = openstack_utils.get_keystone_session(
|
|
cls.oidc_test_openrc, scope='PROJECT')
|
|
# find user's project id
|
|
project_id = keystone_session.get_project_id()
|
|
|
|
# Get authenticated clients
|
|
neutron_client = openstack_utils.get_neutron_session_client(
|
|
keystone_session)
|
|
nova_client = openstack_utils.get_nova_session_client(
|
|
keystone_session)
|
|
|
|
# create 'zaza' key in user's project
|
|
manage_ssh_key(nova_client)
|
|
|
|
# create a router attached to the external network
|
|
ext_net_name = network_config["external_net_name"]
|
|
networks = neutron_client.list_networks(name=ext_net_name)
|
|
ext_network = networks['networks'][0]
|
|
provider_router = openstack_utils.create_provider_router(
|
|
neutron_client, project_id)
|
|
openstack_utils.plug_extnet_into_router(
|
|
neutron_client,
|
|
provider_router,
|
|
ext_network)
|
|
|
|
# create project's private network
|
|
project_network = openstack_utils.create_project_network(
|
|
neutron_client,
|
|
project_id,
|
|
shared=False,
|
|
network_type=network_config["network_type"],
|
|
net_name=network_config["project_net_name"])
|
|
project_subnet = openstack_utils.create_project_subnet(
|
|
neutron_client,
|
|
project_id,
|
|
project_network,
|
|
network_config["private_net_cidr"],
|
|
ip_version=ip_version,
|
|
subnet_name=network_config["project_subnet_name"])
|
|
openstack_utils.update_subnet_dns(
|
|
neutron_client,
|
|
project_subnet,
|
|
network_config["external_dns"])
|
|
openstack_utils.plug_subnet_into_router(
|
|
neutron_client,
|
|
provider_router['name'],
|
|
project_network,
|
|
project_subnet)
|
|
openstack_utils.add_neutron_secgroup_rules(neutron_client, project_id)
|
|
|
|
def test_20_launch_instance(self):
|
|
"""Test launching an instance in a project defined by mapping rules."""
|
|
keystone_session = openstack_utils.get_keystone_session(
|
|
self.oidc_test_openrc, scope='PROJECT')
|
|
|
|
self.launch_guest('test-42',
|
|
instance_key=CIRROS_IMAGE_NAME,
|
|
keystone_session=keystone_session)
|