Merge "Add HEAD API to domain config"

This commit is contained in:
Jenkins 2017-06-23 05:07:57 +00:00 committed by Gerrit Code Review
commit 920c0ec7b3
3 changed files with 183 additions and 59 deletions

View File

@ -42,7 +42,7 @@ Show default configuration settings
The default configuration settings for the options that can be overridden
can be retrieved.
Relationship::
Relationship:
``https://docs.openstack.org/api/openstack-identity/3/rel/domain_config_default``
Response Parameters
@ -145,7 +145,6 @@ Response Example
.. literalinclude:: ./samples/admin/domain-config-group-option-default-response.json
:language: javascript
Show domain group option configuration
======================================

View File

@ -88,13 +88,13 @@ class Routers(wsgi.RoutersBase):
self._add_resource(
mapper, config_controller,
path='/domains/config/default',
get_action='get_domain_config_default',
get_head_action='get_domain_config_default',
rel=json_home.build_v3_resource_relation('domain_config_default'))
self._add_resource(
mapper, config_controller,
path='/domains/config/{group}/default',
get_action='get_domain_config_default',
get_head_action='get_domain_config_default',
rel=json_home.build_v3_resource_relation(
'domain_config_default_group'),
path_vars={
@ -104,7 +104,7 @@ class Routers(wsgi.RoutersBase):
self._add_resource(
mapper, config_controller,
path='/domains/config/{group}/{option}/default',
get_action='get_domain_config_default',
get_head_action='get_domain_config_default',
rel=json_home.build_v3_resource_relation(
'domain_config_default_option'),
path_vars={

View File

@ -122,7 +122,7 @@ class DomainConfigTestCase(test_v3.RestfulTestCase):
self.assertEqual(self.config, r.result['config'])
self.head(url, expected_status=http_client.OK)
def test_get_config_by_group(self):
def test_get_head_config_by_group(self):
"""Call ``GET & HEAD /domains{domain_id}/config/{group}``."""
self.domain_config_api.create_config(self.domain['id'], self.config)
url = '/domains/%(domain_id)s/config/ldap' % {
@ -131,7 +131,7 @@ class DomainConfigTestCase(test_v3.RestfulTestCase):
self.assertEqual({'ldap': self.config['ldap']}, r.result['config'])
self.head(url, expected_status=http_client.OK)
def test_get_config_by_group_invalid_domain(self):
def test_get_head_config_by_group_invalid_domain(self):
"""Call ``GET & HEAD /domains{domain_id}/config/{group}``.
While retrieving Identity API-based domain config by group with an
@ -140,11 +140,13 @@ class DomainConfigTestCase(test_v3.RestfulTestCase):
"""
self.domain_config_api.create_config(self.domain['id'], self.config)
invalid_domain_id = uuid.uuid4().hex
self.get('/domains/%(domain_id)s/config/ldap' % {
'domain_id': invalid_domain_id},
expected_status=exception.DomainNotFound.code)
url = ('/domains/%(domain_id)s/config/ldap' % {
'domain_id': invalid_domain_id}
)
self.get(url, expected_status=exception.DomainNotFound.code)
self.head(url, expected_status=exception.DomainNotFound.code)
def test_get_config_by_option(self):
def test_get_head_config_by_option(self):
"""Call ``GET & HEAD /domains{domain_id}/config/{group}/{option}``."""
self.domain_config_api.create_config(self.domain['id'], self.config)
url = '/domains/%(domain_id)s/config/ldap/url' % {
@ -154,7 +156,7 @@ class DomainConfigTestCase(test_v3.RestfulTestCase):
r.result['config'])
self.head(url, expected_status=http_client.OK)
def test_get_config_by_option_invalid_domain(self):
def test_get_head_config_by_option_invalid_domain(self):
"""Call ``GET & HEAD /domains{domain_id}/config/{group}/{option}``.
While retrieving Identity API-based domain config by option with an
@ -163,38 +165,46 @@ class DomainConfigTestCase(test_v3.RestfulTestCase):
"""
self.domain_config_api.create_config(self.domain['id'], self.config)
invalid_domain_id = uuid.uuid4().hex
self.get('/domains/%(domain_id)s/config/ldap/url' % {
'domain_id': invalid_domain_id},
expected_status=exception.DomainNotFound.code)
url = ('/domains/%(domain_id)s/config/ldap/url' % {
'domain_id': invalid_domain_id}
)
self.get(url, expected_status=exception.DomainNotFound.code)
self.head(url, expected_status=exception.DomainNotFound.code)
def test_get_non_existant_config(self):
def test_get_head_non_existant_config(self):
"""Call ``GET /domains{domain_id}/config when no config defined``."""
self.get('/domains/%(domain_id)s/config' % {
'domain_id': self.domain['id']},
expected_status=http_client.NOT_FOUND)
url = ('/domains/%(domain_id)s/config' % {
'domain_id': self.domain['id']}
)
self.get(url, expected_status=http_client.NOT_FOUND)
self.head(url, expected_status=http_client.NOT_FOUND)
def test_get_non_existant_config_invalid_domain(self):
"""Call ``GET /domains{domain_id}/config when no config defined``.
def test_get_head_non_existant_config_invalid_domain(self):
"""Call ``GET & HEAD /domains/{domain_id}/config with invalid domain``.
While retrieving non-existent Identity API-based domain config with an
invalid domain id provided, the request shall be rejected with a
response 404 domain not found.
"""
invalid_domain_id = uuid.uuid4().hex
self.get('/domains/%(domain_id)s/config' % {
'domain_id': invalid_domain_id},
expected_status=exception.DomainNotFound.code)
url = ('/domains/%(domain_id)s/config' % {
'domain_id': invalid_domain_id}
)
self.get(url, expected_status=exception.DomainNotFound.code)
self.head(url, expected_status=exception.DomainNotFound.code)
def test_get_non_existant_config_group(self):
"""Call ``GET /domains{domain_id}/config/{group_not_exist}``."""
def test_get_head_non_existant_config_group(self):
"""Call ``GET /domains/{domain_id}/config/{group_not_exist}``."""
config = {'ldap': {'url': uuid.uuid4().hex}}
self.domain_config_api.create_config(self.domain['id'], config)
self.get('/domains/%(domain_id)s/config/identity' % {
'domain_id': self.domain['id']},
expected_status=http_client.NOT_FOUND)
url = ('/domains/%(domain_id)s/config/identity' % {
'domain_id': self.domain['id']}
)
self.get(url, expected_status=http_client.NOT_FOUND)
self.head(url, expected_status=http_client.NOT_FOUND)
def test_get_non_existant_config_group_invalid_domain(self):
"""Call ``GET /domains{domain_id}/config/{group_not_exist}``.
def test_get_head_non_existant_config_group_invalid_domain(self):
"""Call ``GET & HEAD /domains/{domain_id}/config/{group}``.
While retrieving non-existent Identity API-based domain config group
with an invalid domain id provided, the request shall be rejected with
@ -203,20 +213,31 @@ class DomainConfigTestCase(test_v3.RestfulTestCase):
config = {'ldap': {'url': uuid.uuid4().hex}}
self.domain_config_api.create_config(self.domain['id'], config)
invalid_domain_id = uuid.uuid4().hex
self.get('/domains/%(domain_id)s/config/identity' % {
'domain_id': invalid_domain_id},
expected_status=exception.DomainNotFound.code)
url = ('/domains/%(domain_id)s/config/identity' % {
'domain_id': invalid_domain_id}
)
self.get(url, expected_status=exception.DomainNotFound.code)
self.head(url, expected_status=exception.DomainNotFound.code)
def test_get_non_existant_config_option(self):
"""Call ``GET /domains{domain_id}/config/group/{option_not_exist}``."""
def test_get_head_non_existant_config_option(self):
"""Test that Not Found is returned when option doesn't exist.
Call ``GET & HEAD /domains/{domain_id}/config/{group}/{opt_not_exist}``
and ensure a Not Found is returned because the option isn't defined
within the group.
"""
config = {'ldap': {'url': uuid.uuid4().hex}}
self.domain_config_api.create_config(self.domain['id'], config)
self.get('/domains/%(domain_id)s/config/ldap/user_tree_dn' % {
'domain_id': self.domain['id']},
expected_status=http_client.NOT_FOUND)
url = ('/domains/%(domain_id)s/config/ldap/user_tree_dn' % {
'domain_id': self.domain['id']}
)
self.get(url, expected_status=http_client.NOT_FOUND)
self.head(url, expected_status=http_client.NOT_FOUND)
def test_get_non_existant_config_option_invalid_domain(self):
"""Call ``GET /domains{domain_id}/config/group/{option_not_exist}``.
def test_get_head_non_existant_config_option_with_invalid_domain(self):
"""Test that Domain Not Found is returned with invalid domain.
Call ``GET & HEAD /domains/{domain_id}/config/{group}/{opt_not_exist}``
While retrieving non-existent Identity API-based domain config option
with an invalid domain id provided, the request shall be rejected with
@ -225,9 +246,11 @@ class DomainConfigTestCase(test_v3.RestfulTestCase):
config = {'ldap': {'url': uuid.uuid4().hex}}
self.domain_config_api.create_config(self.domain['id'], config)
invalid_domain_id = uuid.uuid4().hex
self.get('/domains/%(domain_id)s/config/ldap/user_tree_dn' % {
'domain_id': invalid_domain_id},
expected_status=exception.DomainNotFound.code)
url = ('/domains/%(domain_id)s/config/ldap/user_tree_dn' % {
'domain_id': invalid_domain_id}
)
self.get(url, expected_status=exception.DomainNotFound.code)
self.head(url, expected_status=exception.DomainNotFound.code)
def test_update_config(self):
"""Call ``PATCH /domains/{domain_id}/config``."""
@ -402,8 +425,8 @@ class DomainConfigTestCase(test_v3.RestfulTestCase):
body={'config': new_config},
expected_status=exception.DomainNotFound.code)
def test_get_config_default(self):
"""Call ``GET /domains/config/default``."""
def test_get_head_config_default(self):
"""Call ``GET & HEAD /domains/config/default``."""
# Create a config that overrides a few of the options so that we can
# check that only the defaults are returned.
self.domain_config_api.create_config(self.domain['id'], self.config)
@ -414,9 +437,10 @@ class DomainConfigTestCase(test_v3.RestfulTestCase):
for option in default_config[group]:
self.assertEqual(getattr(getattr(CONF, group), option),
default_config[group][option])
self.head(url, expected_status=http_client.OK)
def test_get_config_default_by_group(self):
"""Call ``GET /domains/config/{group}/default``."""
def test_get_head_config_default_by_group(self):
"""Call ``GET & HEAD /domains/config/{group}/default``."""
# Create a config that overrides a few of the options so that we can
# check that only the defaults are returned.
self.domain_config_api.create_config(self.domain['id'], self.config)
@ -426,9 +450,10 @@ class DomainConfigTestCase(test_v3.RestfulTestCase):
for option in default_config['ldap']:
self.assertEqual(getattr(CONF.ldap, option),
default_config['ldap'][option])
self.head(url, expected_status=http_client.OK)
def test_get_config_default_by_option(self):
"""Call ``GET /domains/config/{group}/{option}/default``."""
def test_get_head_config_default_by_option(self):
"""Call ``GET & HEAD /domains/config/{group}/{option}/default``."""
# Create a config that overrides a few of the options so that we can
# check that only the defaults are returned.
self.domain_config_api.create_config(self.domain['id'], self.config)
@ -436,27 +461,36 @@ class DomainConfigTestCase(test_v3.RestfulTestCase):
r = self.get(url)
default_config = r.result['config']
self.assertEqual(CONF.ldap.url, default_config['url'])
self.head(url, expected_status=http_client.OK)
def test_get_config_default_by_invalid_group(self):
"""Call ``GET for /domains/config/{bad-group}/default``."""
def test_get_head_config_default_by_invalid_group(self):
"""Call ``GET & HEAD for /domains/config/{bad-group}/default``."""
# First try a valid group, but one we don't support for domain config
self.get('/domains/config/resouce/default',
self.get('/domains/config/resource/default',
expected_status=http_client.FORBIDDEN)
self.head('/domains/config/resource/default',
expected_status=http_client.FORBIDDEN)
# Now try a totally invalid group
url = '/domains/config/%s/default' % uuid.uuid4().hex
self.get(url, expected_status=http_client.FORBIDDEN)
self.head(url, expected_status=http_client.FORBIDDEN)
def test_get_config_default_by_invalid_option(self):
"""Call ``GET for /domains/config/{group}/{bad-option}/default``."""
# First try a valid option, but one we don't support for domain config,
# i.e. one that is in the sensitive options list
def test_get_head_config_default_for_unsupported_group(self):
# It should not be possible to expose configuration information for
# groups that the domain configuration API backlists explicitly. Doing
# so would be a security vulnerability because it would leak sensitive
# information over the API.
self.get('/domains/config/ldap/password/default',
expected_status=http_client.FORBIDDEN)
self.head('/domains/config/ldap/password/default',
expected_status=http_client.FORBIDDEN)
# Now try a totally invalid option
def test_get_head_config_default_for_invalid_option(self):
"""Returning invalid configuration options is invalid."""
url = '/domains/config/ldap/%s/default' % uuid.uuid4().hex
self.get(url, expected_status=http_client.FORBIDDEN)
self.head(url, expected_status=http_client.FORBIDDEN)
class SecurityRequirementsTestCase(test_v3.RestfulTestCase):
@ -518,7 +552,7 @@ class SecurityRequirementsTestCase(test_v3.RestfulTestCase):
)
return self.get_requested_token(non_admin_auth_data)
def test_get_security_compliance_config_for_default_domain(self):
def test_get_head_security_compliance_config_for_default_domain(self):
"""Ask for all security compliance configuration options.
Support for enforcing security compliance per domain currently doesn't
@ -557,6 +591,18 @@ class SecurityRequirementsTestCase(test_v3.RestfulTestCase):
admin_response = self.get(url, token=self._get_admin_token())
self.assertEqual(admin_response.result['config'], expected_response)
# Ensure HEAD requests behave the same way
self.head(
url,
token=self._get_non_admin_token(),
expected_status=http_client.OK
)
self.head(
url,
token=self._get_admin_token(),
expected_status=http_client.OK
)
def test_get_security_compliance_config_for_non_default_domain_fails(self):
"""Getting security compliance opts for other domains should fail.
@ -600,6 +646,18 @@ class SecurityRequirementsTestCase(test_v3.RestfulTestCase):
token=self._get_admin_token()
)
# Ensure HEAD requests behave the same way
self.head(
url,
expected_status=http_client.FORBIDDEN,
token=self._get_non_admin_token()
)
self.head(
url,
expected_status=http_client.FORBIDDEN,
token=self._get_admin_token()
)
def test_get_non_whitelisted_security_compliance_opt_fails(self):
"""We only support exposing a subset of security compliance options.
@ -634,6 +692,18 @@ class SecurityRequirementsTestCase(test_v3.RestfulTestCase):
token=self._get_admin_token()
)
# Ensure HEAD requests behave the same way
self.head(
url,
expected_status=http_client.FORBIDDEN,
token=self._get_non_admin_token()
)
self.head(
url,
expected_status=http_client.FORBIDDEN,
token=self._get_admin_token()
)
def test_get_security_compliance_password_regex(self):
"""Ask for the security compliance password regular expression."""
password_regex = uuid.uuid4().hex
@ -665,6 +735,18 @@ class SecurityRequirementsTestCase(test_v3.RestfulTestCase):
password_regex
)
# Ensure HEAD requests behave the same way
self.head(
url,
token=self._get_non_admin_token(),
expected_status=http_client.OK
)
self.head(
url,
token=self._get_admin_token(),
expected_status=http_client.OK
)
def test_get_security_compliance_password_regex_description(self):
"""Ask for the security compliance password regex description."""
password_regex_description = uuid.uuid4().hex
@ -696,6 +778,18 @@ class SecurityRequirementsTestCase(test_v3.RestfulTestCase):
password_regex_description
)
# Ensure HEAD requests behave the same way
self.head(
url,
token=self._get_non_admin_token(),
expected_status=http_client.OK
)
self.head(
url,
token=self._get_admin_token(),
expected_status=http_client.OK
)
def test_get_security_compliance_password_regex_returns_none(self):
"""When an option isn't set, we should explicitly return None."""
group = 'security_compliance'
@ -717,6 +811,18 @@ class SecurityRequirementsTestCase(test_v3.RestfulTestCase):
admin_response = self.get(url, token=self._get_admin_token())
self.assertIsNone(admin_response.result['config'][option])
# Ensure HEAD requests behave the same way
self.head(
url,
token=self._get_non_admin_token(),
expected_status=http_client.OK
)
self.head(
url,
token=self._get_admin_token(),
expected_status=http_client.OK
)
def test_get_security_compliance_password_regex_desc_returns_none(self):
"""When an option isn't set, we should explicitly return None."""
group = 'security_compliance'
@ -738,6 +844,18 @@ class SecurityRequirementsTestCase(test_v3.RestfulTestCase):
admin_response = self.get(url, token=self._get_admin_token())
self.assertIsNone(admin_response.result['config'][option])
# Ensure HEAD requests behave the same way
self.head(
url,
token=self._get_non_admin_token(),
expected_status=http_client.OK
)
self.head(
url,
token=self._get_admin_token(),
expected_status=http_client.OK
)
def test_get_security_compliance_config_with_user_from_other_domain(self):
"""Make sure users from other domains can access password requirements.
@ -807,6 +925,13 @@ class SecurityRequirementsTestCase(test_v3.RestfulTestCase):
password_regex_description
)
# Ensure HEAD requests behave the same way
self.head(
url,
token=user_token,
expected_status=http_client.OK
)
def test_update_security_compliance_config_group_fails(self):
"""Make sure that updates to the entire security group section fail.