Source code for keystone.tests.unit.test_versions

# Copyright 2012 OpenStack Foundation
#
# 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.

import copy
import functools
import random

import mock
from oslo_serialization import jsonutils
from six.moves import http_client
from testtools import matchers as tt_matchers
import webob

from keystone.common import json_home
import keystone.conf
from keystone.tests import unit
from keystone.tests.unit import utils
from keystone.version import controllers


CONF = keystone.conf.CONF

v2_MEDIA_TYPES = [
    {
        "base": "application/json",
        "type": "application/"
                "vnd.openstack.identity-v2.0+json"
    }
]

v2_HTML_DESCRIPTION = {
    "rel": "describedby",
    "type": "text/html",
    "href": "https://docs.openstack.org/"
}


v2_EXPECTED_RESPONSE = {
    "id": "v2.0",
    "status": "deprecated",
    "updated": "2016-08-04T00:00:00Z",
    "links": [
        {
            "rel": "self",
            "href": "",     # Will get filled in after initialization
        },
        v2_HTML_DESCRIPTION
    ],
    "media-types": v2_MEDIA_TYPES
}

v2_VERSION_RESPONSE = {
    "version": v2_EXPECTED_RESPONSE
}

v3_MEDIA_TYPES = [
    {
        "base": "application/json",
        "type": "application/"
                "vnd.openstack.identity-v3+json"
    }
]

v3_EXPECTED_RESPONSE = {
    "id": "v3.8",
    "status": "stable",
    "updated": "2017-02-22T00:00:00Z",
    "links": [
        {
            "rel": "self",
            "href": "",     # Will get filled in after initialization
        }
    ],
    "media-types": v3_MEDIA_TYPES
}

v3_VERSION_RESPONSE = {
    "version": v3_EXPECTED_RESPONSE
}

VERSIONS_RESPONSE = {
    "versions": {
        "values": [
            v3_EXPECTED_RESPONSE,
            v2_EXPECTED_RESPONSE
        ]
    }
}

_build_ec2tokens_relation = functools.partial(
    json_home.build_v3_extension_resource_relation, extension_name='OS-EC2',
    extension_version='1.0')

REVOCATIONS_RELATION = json_home.build_v3_extension_resource_relation(
    'OS-PKI', '1.0', 'revocations')

_build_simple_cert_relation = functools.partial(
    json_home.build_v3_extension_resource_relation,
    extension_name='OS-SIMPLE-CERT', extension_version='1.0')

_build_trust_relation = functools.partial(
    json_home.build_v3_extension_resource_relation, extension_name='OS-TRUST',
    extension_version='1.0')

_build_federation_rel = functools.partial(
    json_home.build_v3_extension_resource_relation,
    extension_name='OS-FEDERATION',
    extension_version='1.0')

_build_oauth1_rel = functools.partial(
    json_home.build_v3_extension_resource_relation,
    extension_name='OS-OAUTH1', extension_version='1.0')

_build_ep_policy_rel = functools.partial(
    json_home.build_v3_extension_resource_relation,
    extension_name='OS-ENDPOINT-POLICY', extension_version='1.0')

_build_ep_filter_rel = functools.partial(
    json_home.build_v3_extension_resource_relation,
    extension_name='OS-EP-FILTER', extension_version='1.0')

_build_os_inherit_rel = functools.partial(
    json_home.build_v3_extension_resource_relation,
    extension_name='OS-INHERIT', extension_version='1.0')

TRUST_ID_PARAMETER_RELATION = json_home.build_v3_extension_parameter_relation(
    'OS-TRUST', '1.0', 'trust_id')

IDP_ID_PARAMETER_RELATION = json_home.build_v3_extension_parameter_relation(
    'OS-FEDERATION', '1.0', 'idp_id')

PROTOCOL_ID_PARAM_RELATION = json_home.build_v3_extension_parameter_relation(
    'OS-FEDERATION', '1.0', 'protocol_id')

MAPPING_ID_PARAM_RELATION = json_home.build_v3_extension_parameter_relation(
    'OS-FEDERATION', '1.0', 'mapping_id')

SP_ID_PARAMETER_RELATION = json_home.build_v3_extension_parameter_relation(
    'OS-FEDERATION', '1.0', 'sp_id')

CONSUMER_ID_PARAMETER_RELATION = (
    json_home.build_v3_extension_parameter_relation(
        'OS-OAUTH1', '1.0', 'consumer_id'))

REQUEST_TOKEN_ID_PARAMETER_RELATION = (
    json_home.build_v3_extension_parameter_relation(
        'OS-OAUTH1', '1.0', 'request_token_id'))

ACCESS_TOKEN_ID_PARAMETER_RELATION = (
    json_home.build_v3_extension_parameter_relation(
        'OS-OAUTH1', '1.0', 'access_token_id'))

ENDPOINT_GROUP_ID_PARAMETER_RELATION = (
    json_home.build_v3_extension_parameter_relation(
        'OS-EP-FILTER', '1.0', 'endpoint_group_id'))

BASE_IDP_PROTOCOL = '/OS-FEDERATION/identity_providers/{idp_id}/protocols'
BASE_EP_POLICY = '/policies/{policy_id}/OS-ENDPOINT-POLICY'
BASE_EP_FILTER_PREFIX = '/OS-EP-FILTER'
BASE_EP_FILTER = BASE_EP_FILTER_PREFIX + '/endpoint_groups/{endpoint_group_id}'
BASE_ACCESS_TOKEN = (
    '/users/{user_id}/OS-OAUTH1/access_tokens/{access_token_id}')

FEDERATED_AUTH_URL = ('/OS-FEDERATION/identity_providers/{idp_id}'
                      '/protocols/{protocol_id}/auth')
FEDERATED_IDP_SPECIFIC_WEBSSO = ('/auth/OS-FEDERATION/identity_providers/'
                                 '{idp_id}/protocols/{protocol_id}/websso')

V3_JSON_HOME_RESOURCES = {
    json_home.build_v3_resource_relation('auth_tokens'): {
        'href': '/auth/tokens'},
    json_home.build_v3_resource_relation('auth_catalog'): {
        'href': '/auth/catalog'},
    json_home.build_v3_resource_relation('auth_projects'): {
        'href': '/auth/projects'},
    json_home.build_v3_resource_relation('auth_domains'): {
        'href': '/auth/domains'},
    json_home.build_v3_resource_relation('credential'): {
        'href-template': '/credentials/{credential_id}',
        'href-vars': {
            'credential_id':
            json_home.build_v3_parameter_relation('credential_id')}},
    json_home.build_v3_resource_relation('credentials'): {
        'href': '/credentials'},
    json_home.build_v3_resource_relation('domain'): {
        'href-template': '/domains/{domain_id}',
        'href-vars': {'domain_id': json_home.Parameters.DOMAIN_ID, }},
    json_home.build_v3_resource_relation('domain_group_role'): {
        'href-template':
        '/domains/{domain_id}/groups/{group_id}/roles/{role_id}',
        'href-vars': {
            'domain_id': json_home.Parameters.DOMAIN_ID,
            'group_id': json_home.Parameters.GROUP_ID,
            'role_id': json_home.Parameters.ROLE_ID, }},
    json_home.build_v3_resource_relation('domain_group_roles'): {
        'href-template': '/domains/{domain_id}/groups/{group_id}/roles',
        'href-vars': {
            'domain_id': json_home.Parameters.DOMAIN_ID,
            'group_id': json_home.Parameters.GROUP_ID}},
    json_home.build_v3_resource_relation('domain_user_role'): {
        'href-template':
        '/domains/{domain_id}/users/{user_id}/roles/{role_id}',
        'href-vars': {
            'domain_id': json_home.Parameters.DOMAIN_ID,
            'role_id': json_home.Parameters.ROLE_ID,
            'user_id': json_home.Parameters.USER_ID, }},
    json_home.build_v3_resource_relation('domain_user_roles'): {
        'href-template': '/domains/{domain_id}/users/{user_id}/roles',
        'href-vars': {
            'domain_id': json_home.Parameters.DOMAIN_ID,
            'user_id': json_home.Parameters.USER_ID, }},
    json_home.build_v3_resource_relation('domains'): {'href': '/domains'},
    json_home.build_v3_resource_relation('endpoint'): {
        'href-template': '/endpoints/{endpoint_id}',
        'href-vars': {
            'endpoint_id':
            json_home.build_v3_parameter_relation('endpoint_id'), }},
    json_home.build_v3_resource_relation('endpoints'): {
        'href': '/endpoints'},
    _build_ec2tokens_relation(resource_name='ec2tokens'): {
        'href': '/ec2tokens'},
    _build_ec2tokens_relation(resource_name='user_credential'): {
        'href-template': '/users/{user_id}/credentials/OS-EC2/{credential_id}',
        'href-vars': {
            'credential_id':
            json_home.build_v3_parameter_relation('credential_id'),
            'user_id': json_home.Parameters.USER_ID, }},
    _build_ec2tokens_relation(resource_name='user_credentials'): {
        'href-template': '/users/{user_id}/credentials/OS-EC2',
        'href-vars': {
            'user_id': json_home.Parameters.USER_ID, }},
    REVOCATIONS_RELATION: {
        'href': '/auth/tokens/OS-PKI/revoked'},
    'https://docs.openstack.org/api/openstack-identity/3/ext/OS-REVOKE/1.0/rel'
    '/events': {
        'href': '/OS-REVOKE/events'},
    _build_simple_cert_relation(resource_name='ca_certificate'): {
        'href': '/OS-SIMPLE-CERT/ca'},
    _build_simple_cert_relation(resource_name='certificates'): {
        'href': '/OS-SIMPLE-CERT/certificates'},
    _build_trust_relation(resource_name='trust'):
    {
        'href-template': '/OS-TRUST/trusts/{trust_id}',
        'href-vars': {'trust_id': TRUST_ID_PARAMETER_RELATION, }},
    _build_trust_relation(resource_name='trust_role'): {
        'href-template': '/OS-TRUST/trusts/{trust_id}/roles/{role_id}',
        'href-vars': {
            'role_id': json_home.Parameters.ROLE_ID,
            'trust_id': TRUST_ID_PARAMETER_RELATION, }},
    _build_trust_relation(resource_name='trust_roles'): {
        'href-template': '/OS-TRUST/trusts/{trust_id}/roles',
        'href-vars': {'trust_id': TRUST_ID_PARAMETER_RELATION, }},
    _build_trust_relation(resource_name='trusts'): {
        'href': '/OS-TRUST/trusts'},
    'https://docs.openstack.org/api/openstack-identity/3/ext/s3tokens/1.0/rel/'
    's3tokens': {
        'href': '/s3tokens'},
    json_home.build_v3_resource_relation('group'): {
        'href-template': '/groups/{group_id}',
        'href-vars': {
            'group_id': json_home.Parameters.GROUP_ID, }},
    json_home.build_v3_resource_relation('group_user'): {
        'href-template': '/groups/{group_id}/users/{user_id}',
        'href-vars': {
            'group_id': json_home.Parameters.GROUP_ID,
            'user_id': json_home.Parameters.USER_ID, }},
    json_home.build_v3_resource_relation('group_users'): {
        'href-template': '/groups/{group_id}/users',
        'href-vars': {'group_id': json_home.Parameters.GROUP_ID, }},
    json_home.build_v3_resource_relation('groups'): {'href': '/groups'},
    json_home.build_v3_resource_relation('policies'): {
        'href': '/policies'},
    json_home.build_v3_resource_relation('policy'): {
        'href-template': '/policies/{policy_id}',
        'href-vars': {
            'policy_id':
            json_home.build_v3_parameter_relation('policy_id'), }},
    json_home.build_v3_resource_relation('project'): {
        'href-template': '/projects/{project_id}',
        'href-vars': {
            'project_id': json_home.Parameters.PROJECT_ID, }},
    json_home.build_v3_resource_relation('project_group_role'): {
        'href-template':
        '/projects/{project_id}/groups/{group_id}/roles/{role_id}',
        'href-vars': {
            'group_id': json_home.Parameters.GROUP_ID,
            'project_id': json_home.Parameters.PROJECT_ID,
            'role_id': json_home.Parameters.ROLE_ID, }},
    json_home.build_v3_resource_relation('project_group_roles'): {
        'href-template': '/projects/{project_id}/groups/{group_id}/roles',
        'href-vars': {
            'group_id': json_home.Parameters.GROUP_ID,
            'project_id': json_home.Parameters.PROJECT_ID, }},
    json_home.build_v3_resource_relation('project_user_role'): {
        'href-template':
        '/projects/{project_id}/users/{user_id}/roles/{role_id}',
        'href-vars': {
            'project_id': json_home.Parameters.PROJECT_ID,
            'role_id': json_home.Parameters.ROLE_ID,
            'user_id': json_home.Parameters.USER_ID, }},
    json_home.build_v3_resource_relation('project_user_roles'): {
        'href-template': '/projects/{project_id}/users/{user_id}/roles',
        'href-vars': {
            'project_id': json_home.Parameters.PROJECT_ID,
            'user_id': json_home.Parameters.USER_ID, }},
    json_home.build_v3_resource_relation('projects'): {
        'href': '/projects'},
    json_home.build_v3_resource_relation('region'): {
        'href-template': '/regions/{region_id}',
        'href-vars': {
            'region_id':
            json_home.build_v3_parameter_relation('region_id'), }},
    json_home.build_v3_resource_relation('regions'): {'href': '/regions'},
    json_home.build_v3_resource_relation('role'): {
        'href-template': '/roles/{role_id}',
        'href-vars': {
            'role_id': json_home.Parameters.ROLE_ID, }},
    json_home.build_v3_resource_relation('implied_roles'): {
        'href-template': '/roles/{prior_role_id}/implies',
        'href-vars': {
            'prior_role_id': json_home.Parameters.ROLE_ID},
        'hints': {'status': 'experimental'}},
    json_home.build_v3_resource_relation('implied_role'): {
        'href-template':
        '/roles/{prior_role_id}/implies/{implied_role_id}',
        'href-vars': {
            'prior_role_id': json_home.Parameters.ROLE_ID,
            'implied_role_id': json_home.Parameters.ROLE_ID,
        },
        'hints': {'status': 'experimental'}},
    json_home.build_v3_resource_relation('role_inferences'): {
        'href': '/role_inferences',
        'hints': {'status': 'experimental'}},
    json_home.build_v3_resource_relation('role_assignments'): {
        'href': '/role_assignments'},
    json_home.build_v3_resource_relation('roles'): {'href': '/roles'},
    json_home.build_v3_resource_relation('service'): {
        'href-template': '/services/{service_id}',
        'href-vars': {
            'service_id':
            json_home.build_v3_parameter_relation('service_id')}},
    json_home.build_v3_resource_relation('services'): {
        'href': '/services'},
    json_home.build_v3_resource_relation('user'): {
        'href-template': '/users/{user_id}',
        'href-vars': {
            'user_id': json_home.Parameters.USER_ID, }},
    json_home.build_v3_resource_relation('user_change_password'): {
        'href-template': '/users/{user_id}/password',
        'href-vars': {'user_id': json_home.Parameters.USER_ID, }},
    json_home.build_v3_resource_relation('user_groups'): {
        'href-template': '/users/{user_id}/groups',
        'href-vars': {'user_id': json_home.Parameters.USER_ID, }},
    json_home.build_v3_resource_relation('user_projects'): {
        'href-template': '/users/{user_id}/projects',
        'href-vars': {'user_id': json_home.Parameters.USER_ID, }},
    json_home.build_v3_resource_relation('users'): {'href': '/users'},
    _build_federation_rel(resource_name='domains'): {
        'href': '/auth/domains'},
    _build_federation_rel(resource_name='websso'): {
        'href-template': '/auth/OS-FEDERATION/websso/{protocol_id}',
        'href-vars': {
            'protocol_id': PROTOCOL_ID_PARAM_RELATION, }},
    _build_federation_rel(resource_name='projects'): {
        'href': '/auth/projects'},
    _build_federation_rel(resource_name='saml2'): {
        'href': '/auth/OS-FEDERATION/saml2'},
    _build_federation_rel(resource_name='ecp'): {
        'href': '/auth/OS-FEDERATION/saml2/ecp'},
    _build_federation_rel(resource_name='metadata'): {
        'href': '/OS-FEDERATION/saml2/metadata'},
    _build_federation_rel(resource_name='identity_providers'): {
        'href': '/OS-FEDERATION/identity_providers'},
    _build_federation_rel(resource_name='service_providers'): {
        'href': '/OS-FEDERATION/service_providers'},
    _build_federation_rel(resource_name='mappings'): {
        'href': '/OS-FEDERATION/mappings'},
    _build_federation_rel(resource_name='identity_provider'):
    {
        'href-template': '/OS-FEDERATION/identity_providers/{idp_id}',
        'href-vars': {'idp_id': IDP_ID_PARAMETER_RELATION, }},
    _build_federation_rel(resource_name='identity_providers'): {
        'href-template': FEDERATED_IDP_SPECIFIC_WEBSSO,
        'href-vars': {
            'idp_id': IDP_ID_PARAMETER_RELATION,
            'protocol_id': PROTOCOL_ID_PARAM_RELATION, }},
    _build_federation_rel(resource_name='service_provider'):
    {
        'href-template': '/OS-FEDERATION/service_providers/{sp_id}',
        'href-vars': {'sp_id': SP_ID_PARAMETER_RELATION, }},
    _build_federation_rel(resource_name='mapping'):
    {
        'href-template': '/OS-FEDERATION/mappings/{mapping_id}',
        'href-vars': {'mapping_id': MAPPING_ID_PARAM_RELATION, }},
    _build_federation_rel(resource_name='identity_provider_protocol'): {
        'href-template': BASE_IDP_PROTOCOL + '/{protocol_id}',
        'href-vars': {
            'idp_id': IDP_ID_PARAMETER_RELATION,
            'protocol_id': PROTOCOL_ID_PARAM_RELATION, }},
    _build_federation_rel(resource_name='identity_provider_protocols'): {
        'href-template': BASE_IDP_PROTOCOL,
        'href-vars': {
            'idp_id': IDP_ID_PARAMETER_RELATION}},
    _build_federation_rel(resource_name='identity_provider_protocol_auth'): {
        'href-template': FEDERATED_AUTH_URL,
        'href-vars': {
            'idp_id': IDP_ID_PARAMETER_RELATION,
            'protocol_id': PROTOCOL_ID_PARAM_RELATION, }},
    _build_oauth1_rel(resource_name='access_tokens'): {
        'href': '/OS-OAUTH1/access_token'},
    _build_oauth1_rel(resource_name='request_tokens'): {
        'href': '/OS-OAUTH1/request_token'},
    _build_oauth1_rel(resource_name='consumers'): {
        'href': '/OS-OAUTH1/consumers'},
    _build_oauth1_rel(resource_name='authorize_request_token'):
    {
        'href-template': '/OS-OAUTH1/authorize/{request_token_id}',
        'href-vars': {'request_token_id':
                      REQUEST_TOKEN_ID_PARAMETER_RELATION, }},
    _build_oauth1_rel(resource_name='consumer'):
    {
        'href-template': '/OS-OAUTH1/consumers/{consumer_id}',
        'href-vars': {'consumer_id': CONSUMER_ID_PARAMETER_RELATION, }},
    _build_oauth1_rel(resource_name='user_access_token'):
    {
        'href-template': BASE_ACCESS_TOKEN,
        'href-vars': {'user_id': json_home.Parameters.USER_ID,
                      'access_token_id':
                      ACCESS_TOKEN_ID_PARAMETER_RELATION, }},
    _build_oauth1_rel(resource_name='user_access_tokens'):
    {
        'href-template': '/users/{user_id}/OS-OAUTH1/access_tokens',
        'href-vars': {'user_id': json_home.Parameters.USER_ID, }},
    _build_oauth1_rel(resource_name='user_access_token_role'):
    {
        'href-template': BASE_ACCESS_TOKEN + '/roles/{role_id}',
        'href-vars': {'user_id': json_home.Parameters.USER_ID,
                      'role_id': json_home.Parameters.ROLE_ID,
                      'access_token_id':
                      ACCESS_TOKEN_ID_PARAMETER_RELATION, }},
    _build_oauth1_rel(resource_name='user_access_token_roles'):
    {
        'href-template': BASE_ACCESS_TOKEN + '/roles',
        'href-vars': {'user_id': json_home.Parameters.USER_ID,
                      'access_token_id':
                      ACCESS_TOKEN_ID_PARAMETER_RELATION, }},
    _build_ep_policy_rel(resource_name='endpoint_policy'):
    {
        'href-template': '/endpoints/{endpoint_id}/OS-ENDPOINT-POLICY/policy',
        'href-vars': {'endpoint_id': json_home.Parameters.ENDPOINT_ID, }},
    _build_ep_policy_rel(resource_name='endpoint_policy_association'):
    {
        'href-template': BASE_EP_POLICY + '/endpoints/{endpoint_id}',
        'href-vars': {'endpoint_id': json_home.Parameters.ENDPOINT_ID,
                      'policy_id': json_home.Parameters.POLICY_ID, }},
    _build_ep_policy_rel(resource_name='policy_endpoints'):
    {
        'href-template': BASE_EP_POLICY + '/endpoints',
        'href-vars': {'policy_id': json_home.Parameters.POLICY_ID, }},
    _build_ep_policy_rel(
        resource_name='region_and_service_policy_association'):
    {
        'href-template': (BASE_EP_POLICY +
                          '/services/{service_id}/regions/{region_id}'),
        'href-vars': {'policy_id': json_home.Parameters.POLICY_ID,
                      'service_id': json_home.Parameters.SERVICE_ID,
                      'region_id': json_home.Parameters.REGION_ID, }},
    _build_ep_policy_rel(resource_name='service_policy_association'):
    {
        'href-template': BASE_EP_POLICY + '/services/{service_id}',
        'href-vars': {'policy_id': json_home.Parameters.POLICY_ID,
                      'service_id': json_home.Parameters.SERVICE_ID, }},
    _build_ep_filter_rel(resource_name='endpoint_group'):
    {
        'href-template': '/OS-EP-FILTER/endpoint_groups/{endpoint_group_id}',
        'href-vars': {'endpoint_group_id':
                      ENDPOINT_GROUP_ID_PARAMETER_RELATION, }},
    _build_ep_filter_rel(
        resource_name='endpoint_group_to_project_association'):
    {
        'href-template': BASE_EP_FILTER + '/projects/{project_id}',
        'href-vars': {'endpoint_group_id':
                      ENDPOINT_GROUP_ID_PARAMETER_RELATION,
                      'project_id': json_home.Parameters.PROJECT_ID, }},
    _build_ep_filter_rel(resource_name='endpoint_groups'):
    {'href': '/OS-EP-FILTER/endpoint_groups'},
    _build_ep_filter_rel(resource_name='endpoint_projects'):
    {
        'href-template': '/OS-EP-FILTER/endpoints/{endpoint_id}/projects',
        'href-vars': {'endpoint_id': json_home.Parameters.ENDPOINT_ID, }},
    _build_ep_filter_rel(resource_name='endpoints_in_endpoint_group'):
    {
        'href-template': BASE_EP_FILTER + '/endpoints',
        'href-vars': {'endpoint_group_id':
                      ENDPOINT_GROUP_ID_PARAMETER_RELATION, }},
    _build_ep_filter_rel(resource_name='project_endpoint_groups'):
    {
        'href-template': (BASE_EP_FILTER_PREFIX + '/projects/{project_id}' +
                          '/endpoint_groups'),
        'href-vars': {'project_id':
                      json_home.Parameters.PROJECT_ID, }},
    _build_ep_filter_rel(resource_name='project_endpoint'):
    {
        'href-template': ('/OS-EP-FILTER/projects/{project_id}'
                          '/endpoints/{endpoint_id}'),
        'href-vars': {'endpoint_id': json_home.Parameters.ENDPOINT_ID,
                      'project_id': json_home.Parameters.PROJECT_ID, }},
    _build_ep_filter_rel(resource_name='project_endpoints'):
    {
        'href-template': '/OS-EP-FILTER/projects/{project_id}/endpoints',
        'href-vars': {'project_id': json_home.Parameters.PROJECT_ID, }},
    _build_ep_filter_rel(
        resource_name='projects_associated_with_endpoint_group'):
    {
        'href-template': BASE_EP_FILTER + '/projects',
        'href-vars': {'endpoint_group_id':
                      ENDPOINT_GROUP_ID_PARAMETER_RELATION, }},
    _build_os_inherit_rel(
        resource_name='domain_user_role_inherited_to_projects'):
    {
        'href-template': '/OS-INHERIT/domains/{domain_id}/users/'
        '{user_id}/roles/{role_id}/inherited_to_projects',
        'href-vars': {
            'domain_id': json_home.Parameters.DOMAIN_ID,
            'role_id': json_home.Parameters.ROLE_ID,
            'user_id': json_home.Parameters.USER_ID, }},
    _build_os_inherit_rel(
        resource_name='domain_group_role_inherited_to_projects'):
    {
        'href-template': '/OS-INHERIT/domains/{domain_id}/groups/'
        '{group_id}/roles/{role_id}/inherited_to_projects',
        'href-vars': {
            'domain_id': json_home.Parameters.DOMAIN_ID,
            'group_id': json_home.Parameters.GROUP_ID,
            'role_id': json_home.Parameters.ROLE_ID, }},
    _build_os_inherit_rel(
        resource_name='domain_user_roles_inherited_to_projects'):
    {
        'href-template': '/OS-INHERIT/domains/{domain_id}/users/'
        '{user_id}/roles/inherited_to_projects',
        'href-vars': {
            'domain_id': json_home.Parameters.DOMAIN_ID,
            'user_id': json_home.Parameters.USER_ID, }},
    _build_os_inherit_rel(
        resource_name='domain_group_roles_inherited_to_projects'):
    {
        'href-template': '/OS-INHERIT/domains/{domain_id}/groups/'
        '{group_id}/roles/inherited_to_projects',
        'href-vars': {
            'domain_id': json_home.Parameters.DOMAIN_ID,
            'group_id': json_home.Parameters.GROUP_ID, }},
    _build_os_inherit_rel(
        resource_name='project_user_role_inherited_to_projects'):
    {
        'href-template': '/OS-INHERIT/projects/{project_id}/users/'
        '{user_id}/roles/{role_id}/inherited_to_projects',
        'href-vars': {
            'project_id': json_home.Parameters.PROJECT_ID,
            'role_id': json_home.Parameters.ROLE_ID,
            'user_id': json_home.Parameters.USER_ID, }},
    _build_os_inherit_rel(
        resource_name='project_group_role_inherited_to_projects'):
    {
        'href-template': '/OS-INHERIT/projects/{project_id}/groups/'
        '{group_id}/roles/{role_id}/inherited_to_projects',
        'href-vars': {
            'project_id': json_home.Parameters.PROJECT_ID,
            'group_id': json_home.Parameters.GROUP_ID,
            'role_id': json_home.Parameters.ROLE_ID, }},
    json_home.build_v3_resource_relation('domain_config'): {
        'href-template':
        '/domains/{domain_id}/config',
        'href-vars': {
            'domain_id': json_home.Parameters.DOMAIN_ID}},
    json_home.build_v3_resource_relation('domain_config_group'): {
        'href-template':
        '/domains/{domain_id}/config/{group}',
        'href-vars': {
            'domain_id': json_home.Parameters.DOMAIN_ID,
            'group': json_home.build_v3_parameter_relation('config_group')}},
    json_home.build_v3_resource_relation('domain_config_option'): {
        'href-template':
        '/domains/{domain_id}/config/{group}/{option}',
        'href-vars': {
            'domain_id': json_home.Parameters.DOMAIN_ID,
            'group': json_home.build_v3_parameter_relation('config_group'),
            'option': json_home.build_v3_parameter_relation('config_option')}},
    json_home.build_v3_resource_relation('domain_config_default'): {
        'href': '/domains/config/default'},
    json_home.build_v3_resource_relation('domain_config_default_group'): {
        'href-template': '/domains/config/{group}/default',
        'href-vars': {
            'group': json_home.build_v3_parameter_relation('config_group')}},
    json_home.build_v3_resource_relation('domain_config_default_option'): {
        'href-template': '/domains/config/{group}/{option}/default',
        'href-vars': {
            'group': json_home.build_v3_parameter_relation('config_group'),
            'option': json_home.build_v3_parameter_relation('config_option')}}
}


[docs]class TestClient(object): def __init__(self, app=None, token=None): self.app = app self.token = token
[docs] def request(self, method, path, headers=None, body=None): if headers is None: headers = {} if self.token: headers.setdefault('X-Auth-Token', self.token) req = webob.Request.blank(path) req.method = method for k, v in headers.items(): req.headers[k] = v if body: req.body = body return req.get_response(self.app)
[docs] def get(self, path, headers=None): return self.request('GET', path=path, headers=headers)
[docs] def post(self, path, headers=None, body=None): return self.request('POST', path=path, headers=headers, body=body)
[docs] def put(self, path, headers=None, body=None): return self.request('PUT', path=path, headers=headers, body=body)
class _VersionsEqual(tt_matchers.MatchesListwise): def __init__(self, expected): super(_VersionsEqual, self).__init__([ tt_matchers.KeysEqual(expected), tt_matchers.KeysEqual(expected['versions']), tt_matchers.HasLength(len(expected['versions']['values'])), tt_matchers.ContainsAll(expected['versions']['values']), ]) def match(self, other): return super(_VersionsEqual, self).match([ other, other['versions'], other['versions']['values'], other['versions']['values'], ])
[docs]class VersionTestCase(unit.TestCase):
[docs] def setUp(self): super(VersionTestCase, self).setUp() self.load_backends() self.public_app = self.loadapp('keystone', 'main') self.admin_app = self.loadapp('keystone', 'admin') self.admin_port = random.randint(10000, 30000) self.public_port = random.randint(40000, 60000) self.config_fixture.config( public_endpoint='http://localhost:%d' % self.public_port, admin_endpoint='http://localhost:%d' % self.admin_port)
[docs] def config_overrides(self): super(VersionTestCase, self).config_overrides()
def _paste_in_port(self, response, port): for link in response['links']: if link['rel'] == 'self': link['href'] = port
[docs] def test_public_versions(self): client = TestClient(self.public_app) resp = client.get('/') self.assertEqual(300, resp.status_int) data = jsonutils.loads(resp.body) expected = VERSIONS_RESPONSE for version in expected['versions']['values']: if version['id'].startswith('v3'): self._paste_in_port( version, 'http://localhost:%s/v3/' % self.public_port) elif version['id'] == 'v2.0': self._paste_in_port( version, 'http://localhost:%s/v2.0/' % self.public_port) self.assertThat(data, _VersionsEqual(expected))
[docs] def test_admin_versions(self): client = TestClient(self.admin_app) resp = client.get('/') self.assertEqual(300, resp.status_int) data = jsonutils.loads(resp.body) expected = VERSIONS_RESPONSE for version in expected['versions']['values']: if version['id'].startswith('v3'): self._paste_in_port( version, 'http://localhost:%s/v3/' % self.admin_port) elif version['id'] == 'v2.0': self._paste_in_port( version, 'http://localhost:%s/v2.0/' % self.admin_port) self.assertThat(data, _VersionsEqual(expected))
[docs] def test_use_site_url_if_endpoint_unset(self): self.config_fixture.config(public_endpoint=None, admin_endpoint=None) for app in (self.public_app, self.admin_app): client = TestClient(app) resp = client.get('/') self.assertEqual(300, resp.status_int) data = jsonutils.loads(resp.body) expected = VERSIONS_RESPONSE for version in expected['versions']['values']: # localhost happens to be the site url for tests if version['id'].startswith('v3'): self._paste_in_port( version, 'http://localhost/v3/') elif version['id'] == 'v2.0': self._paste_in_port( version, 'http://localhost/v2.0/') self.assertThat(data, _VersionsEqual(expected))
[docs] def test_public_version_v2(self): client = TestClient(self.public_app) resp = client.get('/v2.0/') self.assertEqual(http_client.OK, resp.status_int) data = jsonutils.loads(resp.body) expected = v2_VERSION_RESPONSE self._paste_in_port(expected['version'], 'http://localhost:%s/v2.0/' % self.public_port) self.assertEqual(expected, data)
[docs] def test_admin_version_v2(self): client = TestClient(self.admin_app) resp = client.get('/v2.0/') self.assertEqual(http_client.OK, resp.status_int) data = jsonutils.loads(resp.body) expected = v2_VERSION_RESPONSE self._paste_in_port(expected['version'], 'http://localhost:%s/v2.0/' % self.admin_port) self.assertEqual(expected, data)
[docs] def test_use_site_url_if_endpoint_unset_v2(self): self.config_fixture.config(public_endpoint=None, admin_endpoint=None) for app in (self.public_app, self.admin_app): client = TestClient(app) resp = client.get('/v2.0/') self.assertEqual(http_client.OK, resp.status_int) data = jsonutils.loads(resp.body) expected = v2_VERSION_RESPONSE self._paste_in_port(expected['version'], 'http://localhost/v2.0/') self.assertEqual(data, expected)
[docs] def test_public_version_v3(self): client = TestClient(self.public_app) resp = client.get('/v3/') self.assertEqual(http_client.OK, resp.status_int) data = jsonutils.loads(resp.body) expected = v3_VERSION_RESPONSE self._paste_in_port(expected['version'], 'http://localhost:%s/v3/' % self.public_port) self.assertEqual(expected, data)
@utils.wip('waiting on bug #1381961')
[docs] def test_admin_version_v3(self): client = TestClient(self.admin_app) resp = client.get('/v3/') self.assertEqual(http_client.OK, resp.status_int) data = jsonutils.loads(resp.body) expected = v3_VERSION_RESPONSE self._paste_in_port(expected['version'], 'http://localhost:%s/v3/' % self.admin_port) self.assertEqual(expected, data)
[docs] def test_use_site_url_if_endpoint_unset_v3(self): self.config_fixture.config(public_endpoint=None, admin_endpoint=None) for app in (self.public_app, self.admin_app): client = TestClient(app) resp = client.get('/v3/') self.assertEqual(http_client.OK, resp.status_int) data = jsonutils.loads(resp.body) expected = v3_VERSION_RESPONSE self._paste_in_port(expected['version'], 'http://localhost/v3/') self.assertEqual(expected, data)
@mock.patch.object(controllers, '_VERSIONS', ['v3'])
[docs] def test_v2_disabled(self): client = TestClient(self.public_app) # request to /v2.0 should fail resp = client.get('/v2.0/') self.assertEqual(http_client.NOT_FOUND, resp.status_int) # request to /v3 should pass resp = client.get('/v3/') self.assertEqual(http_client.OK, resp.status_int) data = jsonutils.loads(resp.body) expected = v3_VERSION_RESPONSE self._paste_in_port(expected['version'], 'http://localhost:%s/v3/' % self.public_port) self.assertEqual(expected, data) # only v3 information should be displayed by requests to / v3_only_response = { "versions": { "values": [ v3_EXPECTED_RESPONSE ] } } self._paste_in_port(v3_only_response['versions']['values'][0], 'http://localhost:%s/v3/' % self.public_port) resp = client.get('/') self.assertEqual(300, resp.status_int) data = jsonutils.loads(resp.body) self.assertEqual(v3_only_response, data)
@mock.patch.object(controllers, '_VERSIONS', ['v2.0'])
[docs] def test_v3_disabled(self): client = TestClient(self.public_app) # request to /v3 should fail resp = client.get('/v3/') self.assertEqual(http_client.NOT_FOUND, resp.status_int) # request to /v2.0 should pass resp = client.get('/v2.0/') self.assertEqual(http_client.OK, resp.status_int) data = jsonutils.loads(resp.body) expected = v2_VERSION_RESPONSE self._paste_in_port(expected['version'], 'http://localhost:%s/v2.0/' % self.public_port) self.assertEqual(expected, data) # only v2 information should be displayed by requests to / v2_only_response = { "versions": { "values": [ v2_EXPECTED_RESPONSE ] } } self._paste_in_port(v2_only_response['versions']['values'][0], 'http://localhost:%s/v2.0/' % self.public_port) resp = client.get('/') self.assertEqual(300, resp.status_int) data = jsonutils.loads(resp.body) self.assertEqual(v2_only_response, data)
def _test_json_home(self, path, exp_json_home_data): client = TestClient(self.public_app) resp = client.get(path, headers={'Accept': 'application/json-home'}) self.assertThat(resp.status, tt_matchers.Equals('200 OK')) self.assertThat(resp.headers['Content-Type'], tt_matchers.Equals('application/json-home')) self.assertThat(jsonutils.loads(resp.body), tt_matchers.Equals(exp_json_home_data))
[docs] def test_json_home_v3(self): # If the request is /v3 and the Accept header is application/json-home # then the server responds with a JSON Home document. exp_json_home_data = { 'resources': V3_JSON_HOME_RESOURCES} self._test_json_home('/v3', exp_json_home_data)
[docs] def test_json_home_root(self): # If the request is / and the Accept header is application/json-home # then the server responds with a JSON Home document. exp_json_home_data = copy.deepcopy({ 'resources': V3_JSON_HOME_RESOURCES}) json_home.translate_urls(exp_json_home_data, '/v3') self._test_json_home('/', exp_json_home_data)
[docs] def test_accept_type_handling(self): # Accept headers with multiple types and qvalues are handled. def make_request(accept_types=None): client = TestClient(self.public_app) headers = None if accept_types: headers = {'Accept': accept_types} resp = client.get('/v3', headers=headers) self.assertThat(resp.status, tt_matchers.Equals('200 OK')) return resp.headers['Content-Type'] JSON = controllers.MimeTypes.JSON JSON_HOME = controllers.MimeTypes.JSON_HOME JSON_MATCHER = tt_matchers.Equals(JSON) JSON_HOME_MATCHER = tt_matchers.Equals(JSON_HOME) # Default is JSON. self.assertThat(make_request(), JSON_MATCHER) # Can request JSON and get JSON. self.assertThat(make_request(JSON), JSON_MATCHER) # Can request JSONHome and get JSONHome. self.assertThat(make_request(JSON_HOME), JSON_HOME_MATCHER) # If request JSON, JSON Home get JSON. accept_types = '%s, %s' % (JSON, JSON_HOME) self.assertThat(make_request(accept_types), JSON_MATCHER) # If request JSON Home, JSON get JSON. accept_types = '%s, %s' % (JSON_HOME, JSON) self.assertThat(make_request(accept_types), JSON_MATCHER) # If request JSON Home, JSON;q=0.5 get JSON Home. accept_types = '%s, %s;q=0.5' % (JSON_HOME, JSON) self.assertThat(make_request(accept_types), JSON_HOME_MATCHER) # If request some unknown mime-type, get JSON. self.assertThat(make_request(self.getUniqueString()), JSON_MATCHER)
@mock.patch.object(controllers, '_VERSIONS', [])
[docs] def test_no_json_home_document_returned_when_v3_disabled(self): json_home_document = controllers.request_v3_json_home('some_prefix') expected_document = {'resources': {}} self.assertEqual(expected_document, json_home_document)
[docs] def test_extension_property_method_returns_none(self): extension_obj = controllers.Extensions() extensions_property = extension_obj.extensions self.assertIsNone(extensions_property)
[docs]class VersionSingleAppTestCase(unit.TestCase): """Test running with a single application loaded. These are important because when Keystone is running in Apache httpd there's only one application loaded for each instance. """
[docs] def setUp(self): super(VersionSingleAppTestCase, self).setUp() self.load_backends() self.admin_port = random.randint(10000, 30000) self.public_port = random.randint(40000, 60000) self.config_fixture.config( public_endpoint='http://localhost:%d' % self.public_port, admin_endpoint='http://localhost:%d' % self.admin_port)
[docs] def config_overrides(self): super(VersionSingleAppTestCase, self).config_overrides()
def _paste_in_port(self, response, port): for link in response['links']: if link['rel'] == 'self': link['href'] = port def _test_version(self, app_name): def app_port(): if app_name == 'admin': return self.admin_port else: return self.public_port app = self.loadapp('keystone', app_name) client = TestClient(app) resp = client.get('/') self.assertEqual(300, resp.status_int) data = jsonutils.loads(resp.body) expected = VERSIONS_RESPONSE for version in expected['versions']['values']: if version['id'].startswith('v3'): self._paste_in_port( version, 'http://localhost:%s/v3/' % app_port()) elif version['id'] == 'v2.0': self._paste_in_port( version, 'http://localhost:%s/v2.0/' % app_port()) self.assertThat(data, _VersionsEqual(expected))
[docs] def test_public(self): self._test_version('main')
[docs] def test_admin(self): self._test_version('admin')
[docs]class VersionBehindSslTestCase(unit.TestCase):
[docs] def setUp(self): super(VersionBehindSslTestCase, self).setUp() self.load_backends() self.public_app = self.loadapp('keystone', 'main')
[docs] def config_overrides(self): super(VersionBehindSslTestCase, self).config_overrides() self.config_fixture.config( secure_proxy_ssl_header='HTTP_X_FORWARDED_PROTO')
def _paste_in_port(self, response, port): for link in response['links']: if link['rel'] == 'self': link['href'] = port def _get_expected(self, host): expected = VERSIONS_RESPONSE for version in expected['versions']['values']: if version['id'].startswith('v3'): self._paste_in_port(version, host + 'v3/') elif version['id'] == 'v2.0': self._paste_in_port(version, host + 'v2.0/') return expected
[docs] def test_versions_without_headers(self): client = TestClient(self.public_app) host_name = 'host-%d' % random.randint(10, 30) host_port = random.randint(10000, 30000) host = 'http://%s:%s/' % (host_name, host_port) resp = client.get(host) self.assertEqual(300, resp.status_int) data = jsonutils.loads(resp.body) expected = self._get_expected(host) self.assertThat(data, _VersionsEqual(expected))
[docs] def test_versions_with_header(self): client = TestClient(self.public_app) host_name = 'host-%d' % random.randint(10, 30) host_port = random.randint(10000, 30000) resp = client.get('http://%s:%s/' % (host_name, host_port), headers={'X-Forwarded-Proto': 'https'}) self.assertEqual(300, resp.status_int) data = jsonutils.loads(resp.body) expected = self._get_expected('https://%s:%s/' % (host_name, host_port)) self.assertThat(data, _VersionsEqual(expected))