From 67034c4db8613e8cead5e5839edbecf040b4fb91 Mon Sep 17 00:00:00 2001
From: Frode Nordahl <frode.nordahl@canonical.com>
Date: Tue, 10 Jan 2017 08:50:28 +0100
Subject: [PATCH] Update policy.json for Ocata

Refresh v2 and v3 portion of policy.json from upstream keystone
repository @ commit
d4a890a6c8bd6927e229f4b665a982a51c130073

Add functional tests to verify effect of policy

Update functional tests to use keystone_configure_api_version
from charm-helpers

Update functional tests to correctly validate cinder services
when openstack release >= ocata

Enable functional test for ocata, set appropriate cinder
configuration.

Change-Id: Idf07ff3a7c9d7e7eb30792719541319ab3426a41
Closes-Bug: 1651989
Closes-Bug: 1649446
---
 templates/ocata/policy.json   | 428 ++++++++++++++++++++++++++++++++++
 tests/basic_deployment.py     | 154 +++++++++---
 tests/gate-basic-xenial-ocata |   0
 3 files changed, 551 insertions(+), 31 deletions(-)
 create mode 100644 templates/ocata/policy.json
 mode change 100644 => 100755 tests/gate-basic-xenial-ocata

diff --git a/templates/ocata/policy.json b/templates/ocata/policy.json
new file mode 100644
index 00000000..1053fd6a
--- /dev/null
+++ b/templates/ocata/policy.json
@@ -0,0 +1,428 @@
+{% if api_version == 3 -%}
+{
+    "admin_required": "role:{{ admin_role }}",
+    "cloud_admin": "rule:admin_required and (is_admin_project:True or domain_id:{{ admin_domain_id }} or project_id:{{ service_tenant_id }})",
+    "service_role": "role:service",
+    "service_or_admin": "rule:admin_required or rule:service_role",
+    "owner" : "user_id:%(user_id)s or user_id:%(target.token.user_id)s",
+    "admin_or_owner": "(rule:admin_required and domain_id:%(target.token.user.domain.id)s) or rule:owner",
+    "admin_and_matching_domain_id": "rule:admin_required and domain_id:%(domain_id)s",
+    "service_admin_or_owner": "rule:service_or_admin or rule:owner",
+
+    "default": "rule:admin_required",
+
+    "identity:get_region": "",
+    "identity:list_regions": "",
+    "identity:create_region": "rule:cloud_admin",
+    "identity:update_region": "rule:cloud_admin",
+    "identity:delete_region": "rule:cloud_admin",
+
+    "identity:get_service": "rule:admin_required",
+    "identity:list_services": "rule:admin_required",
+    "identity:create_service": "rule:cloud_admin",
+    "identity:update_service": "rule:cloud_admin",
+    "identity:delete_service": "rule:cloud_admin",
+
+    "identity:get_endpoint": "rule:admin_required",
+    "identity:list_endpoints": "rule:admin_required",
+    "identity:create_endpoint": "rule:cloud_admin",
+    "identity:update_endpoint": "rule:cloud_admin",
+    "identity:delete_endpoint": "rule:cloud_admin",
+
+    "identity:get_domain": "rule:cloud_admin or rule:admin_and_matching_domain_id or token.project.domain.id:%(target.domain.id)s",
+    "identity:list_domains": "rule:cloud_admin",
+    "identity:create_domain": "rule:cloud_admin",
+    "identity:update_domain": "rule:cloud_admin",
+    "identity:delete_domain": "rule:cloud_admin",
+
+    "admin_and_matching_target_project_domain_id": "rule:admin_required and domain_id:%(target.project.domain_id)s",
+    "admin_and_matching_project_domain_id": "rule:admin_required and domain_id:%(project.domain_id)s",
+    "identity:get_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id or project_id:%(target.project.id)s",
+    "identity:list_projects": "rule:cloud_admin or rule:admin_and_matching_domain_id",
+    "identity:list_user_projects": "rule:owner or rule:admin_and_matching_domain_id",
+    "identity:create_project": "rule:cloud_admin or rule:admin_and_matching_project_domain_id",
+    "identity:update_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id",
+    "identity:delete_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id",
+
+    "admin_and_matching_target_user_domain_id": "rule:admin_required and domain_id:%(target.user.domain_id)s",
+    "admin_and_matching_user_domain_id": "rule:admin_required and domain_id:%(user.domain_id)s",
+    "identity:get_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id or rule:owner",
+    "identity:list_users": "rule:cloud_admin or rule:admin_and_matching_domain_id",
+    "identity:create_user": "rule:cloud_admin or rule:admin_and_matching_user_domain_id",
+    "identity:update_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id",
+    "identity:delete_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id",
+
+    "admin_and_matching_target_group_domain_id": "rule:admin_required and domain_id:%(target.group.domain_id)s",
+    "admin_and_matching_group_domain_id": "rule:admin_required and domain_id:%(group.domain_id)s",
+    "identity:get_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+    "identity:list_groups": "rule:cloud_admin or rule:admin_and_matching_domain_id",
+    "identity:list_groups_for_user": "rule:owner or rule:admin_and_matching_target_user_domain_id",
+    "identity:create_group": "rule:cloud_admin or rule:admin_and_matching_group_domain_id",
+    "identity:update_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+    "identity:delete_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+    "identity:list_users_in_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+    "identity:remove_user_from_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+    "identity:check_user_in_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+    "identity:add_user_to_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+
+    "identity:get_credential": "rule:admin_required",
+    "identity:list_credentials": "rule:admin_required or user_id:%(user_id)s",
+    "identity:create_credential": "rule:admin_required",
+    "identity:update_credential": "rule:admin_required",
+    "identity:delete_credential": "rule:admin_required",
+
+    "identity:ec2_get_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)",
+    "identity:ec2_list_credentials": "rule:admin_required or rule:owner",
+    "identity:ec2_create_credential": "rule:admin_required or rule:owner",
+    "identity:ec2_delete_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)",
+
+    "identity:get_role": "rule:admin_required",
+    "identity:list_roles": "rule:admin_required",
+    "identity:create_role": "rule:cloud_admin",
+    "identity:update_role": "rule:cloud_admin",
+    "identity:delete_role": "rule:cloud_admin",
+
+    "identity:get_domain_role": "rule:cloud_admin or rule:get_domain_roles",
+    "identity:list_domain_roles": "rule:cloud_admin or rule:list_domain_roles",
+    "identity:create_domain_role": "rule:cloud_admin or rule:domain_admin_matches_domain_role",
+    "identity:update_domain_role": "rule:cloud_admin or rule:domain_admin_matches_target_domain_role",
+    "identity:delete_domain_role": "rule:cloud_admin or rule:domain_admin_matches_target_domain_role",
+    "domain_admin_matches_domain_role": "rule:admin_required and domain_id:%(role.domain_id)s",
+    "get_domain_roles": "rule:domain_admin_matches_target_domain_role or rule:project_admin_matches_target_domain_role",
+    "domain_admin_matches_target_domain_role": "rule:admin_required and domain_id:%(target.role.domain_id)s",
+    "project_admin_matches_target_domain_role": "rule:admin_required and project_domain_id:%(target.role.domain_id)s",
+    "list_domain_roles": "rule:domain_admin_matches_filter_on_list_domain_roles or rule:project_admin_matches_filter_on_list_domain_roles",
+    "domain_admin_matches_filter_on_list_domain_roles": "rule:admin_required and domain_id:%(domain_id)s",
+    "project_admin_matches_filter_on_list_domain_roles": "rule:admin_required and project_domain_id:%(domain_id)s",
+    "admin_and_matching_prior_role_domain_id": "rule:admin_required and domain_id:%(target.prior_role.domain_id)s",
+    "implied_role_matches_prior_role_domain_or_global": "(domain_id:%(target.implied_role.domain_id)s or None:%(target.implied_role.domain_id)s)",
+
+    "identity:get_implied_role": "rule:cloud_admin or rule:admin_and_matching_prior_role_domain_id",
+    "identity:list_implied_roles": "rule:cloud_admin or rule:admin_and_matching_prior_role_domain_id",
+    "identity:create_implied_role": "rule:cloud_admin or (rule:admin_and_matching_prior_role_domain_id and rule:implied_role_matches_prior_role_domain_or_global)",
+    "identity:delete_implied_role": "rule:cloud_admin or rule:admin_and_matching_prior_role_domain_id",
+    "identity:list_role_inference_rules": "rule:cloud_admin",
+    "identity:check_implied_role": "rule:cloud_admin or rule:admin_and_matching_prior_role_domain_id",
+
+    "identity:check_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants",
+    "identity:list_grants": "rule:cloud_admin or rule:domain_admin_for_list_grants or rule:project_admin_for_list_grants",
+    "identity:create_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants",
+    "identity:revoke_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants",
+    "domain_admin_for_grants": "rule:domain_admin_for_global_role_grants or rule:domain_admin_for_domain_role_grants",
+    "domain_admin_for_global_role_grants": "rule:admin_required and None:%(target.role.domain_id)s and rule:domain_admin_grant_match",
+    "domain_admin_for_domain_role_grants": "rule:admin_required and domain_id:%(target.role.domain_id)s and rule:domain_admin_grant_match",
+    "domain_admin_grant_match": "domain_id:%(domain_id)s or domain_id:%(target.project.domain_id)s",
+    "project_admin_for_grants": "rule:project_admin_for_global_role_grants or rule:project_admin_for_domain_role_grants",
+    "project_admin_for_global_role_grants": "rule:admin_required and None:%(target.role.domain_id)s and project_id:%(project_id)s",
+    "project_admin_for_domain_role_grants": "rule:admin_required and project_domain_id:%(target.role.domain_id)s and project_id:%(project_id)s",
+    "domain_admin_for_list_grants": "rule:admin_required and rule:domain_admin_grant_match",
+    "project_admin_for_list_grants": "rule:admin_required and project_id:%(project_id)s",
+
+    "admin_on_domain_filter" : "rule:admin_required and domain_id:%(scope.domain.id)s",
+    "admin_on_project_filter" : "rule:admin_required and project_id:%(scope.project.id)s",
+    "admin_on_domain_of_project_filter" : "rule:admin_required and domain_id:%(target.project.domain_id)s",
+    "identity:list_role_assignments": "rule:cloud_admin or rule:admin_on_domain_filter or rule:admin_on_project_filter",
+    "identity:list_role_assignments_for_tree": "rule:cloud_admin or rule:admin_on_domain_of_project_filter",
+    "identity:get_policy": "rule:cloud_admin",
+    "identity:list_policies": "rule:cloud_admin",
+    "identity:create_policy": "rule:cloud_admin",
+    "identity:update_policy": "rule:cloud_admin",
+    "identity:delete_policy": "rule:cloud_admin",
+
+    "identity:change_password": "rule:owner",
+    "identity:check_token": "rule:admin_or_owner",
+    "identity:validate_token": "rule:service_admin_or_owner",
+    "identity:validate_token_head": "rule:service_or_admin",
+    "identity:revocation_list": "rule:service_or_admin",
+    "identity:revoke_token": "rule:admin_or_owner",
+
+    "identity:create_trust": "user_id:%(trust.trustor_user_id)s",
+    "identity:list_trusts": "",
+    "identity:list_roles_for_trust": "",
+    "identity:get_role_for_trust": "",
+    "identity:delete_trust": "",
+
+    "identity:create_consumer": "rule:admin_required",
+    "identity:get_consumer": "rule:admin_required",
+    "identity:list_consumers": "rule:admin_required",
+    "identity:delete_consumer": "rule:admin_required",
+    "identity:update_consumer": "rule:admin_required",
+
+    "identity:authorize_request_token": "rule:admin_required",
+    "identity:list_access_token_roles": "rule:admin_required",
+    "identity:get_access_token_role": "rule:admin_required",
+    "identity:list_access_tokens": "rule:admin_required",
+    "identity:get_access_token": "rule:admin_required",
+    "identity:delete_access_token": "rule:admin_required",
+
+    "identity:list_projects_for_endpoint": "rule:admin_required",
+    "identity:add_endpoint_to_project": "rule:admin_required",
+    "identity:check_endpoint_in_project": "rule:admin_required",
+    "identity:list_endpoints_for_project": "rule:admin_required",
+    "identity:remove_endpoint_from_project": "rule:admin_required",
+
+    "identity:create_endpoint_group": "rule:admin_required",
+    "identity:list_endpoint_groups": "rule:admin_required",
+    "identity:get_endpoint_group": "rule:admin_required",
+    "identity:update_endpoint_group": "rule:admin_required",
+    "identity:delete_endpoint_group": "rule:admin_required",
+    "identity:list_projects_associated_with_endpoint_group": "rule:admin_required",
+    "identity:list_endpoints_associated_with_endpoint_group": "rule:admin_required",
+    "identity:get_endpoint_group_in_project": "rule:admin_required",
+    "identity:list_endpoint_groups_for_project": "rule:admin_required",
+    "identity:add_endpoint_group_to_project": "rule:admin_required",
+    "identity:remove_endpoint_group_from_project": "rule:admin_required",
+
+    "identity:create_identity_provider": "rule:cloud_admin",
+    "identity:list_identity_providers": "rule:cloud_admin",
+    "identity:get_identity_providers": "rule:cloud_admin",
+    "identity:update_identity_provider": "rule:cloud_admin",
+    "identity:delete_identity_provider": "rule:cloud_admin",
+
+    "identity:create_protocol": "rule:cloud_admin",
+    "identity:update_protocol": "rule:cloud_admin",
+    "identity:get_protocol": "rule:cloud_admin",
+    "identity:list_protocols": "rule:cloud_admin",
+    "identity:delete_protocol": "rule:cloud_admin",
+
+    "identity:create_mapping": "rule:cloud_admin",
+    "identity:get_mapping": "rule:cloud_admin",
+    "identity:list_mappings": "rule:cloud_admin",
+    "identity:delete_mapping": "rule:cloud_admin",
+    "identity:update_mapping": "rule:cloud_admin",
+
+    "identity:create_service_provider": "rule:cloud_admin",
+    "identity:list_service_providers": "rule:cloud_admin",
+    "identity:get_service_provider": "rule:cloud_admin",
+    "identity:update_service_provider": "rule:cloud_admin",
+    "identity:delete_service_provider": "rule:cloud_admin",
+
+    "identity:get_auth_catalog": "",
+    "identity:get_auth_projects": "",
+    "identity:get_auth_domains": "",
+
+    "identity:list_projects_for_user": "",
+    "identity:list_domains_for_user": "",
+
+    "identity:list_revoke_events": "rule:service_or_admin",
+
+    "identity:create_policy_association_for_endpoint": "rule:cloud_admin",
+    "identity:check_policy_association_for_endpoint": "rule:cloud_admin",
+    "identity:delete_policy_association_for_endpoint": "rule:cloud_admin",
+    "identity:create_policy_association_for_service": "rule:cloud_admin",
+    "identity:check_policy_association_for_service": "rule:cloud_admin",
+    "identity:delete_policy_association_for_service": "rule:cloud_admin",
+    "identity:create_policy_association_for_region_and_service": "rule:cloud_admin",
+    "identity:check_policy_association_for_region_and_service": "rule:cloud_admin",
+    "identity:delete_policy_association_for_region_and_service": "rule:cloud_admin",
+    "identity:get_policy_for_endpoint": "rule:cloud_admin",
+    "identity:list_endpoints_for_policy": "rule:cloud_admin",
+
+    "identity:create_domain_config": "rule:cloud_admin",
+    "identity:get_domain_config": "rule:cloud_admin",
+    "identity:get_security_compliance_domain_config": "",
+    "identity:update_domain_config": "rule:cloud_admin",
+    "identity:delete_domain_config": "rule:cloud_admin",
+    "identity:get_domain_config_default": "rule:cloud_admin"
+}
+{% else -%}
+{
+    "admin_required": "role:admin or is_admin:1",
+    "service_role": "role:service",
+    "service_or_admin": "rule:admin_required or rule:service_role",
+    "owner" : "user_id:%(user_id)s",
+    "admin_or_owner": "rule:admin_required or rule:owner",
+    "token_subject": "user_id:%(target.token.user_id)s",
+    "admin_or_token_subject": "rule:admin_required or rule:token_subject",
+    "service_admin_or_token_subject": "rule:service_or_admin or rule:token_subject",
+
+    "default": "rule:admin_required",
+
+    "identity:get_region": "",
+    "identity:list_regions": "",
+    "identity:create_region": "rule:admin_required",
+    "identity:update_region": "rule:admin_required",
+    "identity:delete_region": "rule:admin_required",
+
+    "identity:get_service": "rule:admin_required",
+    "identity:list_services": "rule:admin_required",
+    "identity:create_service": "rule:admin_required",
+    "identity:update_service": "rule:admin_required",
+    "identity:delete_service": "rule:admin_required",
+
+    "identity:get_endpoint": "rule:admin_required",
+    "identity:list_endpoints": "rule:admin_required",
+    "identity:create_endpoint": "rule:admin_required",
+    "identity:update_endpoint": "rule:admin_required",
+    "identity:delete_endpoint": "rule:admin_required",
+
+    "identity:get_domain": "rule:admin_required or token.project.domain.id:%(target.domain.id)s",
+    "identity:list_domains": "rule:admin_required",
+    "identity:create_domain": "rule:admin_required",
+    "identity:update_domain": "rule:admin_required",
+    "identity:delete_domain": "rule:admin_required",
+
+    "identity:get_project": "rule:admin_required or project_id:%(target.project.id)s",
+    "identity:list_projects": "rule:admin_required",
+    "identity:list_user_projects": "rule:admin_or_owner",
+    "identity:create_project": "rule:admin_required",
+    "identity:update_project": "rule:admin_required",
+    "identity:delete_project": "rule:admin_required",
+
+    "identity:get_user": "rule:admin_or_owner",
+    "identity:list_users": "rule:admin_required",
+    "identity:create_user": "rule:admin_required",
+    "identity:update_user": "rule:admin_required",
+    "identity:delete_user": "rule:admin_required",
+    "identity:change_password": "rule:admin_or_owner",
+
+    "identity:get_group": "rule:admin_required",
+    "identity:list_groups": "rule:admin_required",
+    "identity:list_groups_for_user": "rule:admin_or_owner",
+    "identity:create_group": "rule:admin_required",
+    "identity:update_group": "rule:admin_required",
+    "identity:delete_group": "rule:admin_required",
+    "identity:list_users_in_group": "rule:admin_required",
+    "identity:remove_user_from_group": "rule:admin_required",
+    "identity:check_user_in_group": "rule:admin_required",
+    "identity:add_user_to_group": "rule:admin_required",
+
+    "identity:get_credential": "rule:admin_required",
+    "identity:list_credentials": "rule:admin_required",
+    "identity:create_credential": "rule:admin_required",
+    "identity:update_credential": "rule:admin_required",
+    "identity:delete_credential": "rule:admin_required",
+
+    "identity:ec2_get_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)",
+    "identity:ec2_list_credentials": "rule:admin_or_owner",
+    "identity:ec2_create_credential": "rule:admin_or_owner",
+    "identity:ec2_delete_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)",
+
+    "identity:get_role": "rule:admin_required",
+    "identity:list_roles": "rule:admin_required",
+    "identity:create_role": "rule:admin_required",
+    "identity:update_role": "rule:admin_required",
+    "identity:delete_role": "rule:admin_required",
+    "identity:get_domain_role": "rule:admin_required",
+    "identity:list_domain_roles": "rule:admin_required",
+    "identity:create_domain_role": "rule:admin_required",
+    "identity:update_domain_role": "rule:admin_required",
+    "identity:delete_domain_role": "rule:admin_required",
+
+    "identity:get_implied_role": "rule:admin_required ",
+    "identity:list_implied_roles": "rule:admin_required",
+    "identity:create_implied_role": "rule:admin_required",
+    "identity:delete_implied_role": "rule:admin_required",
+    "identity:list_role_inference_rules": "rule:admin_required",
+    "identity:check_implied_role": "rule:admin_required",
+
+    "identity:check_grant": "rule:admin_required",
+    "identity:list_grants": "rule:admin_required",
+    "identity:create_grant": "rule:admin_required",
+    "identity:revoke_grant": "rule:admin_required",
+
+    "identity:list_role_assignments": "rule:admin_required",
+    "identity:list_role_assignments_for_tree": "rule:admin_required",
+
+    "identity:get_policy": "rule:admin_required",
+    "identity:list_policies": "rule:admin_required",
+    "identity:create_policy": "rule:admin_required",
+    "identity:update_policy": "rule:admin_required",
+    "identity:delete_policy": "rule:admin_required",
+
+    "identity:check_token": "rule:admin_or_token_subject",
+    "identity:validate_token": "rule:service_admin_or_token_subject",
+    "identity:validate_token_head": "rule:service_or_admin",
+    "identity:revocation_list": "rule:service_or_admin",
+    "identity:revoke_token": "rule:admin_or_token_subject",
+
+    "identity:create_trust": "user_id:%(trust.trustor_user_id)s",
+    "identity:list_trusts": "",
+    "identity:list_roles_for_trust": "",
+    "identity:get_role_for_trust": "",
+    "identity:delete_trust": "",
+
+    "identity:create_consumer": "rule:admin_required",
+    "identity:get_consumer": "rule:admin_required",
+    "identity:list_consumers": "rule:admin_required",
+    "identity:delete_consumer": "rule:admin_required",
+    "identity:update_consumer": "rule:admin_required",
+
+    "identity:authorize_request_token": "rule:admin_required",
+    "identity:list_access_token_roles": "rule:admin_required",
+    "identity:get_access_token_role": "rule:admin_required",
+    "identity:list_access_tokens": "rule:admin_required",
+    "identity:get_access_token": "rule:admin_required",
+    "identity:delete_access_token": "rule:admin_required",
+
+    "identity:list_projects_for_endpoint": "rule:admin_required",
+    "identity:add_endpoint_to_project": "rule:admin_required",
+    "identity:check_endpoint_in_project": "rule:admin_required",
+    "identity:list_endpoints_for_project": "rule:admin_required",
+    "identity:remove_endpoint_from_project": "rule:admin_required",
+
+    "identity:create_endpoint_group": "rule:admin_required",
+    "identity:list_endpoint_groups": "rule:admin_required",
+    "identity:get_endpoint_group": "rule:admin_required",
+    "identity:update_endpoint_group": "rule:admin_required",
+    "identity:delete_endpoint_group": "rule:admin_required",
+    "identity:list_projects_associated_with_endpoint_group": "rule:admin_required",
+    "identity:list_endpoints_associated_with_endpoint_group": "rule:admin_required",
+    "identity:get_endpoint_group_in_project": "rule:admin_required",
+    "identity:list_endpoint_groups_for_project": "rule:admin_required",
+    "identity:add_endpoint_group_to_project": "rule:admin_required",
+    "identity:remove_endpoint_group_from_project": "rule:admin_required",
+
+    "identity:create_identity_provider": "rule:admin_required",
+    "identity:list_identity_providers": "rule:admin_required",
+    "identity:get_identity_providers": "rule:admin_required",
+    "identity:update_identity_provider": "rule:admin_required",
+    "identity:delete_identity_provider": "rule:admin_required",
+
+    "identity:create_protocol": "rule:admin_required",
+    "identity:update_protocol": "rule:admin_required",
+    "identity:get_protocol": "rule:admin_required",
+    "identity:list_protocols": "rule:admin_required",
+    "identity:delete_protocol": "rule:admin_required",
+
+    "identity:create_mapping": "rule:admin_required",
+    "identity:get_mapping": "rule:admin_required",
+    "identity:list_mappings": "rule:admin_required",
+    "identity:delete_mapping": "rule:admin_required",
+    "identity:update_mapping": "rule:admin_required",
+
+    "identity:create_service_provider": "rule:admin_required",
+    "identity:list_service_providers": "rule:admin_required",
+    "identity:get_service_provider": "rule:admin_required",
+    "identity:update_service_provider": "rule:admin_required",
+    "identity:delete_service_provider": "rule:admin_required",
+
+    "identity:get_auth_catalog": "",
+    "identity:get_auth_projects": "",
+    "identity:get_auth_domains": "",
+
+    "identity:list_projects_for_user": "",
+    "identity:list_domains_for_user": "",
+
+    "identity:list_revoke_events": "rule:service_or_admin",
+
+    "identity:create_policy_association_for_endpoint": "rule:admin_required",
+    "identity:check_policy_association_for_endpoint": "rule:admin_required",
+    "identity:delete_policy_association_for_endpoint": "rule:admin_required",
+    "identity:create_policy_association_for_service": "rule:admin_required",
+    "identity:check_policy_association_for_service": "rule:admin_required",
+    "identity:delete_policy_association_for_service": "rule:admin_required",
+    "identity:create_policy_association_for_region_and_service": "rule:admin_required",
+    "identity:check_policy_association_for_region_and_service": "rule:admin_required",
+    "identity:delete_policy_association_for_region_and_service": "rule:admin_required",
+    "identity:get_policy_for_endpoint": "rule:admin_required",
+    "identity:list_endpoints_for_policy": "rule:admin_required",
+
+    "identity:create_domain_config": "rule:admin_required",
+    "identity:get_domain_config": "rule:admin_required",
+    "identity:get_security_compliance_domain_config": "",
+    "identity:update_domain_config": "rule:admin_required",
+    "identity:delete_domain_config": "rule:admin_required",
+    "identity:get_domain_config_default": "rule:admin_required"
+}
+{% endif -%}
diff --git a/tests/basic_deployment.py b/tests/basic_deployment.py
index a871b623..da0b22a2 100644
--- a/tests/basic_deployment.py
+++ b/tests/basic_deployment.py
@@ -34,7 +34,6 @@ from charmhelpers.contrib.openstack.amulet.utils import (
 )
 import keystoneclient
 from keystoneauth1 import exceptions as ksauth1_exceptions
-from charmhelpers.core.decorators import retry_on_exception
 
 # Use DEBUG to turn on debug logging
 u = OpenStackAmuletUtils(DEBUG)
@@ -144,9 +143,10 @@ class KeystoneBasicDeployment(OpenStackAmuletDeployment):
             'root-password': 'ChangeMe123',
             'sst-password': 'ChangeMe123',
         }
-        cinder_config = {
-            'block-device': 'None',
-        }
+        cinder_config = {'block-device': 'vdb',
+                         'glance-api-version': '2',
+                         'overwrite': 'true',
+                         'ephemeral-unmount': '/mnt'}
         configs = {
             'keystone': keystone_config,
             'percona-cluster': pxc_config,
@@ -154,38 +154,22 @@ class KeystoneBasicDeployment(OpenStackAmuletDeployment):
         }
         super(KeystoneBasicDeployment, self)._configure_services(configs)
 
-    @retry_on_exception(5, base_delay=10)
     def set_api_version(self, api_version):
-        set_alternate = {'preferred-api-version': api_version}
-
-        # Make config change, check for service restarts
         u.log.debug('Setting preferred-api-version={}'.format(api_version))
-        self.d.configure('keystone', set_alternate)
-        self.keystone_api_version = api_version
+        se_rels = []
         for i in range(0, self.keystone_num_units):
-            rel = self.keystone_sentries[i].relation('identity-service',
-                                                     'cinder:identity-service')
-            u.log.debug('keystone unit {} relation data: {}'.format(i, rel))
-            if rel['api_version'] != str(api_version):
-                raise Exception("api_version not propagated through relation"
-                                " data yet ('{}' != '{}')."
-                                "".format(rel['api_version'], api_version))
-            client = self.get_keystone_client(api_version=api_version,
-                                              keystone_ip=rel[
-                                                  'private-address'])
-            # List an artefact that needs authorisation to check admin user
-            # has been setup on each Keystone unit. If that is still in progess
-            # keystoneclient.exceptions.Unauthorized will be thrown and caught
-            # by @retry_on_exception
-            if api_version == 2:
-                client.tenants.list()
-            else:
-                client.projects.list()
+            se_rels.append(
+                (self.keystone_sentries[i], 'cinder:identity-service'),
+            )
+        # Make config change, wait for propagation
+        u.keystone_configure_api_version(se_rels, self, api_version)
+
         # Success if we get here, get and store client.
         if api_version == 2:
             self.keystone_v2 = self.get_keystone_client(api_version=2)
         else:
             self.keystone_v3 = self.get_keystone_client(api_version=3)
+        self.keystone_api_version = api_version
 
     def get_keystone_client(self, api_version=None, keystone_ip=None):
         if keystone_ip is None:
@@ -229,6 +213,7 @@ class KeystoneBasicDeployment(OpenStackAmuletDeployment):
         # Create a demo tenant/role/user
         self.demo_project = 'demoProject'
         self.demo_user_v3 = 'demoUserV3'
+        self.demo_domain_admin = 'demoDomainAdminV3'
         self.demo_domain = 'demoDomain'
         try:
             domain = self.keystone_v3.domains.find(name=self.demo_domain)
@@ -266,6 +251,31 @@ class KeystoneBasicDeployment(OpenStackAmuletDeployment):
                 description='Demo',
                 enabled=True)
 
+        try:
+            self.keystone_v3.roles.find(name='Admin')
+        except keystoneclient.exceptions.NotFound:
+            self.keystone_v3.roles.create(name='Admin')
+
+        if not self.find_keystone_v3_user(self.keystone_v3,
+                                          self.demo_domain_admin,
+                                          self.demo_domain):
+            user = self.keystone_v3.users.create(
+                self.demo_domain_admin,
+                domain=domain.id,
+                project=self.demo_project,
+                password='password',
+                email='demoadminv3@demo.com',
+                description='Demo Admin',
+                enabled=True)
+
+            role = self.keystone_v3.roles.find(name='Admin')
+            u.log.debug("self.keystone_v3.roles.grant('{}', user='{}', "
+                        "domain='{}')".format(role.id, user.id, domain.id))
+            self.keystone_v3.roles.grant(
+                role.id,
+                user=user.id,
+                domain=domain.id)
+
     def _initialize_tests(self):
         """Perform final initialization before tests get run."""
         # Access the sentries for inspecting service units
@@ -291,15 +301,20 @@ class KeystoneBasicDeployment(OpenStackAmuletDeployment):
         """Verify the expected services are running on the corresponding
            service units."""
         services = {
-            self.cinder_sentry: ['cinder-api',
-                                 'cinder-scheduler',
+            self.cinder_sentry: ['cinder-scheduler',
                                  'cinder-volume']
         }
+        if self._get_openstack_release() >= self.xenial_ocata:
+            services.update({self.cinder_sentry: ['apache2']})
+        else:
+            services.update({self.cinder_sentry: ['cinder-api']})
+
         if self.is_liberty_or_newer():
             for i in range(0, self.keystone_num_units):
                 services.update({self.keystone_sentries[i]: ['apache2']})
         else:
             services.update({self.keystone_sentries[0]: ['keystone']})
+
         ret = u.validate_services_by_name(services)
         if ret:
             amulet.raise_status(amulet.FAIL, msg=ret)
@@ -412,6 +427,14 @@ class KeystoneBasicDeployment(OpenStackAmuletDeployment):
             u.log.info('Skipping test, {} < liberty'.format(os_release))
             return False
 
+    def is_mitaka_or_newer(self):
+        os_release = self._get_openstack_release_string()
+        if os_release >= 'mitaka':
+            return True
+        else:
+            u.log.info('Skipping test, {} < mitaka'.format(os_release))
+            return False
+
     def test_112_keystone_tenants(self):
         if self.is_liberty_or_newer():
             self.set_api_version(3)
@@ -466,6 +489,64 @@ class KeystoneBasicDeployment(OpenStackAmuletDeployment):
                 )
                 assert expect[key] == getattr(actual_domain, key)
 
+    def test_121_keystone_demo_domain_admin_access(self):
+        """Verify that end-user domain admin does not have elevated
+           privileges. Catch regressions like LP#1651989"""
+        if self.is_mitaka_or_newer():
+            u.log.debug('Checking keystone end-user domain admin access...')
+            self.set_api_version(3)
+            # Authenticate as end-user domain admin and verify that we have
+            # appropriate access.
+            client = u.authenticate_keystone(
+                self.keystone_sentries[0].info['public-address'],
+                username=self.demo_domain_admin,
+                password='password',
+                api_version=3,
+                user_domain_name=self.demo_domain,
+                domain_name=self.demo_domain,
+            )
+
+            try:
+                # Expect failure
+                client.domains.list()
+            except Exception as e:
+                message = ('Retrieve domain list as end-user domain admin '
+                           'NOT allowed...OK ({})'.format(e))
+                u.log.debug(message)
+                pass
+            else:
+                message = ('Retrieve domain list as end-user domain admin '
+                           'allowed')
+                amulet.raise_status(amulet.FAIL, msg=message)
+
+    def test_122_keystone_project_scoped_admin_access(self):
+        """Verify that user admin in domain admin_domain has access to
+           identity-calls guarded by rule:cloud_admin when using project
+           scoped token."""
+        if self.is_mitaka_or_newer():
+            u.log.debug('Checking keystone project scoped admin access...')
+            self.set_api_version(3)
+            # Authenticate as end-user domain admin and verify that we have
+            # appropriate access.
+            client = u.authenticate_keystone(
+                self.keystone_sentries[0].info['public-address'],
+                username='admin',
+                password='openstack',
+                api_version=3,
+                admin_port=True,
+                user_domain_name='admin_domain',
+                project_domain_name='admin_domain',
+                project_name='admin',
+            )
+
+            try:
+                client.domains.list()
+                u.log.debug('OK')
+            except Exception as e:
+                message = ('Retrieve domain list as admin with project scoped '
+                           'token FAILED. ({})'.format(e))
+                amulet.raise_status(amulet.FAIL, msg=message)
+
     def test_138_service_catalog(self):
         """Verify that the service catalog endpoint data is valid."""
         u.log.debug('Checking keystone service catalog...')
@@ -678,7 +759,18 @@ class KeystoneBasicDeployment(OpenStackAmuletDeployment):
         ks_ci_rel = self.keystone_sentries[0].relation(
             'identity-service',
             'cinder:identity-service')
-        if self._get_openstack_release() >= self.trusty_mitaka:
+        if self._get_openstack_release() >= self.xenial_ocata:
+            expected = {
+                'admin_required': 'role:Admin',
+                'cloud_admin':
+                    'rule:admin_required and '
+                    '(is_admin_project:True or '
+                    'domain_id:{admin_domain_id} or '
+                    'project_id:{service_tenant_id})'.format(
+                        admin_domain_id=ks_ci_rel['admin_domain_id'],
+                        service_tenant_id=ks_ci_rel['service_tenant_id']),
+            }
+        elif self._get_openstack_release() >= self.trusty_mitaka:
             expected = {
                 'admin_required': 'role:Admin',
                 'cloud_admin':
diff --git a/tests/gate-basic-xenial-ocata b/tests/gate-basic-xenial-ocata
old mode 100644
new mode 100755