"Fossies" - the Fresh Open Source Software Archive

Member "keystone-17.0.0/keystone/tests/unit/test_versions.py" (13 May 2020, 40457 Bytes) of package /linux/misc/openstack/keystone-17.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_versions.py": 16.0.1_vs_17.0.0.

    1 # Copyright 2012 OpenStack Foundation
    2 #
    3 # Licensed under the Apache License, Version 2.0 (the "License");
    4 # you may not use this file except in compliance with the License.
    5 # You may obtain a copy of the License at
    6 #
    7 #    http://www.apache.org/licenses/LICENSE-2.0
    8 #
    9 # Unless required by applicable law or agreed to in writing, software
   10 # distributed under the License is distributed on an "AS IS" BASIS,
   11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
   12 # implied.
   13 # See the License for the specific language governing permissions and
   14 # limitations under the License.
   15 
   16 import copy
   17 import functools
   18 import random
   19 
   20 import http.client
   21 from oslo_serialization import jsonutils
   22 from testtools import matchers as tt_matchers
   23 import webob
   24 
   25 from keystone.api import discovery
   26 from keystone.common import json_home
   27 from keystone.tests import unit
   28 
   29 
   30 v3_MEDIA_TYPES = [
   31     {
   32         "base": "application/json",
   33         "type": "application/"
   34                 "vnd.openstack.identity-v3+json"
   35     }
   36 ]
   37 
   38 v3_EXPECTED_RESPONSE = {
   39     "id": "v3.14",
   40     "status": "stable",
   41     "updated": "2020-04-07T00:00:00Z",
   42     "links": [
   43         {
   44             "rel": "self",
   45             "href": "",     # Will get filled in after initialization
   46         }
   47     ],
   48     "media-types": v3_MEDIA_TYPES
   49 }
   50 
   51 v3_VERSION_RESPONSE = {
   52     "version": v3_EXPECTED_RESPONSE
   53 }
   54 
   55 VERSIONS_RESPONSE = {
   56     "versions": {
   57         "values": [
   58             v3_EXPECTED_RESPONSE,
   59         ]
   60     }
   61 }
   62 
   63 _build_ec2tokens_relation = functools.partial(
   64     json_home.build_v3_extension_resource_relation, extension_name='OS-EC2',
   65     extension_version='1.0')
   66 
   67 REVOCATIONS_RELATION = json_home.build_v3_extension_resource_relation(
   68     'OS-PKI', '1.0', 'revocations')
   69 
   70 _build_simple_cert_relation = functools.partial(
   71     json_home.build_v3_extension_resource_relation,
   72     extension_name='OS-SIMPLE-CERT', extension_version='1.0')
   73 
   74 _build_trust_relation = functools.partial(
   75     json_home.build_v3_extension_resource_relation, extension_name='OS-TRUST',
   76     extension_version='1.0')
   77 
   78 _build_federation_rel = functools.partial(
   79     json_home.build_v3_extension_resource_relation,
   80     extension_name='OS-FEDERATION',
   81     extension_version='1.0')
   82 
   83 _build_oauth1_rel = functools.partial(
   84     json_home.build_v3_extension_resource_relation,
   85     extension_name='OS-OAUTH1', extension_version='1.0')
   86 
   87 _build_ep_policy_rel = functools.partial(
   88     json_home.build_v3_extension_resource_relation,
   89     extension_name='OS-ENDPOINT-POLICY', extension_version='1.0')
   90 
   91 _build_ep_filter_rel = functools.partial(
   92     json_home.build_v3_extension_resource_relation,
   93     extension_name='OS-EP-FILTER', extension_version='1.0')
   94 
   95 _build_os_inherit_rel = functools.partial(
   96     json_home.build_v3_extension_resource_relation,
   97     extension_name='OS-INHERIT', extension_version='1.0')
   98 
   99 TRUST_ID_PARAMETER_RELATION = json_home.build_v3_extension_parameter_relation(
  100     'OS-TRUST', '1.0', 'trust_id')
  101 
  102 IDP_ID_PARAMETER_RELATION = json_home.build_v3_extension_parameter_relation(
  103     'OS-FEDERATION', '1.0', 'idp_id')
  104 
  105 PROTOCOL_ID_PARAM_RELATION = json_home.build_v3_extension_parameter_relation(
  106     'OS-FEDERATION', '1.0', 'protocol_id')
  107 
  108 MAPPING_ID_PARAM_RELATION = json_home.build_v3_extension_parameter_relation(
  109     'OS-FEDERATION', '1.0', 'mapping_id')
  110 
  111 SP_ID_PARAMETER_RELATION = json_home.build_v3_extension_parameter_relation(
  112     'OS-FEDERATION', '1.0', 'sp_id')
  113 
  114 CONSUMER_ID_PARAMETER_RELATION = (
  115     json_home.build_v3_extension_parameter_relation(
  116         'OS-OAUTH1', '1.0', 'consumer_id'))
  117 
  118 REQUEST_TOKEN_ID_PARAMETER_RELATION = (
  119     json_home.build_v3_extension_parameter_relation(
  120         'OS-OAUTH1', '1.0', 'request_token_id'))
  121 
  122 ACCESS_TOKEN_ID_PARAMETER_RELATION = (
  123     json_home.build_v3_extension_parameter_relation(
  124         'OS-OAUTH1', '1.0', 'access_token_id'))
  125 
  126 ENDPOINT_GROUP_ID_PARAMETER_RELATION = (
  127     json_home.build_v3_extension_parameter_relation(
  128         'OS-EP-FILTER', '1.0', 'endpoint_group_id'))
  129 
  130 BASE_IDP_PROTOCOL = '/OS-FEDERATION/identity_providers/{idp_id}/protocols'
  131 BASE_EP_POLICY = '/policies/{policy_id}/OS-ENDPOINT-POLICY'
  132 BASE_EP_FILTER_PREFIX = '/OS-EP-FILTER'
  133 BASE_EP_FILTER = BASE_EP_FILTER_PREFIX + '/endpoint_groups/{endpoint_group_id}'
  134 BASE_ACCESS_TOKEN = (
  135     '/users/{user_id}/OS-OAUTH1/access_tokens/{access_token_id}')
  136 
  137 FEDERATED_AUTH_URL = ('/OS-FEDERATION/identity_providers/{idp_id}'
  138                       '/protocols/{protocol_id}/auth')
  139 FEDERATED_IDP_SPECIFIC_WEBSSO = ('/auth/OS-FEDERATION/identity_providers/'
  140                                  '{idp_id}/protocols/{protocol_id}/websso')
  141 
  142 APPLICATION_CREDENTIAL = ('/users/{user_id}/application_credentials/'
  143                           '{application_credential_id}')
  144 APPLICATION_CREDENTIALS = '/users/{user_id}/application_credentials'
  145 APPLICATION_CREDENTIAL_RELATION = (
  146     json_home.build_v3_parameter_relation('application_credential_id'))
  147 
  148 ACCESS_RULE = '/users/{user_id}/access_rules/{access_rule_id}'
  149 ACCESS_RULES = '/users/{user_id}/access_rules'
  150 ACCESS_RULE_RELATION = json_home.build_v3_parameter_relation('access_rule_id')
  151 
  152 V3_JSON_HOME_RESOURCES = {
  153     json_home.build_v3_resource_relation('auth_tokens'): {
  154         'href': '/auth/tokens'},
  155     json_home.build_v3_resource_relation('auth_catalog'): {
  156         'href': '/auth/catalog'},
  157     json_home.build_v3_resource_relation('auth_projects'): {
  158         'href': '/auth/projects'},
  159     json_home.build_v3_resource_relation('auth_domains'): {
  160         'href': '/auth/domains'},
  161     json_home.build_v3_resource_relation('auth_system'): {
  162         'href': '/auth/system'},
  163     json_home.build_v3_resource_relation('credential'): {
  164         'href-template': '/credentials/{credential_id}',
  165         'href-vars': {
  166             'credential_id':
  167             json_home.build_v3_parameter_relation('credential_id')}},
  168     json_home.build_v3_resource_relation('credentials'): {
  169         'href': '/credentials'},
  170     json_home.build_v3_resource_relation('system_user_role'): {
  171         'href-template': '/system/users/{user_id}/roles/{role_id}',
  172         'href-vars': {
  173             'user_id': json_home.Parameters.USER_ID,
  174             'role_id': json_home.Parameters.ROLE_ID
  175         }
  176     },
  177     json_home.build_v3_resource_relation('system_user_roles'): {
  178         'href-template': '/system/users/{user_id}/roles',
  179         'href-vars': {
  180             'user_id': json_home.Parameters.USER_ID
  181         }
  182     },
  183     json_home.build_v3_resource_relation('system_group_role'): {
  184         'href-template': '/system/groups/{group_id}/roles/{role_id}',
  185         'href-vars': {
  186             'group_id': json_home.Parameters.GROUP_ID,
  187             'role_id': json_home.Parameters.ROLE_ID
  188         }
  189     },
  190     json_home.build_v3_resource_relation('system_group_roles'): {
  191         'href-template': '/system/groups/{group_id}/roles',
  192         'href-vars': {
  193             'group_id': json_home.Parameters.GROUP_ID
  194         }
  195     },
  196     json_home.build_v3_resource_relation('domain'): {
  197         'href-template': '/domains/{domain_id}',
  198         'href-vars': {'domain_id': json_home.Parameters.DOMAIN_ID, }},
  199     json_home.build_v3_resource_relation('domain_group_role'): {
  200         'href-template':
  201         '/domains/{domain_id}/groups/{group_id}/roles/{role_id}',
  202         'href-vars': {
  203             'domain_id': json_home.Parameters.DOMAIN_ID,
  204             'group_id': json_home.Parameters.GROUP_ID,
  205             'role_id': json_home.Parameters.ROLE_ID, }},
  206     json_home.build_v3_resource_relation('domain_group_roles'): {
  207         'href-template': '/domains/{domain_id}/groups/{group_id}/roles',
  208         'href-vars': {
  209             'domain_id': json_home.Parameters.DOMAIN_ID,
  210             'group_id': json_home.Parameters.GROUP_ID}},
  211     json_home.build_v3_resource_relation('domain_user_role'): {
  212         'href-template':
  213         '/domains/{domain_id}/users/{user_id}/roles/{role_id}',
  214         'href-vars': {
  215             'domain_id': json_home.Parameters.DOMAIN_ID,
  216             'role_id': json_home.Parameters.ROLE_ID,
  217             'user_id': json_home.Parameters.USER_ID, }},
  218     json_home.build_v3_resource_relation('domain_user_roles'): {
  219         'href-template': '/domains/{domain_id}/users/{user_id}/roles',
  220         'href-vars': {
  221             'domain_id': json_home.Parameters.DOMAIN_ID,
  222             'user_id': json_home.Parameters.USER_ID, }},
  223     json_home.build_v3_resource_relation('domains'): {'href': '/domains'},
  224     json_home.build_v3_resource_relation('endpoint'): {
  225         'href-template': '/endpoints/{endpoint_id}',
  226         'href-vars': {
  227             'endpoint_id':
  228             json_home.build_v3_parameter_relation('endpoint_id'), }},
  229     json_home.build_v3_resource_relation('endpoints'): {
  230         'href': '/endpoints'},
  231     _build_ec2tokens_relation(resource_name='ec2tokens'): {
  232         'href': '/ec2tokens'},
  233     _build_ec2tokens_relation(resource_name='user_credential'): {
  234         'href-template': '/users/{user_id}/credentials/OS-EC2/{credential_id}',
  235         'href-vars': {
  236             'credential_id':
  237             json_home.build_v3_parameter_relation('credential_id'),
  238             'user_id': json_home.Parameters.USER_ID, }},
  239     _build_ec2tokens_relation(resource_name='user_credentials'): {
  240         'href-template': '/users/{user_id}/credentials/OS-EC2',
  241         'href-vars': {
  242             'user_id': json_home.Parameters.USER_ID, }},
  243     REVOCATIONS_RELATION: {
  244         'href': '/auth/tokens/OS-PKI/revoked'},
  245     'https://docs.openstack.org/api/openstack-identity/3/ext/OS-REVOKE/1.0/rel'
  246     '/events': {
  247         'href': '/OS-REVOKE/events'},
  248     _build_simple_cert_relation(resource_name='ca_certificate'): {
  249         'href': '/OS-SIMPLE-CERT/ca'},
  250     _build_simple_cert_relation(resource_name='certificates'): {
  251         'href': '/OS-SIMPLE-CERT/certificates'},
  252     _build_trust_relation(resource_name='trust'):
  253     {
  254         'href-template': '/OS-TRUST/trusts/{trust_id}',
  255         'href-vars': {'trust_id': TRUST_ID_PARAMETER_RELATION, }},
  256     _build_trust_relation(resource_name='trust_role'): {
  257         'href-template': '/OS-TRUST/trusts/{trust_id}/roles/{role_id}',
  258         'href-vars': {
  259             'role_id': json_home.Parameters.ROLE_ID,
  260             'trust_id': TRUST_ID_PARAMETER_RELATION, }},
  261     _build_trust_relation(resource_name='trust_roles'): {
  262         'href-template': '/OS-TRUST/trusts/{trust_id}/roles',
  263         'href-vars': {'trust_id': TRUST_ID_PARAMETER_RELATION, }},
  264     _build_trust_relation(resource_name='trusts'): {
  265         'href': '/OS-TRUST/trusts'},
  266     'https://docs.openstack.org/api/openstack-identity/3/ext/s3tokens/1.0/rel/'
  267     's3tokens': {
  268         'href': '/s3tokens'},
  269     json_home.build_v3_resource_relation('group'): {
  270         'href-template': '/groups/{group_id}',
  271         'href-vars': {
  272             'group_id': json_home.Parameters.GROUP_ID, }},
  273     json_home.build_v3_resource_relation('group_user'): {
  274         'href-template': '/groups/{group_id}/users/{user_id}',
  275         'href-vars': {
  276             'group_id': json_home.Parameters.GROUP_ID,
  277             'user_id': json_home.Parameters.USER_ID, }},
  278     json_home.build_v3_resource_relation('group_users'): {
  279         'href-template': '/groups/{group_id}/users',
  280         'href-vars': {'group_id': json_home.Parameters.GROUP_ID, }},
  281     json_home.build_v3_resource_relation('groups'): {'href': '/groups'},
  282     json_home.build_v3_resource_relation('policies'): {
  283         'href': '/policies'},
  284     json_home.build_v3_resource_relation('policy'): {
  285         'href-template': '/policies/{policy_id}',
  286         'href-vars': {
  287             'policy_id':
  288             json_home.build_v3_parameter_relation('policy_id'), }},
  289     json_home.build_v3_resource_relation('project'): {
  290         'href-template': '/projects/{project_id}',
  291         'href-vars': {
  292             'project_id': json_home.Parameters.PROJECT_ID, }},
  293     json_home.build_v3_resource_relation('project_group_role'): {
  294         'href-template':
  295         '/projects/{project_id}/groups/{group_id}/roles/{role_id}',
  296         'href-vars': {
  297             'group_id': json_home.Parameters.GROUP_ID,
  298             'project_id': json_home.Parameters.PROJECT_ID,
  299             'role_id': json_home.Parameters.ROLE_ID, }},
  300     json_home.build_v3_resource_relation('project_group_roles'): {
  301         'href-template': '/projects/{project_id}/groups/{group_id}/roles',
  302         'href-vars': {
  303             'group_id': json_home.Parameters.GROUP_ID,
  304             'project_id': json_home.Parameters.PROJECT_ID, }},
  305     json_home.build_v3_resource_relation('project_tags'): {
  306         'href-template': '/projects/{project_id}/tags/{value}',
  307         'href-vars': {
  308             'project_id': json_home.Parameters.PROJECT_ID,
  309             'value': json_home.Parameters.TAG_VALUE}},
  310     json_home.build_v3_resource_relation('project_user_role'): {
  311         'href-template':
  312         '/projects/{project_id}/users/{user_id}/roles/{role_id}',
  313         'href-vars': {
  314             'project_id': json_home.Parameters.PROJECT_ID,
  315             'role_id': json_home.Parameters.ROLE_ID,
  316             'user_id': json_home.Parameters.USER_ID, }},
  317     json_home.build_v3_resource_relation('project_user_roles'): {
  318         'href-template': '/projects/{project_id}/users/{user_id}/roles',
  319         'href-vars': {
  320             'project_id': json_home.Parameters.PROJECT_ID,
  321             'user_id': json_home.Parameters.USER_ID, }},
  322     json_home.build_v3_resource_relation('projects'): {
  323         'href': '/projects'},
  324     json_home.build_v3_resource_relation('region'): {
  325         'href-template': '/regions/{region_id}',
  326         'href-vars': {
  327             'region_id':
  328             json_home.build_v3_parameter_relation('region_id'), }},
  329     json_home.build_v3_resource_relation('regions'): {'href': '/regions'},
  330     json_home.build_v3_resource_relation('role'): {
  331         'href-template': '/roles/{role_id}',
  332         'href-vars': {
  333             'role_id': json_home.Parameters.ROLE_ID, }},
  334     json_home.build_v3_resource_relation('implied_roles'): {
  335         'href-template': '/roles/{prior_role_id}/implies',
  336         'href-vars': {
  337             'prior_role_id': json_home.Parameters.ROLE_ID}
  338     },
  339     json_home.build_v3_resource_relation('implied_role'): {
  340         'href-template':
  341         '/roles/{prior_role_id}/implies/{implied_role_id}',
  342         'href-vars': {
  343             'prior_role_id': json_home.Parameters.ROLE_ID,
  344             'implied_role_id': json_home.Parameters.ROLE_ID,
  345         },
  346     },
  347     json_home.build_v3_resource_relation('role_inferences'): {
  348         'href': '/role_inferences',
  349     },
  350     json_home.build_v3_resource_relation('role_assignments'): {
  351         'href': '/role_assignments'},
  352     json_home.build_v3_resource_relation('roles'): {'href': '/roles'},
  353     json_home.build_v3_resource_relation('service'): {
  354         'href-template': '/services/{service_id}',
  355         'href-vars': {
  356             'service_id':
  357             json_home.build_v3_parameter_relation('service_id')}},
  358     json_home.build_v3_resource_relation('services'): {
  359         'href': '/services'},
  360     json_home.build_v3_resource_relation('user'): {
  361         'href-template': '/users/{user_id}',
  362         'href-vars': {
  363             'user_id': json_home.Parameters.USER_ID, }},
  364     json_home.build_v3_resource_relation('user_change_password'): {
  365         'href-template': '/users/{user_id}/password',
  366         'href-vars': {'user_id': json_home.Parameters.USER_ID, }},
  367     json_home.build_v3_resource_relation('user_groups'): {
  368         'href-template': '/users/{user_id}/groups',
  369         'href-vars': {'user_id': json_home.Parameters.USER_ID, }},
  370     json_home.build_v3_resource_relation('user_projects'): {
  371         'href-template': '/users/{user_id}/projects',
  372         'href-vars': {'user_id': json_home.Parameters.USER_ID, }},
  373     json_home.build_v3_resource_relation('users'): {'href': '/users'},
  374     _build_federation_rel(resource_name='domains'): {
  375         'href': '/auth/domains'},
  376     _build_federation_rel(resource_name='websso'): {
  377         'href-template': '/auth/OS-FEDERATION/websso/{protocol_id}',
  378         'href-vars': {
  379             'protocol_id': PROTOCOL_ID_PARAM_RELATION, }},
  380     _build_federation_rel(resource_name='projects'): {
  381         'href': '/auth/projects'},
  382     _build_federation_rel(resource_name='saml2'): {
  383         'href': '/auth/OS-FEDERATION/saml2'},
  384     _build_federation_rel(resource_name='ecp'): {
  385         'href': '/auth/OS-FEDERATION/saml2/ecp'},
  386     _build_federation_rel(resource_name='metadata'): {
  387         'href': '/OS-FEDERATION/saml2/metadata'},
  388     _build_federation_rel(resource_name='identity_providers'): {
  389         'href': '/OS-FEDERATION/identity_providers'},
  390     _build_federation_rel(resource_name='service_providers'): {
  391         'href': '/OS-FEDERATION/service_providers'},
  392     _build_federation_rel(resource_name='mappings'): {
  393         'href': '/OS-FEDERATION/mappings'},
  394     _build_federation_rel(resource_name='identity_provider'):
  395     {
  396         'href-template': '/OS-FEDERATION/identity_providers/{idp_id}',
  397         'href-vars': {'idp_id': IDP_ID_PARAMETER_RELATION, }},
  398     _build_federation_rel(resource_name='identity_providers_websso'): {
  399         'href-template': FEDERATED_IDP_SPECIFIC_WEBSSO,
  400         'href-vars': {
  401             'idp_id': IDP_ID_PARAMETER_RELATION,
  402             'protocol_id': PROTOCOL_ID_PARAM_RELATION, }},
  403     _build_federation_rel(resource_name='service_provider'):
  404     {
  405         'href-template': '/OS-FEDERATION/service_providers/{sp_id}',
  406         'href-vars': {'sp_id': SP_ID_PARAMETER_RELATION, }},
  407     _build_federation_rel(resource_name='mapping'):
  408     {
  409         'href-template': '/OS-FEDERATION/mappings/{mapping_id}',
  410         'href-vars': {'mapping_id': MAPPING_ID_PARAM_RELATION, }},
  411     _build_federation_rel(resource_name='identity_provider_protocol'): {
  412         'href-template': BASE_IDP_PROTOCOL + '/{protocol_id}',
  413         'href-vars': {
  414             'idp_id': IDP_ID_PARAMETER_RELATION,
  415             'protocol_id': PROTOCOL_ID_PARAM_RELATION, }},
  416     _build_federation_rel(resource_name='identity_provider_protocols'): {
  417         'href-template': BASE_IDP_PROTOCOL,
  418         'href-vars': {
  419             'idp_id': IDP_ID_PARAMETER_RELATION}},
  420     _build_federation_rel(resource_name='identity_provider_protocol_auth'): {
  421         'href-template': FEDERATED_AUTH_URL,
  422         'href-vars': {
  423             'idp_id': IDP_ID_PARAMETER_RELATION,
  424             'protocol_id': PROTOCOL_ID_PARAM_RELATION, }},
  425     _build_oauth1_rel(resource_name='access_tokens'): {
  426         'href': '/OS-OAUTH1/access_token'},
  427     _build_oauth1_rel(resource_name='request_tokens'): {
  428         'href': '/OS-OAUTH1/request_token'},
  429     _build_oauth1_rel(resource_name='consumers'): {
  430         'href': '/OS-OAUTH1/consumers'},
  431     _build_oauth1_rel(resource_name='authorize_request_token'):
  432     {
  433         'href-template': '/OS-OAUTH1/authorize/{request_token_id}',
  434         'href-vars': {'request_token_id':
  435                       REQUEST_TOKEN_ID_PARAMETER_RELATION, }},
  436     _build_oauth1_rel(resource_name='consumer'):
  437     {
  438         'href-template': '/OS-OAUTH1/consumers/{consumer_id}',
  439         'href-vars': {'consumer_id': CONSUMER_ID_PARAMETER_RELATION, }},
  440     _build_oauth1_rel(resource_name='user_access_token'):
  441     {
  442         'href-template': BASE_ACCESS_TOKEN,
  443         'href-vars': {'user_id': json_home.Parameters.USER_ID,
  444                       'access_token_id':
  445                       ACCESS_TOKEN_ID_PARAMETER_RELATION, }},
  446     _build_oauth1_rel(resource_name='user_access_tokens'):
  447     {
  448         'href-template': '/users/{user_id}/OS-OAUTH1/access_tokens',
  449         'href-vars': {'user_id': json_home.Parameters.USER_ID, }},
  450     _build_oauth1_rel(resource_name='user_access_token_role'):
  451     {
  452         'href-template': BASE_ACCESS_TOKEN + '/roles/{role_id}',
  453         'href-vars': {'user_id': json_home.Parameters.USER_ID,
  454                       'role_id': json_home.Parameters.ROLE_ID,
  455                       'access_token_id':
  456                       ACCESS_TOKEN_ID_PARAMETER_RELATION, }},
  457     _build_oauth1_rel(resource_name='user_access_token_roles'):
  458     {
  459         'href-template': BASE_ACCESS_TOKEN + '/roles',
  460         'href-vars': {'user_id': json_home.Parameters.USER_ID,
  461                       'access_token_id':
  462                       ACCESS_TOKEN_ID_PARAMETER_RELATION, }},
  463     _build_ep_policy_rel(resource_name='endpoint_policy'):
  464     {
  465         'href-template': '/endpoints/{endpoint_id}/OS-ENDPOINT-POLICY/policy',
  466         'href-vars': {'endpoint_id': json_home.Parameters.ENDPOINT_ID, }},
  467     _build_ep_policy_rel(resource_name='endpoint_policy_association'):
  468     {
  469         'href-template': BASE_EP_POLICY + '/endpoints/{endpoint_id}',
  470         'href-vars': {'endpoint_id': json_home.Parameters.ENDPOINT_ID,
  471                       'policy_id': json_home.Parameters.POLICY_ID, }},
  472     _build_ep_policy_rel(resource_name='policy_endpoints'):
  473     {
  474         'href-template': BASE_EP_POLICY + '/endpoints',
  475         'href-vars': {'policy_id': json_home.Parameters.POLICY_ID, }},
  476     _build_ep_policy_rel(
  477         resource_name='region_and_service_policy_association'):
  478     {
  479         'href-template': (BASE_EP_POLICY +
  480                           '/services/{service_id}/regions/{region_id}'),
  481         'href-vars': {'policy_id': json_home.Parameters.POLICY_ID,
  482                       'service_id': json_home.Parameters.SERVICE_ID,
  483                       'region_id': json_home.Parameters.REGION_ID, }},
  484     _build_ep_policy_rel(resource_name='service_policy_association'):
  485     {
  486         'href-template': BASE_EP_POLICY + '/services/{service_id}',
  487         'href-vars': {'policy_id': json_home.Parameters.POLICY_ID,
  488                       'service_id': json_home.Parameters.SERVICE_ID, }},
  489     _build_ep_filter_rel(resource_name='endpoint_group'):
  490     {
  491         'href-template': '/OS-EP-FILTER/endpoint_groups/{endpoint_group_id}',
  492         'href-vars': {'endpoint_group_id':
  493                       ENDPOINT_GROUP_ID_PARAMETER_RELATION, }},
  494     _build_ep_filter_rel(
  495         resource_name='endpoint_group_to_project_association'):
  496     {
  497         'href-template': BASE_EP_FILTER + '/projects/{project_id}',
  498         'href-vars': {'endpoint_group_id':
  499                       ENDPOINT_GROUP_ID_PARAMETER_RELATION,
  500                       'project_id': json_home.Parameters.PROJECT_ID, }},
  501     _build_ep_filter_rel(resource_name='endpoint_groups'):
  502     {'href': '/OS-EP-FILTER/endpoint_groups'},
  503     _build_ep_filter_rel(resource_name='endpoint_projects'):
  504     {
  505         'href-template': '/OS-EP-FILTER/endpoints/{endpoint_id}/projects',
  506         'href-vars': {'endpoint_id': json_home.Parameters.ENDPOINT_ID, }},
  507     _build_ep_filter_rel(resource_name='endpoints_in_endpoint_group'):
  508     {
  509         'href-template': BASE_EP_FILTER + '/endpoints',
  510         'href-vars': {'endpoint_group_id':
  511                       ENDPOINT_GROUP_ID_PARAMETER_RELATION, }},
  512     _build_ep_filter_rel(resource_name='project_endpoint_groups'):
  513     {
  514         'href-template': (BASE_EP_FILTER_PREFIX + '/projects/{project_id}' +
  515                           '/endpoint_groups'),
  516         'href-vars': {'project_id':
  517                       json_home.Parameters.PROJECT_ID, }},
  518     _build_ep_filter_rel(resource_name='project_endpoint'):
  519     {
  520         'href-template': ('/OS-EP-FILTER/projects/{project_id}'
  521                           '/endpoints/{endpoint_id}'),
  522         'href-vars': {'endpoint_id': json_home.Parameters.ENDPOINT_ID,
  523                       'project_id': json_home.Parameters.PROJECT_ID, }},
  524     _build_ep_filter_rel(resource_name='project_endpoints'):
  525     {
  526         'href-template': '/OS-EP-FILTER/projects/{project_id}/endpoints',
  527         'href-vars': {'project_id': json_home.Parameters.PROJECT_ID, }},
  528     _build_ep_filter_rel(
  529         resource_name='projects_associated_with_endpoint_group'):
  530     {
  531         'href-template': BASE_EP_FILTER + '/projects',
  532         'href-vars': {'endpoint_group_id':
  533                       ENDPOINT_GROUP_ID_PARAMETER_RELATION, }},
  534     _build_os_inherit_rel(
  535         resource_name='domain_user_role_inherited_to_projects'):
  536     {
  537         'href-template': '/OS-INHERIT/domains/{domain_id}/users/'
  538         '{user_id}/roles/{role_id}/inherited_to_projects',
  539         'href-vars': {
  540             'domain_id': json_home.Parameters.DOMAIN_ID,
  541             'role_id': json_home.Parameters.ROLE_ID,
  542             'user_id': json_home.Parameters.USER_ID, }},
  543     _build_os_inherit_rel(
  544         resource_name='domain_group_role_inherited_to_projects'):
  545     {
  546         'href-template': '/OS-INHERIT/domains/{domain_id}/groups/'
  547         '{group_id}/roles/{role_id}/inherited_to_projects',
  548         'href-vars': {
  549             'domain_id': json_home.Parameters.DOMAIN_ID,
  550             'group_id': json_home.Parameters.GROUP_ID,
  551             'role_id': json_home.Parameters.ROLE_ID, }},
  552     _build_os_inherit_rel(
  553         resource_name='domain_user_roles_inherited_to_projects'):
  554     {
  555         'href-template': '/OS-INHERIT/domains/{domain_id}/users/'
  556         '{user_id}/roles/inherited_to_projects',
  557         'href-vars': {
  558             'domain_id': json_home.Parameters.DOMAIN_ID,
  559             'user_id': json_home.Parameters.USER_ID, }},
  560     _build_os_inherit_rel(
  561         resource_name='domain_group_roles_inherited_to_projects'):
  562     {
  563         'href-template': '/OS-INHERIT/domains/{domain_id}/groups/'
  564         '{group_id}/roles/inherited_to_projects',
  565         'href-vars': {
  566             'domain_id': json_home.Parameters.DOMAIN_ID,
  567             'group_id': json_home.Parameters.GROUP_ID, }},
  568     _build_os_inherit_rel(
  569         resource_name='project_user_role_inherited_to_projects'):
  570     {
  571         'href-template': '/OS-INHERIT/projects/{project_id}/users/'
  572         '{user_id}/roles/{role_id}/inherited_to_projects',
  573         'href-vars': {
  574             'project_id': json_home.Parameters.PROJECT_ID,
  575             'role_id': json_home.Parameters.ROLE_ID,
  576             'user_id': json_home.Parameters.USER_ID, }},
  577     _build_os_inherit_rel(
  578         resource_name='project_group_role_inherited_to_projects'):
  579     {
  580         'href-template': '/OS-INHERIT/projects/{project_id}/groups/'
  581         '{group_id}/roles/{role_id}/inherited_to_projects',
  582         'href-vars': {
  583             'project_id': json_home.Parameters.PROJECT_ID,
  584             'group_id': json_home.Parameters.GROUP_ID,
  585             'role_id': json_home.Parameters.ROLE_ID, }},
  586     json_home.build_v3_resource_relation('domain_config'): {
  587         'href-template':
  588         '/domains/{domain_id}/config',
  589         'href-vars': {
  590             'domain_id': json_home.Parameters.DOMAIN_ID}},
  591     json_home.build_v3_resource_relation('domain_config_group'): {
  592         'href-template':
  593         '/domains/{domain_id}/config/{group}',
  594         'href-vars': {
  595             'domain_id': json_home.Parameters.DOMAIN_ID,
  596             'group': json_home.build_v3_parameter_relation('config_group')}},
  597     json_home.build_v3_resource_relation('domain_config_option'): {
  598         'href-template':
  599         '/domains/{domain_id}/config/{group}/{option}',
  600         'href-vars': {
  601             'domain_id': json_home.Parameters.DOMAIN_ID,
  602             'group': json_home.build_v3_parameter_relation('config_group'),
  603             'option': json_home.build_v3_parameter_relation('config_option')}},
  604     json_home.build_v3_resource_relation('domain_config_default'): {
  605         'href': '/domains/config/default'},
  606     json_home.build_v3_resource_relation('domain_config_default_group'): {
  607         'href-template': '/domains/config/{group}/default',
  608         'href-vars': {
  609             'group': json_home.build_v3_parameter_relation('config_group')}},
  610     json_home.build_v3_resource_relation('domain_config_default_option'): {
  611         'href-template': '/domains/config/{group}/{option}/default',
  612         'href-vars': {
  613             'group': json_home.build_v3_parameter_relation('config_group'),
  614             'option': json_home.build_v3_parameter_relation('config_option')}},
  615     json_home.build_v3_resource_relation('registered_limits'): {
  616         'hints': {'status': 'experimental'},
  617         'href': '/registered_limits'},
  618     json_home.build_v3_resource_relation('registered_limit'): {
  619         'href-template': '/registered_limits/{registered_limit_id}',
  620         'href-vars': {
  621             'registered_limit_id': json_home.build_v3_parameter_relation(
  622                 'registered_limit_id')
  623         },
  624         'hints': {'status': 'experimental'}
  625     },
  626     json_home.build_v3_resource_relation('limits'): {
  627         'hints': {'status': 'experimental'},
  628         'href': '/limits'},
  629     json_home.build_v3_resource_relation('limit'): {
  630         'href-template': '/limits/{limit_id}',
  631         'href-vars': {
  632             'limit_id': json_home.build_v3_parameter_relation('limit_id')
  633         },
  634         'hints': {'status': 'experimental'}
  635     },
  636     json_home.build_v3_resource_relation('limit_model'): {
  637         'href': '/limits/model',
  638         'hints': {'status': 'experimental'}
  639     },
  640     json_home.build_v3_resource_relation('application_credentials'): {
  641         'href-template': APPLICATION_CREDENTIALS,
  642         'href-vars': {
  643             'user_id': json_home.build_v3_parameter_relation('user_id')}},
  644     json_home.build_v3_resource_relation('application_credential'): {
  645         'href-template': APPLICATION_CREDENTIAL,
  646         'href-vars': {
  647             'application_credential_id': APPLICATION_CREDENTIAL_RELATION,
  648             'user_id': json_home.build_v3_parameter_relation('user_id')}},
  649     json_home.build_v3_resource_relation('access_rules'): {
  650         'href-template': ACCESS_RULES,
  651         'href-vars': {
  652             'user_id': json_home.build_v3_parameter_relation('user_id')}},
  653     json_home.build_v3_resource_relation('access_rule'): {
  654         'href-template': ACCESS_RULE,
  655         'href-vars': {
  656             'access_rule_id': ACCESS_RULE_RELATION,
  657             'user_id': json_home.build_v3_parameter_relation('user_id')}},
  658 }
  659 
  660 
  661 class TestClient(object):
  662     def __init__(self, app=None, token=None):
  663         self.app = app
  664         self.token = token
  665 
  666     def request(self, method, path, headers=None, body=None):
  667         if headers is None:
  668             headers = {}
  669 
  670         if self.token:
  671             headers.setdefault('X-Auth-Token', self.token)
  672 
  673         req = webob.Request.blank(path)
  674         req.method = method
  675         for k, v in headers.items():
  676             req.headers[k] = v
  677         if body:
  678             req.body = body
  679         return req.get_response(self.app)
  680 
  681     def get(self, path, headers=None):
  682         return self.request('GET', path=path, headers=headers)
  683 
  684     def post(self, path, headers=None, body=None):
  685         return self.request('POST', path=path, headers=headers, body=body)
  686 
  687     def put(self, path, headers=None, body=None):
  688         return self.request('PUT', path=path, headers=headers, body=body)
  689 
  690 
  691 class _VersionsEqual(tt_matchers.MatchesListwise):
  692     def __init__(self, expected):
  693         super(_VersionsEqual, self).__init__([
  694             tt_matchers.KeysEqual(expected),
  695             tt_matchers.KeysEqual(expected['versions']),
  696             tt_matchers.HasLength(len(expected['versions']['values'])),
  697             tt_matchers.ContainsAll(expected['versions']['values']),
  698         ])
  699 
  700     def match(self, other):
  701         return super(_VersionsEqual, self).match([
  702             other,
  703             other['versions'],
  704             other['versions']['values'],
  705             other['versions']['values'],
  706         ])
  707 
  708 
  709 class VersionTestCase(unit.TestCase):
  710     def setUp(self):
  711         super(VersionTestCase, self).setUp()
  712         self.load_backends()
  713         self.public_app = self.loadapp('public')
  714         self.public_port = random.randint(40000, 60000)
  715 
  716         self.config_fixture.config(
  717             public_endpoint='http://localhost:%d' % self.public_port)
  718 
  719     def config_overrides(self):
  720         super(VersionTestCase, self).config_overrides()
  721 
  722     def _paste_in_port(self, response, port):
  723         for link in response['links']:
  724             if link['rel'] == 'self':
  725                 link['href'] = port
  726 
  727     def test_public_versions(self):
  728         client = TestClient(self.public_app)
  729         resp = client.get('/')
  730         self.assertEqual(300, resp.status_int)
  731         data = jsonutils.loads(resp.body)
  732         expected = VERSIONS_RESPONSE
  733         for version in expected['versions']['values']:
  734             if version['id'].startswith('v3'):
  735                 self._paste_in_port(
  736                     version, 'http://localhost:%s/v3/' % self.public_port)
  737         self.assertThat(data, _VersionsEqual(expected))
  738 
  739     def test_use_site_url_if_endpoint_unset(self):
  740         self.config_fixture.config(public_endpoint=None)
  741 
  742         for app in (self.public_app,):
  743             client = TestClient(app)
  744             resp = client.get('/')
  745             self.assertEqual(300, resp.status_int)
  746             data = jsonutils.loads(resp.body)
  747             expected = VERSIONS_RESPONSE
  748             for version in expected['versions']['values']:
  749                 # localhost happens to be the site url for tests
  750                 if version['id'].startswith('v3'):
  751                     self._paste_in_port(
  752                         version, 'http://localhost/v3/')
  753             self.assertThat(data, _VersionsEqual(expected))
  754 
  755     def test_public_version_v3(self):
  756         client = TestClient(self.public_app)
  757         resp = client.get('/v3/')
  758         self.assertEqual(http.client.OK, resp.status_int)
  759         data = jsonutils.loads(resp.body)
  760         expected = v3_VERSION_RESPONSE
  761         self._paste_in_port(expected['version'],
  762                             'http://localhost:%s/v3/' % self.public_port)
  763         self.assertEqual(expected, data)
  764 
  765     def test_use_site_url_if_endpoint_unset_v3(self):
  766         self.config_fixture.config(public_endpoint=None)
  767         for app in (self.public_app,):
  768             client = TestClient(app)
  769             resp = client.get('/v3/')
  770             self.assertEqual(http.client.OK, resp.status_int)
  771             data = jsonutils.loads(resp.body)
  772             expected = v3_VERSION_RESPONSE
  773             self._paste_in_port(expected['version'], 'http://localhost/v3/')
  774             self.assertEqual(expected, data)
  775 
  776     def test_v2_disabled(self):
  777         # NOTE(morgan): This test should be kept, v2.0 is removed and should
  778         # never return, this prevents regression[s]/v2.0 discovery doc
  779         # slipping back in.
  780         client = TestClient(self.public_app)
  781         # request to /v2.0 should fail
  782         resp = client.get('/v2.0/')
  783         # NOTE(morgan): getting a 418 here is indicative of a 404, but from
  784         # the flask app itself (not a handled 404 such as UserNotFound)
  785         self.assertEqual(418, resp.status_int)
  786 
  787         # request to /v3 should pass
  788         resp = client.get('/v3/')
  789         self.assertEqual(http.client.OK, resp.status_int)
  790         data = jsonutils.loads(resp.body)
  791         expected = v3_VERSION_RESPONSE
  792         self._paste_in_port(expected['version'],
  793                             'http://localhost:%s/v3/' % self.public_port)
  794         self.assertEqual(expected, data)
  795 
  796         # only v3 information should be displayed by requests to /
  797         v3_only_response = {
  798             "versions": {
  799                 "values": [
  800                     v3_EXPECTED_RESPONSE
  801                 ]
  802             }
  803         }
  804         self._paste_in_port(v3_only_response['versions']['values'][0],
  805                             'http://localhost:%s/v3/' % self.public_port)
  806         resp = client.get('/')
  807         self.assertEqual(300, resp.status_int)
  808         data = jsonutils.loads(resp.body)
  809         self.assertEqual(v3_only_response, data)
  810 
  811     def _test_json_home(self, path, exp_json_home_data):
  812         client = TestClient(self.public_app)
  813         resp = client.get(path, headers={'Accept': 'application/json-home'})
  814 
  815         self.assertThat(resp.status, tt_matchers.Equals('200 OK'))
  816         self.assertThat(resp.headers['Content-Type'],
  817                         tt_matchers.Equals('application/json-home'))
  818         maxDiff = self.maxDiff
  819         self.maxDiff = None
  820         # NOTE(morgan): Changed from tt_matchers.Equals to make it easier to
  821         # determine issues. Reset maxDiff to the original value at the end
  822         # of the assert.
  823         self.assertDictEqual(exp_json_home_data,
  824                              jsonutils.loads(resp.body))
  825         self.maxDiff = maxDiff
  826 
  827     def test_json_home_v3(self):
  828         # If the request is /v3 and the Accept header is application/json-home
  829         # then the server responds with a JSON Home document.
  830 
  831         exp_json_home_data = {
  832             'resources': V3_JSON_HOME_RESOURCES}
  833 
  834         self._test_json_home('/v3', exp_json_home_data)
  835 
  836     def test_json_home_root(self):
  837         # If the request is / and the Accept header is application/json-home
  838         # then the server responds with a JSON Home document.
  839 
  840         exp_json_home_data = copy.deepcopy({
  841             'resources': V3_JSON_HOME_RESOURCES})
  842         json_home.translate_urls(exp_json_home_data, '/v3')
  843 
  844         self._test_json_home('/', exp_json_home_data)
  845 
  846     def test_accept_type_handling(self):
  847         # Accept headers with multiple types and qvalues are handled.
  848 
  849         def make_request(accept_types=None):
  850             client = TestClient(self.public_app)
  851             headers = None
  852             if accept_types:
  853                 headers = {'Accept': accept_types}
  854             resp = client.get('/v3', headers=headers)
  855             self.assertThat(resp.status, tt_matchers.Equals('200 OK'))
  856             return resp.headers['Content-Type']
  857 
  858         JSON = discovery.MimeTypes.JSON
  859         JSON_HOME = discovery.MimeTypes.JSON_HOME
  860 
  861         JSON_MATCHER = tt_matchers.Equals(JSON)
  862         JSON_HOME_MATCHER = tt_matchers.Equals(JSON_HOME)
  863 
  864         # Default is JSON.
  865         self.assertThat(make_request(), JSON_MATCHER)
  866 
  867         # Can request JSON and get JSON.
  868         self.assertThat(make_request(JSON), JSON_MATCHER)
  869 
  870         # Can request JSONHome and get JSONHome.
  871         self.assertThat(make_request(JSON_HOME), JSON_HOME_MATCHER)
  872 
  873         # If request JSON, JSON Home get JSON.
  874         accept_types = '%s, %s' % (JSON, JSON_HOME)
  875         self.assertThat(make_request(accept_types), JSON_MATCHER)
  876 
  877         # If request JSON Home, JSON get JSON.
  878         accept_types = '%s, %s' % (JSON_HOME, JSON)
  879         self.assertThat(make_request(accept_types), JSON_MATCHER)
  880 
  881         # If request JSON Home, JSON;q=0.5 get JSON Home.
  882         accept_types = '%s, %s;q=0.5' % (JSON_HOME, JSON)
  883         self.assertThat(make_request(accept_types), JSON_HOME_MATCHER)
  884 
  885         # If request some unknown mime-type, get JSON.
  886         self.assertThat(make_request(self.getUniqueString()), JSON_MATCHER)
  887 
  888 
  889 class VersionSingleAppTestCase(unit.TestCase):
  890     """Test running with a single application loaded.
  891 
  892     These are important because when Keystone is running in Apache httpd
  893     there's only one application loaded for each instance.
  894 
  895     """
  896 
  897     def setUp(self):
  898         super(VersionSingleAppTestCase, self).setUp()
  899         self.load_backends()
  900 
  901         self.public_port = random.randint(40000, 60000)
  902 
  903         self.config_fixture.config(
  904             public_endpoint='http://localhost:%d' % self.public_port)
  905 
  906     def config_overrides(self):
  907         super(VersionSingleAppTestCase, self).config_overrides()
  908 
  909     def _paste_in_port(self, response, port):
  910         for link in response['links']:
  911             if link['rel'] == 'self':
  912                 link['href'] = port
  913 
  914     def _test_version(self, app_name):
  915         app = self.loadapp(app_name)
  916         client = TestClient(app)
  917         resp = client.get('/')
  918         self.assertEqual(300, resp.status_int)
  919         data = jsonutils.loads(resp.body)
  920         expected = VERSIONS_RESPONSE
  921         url_with_port = 'http://localhost:%s/v3/' % self.public_port
  922         for version in expected['versions']['values']:
  923             # TODO(morgan): Eliminate the need to do the "paste-in-port" part
  924             # of the tests. Ultimately, this is very hacky and shows we are
  925             # not setting up the test case sanely.
  926             if version['id'].startswith('v3'):
  927                 self._paste_in_port(
  928                     version, url_with_port)
  929         # Explicitly check that a location header is set and it is pointing
  930         # to v3 (The preferred location for now)!
  931         self.assertIn('Location', resp.headers)
  932         self.assertEqual(url_with_port, resp.headers['Location'])
  933         self.assertThat(data, _VersionsEqual(expected))
  934 
  935     def test_public(self):
  936         self._test_version('public')
  937 
  938     def test_admin(self):
  939         self._test_version('admin')