Exemplo n.º 1
0
 def test_get_keystone_session(self):
     self.patch_object(openstack_utils, "session")
     self.patch_object(openstack_utils, "v2")
     _auth = mock.MagicMock()
     self.v2.Password.return_value = _auth
     _openrc = {
         "OS_AUTH_URL": "https://keystone:5000",
         "OS_USERNAME": "******",
         "OS_PASSWORD": "******",
         "OS_TENANT_NAME": "tenant",
     }
     openstack_utils.get_keystone_session(_openrc)
     self.session.Session.assert_called_once_with(auth=_auth, verify=None)
Exemplo n.º 2
0
    def _find_keystone_v3_group(self, group, domain):
        """Find a group within a specified keystone v3 domain.

        :param str group: Group to search for in keystone
        :param str domain: group selected from which domain
        :return: return group if found
        :rtype: Optional[str]
        """
        for ip in self.keystone_ips:
            logging.info('Keystone IP {}'.format(ip))
            session = openstack_utils.get_keystone_session(
                openstack_utils.get_overcloud_auth(address=ip))
            client = openstack_utils.get_keystone_session_client(session)

            domain_groups = client.groups.list(
                domain=client.domains.find(name=domain).id
            )

            for searched_group in domain_groups:
                if searched_group.name.lower() == group.lower():
                    return searched_group

        logging.debug(
            "Group {} was not found. Returning None.".format(group)
        )
        return None
Exemplo n.º 3
0
    def _find_keystone_v3_user(self, username, domain, group=None):
        """Find a user within a specified keystone v3 domain.

        :param str username: Username to search for in keystone
        :param str domain: username selected from which domain
        :param str group: group to search for in keystone for group membership
        :return: return username if found
        :rtype: Optional[str]
        """
        for ip in self.keystone_ips:
            logging.info('Keystone IP {}'.format(ip))
            session = openstack_utils.get_keystone_session(
                openstack_utils.get_overcloud_auth(address=ip))
            client = openstack_utils.get_keystone_session_client(session)

            if group is None:
                domain_users = client.users.list(
                    domain=client.domains.find(name=domain).id,
                )
            else:
                domain_users = client.users.list(
                    domain=client.domains.find(name=domain).id,
                    group=self._find_keystone_v3_group(group, domain).id,
                )

            usernames = [u.name.lower() for u in domain_users]
            if username.lower() in usernames:
                return username

        logging.debug(
            "User {} was not found. Returning None.".format(username)
        )
        return None
Exemplo n.º 4
0
    def setup_for_attempt_operation(self, ip):
        """Create a loadbalancer.

        This is necessary so that the attempt is to show the load-balancer and
        this is an operator that the policy can stop.  Unfortunately, octavia,
        whilst it has a policy for just listing load-balancers, unfortunately,
        it doesn't work; whereas showing the load-balancer can be stopped.

        NB this only works if the setup phase of the octavia tests have been
        completed.

        :param ip: the ip of for keystone.
        :type ip: str
        """
        logging.info("Setting up loadbalancer.")
        auth = openstack_utils.get_overcloud_auth(address=ip)
        sess = openstack_utils.get_keystone_session(auth)

        octavia_client = openstack_utils.get_octavia_session_client(sess)
        neutron_client = openstack_utils.get_neutron_session_client(sess)

        if openstack_utils.dvr_enabled():
            network_name = 'private_lb_fip_network'
        else:
            network_name = 'private'
        resp = neutron_client.list_networks(name=network_name)

        vip_subnet_id = resp['networks'][0]['subnets'][0]

        res = octavia_client.load_balancer_create(
            json={
                'loadbalancer': {
                    'description': 'Created by Zaza',
                    'admin_state_up': True,
                    'vip_subnet_id': vip_subnet_id,
                    'name': 'zaza-lb-0',
                }})
        self.lb_id = res['loadbalancer']['id']
        # now wait for it to get to the active state

        @tenacity.retry(wait=tenacity.wait_fixed(1),
                        reraise=True, stop=tenacity.stop_after_delay(900))
        def wait_for_lb_resource(client, resource_id):
            resp = client.load_balancer_show(resource_id)
            logging.info(resp['provisioning_status'])
            assert resp['provisioning_status'] == 'ACTIVE', (
                'load balancer resource has not reached '
                'expected provisioning status: {}'
                .format(resp))
            return resp

        logging.info('Awaiting loadbalancer to reach provisioning_status '
                     '"ACTIVE"')
        resp = wait_for_lb_resource(octavia_client, self.lb_id)
        logging.info(resp)
        logging.info("Setup loadbalancer complete.")
Exemplo n.º 5
0
    def get_keystone_session_admin_user(self, ip):
        """Return the keystone session admin user.

        :param ip: the IP address to get the session against.
        :type ip: str
        :returns: a keystone session to the IP address
        :rtype: keystoneauth1.session.Session
        """
        return openstack_utils.get_keystone_session(
            openstack_utils.get_overcloud_auth(address=ip))
Exemplo n.º 6
0
    def test_rotate_admin_password(self):
        """Verify action used to rotate admin user's password."""
        ADMIN_PASSWD = 'admin_passwd'
        old_passwd = juju_utils.leader_get(self.application_name, ADMIN_PASSWD)

        # test access using the old password
        with self.v3_keystone_preferred():
            for ip in self.keystone_ips:
                try:
                    ks_session = openstack_utils.get_keystone_session(
                        openstack_utils.get_overcloud_auth(address=ip))
                    ks_client = openstack_utils.get_keystone_session_client(
                        ks_session)
                    ks_client.users.list()
                except keystoneauth1.exceptions.http.Forbidden:
                    raise zaza_exceptions.KeystoneAuthorizationStrict(
                        'Keystone auth with old password FAILED.')

        # run the action to rotate the password
        zaza.model.run_action_on_leader(
            self.application_name,
            'rotate-admin-password',
        )

        # test access using the new password
        with self.v3_keystone_preferred():
            for ip in self.keystone_ips:
                try:
                    ks_session = openstack_utils.get_keystone_session(
                        openstack_utils.get_overcloud_auth(address=ip))
                    ks_client = openstack_utils.get_keystone_session_client(
                        ks_session)
                    ks_client.users.list()
                except keystoneauth1.exceptions.http.Forbidden:
                    raise zaza_exceptions.KeystoneAuthorizationStrict(
                        'Keystone auth with new password FAILED.')

        # make sure the password was actually changed
        new_passwd = juju_utils.leader_get(self.application_name, ADMIN_PASSWD)
        assert old_passwd != new_passwd
Exemplo n.º 7
0
    def test_backward_compatible_uuid_for_default_domain(self):
        """Check domain named ``default`` literally has ``default`` as ID.

        Some third party software chooses to hard code this value for some
        inexplicable reason.
        """
        with self.v3_keystone_preferred():
            ks_session = openstack_utils.get_keystone_session(
                openstack_utils.get_overcloud_auth())
            ks_client = openstack_utils.get_keystone_session_client(ks_session)
            domain = ks_client.domains.get('default')
            logging.info(pprint.pformat(domain))
            assert domain.id == 'default'
Exemplo n.º 8
0
    def test_admin_project_scoped_access(self):
        """Verify cloud admin access using project scoped token.

        `admin` user in `admin_domain` should be able to access API methods
        guarded by `rule:cloud_admin` policy using a token scoped to `admin`
        project in `admin_domain`.

        We implement a policy that enables domain segregation and
        administration delegation [0].  It is important to understand that this
        differs from the default policy.

        In the initial implementation it was necessary to switch between using
        a `domain` scoped and `project` scoped token to successfully manage a
        cloud, but since the introduction of `is_admin` functionality in
        Keystone [1][2][3] and our subsequent adoption of it in Keystone charm
        [4], this is no longer necessary.

        This test here to validate this behaviour.

        0: https://github.com/openstack/keystone/commit/c7a5c6c
        1: https://github.com/openstack/keystone/commit/e702369
        2: https://github.com/openstack/keystone/commit/e923a14
        3: https://github.com/openstack/keystone/commit/9804081
        4: https://github.com/openstack/charm-keystone/commit/10e3d84
        """
        if (openstack_utils.get_os_release() <
                openstack_utils.get_os_release('trusty_mitaka')):
            logging.info('skipping test < trusty_mitaka')
            return
        with self.config_change(
            {'preferred-api-version': self.default_api_version},
            {'preferred-api-version': '3'},
                application_name="keystone"):
            for ip in self.keystone_ips:
                try:
                    logging.info('keystone IP {}'.format(ip))
                    ks_session = openstack_utils.get_keystone_session(
                        openstack_utils.get_overcloud_auth(address=ip))
                    ks_client = openstack_utils.get_keystone_session_client(
                        ks_session)
                    result = ks_client.domains.list()
                    logging.info('.domains.list: "{}"'.format(
                        pprint.pformat(result)))
                except keystoneauth1.exceptions.http.Forbidden as e:
                    raise zaza_exceptions.KeystoneAuthorizationStrict(
                        'Retrieve domain list as admin with project scoped '
                        'token FAILED. ({})'.format(e))
            logging.info('OK')
Exemplo n.º 9
0
    def test_end_user_domain_admin_access(self):
        """Verify that end-user domain admin does not have elevated privileges.

        In additon to validating that the `policy.json` is written and the
        service is restarted on config-changed, the test validates that our
        `policy.json` is correct.

        Catch regressions like LP: #1651989
        """
        if (openstack_utils.get_os_release() <
                openstack_utils.get_os_release('xenial_ocata')):
            logging.info('skipping test < xenial_ocata')
            return
        with self.config_change(
            {'preferred-api-version': self.default_api_version},
            {'preferred-api-version': '3'},
                application_name="keystone"):
            for ip in self.keystone_ips:
                openrc = {
                    'API_VERSION': 3,
                    'OS_USERNAME': DEMO_ADMIN_USER,
                    'OS_PASSWORD': DEMO_ADMIN_USER_PASSWORD,
                    'OS_AUTH_URL': 'http://{}:5000/v3'.format(ip),
                    'OS_USER_DOMAIN_NAME': DEMO_DOMAIN,
                    'OS_DOMAIN_NAME': DEMO_DOMAIN,
                }
                if self.tls_rid:
                    openrc['OS_CACERT'] = openstack_utils.KEYSTONE_LOCAL_CACERT
                    openrc['OS_AUTH_URL'] = (openrc['OS_AUTH_URL'].replace(
                        'http', 'https'))
                logging.info('keystone IP {}'.format(ip))
                keystone_session = openstack_utils.get_keystone_session(
                    openrc, scope='DOMAIN')
                keystone_client = openstack_utils.get_keystone_session_client(
                    keystone_session)
                try:
                    # expect failure
                    keystone_client.domains.list()
                except keystoneauth1.exceptions.http.Forbidden as e:
                    logging.debug('Retrieve domain list as end-user domain '
                                  'admin NOT allowed...OK ({})'.format(e))
                    pass
                else:
                    raise zaza_exceptions.KeystoneAuthorizationPermissive(
                        'Retrieve domain list as end-user domain admin '
                        'allowed when it should not be.')
        logging.info('OK')
Exemplo n.º 10
0
    def _get_keystone_session(self, ip, openrc, scope='DOMAIN'):
        """Return the keystone session for the IP address passed.

        :param ip: the IP address to get the session against.
        :type ip: str
        :param openrc: the params to authenticate with.
        :type openrc: Dict[str, str]
        :param scope: the scope of the token
        :type scope: str
        :returns: a keystone session to the IP address
        :rtype: keystoneauth1.session.Session
        """
        logging.info('Authentication for {} on keystone IP {}'.format(
            openrc['OS_USERNAME'], ip))
        if self.tls_rid:
            openrc['OS_CACERT'] = openstack_utils.get_cacert()
            openrc['OS_AUTH_URL'] = (openrc['OS_AUTH_URL'].replace(
                'http', 'https'))
        logging.info('keystone IP {}'.format(ip))
        keystone_session = openstack_utils.get_keystone_session(openrc,
                                                                scope=scope)
        return keystone_session
Exemplo n.º 11
0
        def _validate_token_data(openrc):
            if self.tls_rid:
                openrc['OS_CACERT'] = openstack_utils.get_cacert()
                openrc['OS_AUTH_URL'] = (
                    openrc['OS_AUTH_URL'].replace('http', 'https'))
            logging.info('keystone IP {}'.format(ip))
            keystone_session = openstack_utils.get_keystone_session(
                openrc)
            keystone_client = openstack_utils.get_keystone_session_client(
                keystone_session)
            token = keystone_session.get_token()
            if (openstack_utils.get_os_release() <
                    openstack_utils.get_os_release('xenial_ocata')):
                if len(token) != 32:
                    raise zaza_exceptions.KeystoneWrongTokenProvider(
                        'We expected a UUID token and got this: "{}"'
                        .format(token))
            else:
                if len(token) < 180:
                    raise zaza_exceptions.KeystoneWrongTokenProvider(
                        'We expected a Fernet token and got this: "{}"'
                        .format(token))
            logging.info('token: "{}"'.format(pprint.pformat(token)))

            if (openstack_utils.get_os_release() <
                    openstack_utils.get_os_release('trusty_mitaka')):
                logging.info('skip: tokens.get_token_data() not allowed prior '
                             'to trusty_mitaka')
                return
            # get_token_data call also gets the service catalog
            token_data = keystone_client.tokens.get_token_data(token)
            if token_data.get('token', {}).get('catalog', None) is None:
                raise zaza_exceptions.KeystoneAuthorizationStrict(
                    # NOTE(fnordahl) the above call will probably throw a
                    # http.Forbidden exception, but just in case
                    'Regular end user not allowed to retrieve the service '
                    'catalog. ("{}")'.format(pprint.pformat(token_data)))
            logging.info('token_data: "{}"'.format(pprint.pformat(token_data)))
Exemplo n.º 12
0
    def cleanup_for_attempt_operation(self, ip):
        """Remove the loadbalancer.

        :param ip: the ip of for keystone.
        :type ip: str
        """
        logging.info("Deleting loadbalancer {}.".format(self.lb_id))
        auth = openstack_utils.get_overcloud_auth(address=ip)
        sess = openstack_utils.get_keystone_session(auth)

        octavia_client = openstack_utils.get_octavia_session_client(sess)
        octavia_client.load_balancer_delete(self.lb_id)
        logging.info("Deleting loadbalancer in progress ...")

        @tenacity.retry(wait=tenacity.wait_fixed(1),
                        reraise=True, stop=tenacity.stop_after_delay(900))
        def wait_til_deleted(client, lb_id):
            lb_list = client.load_balancer_list()
            ids = [lb['id'] for lb in lb_list['loadbalancers']]
            assert lb_id not in ids, 'load balancer still deleting'

        wait_til_deleted(octavia_client, self.lb_id)
        logging.info("Deleted loadbalancer.")
Exemplo n.º 13
0
    def test_end_user_domain_admin_access(self):
        """Verify that end-user domain admin does not have elevated privileges.

        In additon to validating that the `policy.json` is written and the
        service is restarted on config-changed, the test validates that our
        `policy.json` is correct.

        Catch regressions like LP: #1651989
        """
        if (openstack_utils.get_os_release() <
                openstack_utils.get_os_release('xenial_ocata')):
            logging.info('skipping test < xenial_ocata')
            return
        with self.config_change(
            {'preferred-api-version': self.default_api_version},
            {'preferred-api-version': '3'},
                application_name="keystone"):
            for ip in self.keystone_ips:
                openrc = {
                    'API_VERSION': 3,
                    'OS_USERNAME': DEMO_ADMIN_USER,
                    'OS_PASSWORD': DEMO_ADMIN_USER_PASSWORD,
                    'OS_AUTH_URL': 'http://{}:5000/v3'.format(ip),
                    'OS_USER_DOMAIN_NAME': DEMO_DOMAIN,
                    'OS_DOMAIN_NAME': DEMO_DOMAIN,
                }
                if self.tls_rid:
                    openrc['OS_CACERT'] = openstack_utils.KEYSTONE_LOCAL_CACERT
                    openrc['OS_AUTH_URL'] = (openrc['OS_AUTH_URL'].replace(
                        'http', 'https'))
                logging.info('keystone IP {}'.format(ip))
                keystone_session = openstack_utils.get_keystone_session(
                    openrc, scope='DOMAIN')
                keystone_client = openstack_utils.get_keystone_session_client(
                    keystone_session)
                try:
                    # expect failure
                    keystone_client.domains.list()
                except keystoneauth1.exceptions.http.Unauthorized as e:
                    # This is to handle LP bug 1834287. We handle this error
                    # separately because it's a case of the client not being
                    # authenticated whereas the test is about checking if the
                    # client is authenticated but not authorized. We catch it
                    # so that we can log it properly and then re-raise it to
                    # indicate an underlying error that this test is unable
                    # to handle.
                    #
                    # Note that without catching this, the test will fail
                    # anyway but why it failed is not immediately obvious.
                    # This puts the reason front and center for the sake of
                    # efficiency
                    logging.error('Client is not authenticated. Test cannot '
                                  'continue...ERROR ({})'.format(e))
                    raise e
                except keystoneauth1.exceptions.http.Forbidden as e:
                    logging.debug('Retrieve domain list as end-user domain '
                                  'admin NOT allowed...OK ({})'.format(e))
                    pass
                else:
                    raise zaza_exceptions.KeystoneAuthorizationPermissive(
                        'Retrieve domain list as end-user domain admin '
                        'allowed when it should not be.')
        logging.info('OK')
Exemplo n.º 14
0
    def test_disable_service(self):
        """Test that service can be disabled."""
        logging.info("Doing policyd override to disable listing domains")
        self._set_policy_with({'rule.yaml': "{'identity:list_services': '!'}"})

        # verify that the policy.d override does disable the endpoint
        with self.config_change(
            {
                'preferred-api-version': self.default_api_version,
                'use-policyd-override': 'False'
            }, {
                'preferred-api-version': '3',
                'use-policyd-override': 'True'
            },
                application_name="keystone"):
            zaza_model.block_until_all_units_idle()
            for ip in self.keystone_ips:
                try:
                    logging.info('keystone IP {}'.format(ip))
                    openrc = {
                        'API_VERSION': 3,
                        'OS_USERNAME': ch_keystone.DEMO_ADMIN_USER,
                        'OS_PASSWORD': ch_keystone.DEMO_ADMIN_USER_PASSWORD,
                        'OS_AUTH_URL': 'http://{}:5000/v3'.format(ip),
                        'OS_USER_DOMAIN_NAME': ch_keystone.DEMO_DOMAIN,
                        'OS_DOMAIN_NAME': ch_keystone.DEMO_DOMAIN,
                    }
                    if self.tls_rid:
                        openrc['OS_CACERT'] = \
                            openstack_utils.KEYSTONE_LOCAL_CACERT
                        openrc['OS_AUTH_URL'] = (openrc['OS_AUTH_URL'].replace(
                            'http', 'https'))
                    logging.info('keystone IP {}'.format(ip))
                    keystone_session = openstack_utils.get_keystone_session(
                        openrc, scope='DOMAIN')
                    keystone_client = (
                        openstack_utils.get_keystone_session_client(
                            keystone_session))
                    keystone_client.services.list()
                    raise zaza_exceptions.PolicydError(
                        'Retrieve service list as admin with project scoped '
                        'token passed and should have failed. IP = {}'.format(
                            ip))
                except keystoneauth1.exceptions.http.Forbidden:
                    logging.info("keystone IP:{} policyd override disabled "
                                 "services listing by demo user".format(ip))

        # now verify (with the config off) that we can actually access
        # these points
        with self.config_change(
            {'preferred-api-version': self.default_api_version},
            {'preferred-api-version': '3'},
                application_name="keystone"):
            zaza_model.block_until_all_units_idle()
            for ip in self.keystone_ips:
                try:
                    logging.info('keystone IP {}'.format(ip))
                    openrc = {
                        'API_VERSION': 3,
                        'OS_USERNAME': ch_keystone.DEMO_ADMIN_USER,
                        'OS_PASSWORD': ch_keystone.DEMO_ADMIN_USER_PASSWORD,
                        'OS_AUTH_URL': 'http://{}:5000/v3'.format(ip),
                        'OS_USER_DOMAIN_NAME': ch_keystone.DEMO_DOMAIN,
                        'OS_DOMAIN_NAME': ch_keystone.DEMO_DOMAIN,
                    }
                    if self.tls_rid:
                        openrc['OS_CACERT'] = \
                            openstack_utils.KEYSTONE_LOCAL_CACERT
                        openrc['OS_AUTH_URL'] = (openrc['OS_AUTH_URL'].replace(
                            'http', 'https'))
                    logging.info('keystone IP {}'.format(ip))
                    keystone_session = openstack_utils.get_keystone_session(
                        openrc, scope='DOMAIN')
                    keystone_client = (
                        openstack_utils.get_keystone_session_client(
                            keystone_session))
                    keystone_client.services.list()
                    logging.info("keystone IP:{} without policyd override "
                                 "services list working".format(ip))
                except keystoneauth1.exceptions.http.Forbidden:
                    raise zaza_exceptions.PolicydError(
                        'Retrieve services list as demo user with project '
                        'scoped token passed and should have passed. IP = {}'.
                        format(ip))

        logging.info('OK')