Blackify the keystone code base
Improve code maintainability by enabling us to use automatic code formatter. We use black as a relatively fast code formatter (ruff is an lternative, but it will immediately require also changing all quotes chaos). In the next change black is going to be added into the pre-commit allowing contributors to spot formatting issues before sending code to the CI sending precious run hours. Same steps has been performed in the openstasksdk/cli and partially nova. Steps performed: - `black -l 79 -S keystone` - add exceptions to the tox.ini for the lines which black decided not to split Following files are polished manually due to noqa headers and similar being reformatted to wrong strings: keystone/auth/plugins/totp.py keystone/common/password_hashing.py keystone/tests/unit/ksfixtures/__init__.py Change-Id: I832ec4c152fa58fb0088d9f880add86a20ec95fc
This commit is contained in:
parent
24113bb182
commit
a00839ca02
@ -46,10 +46,11 @@ class ResourceBase(ks_flask.ResourceBase):
|
||||
def _check_timestamp(credentials):
|
||||
timestamp = (
|
||||
# AWS Signature v1/v2
|
||||
credentials.get('params', {}).get('Timestamp') or
|
||||
credentials.get('params', {}).get('Timestamp')
|
||||
or
|
||||
# AWS Signature v4
|
||||
credentials.get('headers', {}).get('X-Amz-Date') or
|
||||
credentials.get('params', {}).get('X-Amz-Date')
|
||||
credentials.get('headers', {}).get('X-Amz-Date')
|
||||
or credentials.get('params', {}).get('X-Amz-Date')
|
||||
)
|
||||
if not timestamp:
|
||||
# If the signed payload doesn't include a timestamp then the signer
|
||||
@ -60,12 +61,12 @@ class ResourceBase(ks_flask.ResourceBase):
|
||||
timestamp = timeutils.normalize_time(timestamp)
|
||||
except Exception as e:
|
||||
raise ks_exceptions.Unauthorized(
|
||||
_('Credential timestamp is invalid: %s') % e)
|
||||
_('Credential timestamp is invalid: %s') % e
|
||||
)
|
||||
auth_ttl = datetime.timedelta(minutes=CONF.credential.auth_ttl)
|
||||
current_time = timeutils.normalize_time(timeutils.utcnow())
|
||||
if current_time > timestamp + auth_ttl:
|
||||
raise ks_exceptions.Unauthorized(
|
||||
_('Credential is expired'))
|
||||
raise ks_exceptions.Unauthorized(_('Credential is expired'))
|
||||
|
||||
def handle_authenticate(self):
|
||||
# TODO(morgan): convert this dirty check to JSON Schema validation
|
||||
@ -86,9 +87,9 @@ class ResourceBase(ks_flask.ResourceBase):
|
||||
# Try "credentials" then "credential" and THEN ec2Credentials. Final
|
||||
# default is {}
|
||||
credentials = (
|
||||
self.request_body_json.get('credentials') or
|
||||
self.request_body_json.get('credential') or
|
||||
self.request_body_json.get('ec2Credentials')
|
||||
self.request_body_json.get('credentials')
|
||||
or self.request_body_json.get('credential')
|
||||
or self.request_body_json.get('ec2Credentials')
|
||||
)
|
||||
if not credentials:
|
||||
credentials = {}
|
||||
@ -116,21 +117,24 @@ class ResourceBase(ks_flask.ResourceBase):
|
||||
secret=loaded.get('secret'),
|
||||
trust_id=loaded.get('trust_id'),
|
||||
app_cred_id=loaded.get('app_cred_id'),
|
||||
access_token_id=loaded.get('access_token_id')
|
||||
access_token_id=loaded.get('access_token_id'),
|
||||
)
|
||||
|
||||
# validate the signature
|
||||
self._check_signature(cred_data, credentials)
|
||||
project_ref = PROVIDERS.resource_api.get_project(
|
||||
cred_data['project_id'])
|
||||
cred_data['project_id']
|
||||
)
|
||||
user_ref = PROVIDERS.identity_api.get_user(cred_data['user_id'])
|
||||
|
||||
# validate that the auth info is valid and nothing is disabled
|
||||
try:
|
||||
PROVIDERS.identity_api.assert_user_enabled(
|
||||
user_id=user_ref['id'], user=user_ref)
|
||||
user_id=user_ref['id'], user=user_ref
|
||||
)
|
||||
PROVIDERS.resource_api.assert_project_enabled(
|
||||
project_id=project_ref['id'], project=project_ref)
|
||||
project_id=project_ref['id'], project=project_ref
|
||||
)
|
||||
except AssertionError as e:
|
||||
raise ks_exceptions.Unauthorized from e
|
||||
|
||||
@ -153,16 +157,19 @@ class ResourceBase(ks_flask.ResourceBase):
|
||||
elif cred_data['app_cred_id']:
|
||||
ac_client = PROVIDERS.application_credential_api
|
||||
app_cred = ac_client.get_application_credential(
|
||||
cred_data['app_cred_id'])
|
||||
cred_data['app_cred_id']
|
||||
)
|
||||
roles = [r['id'] for r in app_cred['roles']]
|
||||
elif cred_data['access_token_id']:
|
||||
access_token = PROVIDERS.oauth_api.get_access_token(
|
||||
cred_data['access_token_id'])
|
||||
cred_data['access_token_id']
|
||||
)
|
||||
roles = jsonutils.loads(access_token['role_ids'])
|
||||
auth_context = {'access_token_id': cred_data['access_token_id']}
|
||||
else:
|
||||
roles = PROVIDERS.assignment_api.get_roles_for_user_and_project(
|
||||
user_ref['id'], project_ref['id'])
|
||||
user_ref['id'], project_ref['id']
|
||||
)
|
||||
|
||||
if not roles:
|
||||
raise ks_exceptions.Unauthorized(_('User not valid for project.'))
|
||||
@ -178,9 +185,11 @@ class ResourceBase(ks_flask.ResourceBase):
|
||||
else:
|
||||
user_id = user_ref['id']
|
||||
token = PROVIDERS.token_provider_api.issue_token(
|
||||
user_id=user_id, method_names=method_names,
|
||||
user_id=user_id,
|
||||
method_names=method_names,
|
||||
project_id=project_ref['id'],
|
||||
trust_id=cred_data['trust_id'],
|
||||
app_cred_id=cred_data['app_cred_id'],
|
||||
auth_context=auth_context)
|
||||
auth_context=auth_context,
|
||||
)
|
||||
return token
|
||||
|
@ -33,9 +33,7 @@ PROVIDERS = provider_api.ProviderAPIs
|
||||
|
||||
|
||||
def _check_and_set_default_scoping(auth_info, auth_context):
|
||||
(domain_id, project_id, trust, unscoped, system) = (
|
||||
auth_info.get_scope()
|
||||
)
|
||||
(domain_id, project_id, trust, unscoped, system) = auth_info.get_scope()
|
||||
if trust:
|
||||
project_id = trust['project_id']
|
||||
if system or domain_id or project_id or trust:
|
||||
@ -65,37 +63,53 @@ def _check_and_set_default_scoping(auth_info, auth_context):
|
||||
# make sure user's default project is legit before scoping to it
|
||||
try:
|
||||
default_project_ref = PROVIDERS.resource_api.get_project(
|
||||
default_project_id)
|
||||
default_project_id
|
||||
)
|
||||
default_project_domain_ref = PROVIDERS.resource_api.get_domain(
|
||||
default_project_ref['domain_id'])
|
||||
if (default_project_ref.get('enabled', True) and
|
||||
default_project_domain_ref.get('enabled', True)):
|
||||
default_project_ref['domain_id']
|
||||
)
|
||||
if default_project_ref.get(
|
||||
'enabled', True
|
||||
) and default_project_domain_ref.get('enabled', True):
|
||||
if PROVIDERS.assignment_api.get_roles_for_user_and_project(
|
||||
user_ref['id'], default_project_id):
|
||||
user_ref['id'], default_project_id
|
||||
):
|
||||
auth_info.set_scope(project_id=default_project_id)
|
||||
else:
|
||||
msg = ("User %(user_id)s doesn't have access to"
|
||||
" default project %(project_id)s. The token"
|
||||
" will be unscoped rather than scoped to the"
|
||||
" project.")
|
||||
LOG.debug(msg,
|
||||
{'user_id': user_ref['id'],
|
||||
'project_id': default_project_id})
|
||||
msg = (
|
||||
"User %(user_id)s doesn't have access to"
|
||||
" default project %(project_id)s. The token"
|
||||
" will be unscoped rather than scoped to the"
|
||||
" project."
|
||||
)
|
||||
LOG.debug(
|
||||
msg,
|
||||
{
|
||||
'user_id': user_ref['id'],
|
||||
'project_id': default_project_id,
|
||||
},
|
||||
)
|
||||
else:
|
||||
msg = ("User %(user_id)s's default project %(project_id)s"
|
||||
" is disabled. The token will be unscoped rather"
|
||||
" than scoped to the project.")
|
||||
LOG.debug(msg,
|
||||
{'user_id': user_ref['id'],
|
||||
'project_id': default_project_id})
|
||||
msg = (
|
||||
"User %(user_id)s's default project %(project_id)s"
|
||||
" is disabled. The token will be unscoped rather"
|
||||
" than scoped to the project."
|
||||
)
|
||||
LOG.debug(
|
||||
msg,
|
||||
{'user_id': user_ref['id'], 'project_id': default_project_id},
|
||||
)
|
||||
except (exception.ProjectNotFound, exception.DomainNotFound):
|
||||
# default project or default project domain doesn't exist,
|
||||
# will issue unscoped token instead
|
||||
msg = ("User %(user_id)s's default project %(project_id)s not"
|
||||
" found. The token will be unscoped rather than"
|
||||
" scoped to the project.")
|
||||
LOG.debug(msg, {'user_id': user_ref['id'],
|
||||
'project_id': default_project_id})
|
||||
msg = (
|
||||
"User %(user_id)s's default project %(project_id)s not"
|
||||
" found. The token will be unscoped rather than"
|
||||
" scoped to the project."
|
||||
)
|
||||
LOG.debug(
|
||||
msg, {'user_id': user_ref['id'], 'project_id': default_project_id}
|
||||
)
|
||||
|
||||
|
||||
def authenticate(auth_info, auth_context):
|
||||
@ -112,9 +126,12 @@ def authenticate(auth_info, auth_context):
|
||||
'`authenticate` method is not of type '
|
||||
'`keystone.auth.core.AuthContext`. For security '
|
||||
'purposes this is required. This is likely a programming '
|
||||
'error. Received object of type `%s`', type(auth_context))
|
||||
'error. Received object of type `%s`',
|
||||
type(auth_context),
|
||||
)
|
||||
raise exception.Unauthorized(
|
||||
_('Cannot Authenticate due to internal error.'))
|
||||
_('Cannot Authenticate due to internal error.')
|
||||
)
|
||||
# The 'external' method allows any 'REMOTE_USER' based authentication
|
||||
# In some cases the server can set REMOTE_USER as '' instead of
|
||||
# dropping it, so this must be filtered out
|
||||
@ -125,8 +142,9 @@ def authenticate(auth_info, auth_context):
|
||||
if resp and resp.status:
|
||||
# NOTE(notmorgan): ``external`` plugin cannot be multi-step
|
||||
# it is either a plain success/fail.
|
||||
auth_context.setdefault(
|
||||
'method_names', []).insert(0, 'external')
|
||||
auth_context.setdefault('method_names', []).insert(
|
||||
0, 'external'
|
||||
)
|
||||
# NOTE(notmorgan): All updates to auth_context is handled
|
||||
# here in the .authenticate method.
|
||||
auth_context.update(resp.response_data or {})
|
||||
@ -152,13 +170,13 @@ def authenticate(auth_info, auth_context):
|
||||
resp = method.authenticate(auth_info.get_method_data(method_name))
|
||||
if resp:
|
||||
if resp.status:
|
||||
auth_context.setdefault(
|
||||
'method_names', []).insert(0, method_name)
|
||||
auth_context.setdefault('method_names', []).insert(
|
||||
0, method_name
|
||||
)
|
||||
# NOTE(notmorgan): All updates to auth_context is handled
|
||||
# here in the .authenticate method. If the auth attempt was
|
||||
# not successful do not update the auth_context
|
||||
resp_method_names = resp.response_data.pop(
|
||||
'method_names', [])
|
||||
resp_method_names = resp.response_data.pop('method_names', [])
|
||||
auth_context['method_names'].extend(resp_method_names)
|
||||
auth_context.update(resp.response_data or {})
|
||||
elif resp.response_body:
|
||||
@ -180,8 +198,7 @@ def authenticate_for_token(auth=None):
|
||||
"""Authenticate user and issue a token."""
|
||||
try:
|
||||
auth_info = core.AuthInfo.create(auth=auth)
|
||||
auth_context = core.AuthContext(method_names=[],
|
||||
bind={})
|
||||
auth_context = core.AuthContext(method_names=[], bind={})
|
||||
authenticate(auth_info, auth_context)
|
||||
if auth_context.get('access_token_id'):
|
||||
auth_info.set_scope(None, auth_context['project_id'], None)
|
||||
@ -201,7 +218,8 @@ def authenticate_for_token(auth=None):
|
||||
# the given receipt.
|
||||
if receipt:
|
||||
method_names_set = set(
|
||||
auth_context.get('method_names', []) + receipt.methods)
|
||||
auth_context.get('method_names', []) + receipt.methods
|
||||
)
|
||||
else:
|
||||
method_names_set = set(auth_context.get('method_names', []))
|
||||
method_names = list(method_names_set)
|
||||
@ -213,19 +231,27 @@ def authenticate_for_token(auth=None):
|
||||
|
||||
# Do MFA Rule Validation for the user
|
||||
if not core.UserMFARulesValidator.check_auth_methods_against_rules(
|
||||
auth_context['user_id'], method_names_set):
|
||||
auth_context['user_id'], method_names_set
|
||||
):
|
||||
raise exception.InsufficientAuthMethods(
|
||||
user_id=auth_context['user_id'],
|
||||
methods=method_names)
|
||||
user_id=auth_context['user_id'], methods=method_names
|
||||
)
|
||||
|
||||
expires_at = auth_context.get('expires_at')
|
||||
token_audit_id = auth_context.get('audit_id')
|
||||
|
||||
token = PROVIDERS.token_provider_api.issue_token(
|
||||
auth_context['user_id'], method_names, expires_at=expires_at,
|
||||
system=system, project_id=project_id, domain_id=domain_id,
|
||||
auth_context=auth_context, trust_id=trust_id,
|
||||
app_cred_id=app_cred_id, parent_audit_id=token_audit_id)
|
||||
auth_context['user_id'],
|
||||
method_names,
|
||||
expires_at=expires_at,
|
||||
system=system,
|
||||
project_id=project_id,
|
||||
domain_id=domain_id,
|
||||
auth_context=auth_context,
|
||||
trust_id=trust_id,
|
||||
app_cred_id=app_cred_id,
|
||||
parent_audit_id=token_audit_id,
|
||||
)
|
||||
|
||||
# NOTE(wanghong): We consume a trust use only when we are using
|
||||
# trusts and have successfully issued a token.
|
||||
@ -244,8 +270,8 @@ def federated_authenticate_for_token(identity_provider, protocol_id):
|
||||
'methods': [protocol_id],
|
||||
protocol_id: {
|
||||
'identity_provider': identity_provider,
|
||||
'protocol': protocol_id
|
||||
}
|
||||
'protocol': protocol_id,
|
||||
},
|
||||
}
|
||||
}
|
||||
return authenticate_for_token(auth)
|
||||
|
@ -25,20 +25,19 @@ PROVIDERS = provider_api.ProviderAPIs
|
||||
def build_prior_role_response_data(prior_role_id, prior_role_name):
|
||||
return {
|
||||
'id': prior_role_id,
|
||||
'links': {
|
||||
'self': ks_flask.base_url(path='/roles/%s' % prior_role_id)
|
||||
},
|
||||
'name': prior_role_name}
|
||||
'links': {'self': ks_flask.base_url(path='/roles/%s' % prior_role_id)},
|
||||
'name': prior_role_name,
|
||||
}
|
||||
|
||||
|
||||
def build_implied_role_response_data(implied_role):
|
||||
return {
|
||||
'id': implied_role['id'],
|
||||
'links': {
|
||||
'self': ks_flask.base_url(
|
||||
path='/roles/%s' % implied_role['id'])
|
||||
'self': ks_flask.base_url(path='/roles/%s' % implied_role['id'])
|
||||
},
|
||||
'name': implied_role['name']}
|
||||
'name': implied_role['name'],
|
||||
}
|
||||
|
||||
|
||||
def role_inference_response(prior_role_id):
|
||||
@ -46,5 +45,8 @@ def role_inference_response(prior_role_id):
|
||||
response = {
|
||||
'role_inference': {
|
||||
'prior_role': build_prior_role_response_data(
|
||||
prior_role_id, prior_role['name'])}}
|
||||
prior_role_id, prior_role['name']
|
||||
)
|
||||
}
|
||||
}
|
||||
return response
|
||||
|
@ -22,74 +22,108 @@ from keystone.common import json_home
|
||||
# OS-EC2 "extension"
|
||||
os_ec2_resource_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_resource_relation,
|
||||
extension_name='OS-EC2', extension_version='1.0')
|
||||
extension_name='OS-EC2',
|
||||
extension_version='1.0',
|
||||
)
|
||||
|
||||
# s3token "extension"
|
||||
s3_token_resource_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_resource_relation,
|
||||
extension_name='s3tokens', extension_version='1.0')
|
||||
extension_name='s3tokens',
|
||||
extension_version='1.0',
|
||||
)
|
||||
|
||||
# OS-EP-FILTER "extension"
|
||||
os_ep_filter_resource_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_resource_relation,
|
||||
extension_name='OS-EP-FILTER', extension_version='1.0')
|
||||
extension_name='OS-EP-FILTER',
|
||||
extension_version='1.0',
|
||||
)
|
||||
os_ep_filter_parameter_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_parameter_relation,
|
||||
extension_name='OS-EP-FILTER', extension_version='1.0')
|
||||
extension_name='OS-EP-FILTER',
|
||||
extension_version='1.0',
|
||||
)
|
||||
|
||||
# OS-OAUTH1 "extension"
|
||||
os_oauth1_resource_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_resource_relation,
|
||||
extension_name='OS-OAUTH1', extension_version='1.0')
|
||||
extension_name='OS-OAUTH1',
|
||||
extension_version='1.0',
|
||||
)
|
||||
os_oauth1_parameter_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_parameter_relation,
|
||||
extension_name='OS-OAUTH1', extension_version='1.0')
|
||||
extension_name='OS-OAUTH1',
|
||||
extension_version='1.0',
|
||||
)
|
||||
|
||||
# OS-OAUTH2 "extension"
|
||||
os_oauth2_resource_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_resource_relation,
|
||||
extension_name='OS-OAUTH2', extension_version='1.0')
|
||||
extension_name='OS-OAUTH2',
|
||||
extension_version='1.0',
|
||||
)
|
||||
os_oauth2_parameter_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_parameter_relation,
|
||||
extension_name='OS-OAUTH2', extension_version='1.0')
|
||||
extension_name='OS-OAUTH2',
|
||||
extension_version='1.0',
|
||||
)
|
||||
|
||||
# OS-REVOKE "extension"
|
||||
os_revoke_resource_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_resource_relation,
|
||||
extension_name='OS-REVOKE', extension_version='1.0')
|
||||
extension_name='OS-REVOKE',
|
||||
extension_version='1.0',
|
||||
)
|
||||
|
||||
# OS-SIMPLE-CERT "extension"
|
||||
os_simple_cert_resource_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_resource_relation,
|
||||
extension_name='OS-SIMPLE-CERT', extension_version='1.0')
|
||||
extension_name='OS-SIMPLE-CERT',
|
||||
extension_version='1.0',
|
||||
)
|
||||
|
||||
# OS-TRUST "extension"
|
||||
os_trust_resource_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_resource_relation, extension_name='OS-TRUST',
|
||||
extension_version='1.0')
|
||||
json_home.build_v3_extension_resource_relation,
|
||||
extension_name='OS-TRUST',
|
||||
extension_version='1.0',
|
||||
)
|
||||
os_trust_parameter_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_parameter_relation, extension_name='OS-TRUST',
|
||||
extension_version='1.0')
|
||||
json_home.build_v3_extension_parameter_relation,
|
||||
extension_name='OS-TRUST',
|
||||
extension_version='1.0',
|
||||
)
|
||||
|
||||
# OS-ENDPOINT-POLICY "extension"
|
||||
os_endpoint_policy_resource_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_resource_relation,
|
||||
extension_name='OS-ENDPOINT-POLICY', extension_version='1.0')
|
||||
extension_name='OS-ENDPOINT-POLICY',
|
||||
extension_version='1.0',
|
||||
)
|
||||
|
||||
# OS-FEDERATION "extension"
|
||||
os_federation_resource_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_resource_relation,
|
||||
extension_name='OS-FEDERATION', extension_version='1.0')
|
||||
extension_name='OS-FEDERATION',
|
||||
extension_version='1.0',
|
||||
)
|
||||
os_federation_parameter_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_parameter_relation,
|
||||
extension_name='OS-FEDERATION', extension_version='1.0')
|
||||
extension_name='OS-FEDERATION',
|
||||
extension_version='1.0',
|
||||
)
|
||||
|
||||
# OS-INHERIT "extension"
|
||||
os_inherit_resource_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_resource_relation,
|
||||
extension_name='OS-INHERIT', extension_version='1.0')
|
||||
extension_name='OS-INHERIT',
|
||||
extension_version='1.0',
|
||||
)
|
||||
|
||||
# OS-PKI (revoked) "extension"
|
||||
os_pki_resource_rel_func = functools.partial(
|
||||
json_home.build_v3_extension_resource_relation,
|
||||
extension_name='OS-PKI', extension_version='1.0')
|
||||
extension_name='OS-PKI',
|
||||
extension_version='1.0',
|
||||
)
|
||||
|
@ -35,8 +35,10 @@ def create_base_saml_assertion(auth):
|
||||
token = PROVIDERS.token_provider_api.validate_token(token_id)
|
||||
|
||||
if not token.project_scoped:
|
||||
action = _('Use a project scoped token when attempting to create '
|
||||
'a SAML assertion')
|
||||
action = _(
|
||||
'Use a project scoped token when attempting to create '
|
||||
'a SAML assertion'
|
||||
)
|
||||
raise exception.ForbiddenAction(action=action)
|
||||
|
||||
subject = token.user['name']
|
||||
@ -58,19 +60,27 @@ def create_base_saml_assertion(auth):
|
||||
'JSON:{"name":"group2","domain":{"name":"Default"}}']
|
||||
"""
|
||||
user_groups = []
|
||||
groups = PROVIDERS.identity_api.list_groups_for_user(
|
||||
token.user_id)
|
||||
groups = PROVIDERS.identity_api.list_groups_for_user(token.user_id)
|
||||
for group in groups:
|
||||
user_group = {}
|
||||
group_domain_name = PROVIDERS.resource_api.get_domain(
|
||||
group['domain_id'])['name']
|
||||
group['domain_id']
|
||||
)['name']
|
||||
user_group["name"] = group['name']
|
||||
user_group["domain"] = {'name': group_domain_name}
|
||||
user_groups.append('JSON:' + jsonutils.dumps(user_group))
|
||||
return user_groups
|
||||
|
||||
groups = group_membership()
|
||||
generator = keystone_idp.SAMLGenerator()
|
||||
response = generator.samlize_token(
|
||||
issuer, sp_url, subject, subject_domain_name,
|
||||
role_names, project, project_domain_name, groups)
|
||||
issuer,
|
||||
sp_url,
|
||||
subject,
|
||||
subject_domain_name,
|
||||
role_names,
|
||||
project,
|
||||
project_domain_name,
|
||||
groups,
|
||||
)
|
||||
return response, service_provider
|
||||
|
@ -58,9 +58,11 @@ def _combine_lists_uniquely(a, b):
|
||||
|
||||
def _build_response_headers(service_provider):
|
||||
# URLs in header are encoded into bytes
|
||||
return [('Content-Type', 'text/xml'),
|
||||
('X-sp-url', service_provider['sp_url'].encode('utf-8')),
|
||||
('X-auth-url', service_provider['auth_url'].encode('utf-8'))]
|
||||
return [
|
||||
('Content-Type', 'text/xml'),
|
||||
('X-sp-url', service_provider['sp_url'].encode('utf-8')),
|
||||
('X-auth-url', service_provider['auth_url'].encode('utf-8')),
|
||||
]
|
||||
|
||||
|
||||
def _get_sso_origin_host():
|
||||
@ -87,13 +89,14 @@ def _get_sso_origin_host():
|
||||
host = urllib.parse.unquote_plus(origin)
|
||||
|
||||
# change trusted_dashboard hostnames to lowercase before comparison
|
||||
trusted_dashboards = [k_utils.lower_case_hostname(trusted)
|
||||
for trusted in CONF.federation.trusted_dashboard]
|
||||
trusted_dashboards = [
|
||||
k_utils.lower_case_hostname(trusted)
|
||||
for trusted in CONF.federation.trusted_dashboard
|
||||
]
|
||||
|
||||
if host not in trusted_dashboards:
|
||||
msg = '%(host)s is not a trusted dashboard host' % {'host': host}
|
||||
tr_msg = _('%(host)s is not a trusted dashboard host') % {
|
||||
'host': host}
|
||||
tr_msg = _('%(host)s is not a trusted dashboard host') % {'host': host}
|
||||
LOG.error(msg)
|
||||
raise exception.Unauthorized(tr_msg)
|
||||
|
||||
@ -133,14 +136,16 @@ class AuthProjectsResource(ks_flask.ResourceBase):
|
||||
if user_id:
|
||||
try:
|
||||
user_p_refs = PROVIDERS.assignment_api.list_projects_for_user(
|
||||
user_id)
|
||||
user_id
|
||||
)
|
||||
except exception.UserNotFound: # nosec
|
||||
# federated users have an id but they don't link to anything
|
||||
pass
|
||||
|
||||
if group_ids:
|
||||
grp_p_refs = PROVIDERS.assignment_api.list_projects_for_groups(
|
||||
group_ids)
|
||||
group_ids
|
||||
)
|
||||
refs = _combine_lists_uniquely(user_p_refs, grp_p_refs)
|
||||
return self.wrap_collection(refs)
|
||||
|
||||
@ -165,14 +170,16 @@ class AuthDomainsResource(ks_flask.ResourceBase):
|
||||
if user_id:
|
||||
try:
|
||||
user_d_refs = PROVIDERS.assignment_api.list_domains_for_user(
|
||||
user_id)
|
||||
user_id
|
||||
)
|
||||
except exception.UserNotFound: # nosec
|
||||
# federated users have an id but they don't link to anything
|
||||
pass
|
||||
|
||||
if group_ids:
|
||||
grp_d_refs = PROVIDERS.assignment_api.list_domains_for_groups(
|
||||
group_ids)
|
||||
group_ids
|
||||
)
|
||||
|
||||
refs = _combine_lists_uniquely(user_d_refs, grp_d_refs)
|
||||
return self.wrap_collection(refs)
|
||||
@ -195,7 +202,8 @@ class AuthSystemResource(_AuthFederationWebSSOBase):
|
||||
try:
|
||||
user_assignments = (
|
||||
PROVIDERS.assignment_api.list_system_grants_for_user(
|
||||
user_id)
|
||||
user_id
|
||||
)
|
||||
)
|
||||
except exception.UserNotFound: # nosec
|
||||
# federated users have an id but they don't link to anything
|
||||
@ -204,25 +212,23 @@ class AuthSystemResource(_AuthFederationWebSSOBase):
|
||||
if group_ids:
|
||||
group_assignments = (
|
||||
PROVIDERS.assignment_api.list_system_grants_for_groups(
|
||||
group_ids)
|
||||
group_ids
|
||||
)
|
||||
)
|
||||
|
||||
assignments = _combine_lists_uniquely(
|
||||
user_assignments, group_assignments)
|
||||
user_assignments, group_assignments
|
||||
)
|
||||
|
||||
if assignments:
|
||||
response = {
|
||||
'system': [{'all': True}],
|
||||
'links': {
|
||||
'self': ks_flask.base_url(path='auth/system')
|
||||
}
|
||||
'links': {'self': ks_flask.base_url(path='auth/system')},
|
||||
}
|
||||
else:
|
||||
response = {
|
||||
'system': [],
|
||||
'links': {
|
||||
'self': ks_flask.base_url(path='auth/system')
|
||||
}
|
||||
'links': {'self': ks_flask.base_url(path='auth/system')},
|
||||
}
|
||||
return response
|
||||
|
||||
@ -239,16 +245,17 @@ class AuthCatalogResource(_AuthFederationWebSSOBase):
|
||||
|
||||
if not project_id:
|
||||
raise exception.Forbidden(
|
||||
_('A project-scoped token is required to produce a '
|
||||
'service catalog.'))
|
||||
_(
|
||||
'A project-scoped token is required to produce a '
|
||||
'service catalog.'
|
||||
)
|
||||
)
|
||||
|
||||
return {
|
||||
'catalog': PROVIDERS.catalog_api.get_v3_catalog(
|
||||
user_id, project_id
|
||||
),
|
||||
'links': {
|
||||
'self': ks_flask.base_url(path='auth/catalog')
|
||||
}
|
||||
'links': {'self': ks_flask.base_url(path='auth/catalog')},
|
||||
}
|
||||
|
||||
|
||||
@ -285,18 +292,24 @@ class AuthTokenResource(_AuthFederationWebSSOBase):
|
||||
ENFORCER.enforce_call(action='identity:validate_token')
|
||||
|
||||
token_id = flask.request.headers.get(
|
||||
authorization.SUBJECT_TOKEN_HEADER)
|
||||
authorization.SUBJECT_TOKEN_HEADER
|
||||
)
|
||||
access_rules_support = flask.request.headers.get(
|
||||
authorization.ACCESS_RULES_HEADER)
|
||||
authorization.ACCESS_RULES_HEADER
|
||||
)
|
||||
allow_expired = strutils.bool_from_string(
|
||||
flask.request.args.get('allow_expired'))
|
||||
flask.request.args.get('allow_expired')
|
||||
)
|
||||
window_secs = CONF.token.allow_expired_window if allow_expired else 0
|
||||
include_catalog = 'nocatalog' not in flask.request.args
|
||||
token = PROVIDERS.token_provider_api.validate_token(
|
||||
token_id, window_seconds=window_secs,
|
||||
access_rules_support=access_rules_support)
|
||||
token_id,
|
||||
window_seconds=window_secs,
|
||||
access_rules_support=access_rules_support,
|
||||
)
|
||||
token_resp = render_token.render_token_response_from_model(
|
||||
token, include_catalog=include_catalog)
|
||||
token, include_catalog=include_catalog
|
||||
)
|
||||
resp_body = jsonutils.dumps(token_resp)
|
||||
response = flask.make_response(resp_body, http.client.OK)
|
||||
response.headers['X-Subject-Token'] = token_id
|
||||
@ -329,7 +342,8 @@ class AuthTokenResource(_AuthFederationWebSSOBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:revoke_token')
|
||||
token_id = flask.request.headers.get(
|
||||
authorization.SUBJECT_TOKEN_HEADER)
|
||||
authorization.SUBJECT_TOKEN_HEADER
|
||||
)
|
||||
PROVIDERS.token_provider_api.revoke_token(token_id)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
@ -342,7 +356,8 @@ class AuthFederationWebSSOResource(_AuthFederationWebSSOBase):
|
||||
for idp in idps:
|
||||
try:
|
||||
remote_id_name = federation_utils.get_remote_id_parameter(
|
||||
idp, protocol_id)
|
||||
idp, protocol_id
|
||||
)
|
||||
except exception.FederatedProtocolNotFound:
|
||||
# no protocol for this IdP, so this can't be the IdP we're
|
||||
# looking for
|
||||
@ -360,7 +375,8 @@ class AuthFederationWebSSOResource(_AuthFederationWebSSOBase):
|
||||
ref = PROVIDERS.federation_api.get_idp_from_remote_id(remote_id)
|
||||
identity_provider = ref['idp_id']
|
||||
token = authentication.federated_authenticate_for_token(
|
||||
identity_provider=identity_provider, protocol_id=protocol_id)
|
||||
identity_provider=identity_provider, protocol_id=protocol_id
|
||||
)
|
||||
return cls._render_template_response(host, token.id)
|
||||
|
||||
@ks_flask.unenforced_api
|
||||
@ -378,7 +394,8 @@ class AuthFederationWebSSOIDPsResource(_AuthFederationWebSSOBase):
|
||||
host = _get_sso_origin_host()
|
||||
|
||||
token = authentication.federated_authenticate_for_token(
|
||||
identity_provider=idp_id, protocol_id=protocol_id)
|
||||
identity_provider=idp_id, protocol_id=protocol_id
|
||||
)
|
||||
return cls._render_template_response(host, token.id)
|
||||
|
||||
@ks_flask.unenforced_api
|
||||
@ -423,15 +440,18 @@ class AuthFederationSaml2ECPResource(_AuthFederationWebSSOBase):
|
||||
auth = self.request_body_json.get('auth')
|
||||
validation.lazy_validate(federation_schema.saml_create, auth)
|
||||
saml_assertion, service_provider = saml.create_base_saml_assertion(
|
||||
auth)
|
||||
auth
|
||||
)
|
||||
relay_state_prefix = service_provider['relay_state_prefix']
|
||||
|
||||
generator = keystone_idp.ECPGenerator()
|
||||
ecp_assertion = generator.generate_ecp(
|
||||
saml_assertion, relay_state_prefix)
|
||||
saml_assertion, relay_state_prefix
|
||||
)
|
||||
headers = _build_response_headers(service_provider)
|
||||
response = flask.make_response(
|
||||
ecp_assertion.to_string(), http.client.OK)
|
||||
ecp_assertion.to_string(), http.client.OK
|
||||
)
|
||||
for header, value in headers:
|
||||
response.headers[header] = value
|
||||
return response
|
||||
@ -445,29 +465,34 @@ class AuthAPI(ks_flask.APIBase):
|
||||
ks_flask.construct_resource_map(
|
||||
resource=AuthProjectsResource,
|
||||
url='/auth/projects',
|
||||
alternate_urls=[dict(
|
||||
url='/OS-FEDERATION/projects',
|
||||
json_home=ks_flask.construct_json_home_data(
|
||||
rel='projects',
|
||||
resource_relation_func=(
|
||||
json_home_relations.os_federation_resource_rel_func)
|
||||
alternate_urls=[
|
||||
dict(
|
||||
url='/OS-FEDERATION/projects',
|
||||
json_home=ks_flask.construct_json_home_data(
|
||||
rel='projects',
|
||||
resource_relation_func=(
|
||||
json_home_relations.os_federation_resource_rel_func
|
||||
),
|
||||
),
|
||||
)
|
||||
)],
|
||||
|
||||
],
|
||||
rel='auth_projects',
|
||||
resource_kwargs={}
|
||||
resource_kwargs={},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=AuthDomainsResource,
|
||||
url='/auth/domains',
|
||||
alternate_urls=[dict(
|
||||
url='/OS-FEDERATION/domains',
|
||||
json_home=ks_flask.construct_json_home_data(
|
||||
rel='domains',
|
||||
resource_relation_func=(
|
||||
json_home_relations.os_federation_resource_rel_func)
|
||||
alternate_urls=[
|
||||
dict(
|
||||
url='/OS-FEDERATION/domains',
|
||||
json_home=ks_flask.construct_json_home_data(
|
||||
rel='domains',
|
||||
resource_relation_func=(
|
||||
json_home_relations.os_federation_resource_rel_func
|
||||
),
|
||||
),
|
||||
)
|
||||
)],
|
||||
],
|
||||
rel='auth_domains',
|
||||
resource_kwargs={},
|
||||
),
|
||||
@ -475,27 +500,27 @@ class AuthAPI(ks_flask.APIBase):
|
||||
resource=AuthSystemResource,
|
||||
url='/auth/system',
|
||||
resource_kwargs={},
|
||||
rel='auth_system'
|
||||
rel='auth_system',
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=AuthCatalogResource,
|
||||
url='/auth/catalog',
|
||||
resource_kwargs={},
|
||||
rel='auth_catalog'
|
||||
rel='auth_catalog',
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=AuthTokenOSPKIResource,
|
||||
url='/auth/tokens/OS-PKI/revoked',
|
||||
resource_kwargs={},
|
||||
rel='revocations',
|
||||
resource_relation_func=json_home_relations.os_pki_resource_rel_func
|
||||
resource_relation_func=json_home_relations.os_pki_resource_rel_func,
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=AuthTokenResource,
|
||||
url='/auth/tokens',
|
||||
resource_kwargs={},
|
||||
rel='auth_tokens'
|
||||
)
|
||||
rel='auth_tokens',
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@ -509,16 +534,18 @@ class AuthFederationAPI(ks_flask.APIBase):
|
||||
url='/auth/OS-FEDERATION/saml2',
|
||||
resource_kwargs={},
|
||||
resource_relation_func=(
|
||||
json_home_relations.os_federation_resource_rel_func),
|
||||
rel='saml2'
|
||||
json_home_relations.os_federation_resource_rel_func
|
||||
),
|
||||
rel='saml2',
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=AuthFederationSaml2ECPResource,
|
||||
url='/auth/OS-FEDERATION/saml2/ecp',
|
||||
resource_kwargs={},
|
||||
resource_relation_func=(
|
||||
json_home_relations.os_federation_resource_rel_func),
|
||||
rel='ecp'
|
||||
json_home_relations.os_federation_resource_rel_func
|
||||
),
|
||||
rel='ecp',
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=AuthFederationWebSSOResource,
|
||||
@ -526,28 +553,40 @@ class AuthFederationAPI(ks_flask.APIBase):
|
||||
resource_kwargs={},
|
||||
rel='websso',
|
||||
resource_relation_func=(
|
||||
json_home_relations.os_federation_resource_rel_func),
|
||||
json_home_relations.os_federation_resource_rel_func
|
||||
),
|
||||
path_vars={
|
||||
'protocol_id': (
|
||||
json_home_relations.os_federation_parameter_rel_func(
|
||||
parameter_name='protocol_id'))}
|
||||
parameter_name='protocol_id'
|
||||
)
|
||||
)
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=AuthFederationWebSSOIDPsResource,
|
||||
url=('/auth/OS-FEDERATION/identity_providers/<string:idp_id>/'
|
||||
'protocols/<string:protocol_id>/websso'),
|
||||
url=(
|
||||
'/auth/OS-FEDERATION/identity_providers/<string:idp_id>/'
|
||||
'protocols/<string:protocol_id>/websso'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='identity_providers_websso',
|
||||
resource_relation_func=(
|
||||
json_home_relations.os_federation_resource_rel_func),
|
||||
json_home_relations.os_federation_resource_rel_func
|
||||
),
|
||||
path_vars={
|
||||
'idp_id': (
|
||||
json_home_relations.os_federation_parameter_rel_func(
|
||||
parameter_name='idp_id')),
|
||||
parameter_name='idp_id'
|
||||
)
|
||||
),
|
||||
'protocol_id': (
|
||||
json_home_relations.os_federation_parameter_rel_func(
|
||||
parameter_name='protocol_id'))}
|
||||
)
|
||||
parameter_name='protocol_id'
|
||||
)
|
||||
),
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -65,23 +65,28 @@ class CredentialResource(ks_flask.ResourceBase):
|
||||
blob = jsonutils.loads(ref.get('blob'))
|
||||
except (ValueError, TabError):
|
||||
raise exception.ValidationError(
|
||||
message=_('Invalid blob in credential'))
|
||||
message=_('Invalid blob in credential')
|
||||
)
|
||||
if not blob or not isinstance(blob, dict):
|
||||
raise exception.ValidationError(attribute='blob',
|
||||
target='credential')
|
||||
raise exception.ValidationError(
|
||||
attribute='blob', target='credential'
|
||||
)
|
||||
if blob.get('access') is None:
|
||||
raise exception.ValidationError(attribute='access',
|
||||
target='credential')
|
||||
raise exception.ValidationError(
|
||||
attribute='access', target='credential'
|
||||
)
|
||||
return blob
|
||||
|
||||
def _assign_unique_id(
|
||||
self, ref, trust_id=None, app_cred_id=None, access_token_id=None):
|
||||
self, ref, trust_id=None, app_cred_id=None, access_token_id=None
|
||||
):
|
||||
# Generates an assigns a unique identifier to a credential reference.
|
||||
if ref.get('type', '').lower() == 'ec2':
|
||||
blob = self._validate_blob_json(ref)
|
||||
ref = ref.copy()
|
||||
ref['id'] = hashlib.sha256(
|
||||
blob['access'].encode('utf8')).hexdigest()
|
||||
blob['access'].encode('utf8')
|
||||
).hexdigest()
|
||||
# update the blob with the trust_id or app_cred_id, so credentials
|
||||
# created with a trust- or app cred-scoped token will result in
|
||||
# trust- or app cred-scoped tokens when authentication via
|
||||
@ -105,8 +110,11 @@ class CredentialResource(ks_flask.ResourceBase):
|
||||
target = {'credential': {'user_id': self.oslo_context.user_id}}
|
||||
else:
|
||||
target = None
|
||||
ENFORCER.enforce_call(action='identity:list_credentials',
|
||||
filters=filters, target_attr=target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_credentials',
|
||||
filters=filters,
|
||||
target_attr=target,
|
||||
)
|
||||
hints = self.build_driver_hints(filters)
|
||||
refs = PROVIDERS.credential_api.list_credentials(hints)
|
||||
# If the request was filtered, make sure to return only the
|
||||
@ -122,7 +130,7 @@ class CredentialResource(ks_flask.ResourceBase):
|
||||
cred = PROVIDERS.credential_api.get_credential(ref['id'])
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:get_credential',
|
||||
target_attr={'credential': cred}
|
||||
target_attr={'credential': cred},
|
||||
)
|
||||
filtered_refs.append(ref)
|
||||
except exception.Forbidden:
|
||||
@ -134,7 +142,7 @@ class CredentialResource(ks_flask.ResourceBase):
|
||||
def _get_credential(self, credential_id):
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:get_credential',
|
||||
build_target=_build_target_enforcement
|
||||
build_target=_build_target_enforcement,
|
||||
)
|
||||
credential = PROVIDERS.credential_api.get_credential(credential_id)
|
||||
return self.wrap_member(self._blob_to_json(credential))
|
||||
@ -158,15 +166,20 @@ class CredentialResource(ks_flask.ResourceBase):
|
||||
validation.lazy_validate(schema.credential_create, credential)
|
||||
trust_id = getattr(self.oslo_context, 'trust_id', None)
|
||||
app_cred_id = getattr(
|
||||
self.auth_context['token'], 'application_credential_id', None)
|
||||
self.auth_context['token'], 'application_credential_id', None
|
||||
)
|
||||
access_token_id = getattr(
|
||||
self.auth_context['token'], 'access_token_id', None)
|
||||
self.auth_context['token'], 'access_token_id', None
|
||||
)
|
||||
ref = self._assign_unique_id(
|
||||
self._normalize_dict(credential),
|
||||
trust_id=trust_id, app_cred_id=app_cred_id,
|
||||
access_token_id=access_token_id)
|
||||
trust_id=trust_id,
|
||||
app_cred_id=app_cred_id,
|
||||
access_token_id=access_token_id,
|
||||
)
|
||||
ref = PROVIDERS.credential_api.create_credential(
|
||||
ref['id'], ref, initiator=self.audit_initiator)
|
||||
ref['id'], ref, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref), http.client.CREATED
|
||||
|
||||
def _validate_blob_update_keys(self, credential, ref):
|
||||
@ -176,8 +189,12 @@ class CredentialResource(ks_flask.ResourceBase):
|
||||
if isinstance(old_blob, str):
|
||||
old_blob = jsonutils.loads(old_blob)
|
||||
# if there was a scope set, prevent changing it or unsetting it
|
||||
for key in ['trust_id', 'app_cred_id', 'access_token_id',
|
||||
'access_id']:
|
||||
for key in [
|
||||
'trust_id',
|
||||
'app_cred_id',
|
||||
'access_token_id',
|
||||
'access_id',
|
||||
]:
|
||||
if old_blob.get(key) != new_blob.get(key):
|
||||
message = _('%s can not be updated for credential') % key
|
||||
raise exception.ValidationError(message=message)
|
||||
@ -186,7 +203,7 @@ class CredentialResource(ks_flask.ResourceBase):
|
||||
# Update Credential
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:update_credential',
|
||||
build_target=_build_target_enforcement
|
||||
build_target=_build_target_enforcement,
|
||||
)
|
||||
current = PROVIDERS.credential_api.get_credential(credential_id)
|
||||
|
||||
@ -200,19 +217,23 @@ class CredentialResource(ks_flask.ResourceBase):
|
||||
action='identity:update_credential', target_attr=target
|
||||
)
|
||||
ref = PROVIDERS.credential_api.update_credential(
|
||||
credential_id, credential)
|
||||
credential_id, credential
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
def delete(self, credential_id):
|
||||
# Delete credentials
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:delete_credential',
|
||||
build_target=_build_target_enforcement
|
||||
build_target=_build_target_enforcement,
|
||||
)
|
||||
|
||||
return (PROVIDERS.credential_api.delete_credential(
|
||||
credential_id, initiator=self.audit_initiator),
|
||||
http.client.NO_CONTENT)
|
||||
return (
|
||||
PROVIDERS.credential_api.delete_credential(
|
||||
credential_id, initiator=self.audit_initiator
|
||||
),
|
||||
http.client.NO_CONTENT,
|
||||
)
|
||||
|
||||
|
||||
class CredentialAPI(ks_flask.APIBase):
|
||||
|
@ -31,14 +31,15 @@ def _get_versions_list(identity_url):
|
||||
'id': 'v3.14',
|
||||
'status': 'stable',
|
||||
'updated': '2020-04-07T00:00:00Z',
|
||||
'links': [{
|
||||
'rel': 'self',
|
||||
'href': identity_url,
|
||||
}],
|
||||
'media-types': [{
|
||||
'base': 'application/json',
|
||||
'type': MEDIA_TYPE_JSON % 'v3'
|
||||
}]
|
||||
'links': [
|
||||
{
|
||||
'rel': 'self',
|
||||
'href': identity_url,
|
||||
}
|
||||
],
|
||||
'media-types': [
|
||||
{'base': 'application/json', 'type': MEDIA_TYPE_JSON % 'v3'}
|
||||
],
|
||||
}
|
||||
return versions
|
||||
|
||||
@ -53,7 +54,8 @@ def v3_mime_type_best_match():
|
||||
return MimeTypes.JSON
|
||||
|
||||
return request.accept_mimetypes.best_match(
|
||||
[MimeTypes.JSON, MimeTypes.JSON_HOME])
|
||||
[MimeTypes.JSON, MimeTypes.JSON_HOME]
|
||||
)
|
||||
|
||||
|
||||
@_DISCOVERY_BLUEPRINT.route('/')
|
||||
@ -63,8 +65,10 @@ def get_versions():
|
||||
# understand the JSON-Home document.
|
||||
v3_json_home = json_home.JsonHomeResources.resources()
|
||||
json_home.translate_urls(v3_json_home, '/v3')
|
||||
return flask.Response(response=jsonutils.dumps(v3_json_home),
|
||||
mimetype=MimeTypes.JSON_HOME)
|
||||
return flask.Response(
|
||||
response=jsonutils.dumps(v3_json_home),
|
||||
mimetype=MimeTypes.JSON_HOME,
|
||||
)
|
||||
else:
|
||||
identity_url = '%s/' % ks_flask.base_url()
|
||||
versions = _get_versions_list(identity_url)
|
||||
@ -76,10 +80,11 @@ def get_versions():
|
||||
|
||||
response = flask.Response(
|
||||
response=jsonutils.dumps(
|
||||
{'versions': {
|
||||
'values': list(versions.values())}}),
|
||||
{'versions': {'values': list(versions.values())}}
|
||||
),
|
||||
mimetype=MimeTypes.JSON,
|
||||
status=http.client.MULTIPLE_CHOICES)
|
||||
status=http.client.MULTIPLE_CHOICES,
|
||||
)
|
||||
response.headers['Location'] = preferred_location
|
||||
return response
|
||||
|
||||
@ -90,14 +95,16 @@ def get_version_v3():
|
||||
# RENDER JSON-Home form, we have a clever client who will
|
||||
# understand the JSON-Home document.
|
||||
content = json_home.JsonHomeResources.resources()
|
||||
return flask.Response(response=jsonutils.dumps(content),
|
||||
mimetype=MimeTypes.JSON_HOME)
|
||||
return flask.Response(
|
||||
response=jsonutils.dumps(content), mimetype=MimeTypes.JSON_HOME
|
||||
)
|
||||
else:
|
||||
identity_url = '%s/' % ks_flask.base_url()
|
||||
versions = _get_versions_list(identity_url)
|
||||
return flask.Response(
|
||||
response=jsonutils.dumps({'version': versions['v3']}),
|
||||
mimetype=MimeTypes.JSON)
|
||||
mimetype=MimeTypes.JSON,
|
||||
)
|
||||
|
||||
|
||||
class DiscoveryAPI(object):
|
||||
|
@ -59,14 +59,16 @@ def _build_enforcement_target(allow_non_existing=False):
|
||||
if flask.request.view_args.get('user_id'):
|
||||
try:
|
||||
target['user'] = PROVIDERS.identity_api.get_user(
|
||||
flask.request.view_args['user_id'])
|
||||
flask.request.view_args['user_id']
|
||||
)
|
||||
except exception.UserNotFound:
|
||||
if not allow_non_existing:
|
||||
raise
|
||||
else:
|
||||
try:
|
||||
target['group'] = PROVIDERS.identity_api.get_group(
|
||||
flask.request.view_args.get('group_id'))
|
||||
flask.request.view_args.get('group_id')
|
||||
)
|
||||
except exception.GroupNotFound:
|
||||
if not allow_non_existing:
|
||||
raise
|
||||
@ -77,7 +79,8 @@ class DomainResource(ks_flask.ResourceBase):
|
||||
collection_key = 'domains'
|
||||
member_key = 'domain'
|
||||
get_member_from_driver = PROVIDERS.deferred_provider_lookup(
|
||||
api='resource_api', method='get_domain')
|
||||
api='resource_api', method='get_domain'
|
||||
)
|
||||
|
||||
def get(self, domain_id=None):
|
||||
"""Get domain or list domains.
|
||||
@ -92,7 +95,7 @@ class DomainResource(ks_flask.ResourceBase):
|
||||
def _get_domain(self, domain_id):
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:get_domain',
|
||||
build_target=_build_domain_enforcement_target
|
||||
build_target=_build_domain_enforcement_target,
|
||||
)
|
||||
domain = PROVIDERS.resource_api.get_domain(domain_id)
|
||||
return self.wrap_member(domain)
|
||||
@ -102,16 +105,14 @@ class DomainResource(ks_flask.ResourceBase):
|
||||
target = None
|
||||
if self.oslo_context.domain_id:
|
||||
target = {'domain': {'id': self.oslo_context.domain_id}}
|
||||
ENFORCER.enforce_call(action='identity:list_domains',
|
||||
filters=filters,
|
||||
target_attr=target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_domains', filters=filters, target_attr=target
|
||||
)
|
||||
hints = self.build_driver_hints(filters)
|
||||
refs = PROVIDERS.resource_api.list_domains(hints=hints)
|
||||
if self.oslo_context.domain_id:
|
||||
domain_id = self.oslo_context.domain_id
|
||||
filtered_refs = [
|
||||
ref for ref in refs if ref['id'] == domain_id
|
||||
]
|
||||
filtered_refs = [ref for ref in refs if ref['id'] == domain_id]
|
||||
else:
|
||||
filtered_refs = refs
|
||||
return self.wrap_collection(filtered_refs, hints=hints)
|
||||
@ -137,7 +138,8 @@ class DomainResource(ks_flask.ResourceBase):
|
||||
domain['id'] = domain_id
|
||||
domain = self._normalize_dict(domain)
|
||||
ref = PROVIDERS.resource_api.create_domain(
|
||||
domain['id'], domain, initiator=self.audit_initiator)
|
||||
domain['id'], domain, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref), http.client.CREATED
|
||||
|
||||
def patch(self, domain_id):
|
||||
@ -150,7 +152,8 @@ class DomainResource(ks_flask.ResourceBase):
|
||||
validation.lazy_validate(schema.domain_update, domain)
|
||||
PROVIDERS.resource_api.get_domain(domain_id)
|
||||
ref = PROVIDERS.resource_api.update_domain(
|
||||
domain_id, domain, initiator=self.audit_initiator)
|
||||
domain_id, domain, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
def delete(self, domain_id):
|
||||
@ -160,7 +163,8 @@ class DomainResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:delete_domain')
|
||||
PROVIDERS.resource_api.delete_domain(
|
||||
domain_id, initiator=self.audit_initiator)
|
||||
domain_id, initiator=self.audit_initiator
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -178,14 +182,15 @@ class DomainConfigBase(ks_flask.ResourceBase):
|
||||
config = {}
|
||||
try:
|
||||
PROVIDERS.resource_api.get_domain(domain_id)
|
||||
except Exception as e: # nosec
|
||||
except Exception as e: # nosec
|
||||
# We don't raise out here, we raise out after enforcement, this
|
||||
# ensures we do not leak domain existance.
|
||||
err = e
|
||||
finally:
|
||||
if group and group == 'security_compliance':
|
||||
config = self._get_security_compliance_config(
|
||||
domain_id, group, option)
|
||||
domain_id, group, option
|
||||
)
|
||||
else:
|
||||
config = self._get_config(domain_id, group, option)
|
||||
if err is not None:
|
||||
@ -195,13 +200,16 @@ class DomainConfigBase(ks_flask.ResourceBase):
|
||||
def _get_config(self, domain_id, group, option):
|
||||
ENFORCER.enforce_call(action='identity:get_domain_config')
|
||||
return PROVIDERS.domain_config_api.get_config(
|
||||
domain_id, group=group, option=option)
|
||||
domain_id, group=group, option=option
|
||||
)
|
||||
|
||||
def _get_security_compliance_config(self, domain_id, group, option):
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:get_security_compliance_domain_config')
|
||||
action='identity:get_security_compliance_domain_config'
|
||||
)
|
||||
return PROVIDERS.domain_config_api.get_security_compliance_config(
|
||||
domain_id, group, option=option)
|
||||
domain_id, group, option=option
|
||||
)
|
||||
|
||||
def patch(self, domain_id=None, group=None, option=None):
|
||||
"""Update domain config option.
|
||||
@ -214,7 +222,8 @@ class DomainConfigBase(ks_flask.ResourceBase):
|
||||
PROVIDERS.resource_api.get_domain(domain_id)
|
||||
config = self.request_body_json.get('config', {})
|
||||
ref = PROVIDERS.domain_config_api.update_config(
|
||||
domain_id, config, group, option=option)
|
||||
domain_id, config, group, option=option
|
||||
)
|
||||
return {self.member_key: ref}
|
||||
|
||||
def delete(self, domain_id=None, group=None, option=None):
|
||||
@ -227,7 +236,8 @@ class DomainConfigBase(ks_flask.ResourceBase):
|
||||
ENFORCER.enforce_call(action='identity:delete_domain_config')
|
||||
PROVIDERS.resource_api.get_domain(domain_id)
|
||||
PROVIDERS.domain_config_api.delete_config(
|
||||
domain_id, group, option=option)
|
||||
domain_id, group, option=option
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -313,7 +323,8 @@ class DefaultConfigOptionResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:get_domain_config_default')
|
||||
ref = PROVIDERS.domain_config_api.get_config_default(
|
||||
group=group, option=option)
|
||||
group=group, option=option
|
||||
)
|
||||
return {'config': ref}
|
||||
|
||||
|
||||
@ -325,12 +336,14 @@ class DomainUserListResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_grants',
|
||||
build_target=_build_enforcement_target)
|
||||
build_target=_build_enforcement_target,
|
||||
)
|
||||
refs = PROVIDERS.assignment_api.list_grants(
|
||||
domain_id=domain_id, user_id=user_id,
|
||||
inherited_to_projects=False)
|
||||
domain_id=domain_id, user_id=user_id, inherited_to_projects=False
|
||||
)
|
||||
return ks_flask.ResourceBase.wrap_collection(
|
||||
refs, collection_name='roles')
|
||||
refs, collection_name='roles'
|
||||
)
|
||||
|
||||
|
||||
class DomainUserResource(ks_flask.ResourceBase):
|
||||
@ -344,10 +357,14 @@ class DomainUserResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:check_grant',
|
||||
build_target=_build_enforcement_target)
|
||||
build_target=_build_enforcement_target,
|
||||
)
|
||||
PROVIDERS.assignment_api.get_grant(
|
||||
role_id, domain_id=domain_id, user_id=user_id,
|
||||
inherited_to_projects=False)
|
||||
role_id,
|
||||
domain_id=domain_id,
|
||||
user_id=user_id,
|
||||
inherited_to_projects=False,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def put(self, domain_id=None, user_id=None, role_id=None):
|
||||
@ -357,10 +374,15 @@ class DomainUserResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:create_grant',
|
||||
build_target=_build_enforcement_target)
|
||||
build_target=_build_enforcement_target,
|
||||
)
|
||||
PROVIDERS.assignment_api.create_grant(
|
||||
role_id, domain_id=domain_id, user_id=user_id,
|
||||
inherited_to_projects=False, initiator=self.audit_initiator)
|
||||
role_id,
|
||||
domain_id=domain_id,
|
||||
user_id=user_id,
|
||||
inherited_to_projects=False,
|
||||
initiator=self.audit_initiator,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def delete(self, domain_id=None, user_id=None, role_id=None):
|
||||
@ -370,11 +392,17 @@ class DomainUserResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:revoke_grant',
|
||||
build_target=functools.partial(_build_enforcement_target,
|
||||
allow_non_existing=True))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target, allow_non_existing=True
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.delete_grant(
|
||||
role_id, domain_id=domain_id, user_id=user_id,
|
||||
inherited_to_projects=False, initiator=self.audit_initiator)
|
||||
role_id,
|
||||
domain_id=domain_id,
|
||||
user_id=user_id,
|
||||
inherited_to_projects=False,
|
||||
initiator=self.audit_initiator,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -386,12 +414,14 @@ class DomainGroupListResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_grants',
|
||||
build_target=_build_enforcement_target)
|
||||
build_target=_build_enforcement_target,
|
||||
)
|
||||
refs = PROVIDERS.assignment_api.list_grants(
|
||||
domain_id=domain_id, group_id=group_id,
|
||||
inherited_to_projects=False)
|
||||
domain_id=domain_id, group_id=group_id, inherited_to_projects=False
|
||||
)
|
||||
return ks_flask.ResourceBase.wrap_collection(
|
||||
refs, collection_name='roles')
|
||||
refs, collection_name='roles'
|
||||
)
|
||||
|
||||
|
||||
class DomainGroupResource(ks_flask.ResourceBase):
|
||||
@ -405,10 +435,14 @@ class DomainGroupResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:check_grant',
|
||||
build_target=_build_enforcement_target)
|
||||
build_target=_build_enforcement_target,
|
||||
)
|
||||
PROVIDERS.assignment_api.get_grant(
|
||||
role_id, domain_id=domain_id, group_id=group_id,
|
||||
inherited_to_projects=False)
|
||||
role_id,
|
||||
domain_id=domain_id,
|
||||
group_id=group_id,
|
||||
inherited_to_projects=False,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def put(self, domain_id=None, group_id=None, role_id=None):
|
||||
@ -418,10 +452,15 @@ class DomainGroupResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:create_grant',
|
||||
build_target=_build_enforcement_target)
|
||||
build_target=_build_enforcement_target,
|
||||
)
|
||||
PROVIDERS.assignment_api.create_grant(
|
||||
role_id, domain_id=domain_id, group_id=group_id,
|
||||
inherited_to_projects=False, initiator=self.audit_initiator)
|
||||
role_id,
|
||||
domain_id=domain_id,
|
||||
group_id=group_id,
|
||||
inherited_to_projects=False,
|
||||
initiator=self.audit_initiator,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def delete(self, domain_id=None, group_id=None, role_id=None):
|
||||
@ -431,11 +470,17 @@ class DomainGroupResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:revoke_grant',
|
||||
build_target=functools.partial(_build_enforcement_target,
|
||||
allow_non_existing=True))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target, allow_non_existing=True
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.delete_grant(
|
||||
role_id, domain_id=domain_id, group_id=group_id,
|
||||
inherited_to_projects=False, initiator=self.audit_initiator)
|
||||
role_id,
|
||||
domain_id=domain_id,
|
||||
group_id=group_id,
|
||||
inherited_to_projects=False,
|
||||
initiator=self.audit_initiator,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -451,8 +496,8 @@ class DomainAPI(ks_flask.APIBase):
|
||||
url=('/domains/<string:domain_id>/config'),
|
||||
resource_kwargs={},
|
||||
rel='domain_config',
|
||||
path_vars={
|
||||
'domain_id': json_home.Parameters.DOMAIN_ID}),
|
||||
path_vars={'domain_id': json_home.Parameters.DOMAIN_ID},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=DomainConfigGroupResource,
|
||||
url='/domains/<string:domain_id>/config/<string:group>',
|
||||
@ -460,81 +505,96 @@ class DomainAPI(ks_flask.APIBase):
|
||||
rel='domain_config_group',
|
||||
path_vars={
|
||||
'domain_id': json_home.Parameters.DOMAIN_ID,
|
||||
'group': CONFIG_GROUP}),
|
||||
'group': CONFIG_GROUP,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=DomainConfigOptionResource,
|
||||
url=('/domains/<string:domain_id>/config/<string:group>'
|
||||
'/<string:option>'),
|
||||
url=(
|
||||
'/domains/<string:domain_id>/config/<string:group>'
|
||||
'/<string:option>'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='domain_config_option',
|
||||
path_vars={
|
||||
'domain_id': json_home.Parameters.DOMAIN_ID,
|
||||
'group': CONFIG_GROUP,
|
||||
'option': CONFIG_OPTION}),
|
||||
'option': CONFIG_OPTION,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=DefaultConfigResource,
|
||||
url=('/domains/config/default'),
|
||||
resource_kwargs={},
|
||||
rel='domain_config_default',
|
||||
path_vars={}),
|
||||
path_vars={},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=DefaultConfigGroupResource,
|
||||
url='/domains/config/<string:group>/default',
|
||||
resource_kwargs={},
|
||||
rel='domain_config_default_group',
|
||||
path_vars={
|
||||
'group': CONFIG_GROUP}),
|
||||
path_vars={'group': CONFIG_GROUP},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=DefaultConfigOptionResource,
|
||||
url=('/domains/config/<string:group>'
|
||||
'/<string:option>/default'),
|
||||
url=('/domains/config/<string:group>' '/<string:option>/default'),
|
||||
resource_kwargs={},
|
||||
rel='domain_config_default_option',
|
||||
path_vars={
|
||||
'group': CONFIG_GROUP,
|
||||
'option': CONFIG_OPTION}),
|
||||
path_vars={'group': CONFIG_GROUP, 'option': CONFIG_OPTION},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=DomainUserListResource,
|
||||
url=('/domains/<string:domain_id>/users'
|
||||
'/<string:user_id>/roles'),
|
||||
url=(
|
||||
'/domains/<string:domain_id>/users' '/<string:user_id>/roles'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='domain_user_roles',
|
||||
path_vars={
|
||||
'domain_id': json_home.Parameters.DOMAIN_ID,
|
||||
'user_id': json_home.Parameters.USER_ID,
|
||||
}),
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=DomainUserResource,
|
||||
url=('/domains/<string:domain_id>/users'
|
||||
'/<string:user_id>/roles/<string:role_id>'),
|
||||
url=(
|
||||
'/domains/<string:domain_id>/users'
|
||||
'/<string:user_id>/roles/<string:role_id>'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='domain_user_role',
|
||||
path_vars={
|
||||
'domain_id': json_home.Parameters.DOMAIN_ID,
|
||||
'user_id': json_home.Parameters.USER_ID,
|
||||
'role_id': json_home.Parameters.ROLE_ID
|
||||
}),
|
||||
'role_id': json_home.Parameters.ROLE_ID,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=DomainGroupListResource,
|
||||
url=('/domains/<string:domain_id>/groups'
|
||||
'/<string:group_id>/roles'),
|
||||
url=(
|
||||
'/domains/<string:domain_id>/groups' '/<string:group_id>/roles'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='domain_group_roles',
|
||||
path_vars={
|
||||
'domain_id': json_home.Parameters.DOMAIN_ID,
|
||||
'group_id': json_home.Parameters.GROUP_ID,
|
||||
}),
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=DomainGroupResource,
|
||||
url=('/domains/<string:domain_id>/groups'
|
||||
'/<string:group_id>/roles/<string:role_id>'),
|
||||
url=(
|
||||
'/domains/<string:domain_id>/groups'
|
||||
'/<string:group_id>/roles/<string:role_id>'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='domain_group_role',
|
||||
path_vars={
|
||||
'domain_id': json_home.Parameters.DOMAIN_ID,
|
||||
'group_id': json_home.Parameters.GROUP_ID,
|
||||
'role_id': json_home.Parameters.ROLE_ID
|
||||
})
|
||||
'role_id': json_home.Parameters.ROLE_ID,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -51,14 +51,12 @@ class EC2TokensResource(EC2_S3_Resource.ResourceBase):
|
||||
# other programming language libraries, JAVA for example.
|
||||
signer = ec2_utils.Ec2Signer(creds_ref['secret'])
|
||||
signature = signer.generate(credentials)
|
||||
if utils.auth_str_equal(
|
||||
credentials['signature'], signature):
|
||||
if utils.auth_str_equal(credentials['signature'], signature):
|
||||
return True
|
||||
raise exception.Unauthorized(_('Invalid EC2 signature.'))
|
||||
# Raise the exception when credentials.get('signature') is None
|
||||
else:
|
||||
raise exception.Unauthorized(
|
||||
_('EC2 signature not supplied.'))
|
||||
raise exception.Unauthorized(_('EC2 signature not supplied.'))
|
||||
|
||||
@ks_flask.unenforced_api
|
||||
def post(self):
|
||||
@ -86,7 +84,9 @@ class EC2TokensAPI(ks_flask.APIBase):
|
||||
resource_kwargs={},
|
||||
rel='ec2tokens',
|
||||
resource_relation_func=(
|
||||
json_home_relations.os_ec2_resource_rel_func))
|
||||
json_home_relations.os_ec2_resource_rel_func
|
||||
),
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
|
@ -43,7 +43,8 @@ class EndpointResource(ks_flask.ResourceBase):
|
||||
collection_key = 'endpoints'
|
||||
member_key = 'endpoint'
|
||||
get_member_from_driver = PROVIDERS.deferred_provider_lookup(
|
||||
api='catalog_api', method='get_endpoint')
|
||||
api='catalog_api', method='get_endpoint'
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _validate_endpoint_region(endpoint):
|
||||
@ -54,8 +55,10 @@ class EndpointResource(ks_flask.ResourceBase):
|
||||
then for backward compatibility, we will auto-create the region.
|
||||
|
||||
"""
|
||||
if (endpoint.get('region_id') is None and
|
||||
endpoint.get('region') is not None):
|
||||
if (
|
||||
endpoint.get('region_id') is None
|
||||
and endpoint.get('region') is not None
|
||||
):
|
||||
# To maintain backward compatibility with clients that are
|
||||
# using the v3 API in the same way as they used the v2 API,
|
||||
# create the endpoint region, if that region does not exist
|
||||
@ -66,22 +69,26 @@ class EndpointResource(ks_flask.ResourceBase):
|
||||
except exception.RegionNotFound:
|
||||
region = dict(id=endpoint['region_id'])
|
||||
PROVIDERS.catalog_api.create_region(
|
||||
region, initiator=notifications.build_audit_initiator())
|
||||
region, initiator=notifications.build_audit_initiator()
|
||||
)
|
||||
return endpoint
|
||||
|
||||
def _get_endpoint(self, endpoint_id):
|
||||
ENFORCER.enforce_call(action='identity:get_endpoint')
|
||||
return self.wrap_member(_filter_endpoint(
|
||||
PROVIDERS.catalog_api.get_endpoint(endpoint_id)))
|
||||
return self.wrap_member(
|
||||
_filter_endpoint(PROVIDERS.catalog_api.get_endpoint(endpoint_id))
|
||||
)
|
||||
|
||||
def _list_endpoints(self):
|
||||
filters = ['interface', 'service_id', 'region_id']
|
||||
ENFORCER.enforce_call(action='identity:list_endpoints',
|
||||
filters=filters)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_endpoints', filters=filters
|
||||
)
|
||||
hints = self.build_driver_hints(filters)
|
||||
refs = PROVIDERS.catalog_api.list_endpoints(hints=hints)
|
||||
return self.wrap_collection([_filter_endpoint(r) for r in refs],
|
||||
hints=hints)
|
||||
return self.wrap_collection(
|
||||
[_filter_endpoint(r) for r in refs], hints=hints
|
||||
)
|
||||
|
||||
def get(self, endpoint_id=None):
|
||||
if endpoint_id is not None:
|
||||
@ -96,7 +103,8 @@ class EndpointResource(ks_flask.ResourceBase):
|
||||
endpoint = self._assign_unique_id(self._normalize_dict(endpoint))
|
||||
endpoint = self._validate_endpoint_region(endpoint)
|
||||
ref = PROVIDERS.catalog_api.create_endpoint(
|
||||
endpoint['id'], endpoint, initiator=self.audit_initiator)
|
||||
endpoint['id'], endpoint, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(_filter_endpoint(ref)), http.client.CREATED
|
||||
|
||||
def patch(self, endpoint_id):
|
||||
@ -106,13 +114,15 @@ class EndpointResource(ks_flask.ResourceBase):
|
||||
self._require_matching_id(endpoint)
|
||||
endpoint = self._validate_endpoint_region(endpoint)
|
||||
ref = PROVIDERS.catalog_api.update_endpoint(
|
||||
endpoint_id, endpoint, initiator=self.audit_initiator)
|
||||
endpoint_id, endpoint, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(_filter_endpoint(ref))
|
||||
|
||||
def delete(self, endpoint_id):
|
||||
ENFORCER.enforce_call(action='identity:delete_endpoint')
|
||||
PROVIDERS.catalog_api.delete_endpoint(endpoint_id,
|
||||
initiator=self.audit_initiator)
|
||||
PROVIDERS.catalog_api.delete_endpoint(
|
||||
endpoint_id, initiator=self.audit_initiator
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -121,9 +131,11 @@ class EndpointPolicyEndpointResource(flask_restful.Resource):
|
||||
ENFORCER.enforce_call(action='identity:get_policy_for_endpoint')
|
||||
PROVIDERS.catalog_api.get_endpoint(endpoint_id)
|
||||
ref = PROVIDERS.endpoint_policy_api.get_policy_for_endpoint(
|
||||
endpoint_id)
|
||||
endpoint_id
|
||||
)
|
||||
return ks_flask.ResourceBase.wrap_member(
|
||||
ref, collection_name='endpoints', member_name='policy')
|
||||
ref, collection_name='endpoints', member_name='policy'
|
||||
)
|
||||
|
||||
|
||||
class EndpointAPI(ks_flask.APIBase):
|
||||
@ -137,7 +149,8 @@ class EndpointAPI(ks_flask.APIBase):
|
||||
resource_kwargs={},
|
||||
rel='endpoint_policy',
|
||||
resource_relation_func=_resource_rel_func,
|
||||
path_vars={'endpoint_id': json_home.Parameters.ENDPOINT_ID})
|
||||
path_vars={'endpoint_id': json_home.Parameters.ENDPOINT_ID},
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
|
@ -51,7 +51,8 @@ class GroupsResource(ks_flask.ResourceBase):
|
||||
collection_key = 'groups'
|
||||
member_key = 'group'
|
||||
get_member_from_driver = PROVIDERS.deferred_provider_lookup(
|
||||
api='identity_api', method='get_group')
|
||||
api='identity_api', method='get_group'
|
||||
)
|
||||
|
||||
def get(self, group_id=None):
|
||||
if group_id is not None:
|
||||
@ -65,7 +66,7 @@ class GroupsResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:get_group',
|
||||
build_target=_build_group_target_enforcement
|
||||
build_target=_build_group_target_enforcement,
|
||||
)
|
||||
return self.wrap_member(PROVIDERS.identity_api.get_group(group_id))
|
||||
|
||||
@ -78,12 +79,14 @@ class GroupsResource(ks_flask.ResourceBase):
|
||||
target = None
|
||||
if self.oslo_context.domain_id:
|
||||
target = {'group': {'domain_id': self.oslo_context.domain_id}}
|
||||
ENFORCER.enforce_call(action='identity:list_groups', filters=filters,
|
||||
target_attr=target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_groups', filters=filters, target_attr=target
|
||||
)
|
||||
hints = self.build_driver_hints(filters)
|
||||
domain = self._get_domain_id_for_list_request()
|
||||
refs = PROVIDERS.identity_api.list_groups(domain_scope=domain,
|
||||
hints=hints)
|
||||
refs = PROVIDERS.identity_api.list_groups(
|
||||
domain_scope=domain, hints=hints
|
||||
)
|
||||
if self.oslo_context.domain_id:
|
||||
filtered_refs = []
|
||||
for ref in refs:
|
||||
@ -106,7 +109,8 @@ class GroupsResource(ks_flask.ResourceBase):
|
||||
group = self._normalize_dict(group)
|
||||
group = self._normalize_domain_id(group)
|
||||
ref = PROVIDERS.identity_api.create_group(
|
||||
group, initiator=self.audit_initiator)
|
||||
group, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref), http.client.CREATED
|
||||
|
||||
def patch(self, group_id):
|
||||
@ -116,13 +120,14 @@ class GroupsResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:update_group',
|
||||
build_target=_build_group_target_enforcement
|
||||
build_target=_build_group_target_enforcement,
|
||||
)
|
||||
group = self.request_body_json.get('group', {})
|
||||
validation.lazy_validate(schema.group_update, group)
|
||||
self._require_matching_id(group)
|
||||
ref = PROVIDERS.identity_api.update_group(
|
||||
group_id, group, initiator=self.audit_initiator)
|
||||
group_id, group, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
def delete(self, group_id):
|
||||
@ -132,7 +137,8 @@ class GroupsResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:delete_group')
|
||||
PROVIDERS.identity_api.delete_group(
|
||||
group_id, initiator=self.audit_initiator)
|
||||
group_id, initiator=self.audit_initiator
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -151,19 +157,24 @@ class GroupUsersResource(ks_flask.ResourceBase):
|
||||
# data, leage target empty. This is the safest route and does not
|
||||
# leak data before enforcement happens.
|
||||
pass
|
||||
ENFORCER.enforce_call(action='identity:list_users_in_group',
|
||||
target_attr=target, filters=filters)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_users_in_group',
|
||||
target_attr=target,
|
||||
filters=filters,
|
||||
)
|
||||
hints = ks_flask.ResourceBase.build_driver_hints(filters)
|
||||
refs = PROVIDERS.identity_api.list_users_in_group(
|
||||
group_id, hints=hints)
|
||||
if (self.oslo_context.domain_id):
|
||||
group_id, hints=hints
|
||||
)
|
||||
if self.oslo_context.domain_id:
|
||||
filtered_refs = []
|
||||
for ref in refs:
|
||||
if ref['domain_id'] == self.oslo_context.domain_id:
|
||||
filtered_refs.append(ref)
|
||||
refs = filtered_refs
|
||||
return ks_flask.ResourceBase.wrap_collection(
|
||||
refs, hints=hints, collection_name='users')
|
||||
refs, hints=hints, collection_name='users'
|
||||
)
|
||||
|
||||
|
||||
class UserGroupCRUDResource(flask_restful.Resource):
|
||||
@ -191,8 +202,10 @@ class UserGroupCRUDResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:check_user_in_group',
|
||||
build_target=functools.partial(self._build_enforcement_target_attr,
|
||||
user_id, group_id))
|
||||
build_target=functools.partial(
|
||||
self._build_enforcement_target_attr, user_id, group_id
|
||||
),
|
||||
)
|
||||
PROVIDERS.identity_api.check_user_in_group(user_id, group_id)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
@ -203,10 +216,13 @@ class UserGroupCRUDResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:add_user_to_group',
|
||||
build_target=functools.partial(self._build_enforcement_target_attr,
|
||||
user_id, group_id))
|
||||
build_target=functools.partial(
|
||||
self._build_enforcement_target_attr, user_id, group_id
|
||||
),
|
||||
)
|
||||
PROVIDERS.identity_api.add_user_to_group(
|
||||
user_id, group_id, initiator=notifications.build_audit_initiator())
|
||||
user_id, group_id, initiator=notifications.build_audit_initiator()
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def delete(self, group_id, user_id):
|
||||
@ -216,10 +232,13 @@ class UserGroupCRUDResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:remove_user_from_group',
|
||||
build_target=functools.partial(self._build_enforcement_target_attr,
|
||||
user_id, group_id))
|
||||
build_target=functools.partial(
|
||||
self._build_enforcement_target_attr, user_id, group_id
|
||||
),
|
||||
)
|
||||
PROVIDERS.identity_api.remove_user_from_group(
|
||||
user_id, group_id, initiator=notifications.build_audit_initiator())
|
||||
user_id, group_id, initiator=notifications.build_audit_initiator()
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -233,7 +252,8 @@ class GroupAPI(ks_flask.APIBase):
|
||||
url='/groups/<string:group_id>/users',
|
||||
resource_kwargs={},
|
||||
rel='group_users',
|
||||
path_vars={'group_id': json_home.Parameters.GROUP_ID}),
|
||||
path_vars={'group_id': json_home.Parameters.GROUP_ID},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=UserGroupCRUDResource,
|
||||
url='/groups/<string:group_id>/users/<string:user_id>',
|
||||
@ -241,7 +261,9 @@ class GroupAPI(ks_flask.APIBase):
|
||||
rel='group_user',
|
||||
path_vars={
|
||||
'group_id': json_home.Parameters.GROUP_ID,
|
||||
'user_id': json_home.Parameters.USER_ID})
|
||||
'user_id': json_home.Parameters.USER_ID,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -55,11 +55,17 @@ class LimitsResource(ks_flask.ResourceBase):
|
||||
member_key = 'limit'
|
||||
json_home_resource_status = json_home.Status.EXPERIMENTAL
|
||||
get_member_from_driver = PROVIDERS.deferred_provider_lookup(
|
||||
api='unified_limit_api', method='get_limit')
|
||||
api='unified_limit_api', method='get_limit'
|
||||
)
|
||||
|
||||
def _list_limits(self):
|
||||
filters = ['service_id', 'region_id', 'resource_name', 'project_id',
|
||||
'domain_id']
|
||||
filters = [
|
||||
'service_id',
|
||||
'region_id',
|
||||
'resource_name',
|
||||
'project_id',
|
||||
'domain_id',
|
||||
]
|
||||
|
||||
ENFORCER.enforce_call(action='identity:list_limits', filters=filters)
|
||||
|
||||
@ -90,8 +96,10 @@ class LimitsResource(ks_flask.ResourceBase):
|
||||
return self.wrap_collection(filtered_refs, hints=hints)
|
||||
|
||||
def _get_limit(self, limit_id):
|
||||
ENFORCER.enforce_call(action='identity:get_limit',
|
||||
build_target=_build_limit_enforcement_target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:get_limit',
|
||||
build_target=_build_limit_enforcement_target,
|
||||
)
|
||||
ref = PROVIDERS.unified_limit_api.get_limit(limit_id)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
@ -103,10 +111,13 @@ class LimitsResource(ks_flask.ResourceBase):
|
||||
def post(self):
|
||||
ENFORCER.enforce_call(action='identity:create_limits')
|
||||
limits_b = (flask.request.get_json(silent=True, force=True) or {}).get(
|
||||
'limits', {})
|
||||
'limits', {}
|
||||
)
|
||||
validation.lazy_validate(schema.limit_create, limits_b)
|
||||
limits = [self._assign_unique_id(self._normalize_dict(limit))
|
||||
for limit in limits_b]
|
||||
limits = [
|
||||
self._assign_unique_id(self._normalize_dict(limit))
|
||||
for limit in limits_b
|
||||
]
|
||||
refs = PROVIDERS.unified_limit_api.create_limits(limits)
|
||||
refs = self.wrap_collection(refs)
|
||||
refs.pop('links')
|
||||
@ -115,7 +126,8 @@ class LimitsResource(ks_flask.ResourceBase):
|
||||
def patch(self, limit_id):
|
||||
ENFORCER.enforce_call(action='identity:update_limit')
|
||||
limit = (flask.request.get_json(silent=True, force=True) or {}).get(
|
||||
'limit', {})
|
||||
'limit', {}
|
||||
)
|
||||
validation.lazy_validate(schema.limit_update, limit)
|
||||
self._require_matching_id(limit)
|
||||
ref = PROVIDERS.unified_limit_api.update_limit(limit_id, limit)
|
||||
@ -123,8 +135,10 @@ class LimitsResource(ks_flask.ResourceBase):
|
||||
|
||||
def delete(self, limit_id):
|
||||
ENFORCER.enforce_call(action='identity:delete_limit')
|
||||
return (PROVIDERS.unified_limit_api.delete_limit(limit_id),
|
||||
http.client.NO_CONTENT)
|
||||
return (
|
||||
PROVIDERS.unified_limit_api.delete_limit(limit_id),
|
||||
http.client.NO_CONTENT,
|
||||
)
|
||||
|
||||
|
||||
class LimitModelResource(flask_restful.Resource):
|
||||
@ -144,7 +158,7 @@ class LimitsAPI(ks_flask.APIBase):
|
||||
resource_kwargs={},
|
||||
url='/limits/model',
|
||||
rel='limit_model',
|
||||
status=json_home.Status.EXPERIMENTAL
|
||||
status=json_home.Status.EXPERIMENTAL,
|
||||
)
|
||||
]
|
||||
|
||||
|
@ -34,7 +34,8 @@ _build_resource_relation = json_home_relations.os_ep_filter_resource_rel_func
|
||||
_build_parameter_relation = json_home_relations.os_ep_filter_parameter_rel_func
|
||||
|
||||
_ENDPOINT_GROUP_PARAMETER_RELATION = _build_parameter_relation(
|
||||
parameter_name='endpoint_group_id')
|
||||
parameter_name='endpoint_group_id'
|
||||
)
|
||||
|
||||
|
||||
# NOTE(morgan): This is shared from keystone.api.endpoint, this is a special
|
||||
@ -58,17 +59,20 @@ class EndpointGroupsResource(ks_flask.ResourceBase):
|
||||
if key not in valid_filter_keys:
|
||||
raise exception.ValidationError(
|
||||
attribute=' or '.join(valid_filter_keys),
|
||||
target='endpoint_group')
|
||||
target='endpoint_group',
|
||||
)
|
||||
|
||||
def _get_endpoint_group(self, endpoint_group_id):
|
||||
ENFORCER.enforce_call(action='identity:get_endpoint_group')
|
||||
return self.wrap_member(
|
||||
PROVIDERS.catalog_api.get_endpoint_group(endpoint_group_id))
|
||||
PROVIDERS.catalog_api.get_endpoint_group(endpoint_group_id)
|
||||
)
|
||||
|
||||
def _list_endpoint_groups(self):
|
||||
filters = ('name')
|
||||
ENFORCER.enforce_call(action='identity:list_endpoint_groups',
|
||||
filters=filters)
|
||||
filters = 'name'
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_endpoint_groups', filters=filters
|
||||
)
|
||||
hints = self.build_driver_hints(filters)
|
||||
refs = PROVIDERS.catalog_api.list_endpoint_groups(hints)
|
||||
return self.wrap_collection(refs, hints=hints)
|
||||
@ -89,8 +93,14 @@ class EndpointGroupsResource(ks_flask.ResourceBase):
|
||||
raise exception.ValidationError(message=msg)
|
||||
self._require_valid_filter(ep_group)
|
||||
ep_group = self._assign_unique_id(ep_group)
|
||||
return self.wrap_member(PROVIDERS.catalog_api.create_endpoint_group(
|
||||
ep_group['id'], ep_group)), http.client.CREATED
|
||||
return (
|
||||
self.wrap_member(
|
||||
PROVIDERS.catalog_api.create_endpoint_group(
|
||||
ep_group['id'], ep_group
|
||||
)
|
||||
),
|
||||
http.client.CREATED,
|
||||
)
|
||||
|
||||
def patch(self, endpoint_group_id):
|
||||
ENFORCER.enforce_call(action='identity:update_endpoint_group')
|
||||
@ -99,13 +109,18 @@ class EndpointGroupsResource(ks_flask.ResourceBase):
|
||||
if 'filters' in ep_group:
|
||||
self._require_valid_filter(ep_group)
|
||||
self._require_matching_id(ep_group)
|
||||
return self.wrap_member(PROVIDERS.catalog_api.update_endpoint_group(
|
||||
endpoint_group_id, ep_group))
|
||||
return self.wrap_member(
|
||||
PROVIDERS.catalog_api.update_endpoint_group(
|
||||
endpoint_group_id, ep_group
|
||||
)
|
||||
)
|
||||
|
||||
def delete(self, endpoint_group_id):
|
||||
ENFORCER.enforce_call(action='identity:delete_endpoint_group')
|
||||
return (PROVIDERS.catalog_api.delete_endpoint_group(endpoint_group_id),
|
||||
http.client.NO_CONTENT)
|
||||
return (
|
||||
PROVIDERS.catalog_api.delete_endpoint_group(endpoint_group_id),
|
||||
http.client.NO_CONTENT,
|
||||
)
|
||||
|
||||
|
||||
class EPFilterEndpointProjectsResource(flask_restful.Resource):
|
||||
@ -114,10 +129,13 @@ class EPFilterEndpointProjectsResource(flask_restful.Resource):
|
||||
ENFORCER.enforce_call(action='identity:list_projects_for_endpoint')
|
||||
PROVIDERS.catalog_api.get_endpoint(endpoint_id)
|
||||
refs = PROVIDERS.catalog_api.list_projects_for_endpoint(endpoint_id)
|
||||
projects = [PROVIDERS.resource_api.get_project(ref['project_id'])
|
||||
for ref in refs]
|
||||
projects = [
|
||||
PROVIDERS.resource_api.get_project(ref['project_id'])
|
||||
for ref in refs
|
||||
]
|
||||
return ks_flask.ResourceBase.wrap_collection(
|
||||
projects, collection_name='projects')
|
||||
projects, collection_name='projects'
|
||||
)
|
||||
|
||||
|
||||
class EPFilterProjectsEndpointsResource(flask_restful.Resource):
|
||||
@ -126,7 +144,8 @@ class EPFilterProjectsEndpointsResource(flask_restful.Resource):
|
||||
PROVIDERS.catalog_api.get_endpoint(endpoint_id)
|
||||
PROVIDERS.resource_api.get_project(project_id)
|
||||
PROVIDERS.catalog_api.check_endpoint_in_project(
|
||||
endpoint_id, project_id)
|
||||
endpoint_id, project_id
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def put(self, project_id, endpoint_id):
|
||||
@ -138,8 +157,12 @@ class EPFilterProjectsEndpointsResource(flask_restful.Resource):
|
||||
|
||||
def delete(self, project_id, endpoint_id):
|
||||
ENFORCER.enforce_call(action='identity:remove_endpoint_from_project')
|
||||
return (PROVIDERS.catalog_api.remove_endpoint_from_project(
|
||||
endpoint_id, project_id), http.client.NO_CONTENT)
|
||||
return (
|
||||
PROVIDERS.catalog_api.remove_endpoint_from_project(
|
||||
endpoint_id, project_id
|
||||
),
|
||||
http.client.NO_CONTENT,
|
||||
)
|
||||
|
||||
|
||||
class EPFilterProjectEndpointsListResource(flask_restful.Resource):
|
||||
@ -147,49 +170,62 @@ class EPFilterProjectEndpointsListResource(flask_restful.Resource):
|
||||
ENFORCER.enforce_call(action='identity:list_endpoints_for_project')
|
||||
PROVIDERS.resource_api.get_project(project_id)
|
||||
filtered_endpoints = PROVIDERS.catalog_api.list_endpoints_for_project(
|
||||
project_id)
|
||||
project_id
|
||||
)
|
||||
|
||||
return ks_flask.ResourceBase.wrap_collection(
|
||||
[_filter_endpoint(v) for v in filtered_endpoints.values()],
|
||||
collection_name='endpoints')
|
||||
collection_name='endpoints',
|
||||
)
|
||||
|
||||
|
||||
class EndpointFilterProjectEndpointGroupsListResource(flask_restful.Resource):
|
||||
def get(self, project_id):
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_endpoint_groups_for_project')
|
||||
action='identity:list_endpoint_groups_for_project'
|
||||
)
|
||||
return EndpointGroupsResource.wrap_collection(
|
||||
PROVIDERS.catalog_api.get_endpoint_groups_for_project(project_id))
|
||||
PROVIDERS.catalog_api.get_endpoint_groups_for_project(project_id)
|
||||
)
|
||||
|
||||
|
||||
class EndpointFilterEPGroupsProjects(flask_restful.Resource):
|
||||
def get(self, endpoint_group_id):
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_projects_associated_with_endpoint_group')
|
||||
endpoint_group_refs = (PROVIDERS.catalog_api.
|
||||
list_projects_associated_with_endpoint_group(
|
||||
endpoint_group_id))
|
||||
action='identity:list_projects_associated_with_endpoint_group'
|
||||
)
|
||||
endpoint_group_refs = (
|
||||
PROVIDERS.catalog_api.list_projects_associated_with_endpoint_group(
|
||||
endpoint_group_id
|
||||
)
|
||||
)
|
||||
projects = []
|
||||
for endpoint_group_ref in endpoint_group_refs:
|
||||
project = PROVIDERS.resource_api.get_project(
|
||||
endpoint_group_ref['project_id'])
|
||||
endpoint_group_ref['project_id']
|
||||
)
|
||||
if project:
|
||||
projects.append(project)
|
||||
|
||||
return ks_flask.ResourceBase.wrap_collection(
|
||||
projects, collection_name='projects')
|
||||
projects, collection_name='projects'
|
||||
)
|
||||
|
||||
|
||||
class EndpointFilterEPGroupsEndpoints(flask_restful.Resource):
|
||||
def get(self, endpoint_group_id):
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_endpoints_associated_with_endpoint_group')
|
||||
filtered_endpoints = (PROVIDERS.catalog_api.
|
||||
get_endpoints_filtered_by_endpoint_group(
|
||||
endpoint_group_id))
|
||||
action='identity:list_endpoints_associated_with_endpoint_group'
|
||||
)
|
||||
filtered_endpoints = (
|
||||
PROVIDERS.catalog_api.get_endpoints_filtered_by_endpoint_group(
|
||||
endpoint_group_id
|
||||
)
|
||||
)
|
||||
return ks_flask.ResourceBase.wrap_collection(
|
||||
[_filter_endpoint(e) for e in filtered_endpoints],
|
||||
collection_name='endpoints')
|
||||
collection_name='endpoints',
|
||||
)
|
||||
|
||||
|
||||
class EPFilterGroupsProjectsResource(ks_flask.ResourceBase):
|
||||
@ -198,10 +234,14 @@ class EPFilterGroupsProjectsResource(ks_flask.ResourceBase):
|
||||
|
||||
@classmethod
|
||||
def _add_self_referential_link(cls, ref, collection_name=None):
|
||||
url = ('/OS-EP-FILTER/endpoint_groups/%(endpoint_group_id)s'
|
||||
'/projects/%(project_id)s' % {
|
||||
'endpoint_group_id': ref['endpoint_group_id'],
|
||||
'project_id': ref['project_id']})
|
||||
url = (
|
||||
'/OS-EP-FILTER/endpoint_groups/%(endpoint_group_id)s'
|
||||
'/projects/%(project_id)s'
|
||||
% {
|
||||
'endpoint_group_id': ref['endpoint_group_id'],
|
||||
'project_id': ref['project_id'],
|
||||
}
|
||||
)
|
||||
ref.setdefault('links', {})
|
||||
ref['links']['self'] = url
|
||||
|
||||
@ -210,7 +250,8 @@ class EPFilterGroupsProjectsResource(ks_flask.ResourceBase):
|
||||
PROVIDERS.resource_api.get_project(project_id)
|
||||
PROVIDERS.catalog_api.get_endpoint_group(endpoint_group_id)
|
||||
ref = PROVIDERS.catalog_api.get_endpoint_group_in_project(
|
||||
endpoint_group_id, project_id)
|
||||
endpoint_group_id, project_id
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
def put(self, endpoint_group_id, project_id):
|
||||
@ -218,16 +259,19 @@ class EPFilterGroupsProjectsResource(ks_flask.ResourceBase):
|
||||
PROVIDERS.resource_api.get_project(project_id)
|
||||
PROVIDERS.catalog_api.get_endpoint_group(endpoint_group_id)
|
||||
PROVIDERS.catalog_api.add_endpoint_group_to_project(
|
||||
endpoint_group_id, project_id)
|
||||
endpoint_group_id, project_id
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def delete(self, endpoint_group_id, project_id):
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:remove_endpoint_group_from_project')
|
||||
action='identity:remove_endpoint_group_from_project'
|
||||
)
|
||||
PROVIDERS.resource_api.get_project(project_id)
|
||||
PROVIDERS.catalog_api.get_endpoint_group(endpoint_group_id)
|
||||
PROVIDERS.catalog_api.remove_endpoint_group_from_project(
|
||||
endpoint_group_id, project_id)
|
||||
endpoint_group_id, project_id
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -243,9 +287,8 @@ class EPFilterAPI(ks_flask.APIBase):
|
||||
resource_kwargs={},
|
||||
rel='endpoint_projects',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={
|
||||
'endpoint_id': json_home.Parameters.ENDPOINT_ID
|
||||
}),
|
||||
path_vars={'endpoint_id': json_home.Parameters.ENDPOINT_ID},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=EPFilterProjectsEndpointsResource,
|
||||
url='/projects/<string:project_id>/endpoints/<string:endpoint_id>',
|
||||
@ -254,21 +297,25 @@ class EPFilterAPI(ks_flask.APIBase):
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={
|
||||
'endpoint_id': json_home.Parameters.ENDPOINT_ID,
|
||||
'project_id': json_home.Parameters.PROJECT_ID}),
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=EPFilterProjectEndpointsListResource,
|
||||
url='/projects/<string:project_id>/endpoints',
|
||||
resource_kwargs={},
|
||||
rel='project_endpoints',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={'project_id': json_home.Parameters.PROJECT_ID}),
|
||||
path_vars={'project_id': json_home.Parameters.PROJECT_ID},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=EndpointFilterProjectEndpointGroupsListResource,
|
||||
url='/projects/<string:project_id>/endpoint_groups',
|
||||
resource_kwargs={},
|
||||
rel='project_endpoint_groups',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={'project_id': json_home.Parameters.PROJECT_ID}),
|
||||
path_vars={'project_id': json_home.Parameters.PROJECT_ID},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=EndpointFilterEPGroupsEndpoints,
|
||||
url='/endpoint_groups/<string:endpoint_group_id>/endpoints',
|
||||
@ -276,7 +323,9 @@ class EPFilterAPI(ks_flask.APIBase):
|
||||
rel='endpoints_in_endpoint_group',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={
|
||||
'endpoint_group_id': _ENDPOINT_GROUP_PARAMETER_RELATION}),
|
||||
'endpoint_group_id': _ENDPOINT_GROUP_PARAMETER_RELATION
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=EndpointFilterEPGroupsProjects,
|
||||
url='/endpoint_groups/<string:endpoint_group_id>/projects',
|
||||
@ -284,17 +333,23 @@ class EPFilterAPI(ks_flask.APIBase):
|
||||
rel='projects_associated_with_endpoint_group',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={
|
||||
'endpoint_group_id': _ENDPOINT_GROUP_PARAMETER_RELATION}),
|
||||
'endpoint_group_id': _ENDPOINT_GROUP_PARAMETER_RELATION
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=EPFilterGroupsProjectsResource,
|
||||
url=('/endpoint_groups/<string:endpoint_group_id>/projects/'
|
||||
'<string:project_id>'),
|
||||
url=(
|
||||
'/endpoint_groups/<string:endpoint_group_id>/projects/'
|
||||
'<string:project_id>'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='endpoint_group_to_project_association',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={'project_id': json_home.Parameters.PROJECT_ID,
|
||||
'endpoint_group_id': _ENDPOINT_GROUP_PARAMETER_RELATION
|
||||
}),
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
'endpoint_group_id': _ENDPOINT_GROUP_PARAMETER_RELATION,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -43,7 +43,8 @@ _build_resource_relation = json_home_relations.os_federation_resource_rel_func
|
||||
|
||||
IDP_ID_PARAMETER_RELATION = _build_param_relation(parameter_name='idp_id')
|
||||
PROTOCOL_ID_PARAMETER_RELATION = _build_param_relation(
|
||||
parameter_name='protocol_id')
|
||||
parameter_name='protocol_id'
|
||||
)
|
||||
SP_ID_PARAMETER_RELATION = _build_param_relation(parameter_name='sp_id')
|
||||
|
||||
|
||||
@ -76,10 +77,17 @@ class IdentityProvidersResource(_ResourceBase):
|
||||
collection_key = 'identity_providers'
|
||||
member_key = 'identity_provider'
|
||||
api_prefix = '/OS-FEDERATION'
|
||||
_public_parameters = frozenset(['id', 'enabled', 'description',
|
||||
'remote_ids', 'links', 'domain_id',
|
||||
'authorization_ttl'
|
||||
])
|
||||
_public_parameters = frozenset(
|
||||
[
|
||||
'id',
|
||||
'enabled',
|
||||
'description',
|
||||
'remote_ids',
|
||||
'links',
|
||||
'domain_id',
|
||||
'authorization_ttl',
|
||||
]
|
||||
)
|
||||
_id_path_param_name_override = 'idp_id'
|
||||
|
||||
@staticmethod
|
||||
@ -117,8 +125,9 @@ class IdentityProvidersResource(_ResourceBase):
|
||||
GET/HEAD /OS-FEDERATION/identity_providers
|
||||
"""
|
||||
filters = ['id', 'enabled']
|
||||
ENFORCER.enforce_call(action='identity:list_identity_providers',
|
||||
filters=filters)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_identity_providers', filters=filters
|
||||
)
|
||||
hints = self.build_driver_hints(filters)
|
||||
refs = PROVIDERS.federation_api.list_idps(hints=hints)
|
||||
refs = [self.filter_params(r) for r in refs]
|
||||
@ -135,12 +144,10 @@ class IdentityProvidersResource(_ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:create_identity_provider')
|
||||
idp = self.request_body_json.get('identity_provider', {})
|
||||
validation.lazy_validate(schema.identity_provider_create,
|
||||
idp)
|
||||
validation.lazy_validate(schema.identity_provider_create, idp)
|
||||
idp = self._normalize_dict(idp)
|
||||
idp.setdefault('enabled', False)
|
||||
idp_ref = PROVIDERS.federation_api.create_idp(
|
||||
idp_id, idp)
|
||||
idp_ref = PROVIDERS.federation_api.create_idp(idp_id, idp)
|
||||
return self.wrap_member(idp_ref), http.client.CREATED
|
||||
|
||||
def patch(self, idp_id):
|
||||
@ -148,8 +155,7 @@ class IdentityProvidersResource(_ResourceBase):
|
||||
idp = self.request_body_json.get('identity_provider', {})
|
||||
validation.lazy_validate(schema.identity_provider_update, idp)
|
||||
idp = self._normalize_dict(idp)
|
||||
idp_ref = PROVIDERS.federation_api.update_idp(
|
||||
idp_id, idp)
|
||||
idp_ref = PROVIDERS.federation_api.update_idp(idp_id, idp)
|
||||
return self.wrap_member(idp_ref)
|
||||
|
||||
def delete(self, idp_id):
|
||||
@ -162,8 +168,7 @@ class _IdentityProvidersProtocolsResourceBase(_ResourceBase):
|
||||
collection_key = 'protocols'
|
||||
member_key = 'protocol'
|
||||
_public_parameters = frozenset(['id', 'mapping_id', 'links'])
|
||||
json_home_additional_parameters = {
|
||||
'idp_id': IDP_ID_PARAMETER_RELATION}
|
||||
json_home_additional_parameters = {'idp_id': IDP_ID_PARAMETER_RELATION}
|
||||
json_home_collection_resource_name_override = 'identity_provider_protocols'
|
||||
json_home_member_resource_name_override = 'identity_provider_protocol'
|
||||
|
||||
@ -179,7 +184,8 @@ class _IdentityProvidersProtocolsResourceBase(_ResourceBase):
|
||||
"""
|
||||
ref.setdefault('links', {})
|
||||
ref['links']['identity_provider'] = ks_flask.base_url(
|
||||
path=ref['idp_id'])
|
||||
path=ref['idp_id']
|
||||
)
|
||||
|
||||
|
||||
class IDPProtocolsListResource(_IdentityProvidersProtocolsResourceBase):
|
||||
@ -220,8 +226,9 @@ class IDPProtocolsCRUDResource(_IdentityProvidersProtocolsResourceBase):
|
||||
protocol = self.request_body_json.get('protocol', {})
|
||||
validation.lazy_validate(schema.protocol_create, protocol)
|
||||
protocol = self._normalize_dict(protocol)
|
||||
ref = PROVIDERS.federation_api.create_protocol(idp_id, protocol_id,
|
||||
protocol)
|
||||
ref = PROVIDERS.federation_api.create_protocol(
|
||||
idp_id, protocol_id, protocol
|
||||
)
|
||||
return self.wrap_member(ref), http.client.CREATED
|
||||
|
||||
def patch(self, idp_id, protocol_id):
|
||||
@ -233,8 +240,9 @@ class IDPProtocolsCRUDResource(_IdentityProvidersProtocolsResourceBase):
|
||||
ENFORCER.enforce_call(action='identity:update_protocol')
|
||||
protocol = self.request_body_json.get('protocol', {})
|
||||
validation.lazy_validate(schema.protocol_update, protocol)
|
||||
ref = PROVIDERS.federation_api.update_protocol(idp_id, protocol_id,
|
||||
protocol)
|
||||
ref = PROVIDERS.federation_api.update_protocol(
|
||||
idp_id, protocol_id, protocol
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
def delete(self, idp_id, protocol_id):
|
||||
@ -264,8 +272,9 @@ class MappingResource(_ResourceBase):
|
||||
HEAD/GET /OS-FEDERATION/mappings/{mapping_id}
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:get_mapping')
|
||||
return self.wrap_member(PROVIDERS.federation_api.get_mapping(
|
||||
mapping_id))
|
||||
return self.wrap_member(
|
||||
PROVIDERS.federation_api.get_mapping(mapping_id)
|
||||
)
|
||||
|
||||
def _list_mappings(self):
|
||||
"""List mappings.
|
||||
@ -276,22 +285,28 @@ class MappingResource(_ResourceBase):
|
||||
return self.wrap_collection(PROVIDERS.federation_api.list_mappings())
|
||||
|
||||
def _internal_normalize_and_validate_attribute_mapping(
|
||||
self, action_executed_message="created"):
|
||||
self, action_executed_message="created"
|
||||
):
|
||||
mapping = self.request_body_json.get('mapping', {})
|
||||
mapping = self._normalize_dict(mapping)
|
||||
|
||||
if not mapping.get('schema_version'):
|
||||
default_schema_version =\
|
||||
default_schema_version = (
|
||||
utils.get_default_attribute_mapping_schema_version()
|
||||
LOG.debug("A mapping [%s] was %s without providing a "
|
||||
"'schema_version'; therefore, we need to set one. The "
|
||||
"current default is [%s]. We will use this value for "
|
||||
"the attribute mapping being registered. It is "
|
||||
"recommended that one does not rely on this default "
|
||||
"value, as it can change, and the already persisted "
|
||||
"attribute mappings will remain with the previous "
|
||||
"default values.", mapping, action_executed_message,
|
||||
default_schema_version)
|
||||
)
|
||||
LOG.debug(
|
||||
"A mapping [%s] was %s without providing a "
|
||||
"'schema_version'; therefore, we need to set one. The "
|
||||
"current default is [%s]. We will use this value for "
|
||||
"the attribute mapping being registered. It is "
|
||||
"recommended that one does not rely on this default "
|
||||
"value, as it can change, and the already persisted "
|
||||
"attribute mappings will remain with the previous "
|
||||
"default values.",
|
||||
mapping,
|
||||
action_executed_message,
|
||||
default_schema_version,
|
||||
)
|
||||
mapping['schema_version'] = default_schema_version
|
||||
utils.validate_mapping_structure(mapping)
|
||||
return mapping
|
||||
@ -304,7 +319,8 @@ class MappingResource(_ResourceBase):
|
||||
ENFORCER.enforce_call(action='identity:create_mapping')
|
||||
|
||||
am = self._internal_normalize_and_validate_attribute_mapping(
|
||||
"registered")
|
||||
"registered"
|
||||
)
|
||||
mapping_ref = PROVIDERS.federation_api.create_mapping(mapping_id, am)
|
||||
|
||||
return self.wrap_member(mapping_ref), http.client.CREATED
|
||||
@ -334,8 +350,17 @@ class MappingResource(_ResourceBase):
|
||||
class ServiceProvidersResource(_ResourceBase):
|
||||
collection_key = 'service_providers'
|
||||
member_key = 'service_provider'
|
||||
_public_parameters = frozenset(['auth_url', 'id', 'enabled', 'description',
|
||||
'links', 'relay_state_prefix', 'sp_url'])
|
||||
_public_parameters = frozenset(
|
||||
[
|
||||
'auth_url',
|
||||
'id',
|
||||
'enabled',
|
||||
'description',
|
||||
'links',
|
||||
'relay_state_prefix',
|
||||
'sp_url',
|
||||
]
|
||||
)
|
||||
_id_path_param_name_override = 'sp_id'
|
||||
api_prefix = '/OS-FEDERATION'
|
||||
|
||||
@ -358,12 +383,14 @@ class ServiceProvidersResource(_ResourceBase):
|
||||
GET/HEAD /OS-FEDERATION/service_providers
|
||||
"""
|
||||
filters = ['id', 'enabled']
|
||||
ENFORCER.enforce_call(action='identity:list_service_providers',
|
||||
filters=filters)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_service_providers', filters=filters
|
||||
)
|
||||
hints = self.build_driver_hints(filters)
|
||||
refs = [self.filter_params(r)
|
||||
for r in
|
||||
PROVIDERS.federation_api.list_sps(hints=hints)]
|
||||
refs = [
|
||||
self.filter_params(r)
|
||||
for r in PROVIDERS.federation_api.list_sps(hints=hints)
|
||||
]
|
||||
return self.wrap_collection(refs, hints=hints)
|
||||
|
||||
def put(self, sp_id):
|
||||
@ -452,7 +479,7 @@ class OSFederationAuthResource(flask_restful.Resource):
|
||||
'methods': [protocol_id],
|
||||
protocol_id: {
|
||||
'identity_provider': idp_id,
|
||||
'protocol': protocol_id
|
||||
'protocol': protocol_id,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -476,17 +503,22 @@ class OSFederationAPI(ks_flask.APIBase):
|
||||
url='/saml2/metadata',
|
||||
resource_kwargs={},
|
||||
rel='metadata',
|
||||
resource_relation_func=_build_resource_relation),
|
||||
resource_relation_func=_build_resource_relation,
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=OSFederationAuthResource,
|
||||
url=('/identity_providers/<string:idp_id>/protocols/'
|
||||
'<string:protocol_id>/auth'),
|
||||
url=(
|
||||
'/identity_providers/<string:idp_id>/protocols/'
|
||||
'<string:protocol_id>/auth'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='identity_provider_protocol_auth',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={
|
||||
'idp_id': IDP_ID_PARAMETER_RELATION,
|
||||
'protocol_id': PROTOCOL_ID_PARAMETER_RELATION}),
|
||||
'protocol_id': PROTOCOL_ID_PARAMETER_RELATION,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@ -505,15 +537,17 @@ class OSFederationIdentityProvidersProtocolsAPI(ks_flask.APIBase):
|
||||
resource_mapping = [
|
||||
ks_flask.construct_resource_map(
|
||||
resource=IDPProtocolsCRUDResource,
|
||||
url=('/OS-FEDERATION/identity_providers/<string:idp_id>/protocols/'
|
||||
'<string:protocol_id>'),
|
||||
url=(
|
||||
'/OS-FEDERATION/identity_providers/<string:idp_id>/protocols/'
|
||||
'<string:protocol_id>'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='identity_provider_protocol',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={
|
||||
'idp_id': IDP_ID_PARAMETER_RELATION,
|
||||
'protocol_id': PROTOCOL_ID_PARAMETER_RELATION
|
||||
}
|
||||
'protocol_id': PROTOCOL_ID_PARAMETER_RELATION,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=IDPProtocolsListResource,
|
||||
@ -521,9 +555,7 @@ class OSFederationIdentityProvidersProtocolsAPI(ks_flask.APIBase):
|
||||
resource_kwargs={},
|
||||
rel='identity_provider_protocols',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={
|
||||
'idp_id': IDP_ID_PARAMETER_RELATION
|
||||
}
|
||||
path_vars={'idp_id': IDP_ID_PARAMETER_RELATION},
|
||||
),
|
||||
]
|
||||
|
||||
@ -549,5 +581,5 @@ APIs = (
|
||||
OSFederationIdentityProvidersAPI,
|
||||
OSFederationIdentityProvidersProtocolsAPI,
|
||||
OSFederationMappingsAPI,
|
||||
OSFederationServiceProvidersAPI
|
||||
OSFederationServiceProvidersAPI,
|
||||
)
|
||||
|
@ -32,9 +32,14 @@ LOG = log.getLogger(__name__)
|
||||
_build_resource_relation = json_home_relations.os_inherit_resource_rel_func
|
||||
|
||||
|
||||
def _build_enforcement_target_attr(role_id=None, user_id=None, group_id=None,
|
||||
project_id=None, domain_id=None,
|
||||
allow_non_existing=False):
|
||||
def _build_enforcement_target_attr(
|
||||
role_id=None,
|
||||
user_id=None,
|
||||
group_id=None,
|
||||
project_id=None,
|
||||
domain_id=None,
|
||||
allow_non_existing=False,
|
||||
):
|
||||
"""Check protection for role grant APIs.
|
||||
|
||||
The policy rule might want to inspect attributes of any of the entities
|
||||
@ -59,25 +64,33 @@ def _build_enforcement_target_attr(role_id=None, user_id=None, group_id=None,
|
||||
try:
|
||||
target['role'] = PROVIDERS.role_api.get_role(role_id)
|
||||
except exception.RoleNotFound:
|
||||
LOG.info('Role (%(role_id)s) not found, Enforcement target of '
|
||||
'`role` remaind empty', {'role_id': role_id})
|
||||
LOG.info(
|
||||
'Role (%(role_id)s) not found, Enforcement target of '
|
||||
'`role` remaind empty',
|
||||
{'role_id': role_id},
|
||||
)
|
||||
target['role'] = {}
|
||||
if user_id:
|
||||
try:
|
||||
target['user'] = PROVIDERS.identity_api.get_user(user_id)
|
||||
except exception.UserNotFound:
|
||||
if not allow_non_existing:
|
||||
LOG.info('User (%(user_id)s) was not found. Enforcement target'
|
||||
' of `user` remains empty.', {'user_id': user_id})
|
||||
LOG.info(
|
||||
'User (%(user_id)s) was not found. Enforcement target'
|
||||
' of `user` remains empty.',
|
||||
{'user_id': user_id},
|
||||
)
|
||||
target['user'] = {}
|
||||
else:
|
||||
try:
|
||||
target['group'] = PROVIDERS.identity_api.get_group(group_id)
|
||||
except exception.GroupNotFound:
|
||||
if not allow_non_existing:
|
||||
LOG.info('Group (%(group_id)s) was not found. Enforcement '
|
||||
'target of `group` remains empty.',
|
||||
{'group_id': group_id})
|
||||
LOG.info(
|
||||
'Group (%(group_id)s) was not found. Enforcement '
|
||||
'target of `group` remains empty.',
|
||||
{'group_id': group_id},
|
||||
)
|
||||
target['group'] = {}
|
||||
|
||||
# NOTE(lbragstad): This if/else check will need to be expanded in the
|
||||
@ -86,17 +99,21 @@ def _build_enforcement_target_attr(role_id=None, user_id=None, group_id=None,
|
||||
try:
|
||||
target['domain'] = PROVIDERS.resource_api.get_domain(domain_id)
|
||||
except exception.DomainNotFound:
|
||||
LOG.info('Domain (%(domain_id)s) was not found. Enforcement '
|
||||
'target of `domain` remains empty.',
|
||||
{'domain_id': domain_id})
|
||||
LOG.info(
|
||||
'Domain (%(domain_id)s) was not found. Enforcement '
|
||||
'target of `domain` remains empty.',
|
||||
{'domain_id': domain_id},
|
||||
)
|
||||
target['domain'] = {}
|
||||
elif project_id:
|
||||
try:
|
||||
target['project'] = PROVIDERS.resource_api.get_project(project_id)
|
||||
except exception.ProjectNotFound:
|
||||
LOG.info('Project (%(project_id)s) was not found. Enforcement '
|
||||
'target of `project` remains empty.',
|
||||
{'project_id': project_id})
|
||||
LOG.info(
|
||||
'Project (%(project_id)s) was not found. Enforcement '
|
||||
'target of `project` remains empty.',
|
||||
{'project_id': project_id},
|
||||
)
|
||||
target['project'] = {}
|
||||
|
||||
return target
|
||||
@ -111,13 +128,19 @@ class OSInheritDomainGroupRolesResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:check_grant',
|
||||
build_target=functools.partial(_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id,
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.get_grant(
|
||||
domain_id=domain_id, group_id=group_id, role_id=role_id,
|
||||
inherited_to_projects=True)
|
||||
domain_id=domain_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id,
|
||||
inherited_to_projects=True,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def put(self, domain_id, group_id, role_id):
|
||||
@ -128,13 +151,19 @@ class OSInheritDomainGroupRolesResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:create_grant',
|
||||
build_target=functools.partial(_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id,
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.create_grant(
|
||||
domain_id=domain_id, group_id=group_id, role_id=role_id,
|
||||
inherited_to_projects=True)
|
||||
domain_id=domain_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id,
|
||||
inherited_to_projects=True,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def delete(self, domain_id, group_id, role_id):
|
||||
@ -145,13 +174,19 @@ class OSInheritDomainGroupRolesResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:revoke_grant',
|
||||
build_target=functools.partial(_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id,
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.delete_grant(
|
||||
domain_id=domain_id, group_id=group_id, role_id=role_id,
|
||||
inherited_to_projects=True)
|
||||
domain_id=domain_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id,
|
||||
inherited_to_projects=True,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -164,13 +199,18 @@ class OSInheritDomainGroupRolesListResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_grants',
|
||||
build_target=functools.partial(_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
group_id=group_id))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
group_id=group_id,
|
||||
),
|
||||
)
|
||||
refs = PROVIDERS.assignment_api.list_grants(
|
||||
domain_id=domain_id, group_id=group_id, inherited_to_projects=True)
|
||||
domain_id=domain_id, group_id=group_id, inherited_to_projects=True
|
||||
)
|
||||
return ks_flask.ResourceBase.wrap_collection(
|
||||
refs, collection_name='roles')
|
||||
refs, collection_name='roles'
|
||||
)
|
||||
|
||||
|
||||
class OSInheritDomainUserRolesResource(flask_restful.Resource):
|
||||
@ -182,13 +222,19 @@ class OSInheritDomainUserRolesResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:check_grant',
|
||||
build_target=functools.partial(_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id,
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.get_grant(
|
||||
domain_id=domain_id, user_id=user_id, role_id=role_id,
|
||||
inherited_to_projects=True)
|
||||
domain_id=domain_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id,
|
||||
inherited_to_projects=True,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def put(self, domain_id, user_id, role_id):
|
||||
@ -199,13 +245,19 @@ class OSInheritDomainUserRolesResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:create_grant',
|
||||
build_target=functools.partial(_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id,
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.create_grant(
|
||||
domain_id=domain_id, user_id=user_id, role_id=role_id,
|
||||
inherited_to_projects=True)
|
||||
domain_id=domain_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id,
|
||||
inherited_to_projects=True,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def delete(self, domain_id, user_id, role_id):
|
||||
@ -216,13 +268,19 @@ class OSInheritDomainUserRolesResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:revoke_grant',
|
||||
build_target=functools.partial(_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id,
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.delete_grant(
|
||||
domain_id=domain_id, user_id=user_id, role_id=role_id,
|
||||
inherited_to_projects=True)
|
||||
domain_id=domain_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id,
|
||||
inherited_to_projects=True,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -235,13 +293,18 @@ class OSInheritDomainUserRolesListResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_grants',
|
||||
build_target=functools.partial(_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
user_id=user_id))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target_attr,
|
||||
domain_id=domain_id,
|
||||
user_id=user_id,
|
||||
),
|
||||
)
|
||||
refs = PROVIDERS.assignment_api.list_grants(
|
||||
domain_id=domain_id, user_id=user_id, inherited_to_projects=True)
|
||||
domain_id=domain_id, user_id=user_id, inherited_to_projects=True
|
||||
)
|
||||
return ks_flask.ResourceBase.wrap_collection(
|
||||
refs, collection_name='roles')
|
||||
refs, collection_name='roles'
|
||||
)
|
||||
|
||||
|
||||
class OSInheritProjectUserResource(flask_restful.Resource):
|
||||
@ -253,13 +316,19 @@ class OSInheritProjectUserResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:check_grant',
|
||||
build_target=functools.partial(_build_enforcement_target_attr,
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target_attr,
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id,
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.get_grant(
|
||||
project_id=project_id, user_id=user_id, role_id=role_id,
|
||||
inherited_to_projects=True)
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id,
|
||||
inherited_to_projects=True,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def put(self, project_id, user_id, role_id):
|
||||
@ -270,13 +339,19 @@ class OSInheritProjectUserResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:create_grant',
|
||||
build_target=functools.partial(_build_enforcement_target_attr,
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target_attr,
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id,
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.create_grant(
|
||||
project_id=project_id, user_id=user_id, role_id=role_id,
|
||||
inherited_to_projects=True)
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id,
|
||||
inherited_to_projects=True,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def delete(self, project_id, user_id, role_id):
|
||||
@ -287,13 +362,19 @@ class OSInheritProjectUserResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:revoke_grant',
|
||||
build_target=functools.partial(_build_enforcement_target_attr,
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target_attr,
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id,
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.delete_grant(
|
||||
project_id=project_id, user_id=user_id, role_id=role_id,
|
||||
inherited_to_projects=True)
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
role_id=role_id,
|
||||
inherited_to_projects=True,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -306,13 +387,19 @@ class OSInheritProjectGroupResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:check_grant',
|
||||
build_target=functools.partial(_build_enforcement_target_attr,
|
||||
project_id=project_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target_attr,
|
||||
project_id=project_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id,
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.get_grant(
|
||||
project_id=project_id, group_id=group_id, role_id=role_id,
|
||||
inherited_to_projects=True)
|
||||
project_id=project_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id,
|
||||
inherited_to_projects=True,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def put(self, project_id, group_id, role_id):
|
||||
@ -323,13 +410,19 @@ class OSInheritProjectGroupResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:create_grant',
|
||||
build_target=functools.partial(_build_enforcement_target_attr,
|
||||
project_id=project_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target_attr,
|
||||
project_id=project_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id,
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.create_grant(
|
||||
project_id=project_id, group_id=group_id, role_id=role_id,
|
||||
inherited_to_projects=True)
|
||||
project_id=project_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id,
|
||||
inherited_to_projects=True,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def delete(self, project_id, group_id, role_id):
|
||||
@ -340,13 +433,19 @@ class OSInheritProjectGroupResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:revoke_grant',
|
||||
build_target=functools.partial(_build_enforcement_target_attr,
|
||||
project_id=project_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id))
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target_attr,
|
||||
project_id=project_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id,
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.delete_grant(
|
||||
project_id=project_id, group_id=group_id, role_id=role_id,
|
||||
inherited_to_projects=True)
|
||||
project_id=project_id,
|
||||
group_id=group_id,
|
||||
role_id=role_id,
|
||||
inherited_to_projects=True,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -358,68 +457,92 @@ class OSInheritAPI(ks_flask.APIBase):
|
||||
resource_mapping = [
|
||||
ks_flask.construct_resource_map(
|
||||
resource=OSInheritDomainGroupRolesResource,
|
||||
url=('/domains/<string:domain_id>/groups/<string:group_id>/roles'
|
||||
'/<string:role_id>/inherited_to_projects'),
|
||||
url=(
|
||||
'/domains/<string:domain_id>/groups/<string:group_id>/roles'
|
||||
'/<string:role_id>/inherited_to_projects'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='domain_group_role_inherited_to_projects',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={
|
||||
'domain_id': json_home.Parameters.DOMAIN_ID,
|
||||
'group_id': json_home.Parameters.GROUP_ID,
|
||||
'role_id': json_home.Parameters.ROLE_ID}),
|
||||
'role_id': json_home.Parameters.ROLE_ID,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=OSInheritDomainGroupRolesListResource,
|
||||
url=('/domains/<string:domain_id>/groups/<string:group_id>/roles'
|
||||
'/inherited_to_projects'),
|
||||
url=(
|
||||
'/domains/<string:domain_id>/groups/<string:group_id>/roles'
|
||||
'/inherited_to_projects'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='domain_group_roles_inherited_to_projects',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={
|
||||
'domain_id': json_home.Parameters.DOMAIN_ID,
|
||||
'group_id': json_home.Parameters.GROUP_ID}),
|
||||
'group_id': json_home.Parameters.GROUP_ID,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=OSInheritDomainUserRolesResource,
|
||||
url=('/domains/<string:domain_id>/users/<string:user_id>/roles'
|
||||
'/<string:role_id>/inherited_to_projects'),
|
||||
url=(
|
||||
'/domains/<string:domain_id>/users/<string:user_id>/roles'
|
||||
'/<string:role_id>/inherited_to_projects'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='domain_user_role_inherited_to_projects',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={
|
||||
'domain_id': json_home.Parameters.DOMAIN_ID,
|
||||
'user_id': json_home.Parameters.USER_ID,
|
||||
'role_id': json_home.Parameters.ROLE_ID}),
|
||||
'role_id': json_home.Parameters.ROLE_ID,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=OSInheritDomainUserRolesListResource,
|
||||
url=('/domains/<string:domain_id>/users/<string:user_id>/roles'
|
||||
'/inherited_to_projects'),
|
||||
url=(
|
||||
'/domains/<string:domain_id>/users/<string:user_id>/roles'
|
||||
'/inherited_to_projects'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='domain_user_roles_inherited_to_projects',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={
|
||||
'domain_id': json_home.Parameters.DOMAIN_ID,
|
||||
'user_id': json_home.Parameters.USER_ID}),
|
||||
'user_id': json_home.Parameters.USER_ID,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=OSInheritProjectUserResource,
|
||||
url=('projects/<string:project_id>/users/<string:user_id>/roles'
|
||||
'/<string:role_id>/inherited_to_projects'),
|
||||
url=(
|
||||
'projects/<string:project_id>/users/<string:user_id>/roles'
|
||||
'/<string:role_id>/inherited_to_projects'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='project_user_role_inherited_to_projects',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
'user_id': json_home.Parameters.USER_ID,
|
||||
'role_id': json_home.Parameters.ROLE_ID}),
|
||||
'role_id': json_home.Parameters.ROLE_ID,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=OSInheritProjectGroupResource,
|
||||
url=('projects/<string:project_id>/groups/<string:group_id>/roles'
|
||||
'/<string:role_id>/inherited_to_projects'),
|
||||
url=(
|
||||
'projects/<string:project_id>/groups/<string:group_id>/roles'
|
||||
'/<string:role_id>/inherited_to_projects'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='project_group_role_inherited_to_projects',
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
'group_id': json_home.Parameters.GROUP_ID,
|
||||
'role_id': json_home.Parameters.ROLE_ID})
|
||||
'role_id': json_home.Parameters.ROLE_ID,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -46,7 +46,8 @@ _build_resource_relation = json_home_relations.os_oauth1_resource_rel_func
|
||||
_build_parameter_relation = json_home_relations.os_oauth1_parameter_rel_func
|
||||
|
||||
_ACCESS_TOKEN_ID_PARAMETER_RELATION = _build_parameter_relation(
|
||||
parameter_name='access_token_id')
|
||||
parameter_name='access_token_id'
|
||||
)
|
||||
|
||||
|
||||
def _normalize_role_list(authorize_roles):
|
||||
@ -55,8 +56,9 @@ def _normalize_role_list(authorize_roles):
|
||||
if role.get('id'):
|
||||
roles.add(role['id'])
|
||||
else:
|
||||
roles.add(PROVIDERS.role_api.get_unique_role_by_name(
|
||||
role['name'])['id'])
|
||||
roles.add(
|
||||
PROVIDERS.role_api.get_unique_role_by_name(role['name'])['id']
|
||||
)
|
||||
return roles
|
||||
|
||||
|
||||
@ -102,12 +104,14 @@ class ConsumerResource(ks_flask.ResourceBase):
|
||||
def post(self):
|
||||
ENFORCER.enforce_call(action='identity:create_consumer')
|
||||
consumer = (flask.request.get_json(force=True, silent=True) or {}).get(
|
||||
'consumer', {})
|
||||
'consumer', {}
|
||||
)
|
||||
consumer = self._normalize_dict(consumer)
|
||||
validation.lazy_validate(schema.consumer_create, consumer)
|
||||
consumer = self._assign_unique_id(consumer)
|
||||
ref = PROVIDERS.oauth_api.create_consumer(
|
||||
consumer, initiator=self.audit_initiator)
|
||||
consumer, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref), http.client.CREATED
|
||||
|
||||
def delete(self, consumer_id):
|
||||
@ -116,23 +120,25 @@ class ConsumerResource(ks_flask.ResourceBase):
|
||||
'Invalidating token cache because consumer %(consumer_id)s has '
|
||||
'been deleted. Authorization for users with OAuth tokens will be '
|
||||
'recalculated and enforced accordingly the next time they '
|
||||
'authenticate or validate a token.' %
|
||||
{'consumer_id': consumer_id}
|
||||
'authenticate or validate a token.' % {'consumer_id': consumer_id}
|
||||
)
|
||||
notifications.invalidate_token_cache_notification(reason)
|
||||
PROVIDERS.oauth_api.delete_consumer(
|
||||
consumer_id, initiator=self.audit_initiator)
|
||||
consumer_id, initiator=self.audit_initiator
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def patch(self, consumer_id):
|
||||
ENFORCER.enforce_call(action='identity:update_consumer')
|
||||
consumer = (flask.request.get_json(force=True, silent=True) or {}).get(
|
||||
'consumer', {})
|
||||
'consumer', {}
|
||||
)
|
||||
validation.lazy_validate(schema.consumer_update, consumer)
|
||||
consumer = self._normalize_dict(consumer)
|
||||
self._require_matching_id(consumer)
|
||||
ref = PROVIDERS.oauth_api.update_consumer(
|
||||
consumer_id, consumer, initiator=self.audit_initiator)
|
||||
consumer_id, consumer, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
|
||||
@ -142,14 +148,17 @@ class RequestTokenResource(_OAuth1ResourceBase):
|
||||
oauth_headers = oauth1.get_oauth_headers(flask.request.headers)
|
||||
consumer_id = oauth_headers.get('oauth_consumer_key')
|
||||
requested_project_id = flask.request.headers.get(
|
||||
'Requested-Project-Id')
|
||||
'Requested-Project-Id'
|
||||
)
|
||||
|
||||
if not consumer_id:
|
||||
raise exception.ValidationError(
|
||||
attribute='oauth_consumer_key', target='request')
|
||||
attribute='oauth_consumer_key', target='request'
|
||||
)
|
||||
if not requested_project_id:
|
||||
raise exception.ValidationError(
|
||||
attribute='Requested-Project-Id', target='request')
|
||||
attribute='Requested-Project-Id', target='request'
|
||||
)
|
||||
|
||||
# NOTE(stevemar): Ensure consumer and requested project exist
|
||||
PROVIDERS.resource_api.get_project(requested_project_id)
|
||||
@ -160,10 +169,14 @@ class RequestTokenResource(_OAuth1ResourceBase):
|
||||
req_headers.update(flask.request.headers)
|
||||
request_verifier = oauth1.RequestTokenEndpoint(
|
||||
request_validator=validator.OAuthValidator(),
|
||||
token_generator=oauth1.token_generator)
|
||||
token_generator=oauth1.token_generator,
|
||||
)
|
||||
h, b, s = request_verifier.create_request_token_response(
|
||||
url, http_method='POST', body=flask.request.args,
|
||||
headers=req_headers)
|
||||
url,
|
||||
http_method='POST',
|
||||
body=flask.request.args,
|
||||
headers=req_headers,
|
||||
)
|
||||
if not b:
|
||||
msg = _('Invalid signature')
|
||||
raise exception.Unauthorized(message=msg)
|
||||
@ -174,11 +187,13 @@ class RequestTokenResource(_OAuth1ResourceBase):
|
||||
consumer_id,
|
||||
requested_project_id,
|
||||
request_token_duration,
|
||||
initiator=notifications.build_audit_initiator())
|
||||
initiator=notifications.build_audit_initiator(),
|
||||
)
|
||||
|
||||
result = ('oauth_token=%(key)s&oauth_token_secret=%(secret)s'
|
||||
% {'key': token_ref['id'],
|
||||
'secret': token_ref['request_secret']})
|
||||
result = 'oauth_token=%(key)s&oauth_token_secret=%(secret)s' % {
|
||||
'key': token_ref['id'],
|
||||
'secret': token_ref['request_secret'],
|
||||
}
|
||||
|
||||
if CONF.oauth1.request_token_duration > 0:
|
||||
expiry_bit = '&oauth_expires_at=%s' % token_ref['expires_at']
|
||||
@ -199,35 +214,40 @@ class AccessTokenResource(_OAuth1ResourceBase):
|
||||
|
||||
if not consumer_id:
|
||||
raise exception.ValidationError(
|
||||
attribute='oauth_consumer_key', target='request')
|
||||
attribute='oauth_consumer_key', target='request'
|
||||
)
|
||||
if not request_token_id:
|
||||
raise exception.ValidationError(
|
||||
attribute='oauth_token', target='request')
|
||||
attribute='oauth_token', target='request'
|
||||
)
|
||||
if not oauth_verifier:
|
||||
raise exception.ValidationError(
|
||||
attribute='oauth_verifier', target='request')
|
||||
attribute='oauth_verifier', target='request'
|
||||
)
|
||||
|
||||
req_token = PROVIDERS.oauth_api.get_request_token(
|
||||
request_token_id)
|
||||
req_token = PROVIDERS.oauth_api.get_request_token(request_token_id)
|
||||
|
||||
expires_at = req_token['expires_at']
|
||||
if expires_at:
|
||||
now = timeutils.utcnow()
|
||||
expires = timeutils.normalize_time(
|
||||
timeutils.parse_isotime(expires_at))
|
||||
timeutils.parse_isotime(expires_at)
|
||||
)
|
||||
if now > expires:
|
||||
raise exception.Unauthorized(_('Request token is expired'))
|
||||
|
||||
url = _update_url_scheme()
|
||||
access_verifier = oauth1.AccessTokenEndpoint(
|
||||
request_validator=validator.OAuthValidator(),
|
||||
token_generator=oauth1.token_generator)
|
||||
token_generator=oauth1.token_generator,
|
||||
)
|
||||
try:
|
||||
h, b, s = access_verifier.create_access_token_response(
|
||||
url,
|
||||
http_method='POST',
|
||||
body=flask.request.args,
|
||||
headers=dict(flask.request.headers))
|
||||
headers=dict(flask.request.headers),
|
||||
)
|
||||
except NotImplementedError:
|
||||
# Client key or request token validation failed, since keystone
|
||||
# does not yet support dummy client or dummy request token,
|
||||
@ -239,10 +259,14 @@ class AccessTokenResource(_OAuth1ResourceBase):
|
||||
LOG.warning('Provided consumer does not exist.')
|
||||
raise exception.Unauthorized(message=msg)
|
||||
if req_token['consumer_id'] != consumer_id:
|
||||
msg = ('Provided consumer key does not match stored consumer '
|
||||
'key.')
|
||||
tr_msg = _('Provided consumer key does not match stored '
|
||||
'consumer key.')
|
||||
msg = (
|
||||
'Provided consumer key does not match stored consumer '
|
||||
'key.'
|
||||
)
|
||||
tr_msg = _(
|
||||
'Provided consumer key does not match stored '
|
||||
'consumer key.'
|
||||
)
|
||||
LOG.warning(msg)
|
||||
raise exception.Unauthorized(message=tr_msg)
|
||||
# The response body is empty since either one of the following reasons
|
||||
@ -266,11 +290,13 @@ class AccessTokenResource(_OAuth1ResourceBase):
|
||||
token_ref = PROVIDERS.oauth_api.create_access_token(
|
||||
request_token_id,
|
||||
access_token_duration,
|
||||
initiator=notifications.build_audit_initiator())
|
||||
initiator=notifications.build_audit_initiator(),
|
||||
)
|
||||
|
||||
result = ('oauth_token=%(key)s&oauth_token_secret=%(secret)s'
|
||||
% {'key': token_ref['id'],
|
||||
'secret': token_ref['access_secret']})
|
||||
result = 'oauth_token=%(key)s&oauth_token_secret=%(secret)s' % {
|
||||
'key': token_ref['id'],
|
||||
'secret': token_ref['access_secret'],
|
||||
}
|
||||
|
||||
if CONF.oauth1.access_token_duration > 0:
|
||||
expiry_bit = '&oauth_expires_at=%s' % (token_ref['expires_at'])
|
||||
@ -285,13 +311,17 @@ class AuthorizeResource(_OAuth1ResourceBase):
|
||||
def put(self, request_token_id):
|
||||
ENFORCER.enforce_call(action='identity:authorize_request_token')
|
||||
roles = (flask.request.get_json(force=True, silent=True) or {}).get(
|
||||
'roles', [])
|
||||
'roles', []
|
||||
)
|
||||
validation.lazy_validate(schema.request_token_authorize, roles)
|
||||
ctx = flask.request.environ[context.REQUEST_CONTEXT_ENV]
|
||||
if ctx.is_delegated_auth:
|
||||
raise exception.Forbidden(
|
||||
_('Cannot authorize a request token with a token issued via '
|
||||
'delegation.'))
|
||||
_(
|
||||
'Cannot authorize a request token with a token issued via '
|
||||
'delegation.'
|
||||
)
|
||||
)
|
||||
|
||||
req_token = PROVIDERS.oauth_api.get_request_token(request_token_id)
|
||||
|
||||
@ -299,7 +329,8 @@ class AuthorizeResource(_OAuth1ResourceBase):
|
||||
if expires_at:
|
||||
now = timeutils.utcnow()
|
||||
expires = timeutils.normalize_time(
|
||||
timeutils.parse_isotime(expires_at))
|
||||
timeutils.parse_isotime(expires_at)
|
||||
)
|
||||
if now > expires:
|
||||
raise exception.Unauthorized(_('Request token is expired'))
|
||||
|
||||
@ -308,7 +339,8 @@ class AuthorizeResource(_OAuth1ResourceBase):
|
||||
# verify the authorizing user has the roles
|
||||
try:
|
||||
auth_context = flask.request.environ[
|
||||
authorization.AUTH_CONTEXT_ENV]
|
||||
authorization.AUTH_CONTEXT_ENV
|
||||
]
|
||||
user_token_ref = auth_context['token']
|
||||
except KeyError:
|
||||
LOG.warning("Couldn't find the auth context.")
|
||||
@ -317,7 +349,8 @@ class AuthorizeResource(_OAuth1ResourceBase):
|
||||
user_id = user_token_ref.user_id
|
||||
project_id = req_token['requested_project_id']
|
||||
user_roles = PROVIDERS.assignment_api.get_roles_for_user_and_project(
|
||||
user_id, project_id)
|
||||
user_id, project_id
|
||||
)
|
||||
cred_set = set(user_roles)
|
||||
|
||||
if not cred_set.issuperset(authed_roles):
|
||||
@ -329,7 +362,8 @@ class AuthorizeResource(_OAuth1ResourceBase):
|
||||
|
||||
# finally authorize the token
|
||||
authed_token = PROVIDERS.oauth_api.authorize_request_token(
|
||||
request_token_id, user_id, role_ids)
|
||||
request_token_id, user_id, role_ids
|
||||
)
|
||||
|
||||
to_return = {'token': {'oauth_verifier': authed_token['verifier']}}
|
||||
return to_return
|
||||
@ -346,14 +380,14 @@ class OSAuth1API(ks_flask.APIBase):
|
||||
url='/request_token',
|
||||
resource_kwargs={},
|
||||
rel='request_tokens',
|
||||
resource_relation_func=_build_resource_relation
|
||||
resource_relation_func=_build_resource_relation,
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=AccessTokenResource,
|
||||
url='/access_token',
|
||||
rel='access_tokens',
|
||||
resource_kwargs={},
|
||||
resource_relation_func=_build_resource_relation
|
||||
resource_relation_func=_build_resource_relation,
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=AuthorizeResource,
|
||||
@ -363,8 +397,11 @@ class OSAuth1API(ks_flask.APIBase):
|
||||
resource_relation_func=_build_resource_relation,
|
||||
path_vars={
|
||||
'request_token_id': _build_parameter_relation(
|
||||
parameter_name='request_token_id')
|
||||
})]
|
||||
parameter_name='request_token_id'
|
||||
)
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
APIs = (OSAuth1API,)
|
||||
|
@ -42,7 +42,8 @@ class AccessTokenResource(ks_flask.ResourceBase):
|
||||
raise exception.OAuth2OtherError(
|
||||
int(http.client.METHOD_NOT_ALLOWED),
|
||||
http.client.responses[http.client.METHOD_NOT_ALLOWED],
|
||||
_('The method is not allowed for the requested URL.'))
|
||||
_('The method is not allowed for the requested URL.'),
|
||||
)
|
||||
|
||||
@ks_flask.unenforced_api
|
||||
def get(self):
|
||||
@ -80,18 +81,22 @@ class AccessTokenResource(ks_flask.ResourceBase):
|
||||
error = exception.OAuth2InvalidRequest(
|
||||
int(http.client.BAD_REQUEST),
|
||||
http.client.responses[http.client.BAD_REQUEST],
|
||||
_('The parameter grant_type is required.'))
|
||||
LOG.info('Get OAuth2.0 Access Token API: '
|
||||
f'{error.message_format}')
|
||||
_('The parameter grant_type is required.'),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: ' f'{error.message_format}'
|
||||
)
|
||||
raise error
|
||||
if grant_type != 'client_credentials':
|
||||
error = exception.OAuth2UnsupportedGrantType(
|
||||
int(http.client.BAD_REQUEST),
|
||||
http.client.responses[http.client.BAD_REQUEST],
|
||||
_('The parameter grant_type %s is not supported.'
|
||||
) % grant_type)
|
||||
LOG.info('Get OAuth2.0 Access Token API: '
|
||||
f'{error.message_format}')
|
||||
_('The parameter grant_type %s is not supported.')
|
||||
% grant_type,
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: ' f'{error.message_format}'
|
||||
)
|
||||
raise error
|
||||
|
||||
auth_method = ''
|
||||
@ -107,9 +112,12 @@ class AccessTokenResource(ks_flask.ResourceBase):
|
||||
error = exception.OAuth2InvalidClient(
|
||||
int(http.client.UNAUTHORIZED),
|
||||
http.client.responses[http.client.UNAUTHORIZED],
|
||||
_('Client authentication failed.'))
|
||||
LOG.info('Get OAuth2.0 Access Token API: '
|
||||
'failed to get a client_id from the request.')
|
||||
_('Client authentication failed.'),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: '
|
||||
'failed to get a client_id from the request.'
|
||||
)
|
||||
raise error
|
||||
if client_cert:
|
||||
auth_method = 'tls_client_auth'
|
||||
@ -125,9 +133,12 @@ class AccessTokenResource(ks_flask.ResourceBase):
|
||||
error = exception.OAuth2InvalidClient(
|
||||
int(http.client.UNAUTHORIZED),
|
||||
http.client.responses[http.client.UNAUTHORIZED],
|
||||
_('Client authentication failed.'))
|
||||
LOG.info('Get OAuth2.0 Access Token API: '
|
||||
'failed to get client credentials from the request.')
|
||||
_('Client authentication failed.'),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: '
|
||||
'failed to get client credentials from the request.'
|
||||
)
|
||||
raise error
|
||||
|
||||
def _client_secret_basic(self, client_id, client_secret):
|
||||
@ -137,8 +148,8 @@ class AccessTokenResource(ks_flask.ResourceBase):
|
||||
'methods': ['application_credential'],
|
||||
'application_credential': {
|
||||
'id': client_id,
|
||||
'secret': client_secret
|
||||
}
|
||||
'secret': client_secret,
|
||||
},
|
||||
}
|
||||
}
|
||||
try:
|
||||
@ -146,32 +157,37 @@ class AccessTokenResource(ks_flask.ResourceBase):
|
||||
except exception.Error as error:
|
||||
if error.code == 401:
|
||||
error = exception.OAuth2InvalidClient(
|
||||
error.code, error.title,
|
||||
str(error))
|
||||
error.code, error.title, str(error)
|
||||
)
|
||||
elif error.code == 400:
|
||||
error = exception.OAuth2InvalidRequest(
|
||||
error.code, error.title,
|
||||
str(error))
|
||||
error.code, error.title, str(error)
|
||||
)
|
||||
else:
|
||||
error = exception.OAuth2OtherError(
|
||||
error.code, error.title,
|
||||
error.code,
|
||||
error.title,
|
||||
'An unknown error occurred and failed to get an OAuth2.0 '
|
||||
'access token.')
|
||||
'access token.',
|
||||
)
|
||||
LOG.exception(error)
|
||||
raise error
|
||||
except Exception as error:
|
||||
error = exception.OAuth2OtherError(
|
||||
int(http.client.INTERNAL_SERVER_ERROR),
|
||||
http.client.responses[http.client.INTERNAL_SERVER_ERROR],
|
||||
str(error))
|
||||
str(error),
|
||||
)
|
||||
LOG.exception(error)
|
||||
raise error
|
||||
|
||||
resp = make_response({
|
||||
'access_token': token.id,
|
||||
'token_type': 'Bearer',
|
||||
'expires_in': CONF.token.expiration
|
||||
})
|
||||
resp = make_response(
|
||||
{
|
||||
'access_token': token.id,
|
||||
'token_type': 'Bearer',
|
||||
'expires_in': CONF.token.expiration,
|
||||
}
|
||||
)
|
||||
resp.status = '200 OK'
|
||||
return resp
|
||||
|
||||
@ -183,14 +199,18 @@ class AccessTokenResource(ks_flask.ResourceBase):
|
||||
error = exception.OAuth2InvalidClient(
|
||||
int(http.client.UNAUTHORIZED),
|
||||
http.client.responses[http.client.UNAUTHORIZED],
|
||||
_('Client authentication failed.'))
|
||||
LOG.info('Get OAuth2.0 Access Token API: '
|
||||
'mapping id %s is not found. ',
|
||||
mapping_id)
|
||||
_('Client authentication failed.'),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: '
|
||||
'mapping id %s is not found. ',
|
||||
mapping_id,
|
||||
)
|
||||
raise error
|
||||
|
||||
rule_processor = federation_utils.RuleProcessor(
|
||||
mapping.get('id'), mapping.get('rules'))
|
||||
mapping.get('id'), mapping.get('rules')
|
||||
)
|
||||
try:
|
||||
mapped_properties = rule_processor.process(cert_dn)
|
||||
except exception.Error as error:
|
||||
@ -198,24 +218,32 @@ class AccessTokenResource(ks_flask.ResourceBase):
|
||||
error = exception.OAuth2InvalidClient(
|
||||
int(http.client.UNAUTHORIZED),
|
||||
http.client.responses[http.client.UNAUTHORIZED],
|
||||
_('Client authentication failed.'))
|
||||
LOG.info('Get OAuth2.0 Access Token API: '
|
||||
'mapping rule process failed. '
|
||||
'mapping_id: %s, rules: %s, data: %s.',
|
||||
mapping_id, mapping.get('rules'),
|
||||
jsonutils.dumps(cert_dn))
|
||||
_('Client authentication failed.'),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: '
|
||||
'mapping rule process failed. '
|
||||
'mapping_id: %s, rules: %s, data: %s.',
|
||||
mapping_id,
|
||||
mapping.get('rules'),
|
||||
jsonutils.dumps(cert_dn),
|
||||
)
|
||||
raise error
|
||||
except Exception as error:
|
||||
LOG.exception(error)
|
||||
error = exception.OAuth2OtherError(
|
||||
int(http.client.INTERNAL_SERVER_ERROR),
|
||||
http.client.responses[http.client.INTERNAL_SERVER_ERROR],
|
||||
str(error))
|
||||
LOG.info('Get OAuth2.0 Access Token API: '
|
||||
'mapping rule process failed. '
|
||||
'mapping_id: %s, rules: %s, data: %s.',
|
||||
mapping_id, mapping.get('rules'),
|
||||
jsonutils.dumps(cert_dn))
|
||||
str(error),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: '
|
||||
'mapping rule process failed. '
|
||||
'mapping_id: %s, rules: %s, data: %s.',
|
||||
mapping_id,
|
||||
mapping.get('rules'),
|
||||
jsonutils.dumps(cert_dn),
|
||||
)
|
||||
raise error
|
||||
|
||||
mapping_user = mapped_properties.get('user', {})
|
||||
@ -229,50 +257,77 @@ class AccessTokenResource(ks_flask.ResourceBase):
|
||||
error = exception.OAuth2InvalidClient(
|
||||
int(http.client.UNAUTHORIZED),
|
||||
http.client.responses[http.client.UNAUTHORIZED],
|
||||
_('Client authentication failed.'))
|
||||
LOG.info('Get OAuth2.0 Access Token API: %s check failed. '
|
||||
'DN value: %s, DB value: %s.',
|
||||
'user name', mapping_user_name, user.get('name'))
|
||||
_('Client authentication failed.'),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: %s check failed. '
|
||||
'DN value: %s, DB value: %s.',
|
||||
'user name',
|
||||
mapping_user_name,
|
||||
user.get('name'),
|
||||
)
|
||||
raise error
|
||||
if mapping_user_id and mapping_user_id != user.get('id'):
|
||||
error = exception.OAuth2InvalidClient(
|
||||
int(http.client.UNAUTHORIZED),
|
||||
http.client.responses[http.client.UNAUTHORIZED],
|
||||
_('Client authentication failed.'))
|
||||
LOG.info('Get OAuth2.0 Access Token API: %s check failed. '
|
||||
'DN value: %s, DB value: %s.',
|
||||
'user id', mapping_user_id, user.get('id'))
|
||||
_('Client authentication failed.'),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: %s check failed. '
|
||||
'DN value: %s, DB value: %s.',
|
||||
'user id',
|
||||
mapping_user_id,
|
||||
user.get('id'),
|
||||
)
|
||||
raise error
|
||||
if mapping_user_email and mapping_user_email != user.get('email'):
|
||||
error = exception.OAuth2InvalidClient(
|
||||
int(http.client.UNAUTHORIZED),
|
||||
http.client.responses[http.client.UNAUTHORIZED],
|
||||
_('Client authentication failed.'))
|
||||
LOG.info('Get OAuth2.0 Access Token API: %s check failed. '
|
||||
'DN value: %s, DB value: %s.',
|
||||
'user email', mapping_user_email, user.get('email'))
|
||||
_('Client authentication failed.'),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: %s check failed. '
|
||||
'DN value: %s, DB value: %s.',
|
||||
'user email',
|
||||
mapping_user_email,
|
||||
user.get('email'),
|
||||
)
|
||||
raise error
|
||||
if (mapping_user_domain_id and
|
||||
mapping_user_domain_id != user_domain.get('id')):
|
||||
if (
|
||||
mapping_user_domain_id
|
||||
and mapping_user_domain_id != user_domain.get('id')
|
||||
):
|
||||
error = exception.OAuth2InvalidClient(
|
||||
int(http.client.UNAUTHORIZED),
|
||||
http.client.responses[http.client.UNAUTHORIZED],
|
||||
_('Client authentication failed.'))
|
||||
LOG.info('Get OAuth2.0 Access Token API: %s check failed. '
|
||||
'DN value: %s, DB value: %s.',
|
||||
'user domain id', mapping_user_domain_id,
|
||||
user_domain.get('id'))
|
||||
_('Client authentication failed.'),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: %s check failed. '
|
||||
'DN value: %s, DB value: %s.',
|
||||
'user domain id',
|
||||
mapping_user_domain_id,
|
||||
user_domain.get('id'),
|
||||
)
|
||||
raise error
|
||||
if (mapping_user_domain_name and
|
||||
mapping_user_domain_name != user_domain.get('name')):
|
||||
if (
|
||||
mapping_user_domain_name
|
||||
and mapping_user_domain_name != user_domain.get('name')
|
||||
):
|
||||
error = exception.OAuth2InvalidClient(
|
||||
int(http.client.UNAUTHORIZED),
|
||||
http.client.responses[http.client.UNAUTHORIZED],
|
||||
_('Client authentication failed.'))
|
||||
LOG.info('Get OAuth2.0 Access Token API: %s check failed. '
|
||||
'DN value: %s, DB value: %s.',
|
||||
'user domain name', mapping_user_domain_name,
|
||||
user_domain.get('name'))
|
||||
_('Client authentication failed.'),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: %s check failed. '
|
||||
'DN value: %s, DB value: %s.',
|
||||
'user domain name',
|
||||
mapping_user_domain_name,
|
||||
user_domain.get('name'),
|
||||
)
|
||||
raise error
|
||||
|
||||
def _tls_client_auth(self, client_id, client_cert):
|
||||
@ -283,9 +338,12 @@ class AccessTokenResource(ks_flask.ResourceBase):
|
||||
error = exception.OAuth2InvalidClient(
|
||||
int(http.client.UNAUTHORIZED),
|
||||
http.client.responses[http.client.UNAUTHORIZED],
|
||||
_('Client authentication failed.'))
|
||||
LOG.info('Get OAuth2.0 Access Token API: '
|
||||
'failed to get the subject DN from the certificate.')
|
||||
_('Client authentication failed.'),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: '
|
||||
'failed to get the subject DN from the certificate.'
|
||||
)
|
||||
raise error
|
||||
try:
|
||||
cert_issuer_dn = utils.get_certificate_issuer_dn(client_cert)
|
||||
@ -293,17 +351,22 @@ class AccessTokenResource(ks_flask.ResourceBase):
|
||||
error = exception.OAuth2InvalidClient(
|
||||
int(http.client.UNAUTHORIZED),
|
||||
http.client.responses[http.client.UNAUTHORIZED],
|
||||
_('Client authentication failed.'))
|
||||
LOG.info('Get OAuth2.0 Access Token API: '
|
||||
'failed to get the issuer DN from the certificate.')
|
||||
_('Client authentication failed.'),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: '
|
||||
'failed to get the issuer DN from the certificate.'
|
||||
)
|
||||
raise error
|
||||
client_cert_dn = {}
|
||||
for key in cert_subject_dn:
|
||||
client_cert_dn['SSL_CLIENT_SUBJECT_DN_%s' %
|
||||
key.upper()] = cert_subject_dn.get(key)
|
||||
client_cert_dn['SSL_CLIENT_SUBJECT_DN_%s' % key.upper()] = (
|
||||
cert_subject_dn.get(key)
|
||||
)
|
||||
for key in cert_issuer_dn:
|
||||
client_cert_dn['SSL_CLIENT_ISSUER_DN_%s' %
|
||||
key.upper()] = cert_issuer_dn.get(key)
|
||||
client_cert_dn['SSL_CLIENT_ISSUER_DN_%s' % key.upper()] = (
|
||||
cert_issuer_dn.get(key)
|
||||
)
|
||||
|
||||
try:
|
||||
user = PROVIDERS.identity_api.get_user(client_id)
|
||||
@ -311,24 +374,29 @@ class AccessTokenResource(ks_flask.ResourceBase):
|
||||
error = exception.OAuth2InvalidClient(
|
||||
int(http.client.UNAUTHORIZED),
|
||||
http.client.responses[http.client.UNAUTHORIZED],
|
||||
_('Client authentication failed.'))
|
||||
LOG.info('Get OAuth2.0 Access Token API: '
|
||||
'the user does not exist. user id: %s.',
|
||||
client_id)
|
||||
_('Client authentication failed.'),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: '
|
||||
'the user does not exist. user id: %s.',
|
||||
client_id,
|
||||
)
|
||||
raise error
|
||||
project_id = user.get('default_project_id')
|
||||
if not project_id:
|
||||
error = exception.OAuth2InvalidClient(
|
||||
int(http.client.UNAUTHORIZED),
|
||||
http.client.responses[http.client.UNAUTHORIZED],
|
||||
_('Client authentication failed.'))
|
||||
LOG.info('Get OAuth2.0 Access Token API: '
|
||||
'the user does not have default project. user id: %s.',
|
||||
client_id)
|
||||
_('Client authentication failed.'),
|
||||
)
|
||||
LOG.info(
|
||||
'Get OAuth2.0 Access Token API: '
|
||||
'the user does not have default project. user id: %s.',
|
||||
client_id,
|
||||
)
|
||||
raise error
|
||||
|
||||
user_domain = PROVIDERS.resource_api.get_domain(
|
||||
user.get('domain_id'))
|
||||
user_domain = PROVIDERS.resource_api.get_domain(user.get('domain_id'))
|
||||
self._check_mapped_properties(client_cert_dn, user, user_domain)
|
||||
thumbprint = utils.get_certificate_thumbprint(client_cert)
|
||||
LOG.debug(f'The mTLS certificate thumbprint: {thumbprint}')
|
||||
@ -337,37 +405,42 @@ class AccessTokenResource(ks_flask.ResourceBase):
|
||||
user_id=client_id,
|
||||
method_names=['oauth2_credential'],
|
||||
project_id=project_id,
|
||||
thumbprint=thumbprint
|
||||
thumbprint=thumbprint,
|
||||
)
|
||||
except exception.Error as error:
|
||||
if error.code == 401:
|
||||
error = exception.OAuth2InvalidClient(
|
||||
error.code, error.title,
|
||||
str(error))
|
||||
error.code, error.title, str(error)
|
||||
)
|
||||
elif error.code == 400:
|
||||
error = exception.OAuth2InvalidRequest(
|
||||
error.code, error.title,
|
||||
str(error))
|
||||
error.code, error.title, str(error)
|
||||
)
|
||||
else:
|
||||
error = exception.OAuth2OtherError(
|
||||
error.code, error.title,
|
||||
error.code,
|
||||
error.title,
|
||||
'An unknown error occurred and failed to get an OAuth2.0 '
|
||||
'access token.')
|
||||
'access token.',
|
||||
)
|
||||
LOG.exception(error)
|
||||
raise error
|
||||
except Exception as error:
|
||||
error = exception.OAuth2OtherError(
|
||||
int(http.client.INTERNAL_SERVER_ERROR),
|
||||
http.client.responses[http.client.INTERNAL_SERVER_ERROR],
|
||||
str(error))
|
||||
str(error),
|
||||
)
|
||||
LOG.exception(error)
|
||||
raise error
|
||||
|
||||
resp = make_response({
|
||||
'access_token': token.id,
|
||||
'token_type': 'Bearer',
|
||||
'expires_in': CONF.token.expiration
|
||||
})
|
||||
resp = make_response(
|
||||
{
|
||||
'access_token': token.id,
|
||||
'token_type': 'Bearer',
|
||||
'expires_in': CONF.token.expiration,
|
||||
}
|
||||
)
|
||||
resp.status = '200 OK'
|
||||
return resp
|
||||
|
||||
@ -383,8 +456,9 @@ class OSAuth2API(ks_flask.APIBase):
|
||||
url='/token',
|
||||
rel='token',
|
||||
resource_kwargs={},
|
||||
resource_relation_func=_build_resource_relation
|
||||
)]
|
||||
resource_relation_func=_build_resource_relation,
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
APIs = (OSAuth2API,)
|
||||
|
@ -39,10 +39,12 @@ class OSRevokeResource(flask_restful.Resource):
|
||||
if since:
|
||||
try:
|
||||
last_fetch = timeutils.normalize_time(
|
||||
timeutils.parse_isotime(since))
|
||||
timeutils.parse_isotime(since)
|
||||
)
|
||||
except ValueError:
|
||||
raise exception.ValidationError(
|
||||
message=_('invalidate date format %s') % since)
|
||||
message=_('invalidate date format %s') % since
|
||||
)
|
||||
# FIXME(notmorgan): The revocation events cannot have resource options
|
||||
# added to them or lazy-loaded relationships as long as to_dict
|
||||
# is called outside of an active session context. This API is unused
|
||||
@ -51,12 +53,14 @@ class OSRevokeResource(flask_restful.Resource):
|
||||
# events themselves.
|
||||
events = PROVIDERS.revoke_api.list_events(last_fetch=last_fetch)
|
||||
# Build the links by hand as the standard controller calls require ids
|
||||
response = {'events': [event.to_dict() for event in events],
|
||||
'links': {
|
||||
'next': None,
|
||||
'self': ks_flask.base_url(path='/OS-REVOKE/events'),
|
||||
'previous': None}
|
||||
}
|
||||
response = {
|
||||
'events': [event.to_dict() for event in events],
|
||||
'links': {
|
||||
'next': None,
|
||||
'self': ks_flask.base_url(path='/OS-REVOKE/events'),
|
||||
'previous': None,
|
||||
},
|
||||
}
|
||||
return response
|
||||
|
||||
|
||||
@ -71,7 +75,7 @@ class OSRevokeAPI(ks_flask.APIBase):
|
||||
url='/events',
|
||||
resource_kwargs={},
|
||||
rel='events',
|
||||
resource_relation_func=_build_resource_relation
|
||||
resource_relation_func=_build_resource_relation,
|
||||
)
|
||||
]
|
||||
|
||||
|
@ -31,16 +31,22 @@ class SimpleCertCAResource(flask_restful.Resource):
|
||||
@ks_flask.unenforced_api
|
||||
def get(self):
|
||||
raise exception.Gone(
|
||||
message=_('This API is no longer available due to the removal '
|
||||
'of support for PKI tokens.'))
|
||||
message=_(
|
||||
'This API is no longer available due to the removal '
|
||||
'of support for PKI tokens.'
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class SimpleCertListResource(flask_restful.Resource):
|
||||
@ks_flask.unenforced_api
|
||||
def get(self):
|
||||
raise exception.Gone(
|
||||
message=_('This API is no longer available due to the removal '
|
||||
'of support for PKI tokens.'))
|
||||
message=_(
|
||||
'This API is no longer available due to the removal '
|
||||
'of support for PKI tokens.'
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class SimpleCertAPI(ks_flask.APIBase):
|
||||
@ -53,13 +59,15 @@ class SimpleCertAPI(ks_flask.APIBase):
|
||||
url='/OS-SIMPLE-CERT/ca',
|
||||
resource_kwargs={},
|
||||
rel='ca_certificate',
|
||||
resource_relation_func=_build_resource_relation),
|
||||
resource_relation_func=_build_resource_relation,
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=SimpleCertListResource,
|
||||
url='/OS-SIMPLE-CERT/certificates',
|
||||
resource_kwargs={},
|
||||
rel='certificates',
|
||||
resource_relation_func=_build_resource_relation),
|
||||
resource_relation_func=_build_resource_relation,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -41,7 +41,7 @@ class PolicyResource(ks_flask.ResourceBase):
|
||||
|
||||
@versionutils.deprecated(
|
||||
as_of=versionutils.deprecated.QUEENS,
|
||||
what='identity:get_policy of the v3 Policy APIs'
|
||||
what='identity:get_policy of the v3 Policy APIs',
|
||||
)
|
||||
def _get_policy(self, policy_id):
|
||||
ENFORCER.enforce_call(action='identity:get_policy')
|
||||
@ -50,7 +50,7 @@ class PolicyResource(ks_flask.ResourceBase):
|
||||
|
||||
@versionutils.deprecated(
|
||||
as_of=versionutils.deprecated.QUEENS,
|
||||
what='identity:list_policies of the v3 Policy APIs'
|
||||
what='identity:list_policies of the v3 Policy APIs',
|
||||
)
|
||||
def _list_policies(self):
|
||||
ENFORCER.enforce_call(action='identity:list_policies')
|
||||
@ -61,7 +61,7 @@ class PolicyResource(ks_flask.ResourceBase):
|
||||
|
||||
@versionutils.deprecated(
|
||||
as_of=versionutils.deprecated.QUEENS,
|
||||
what='identity:create_policy of the v3 Policy APIs'
|
||||
what='identity:create_policy of the v3 Policy APIs',
|
||||
)
|
||||
def post(self):
|
||||
ENFORCER.enforce_call(action='identity:create_policy')
|
||||
@ -76,7 +76,7 @@ class PolicyResource(ks_flask.ResourceBase):
|
||||
|
||||
@versionutils.deprecated(
|
||||
as_of=versionutils.deprecated.QUEENS,
|
||||
what='identity:update_policy of the v3 Policy APIs'
|
||||
what='identity:update_policy of the v3 Policy APIs',
|
||||
)
|
||||
def patch(self, policy_id):
|
||||
ENFORCER.enforce_call(action='identity:update_policy')
|
||||
@ -90,7 +90,7 @@ class PolicyResource(ks_flask.ResourceBase):
|
||||
|
||||
@versionutils.deprecated(
|
||||
as_of=versionutils.deprecated.QUEENS,
|
||||
what='identity:delete_policy of the v3 Policy APIs'
|
||||
what='identity:delete_policy of the v3 Policy APIs',
|
||||
)
|
||||
def delete(self, policy_id):
|
||||
ENFORCER.enforce_call(action='identity:delete_policy')
|
||||
@ -231,45 +231,51 @@ class PolicyAPI(ks_flask.APIBase):
|
||||
resource_kwargs={},
|
||||
rel='policy_endpoints',
|
||||
path_vars={'policy_id': json_home.Parameters.POLICY_ID},
|
||||
resource_relation_func=_resource_rel_func
|
||||
resource_relation_func=_resource_rel_func,
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=EndpointPolicyAssociations,
|
||||
url=('/policies/<string:policy_id>/OS-ENDPOINT-POLICY/'
|
||||
'endpoints/<string:endpoint_id>'),
|
||||
url=(
|
||||
'/policies/<string:policy_id>/OS-ENDPOINT-POLICY/'
|
||||
'endpoints/<string:endpoint_id>'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='endpoint_policy_association',
|
||||
path_vars={
|
||||
'policy_id': json_home.Parameters.POLICY_ID,
|
||||
'endpoint_id': json_home.Parameters.ENDPOINT_ID
|
||||
'endpoint_id': json_home.Parameters.ENDPOINT_ID,
|
||||
},
|
||||
resource_relation_func=_resource_rel_func
|
||||
resource_relation_func=_resource_rel_func,
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=ServicePolicyAssociations,
|
||||
url=('/policies/<string:policy_id>/OS-ENDPOINT-POLICY/'
|
||||
'services/<string:service_id>'),
|
||||
url=(
|
||||
'/policies/<string:policy_id>/OS-ENDPOINT-POLICY/'
|
||||
'services/<string:service_id>'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='service_policy_association',
|
||||
path_vars={
|
||||
'policy_id': json_home.Parameters.POLICY_ID,
|
||||
'service_id': json_home.Parameters.SERVICE_ID
|
||||
'service_id': json_home.Parameters.SERVICE_ID,
|
||||
},
|
||||
resource_relation_func=_resource_rel_func
|
||||
resource_relation_func=_resource_rel_func,
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=ServiceRegionPolicyAssociations,
|
||||
url=('/policies/<string:policy_id>/OS-ENDPOINT-POLICY/'
|
||||
'services/<string:service_id>/regions/<string:region_id>'),
|
||||
url=(
|
||||
'/policies/<string:policy_id>/OS-ENDPOINT-POLICY/'
|
||||
'services/<string:service_id>/regions/<string:region_id>'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='region_and_service_policy_association',
|
||||
path_vars={
|
||||
'policy_id': json_home.Parameters.POLICY_ID,
|
||||
'service_id': json_home.Parameters.SERVICE_ID,
|
||||
'region_id': json_home.Parameters.REGION_ID
|
||||
'region_id': json_home.Parameters.REGION_ID,
|
||||
},
|
||||
resource_relation_func=_resource_rel_func
|
||||
)
|
||||
resource_relation_func=_resource_rel_func,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -50,7 +50,8 @@ class ProjectResource(ks_flask.ResourceBase):
|
||||
collection_key = 'projects'
|
||||
member_key = 'project'
|
||||
get_member_from_driver = PROVIDERS.deferred_provider_lookup(
|
||||
api='resource_api', method='get_project')
|
||||
api='resource_api', method='get_project'
|
||||
)
|
||||
|
||||
def _expand_project_ref(self, ref):
|
||||
parents_as_list = self.query_filter_is_true('parents_as_list')
|
||||
@ -63,21 +64,25 @@ class ProjectResource(ks_flask.ResourceBase):
|
||||
|
||||
# parents_as_list and parents_as_ids are mutually exclusive
|
||||
if parents_as_list and parents_as_ids:
|
||||
msg = _('Cannot use parents_as_list and parents_as_ids query '
|
||||
'params at the same time.')
|
||||
msg = _(
|
||||
'Cannot use parents_as_list and parents_as_ids query '
|
||||
'params at the same time.'
|
||||
)
|
||||
raise exception.ValidationError(msg)
|
||||
|
||||
# subtree_as_list and subtree_as_ids are mutually exclusive
|
||||
if subtree_as_list and subtree_as_ids:
|
||||
msg = _('Cannot use subtree_as_list and subtree_as_ids query '
|
||||
'params at the same time.')
|
||||
msg = _(
|
||||
'Cannot use subtree_as_list and subtree_as_ids query '
|
||||
'params at the same time.'
|
||||
)
|
||||
raise exception.ValidationError(msg)
|
||||
|
||||
if parents_as_list:
|
||||
parents = PROVIDERS.resource_api.list_project_parents(
|
||||
ref['id'], self.oslo_context.user_id, include_limits)
|
||||
ref['parents'] = [self.wrap_member(p)
|
||||
for p in parents]
|
||||
ref['id'], self.oslo_context.user_id, include_limits
|
||||
)
|
||||
ref['parents'] = [self.wrap_member(p) for p in parents]
|
||||
elif parents_as_ids:
|
||||
ref['parents'] = PROVIDERS.resource_api.get_project_parents_as_ids(
|
||||
ref
|
||||
@ -85,9 +90,9 @@ class ProjectResource(ks_flask.ResourceBase):
|
||||
|
||||
if subtree_as_list:
|
||||
subtree = PROVIDERS.resource_api.list_projects_in_subtree(
|
||||
ref['id'], self.oslo_context.user_id, include_limits)
|
||||
ref['subtree'] = [self.wrap_member(p)
|
||||
for p in subtree]
|
||||
ref['id'], self.oslo_context.user_id, include_limits
|
||||
)
|
||||
ref['subtree'] = [self.wrap_member(p) for p in subtree]
|
||||
elif subtree_as_ids:
|
||||
ref['subtree'] = (
|
||||
PROVIDERS.resource_api.get_projects_in_subtree_as_ids(
|
||||
@ -102,7 +107,7 @@ class ProjectResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:get_project',
|
||||
build_target=_build_project_target_enforcement
|
||||
build_target=_build_project_target_enforcement,
|
||||
)
|
||||
project = PROVIDERS.resource_api.get_project(project_id)
|
||||
self._expand_project_ref(project)
|
||||
@ -117,9 +122,11 @@ class ProjectResource(ks_flask.ResourceBase):
|
||||
target = None
|
||||
if self.oslo_context.domain_id:
|
||||
target = {'domain_id': self.oslo_context.domain_id}
|
||||
ENFORCER.enforce_call(action='identity:list_projects',
|
||||
filters=filters,
|
||||
target_attr=target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_projects',
|
||||
filters=filters,
|
||||
target_attr=target,
|
||||
)
|
||||
hints = self.build_driver_hints(filters)
|
||||
|
||||
# If 'is_domain' has not been included as a query, we default it to
|
||||
@ -174,9 +181,8 @@ class ProjectResource(ks_flask.ResourceBase):
|
||||
project = self._normalize_dict(project)
|
||||
try:
|
||||
ref = PROVIDERS.resource_api.create_project(
|
||||
project['id'],
|
||||
project,
|
||||
initiator=self.audit_initiator)
|
||||
project['id'], project, initiator=self.audit_initiator
|
||||
)
|
||||
except (exception.DomainNotFound, exception.ProjectNotFound) as e:
|
||||
raise exception.ValidationError(e)
|
||||
return self.wrap_member(ref), http.client.CREATED
|
||||
@ -188,15 +194,14 @@ class ProjectResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:update_project',
|
||||
build_target=_build_project_target_enforcement
|
||||
build_target=_build_project_target_enforcement,
|
||||
)
|
||||
project = self.request_body_json.get('project', {})
|
||||
validation.lazy_validate(schema.project_update, project)
|
||||
self._require_matching_id(project)
|
||||
ref = PROVIDERS.resource_api.update_project(
|
||||
project_id,
|
||||
project,
|
||||
initiator=self.audit_initiator)
|
||||
project_id, project, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
def delete(self, project_id):
|
||||
@ -206,11 +211,11 @@ class ProjectResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:delete_project',
|
||||
build_target=_build_project_target_enforcement
|
||||
build_target=_build_project_target_enforcement,
|
||||
)
|
||||
PROVIDERS.resource_api.delete_project(
|
||||
project_id,
|
||||
initiator=self.audit_initiator)
|
||||
project_id, initiator=self.audit_initiator
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -218,7 +223,8 @@ class _ProjectTagResourceBase(ks_flask.ResourceBase):
|
||||
collection_key = 'projects'
|
||||
member_key = 'tags'
|
||||
get_member_from_driver = PROVIDERS.deferred_provider_lookup(
|
||||
api='resource_api', method='get_project_tag')
|
||||
api='resource_api', method='get_project_tag'
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def wrap_member(cls, ref, collection_name=None, member_name=None):
|
||||
@ -226,7 +232,7 @@ class _ProjectTagResourceBase(ks_flask.ResourceBase):
|
||||
# NOTE(gagehugo): Overriding this due to how the common controller
|
||||
# expects the ref to have an id, which for tags it does not.
|
||||
new_ref = {'links': {'self': ks_flask.full_url()}}
|
||||
new_ref[member_name] = (ref or [])
|
||||
new_ref[member_name] = ref or []
|
||||
return new_ref
|
||||
|
||||
|
||||
@ -238,7 +244,7 @@ class ProjectTagsResource(_ProjectTagResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_project_tags',
|
||||
build_target=_build_project_target_enforcement
|
||||
build_target=_build_project_target_enforcement,
|
||||
)
|
||||
ref = PROVIDERS.resource_api.list_project_tags(project_id)
|
||||
return self.wrap_member(ref)
|
||||
@ -250,12 +256,13 @@ class ProjectTagsResource(_ProjectTagResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:update_project_tags',
|
||||
build_target=_build_project_target_enforcement
|
||||
build_target=_build_project_target_enforcement,
|
||||
)
|
||||
tags = self.request_body_json.get('tags', {})
|
||||
validation.lazy_validate(schema.project_tags_update, tags)
|
||||
ref = PROVIDERS.resource_api.update_project_tags(
|
||||
project_id, tags, initiator=self.audit_initiator)
|
||||
project_id, tags, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
def delete(self, project_id):
|
||||
@ -265,7 +272,7 @@ class ProjectTagsResource(_ProjectTagResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:delete_project_tags',
|
||||
build_target=_build_project_target_enforcement
|
||||
build_target=_build_project_target_enforcement,
|
||||
)
|
||||
PROVIDERS.resource_api.update_project_tags(project_id, [])
|
||||
return None, http.client.NO_CONTENT
|
||||
@ -291,7 +298,7 @@ class ProjectTagResource(_ProjectTagResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:create_project_tag',
|
||||
build_target=_build_project_target_enforcement
|
||||
build_target=_build_project_target_enforcement,
|
||||
)
|
||||
validation.lazy_validate(schema.project_tag_create, value)
|
||||
# Check if we will exceed the max number of tags on this project
|
||||
@ -299,9 +306,7 @@ class ProjectTagResource(_ProjectTagResourceBase):
|
||||
tags.append(value)
|
||||
validation.lazy_validate(schema.project_tags_update, tags)
|
||||
PROVIDERS.resource_api.create_project_tag(
|
||||
project_id,
|
||||
value,
|
||||
initiator=self.audit_initiator
|
||||
project_id, value, initiator=self.audit_initiator
|
||||
)
|
||||
url = '/'.join((ks_flask.base_url(), project_id, 'tags', value))
|
||||
response = flask.make_response('', http.client.CREATED)
|
||||
@ -315,7 +320,7 @@ class ProjectTagResource(_ProjectTagResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:delete_project_tag',
|
||||
build_target=_build_project_target_enforcement
|
||||
build_target=_build_project_target_enforcement,
|
||||
)
|
||||
PROVIDERS.resource_api.delete_project_tag(project_id, value)
|
||||
return None, http.client.NO_CONTENT
|
||||
@ -325,17 +330,22 @@ class _ProjectGrantResourceBase(ks_flask.ResourceBase):
|
||||
collection_key = 'roles'
|
||||
member_key = 'role'
|
||||
get_member_from_driver = PROVIDERS.deferred_provider_lookup(
|
||||
api='role_api', method='get_role')
|
||||
api='role_api', method='get_role'
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _check_if_inherited():
|
||||
return flask.request.path.endswith('/inherited_to_projects')
|
||||
|
||||
@staticmethod
|
||||
def _build_enforcement_target_attr(role_id=None, user_id=None,
|
||||
group_id=None, domain_id=None,
|
||||
project_id=None,
|
||||
allow_non_existing=False):
|
||||
def _build_enforcement_target_attr(
|
||||
role_id=None,
|
||||
user_id=None,
|
||||
group_id=None,
|
||||
domain_id=None,
|
||||
project_id=None,
|
||||
allow_non_existing=False,
|
||||
):
|
||||
ref = {}
|
||||
if role_id:
|
||||
ref['role'] = PROVIDERS.role_api.get_role(role_id)
|
||||
@ -368,13 +378,19 @@ class ProjectUserGrantResource(_ProjectGrantResourceBase):
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:check_grant',
|
||||
build_target=functools.partial(
|
||||
self._build_enforcement_target_attr, role_id=role_id,
|
||||
project_id=project_id, user_id=user_id)
|
||||
self._build_enforcement_target_attr,
|
||||
role_id=role_id,
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
),
|
||||
)
|
||||
inherited = self._check_if_inherited()
|
||||
PROVIDERS.assignment_api.get_grant(
|
||||
role_id=role_id, user_id=user_id, project_id=project_id,
|
||||
inherited_to_projects=inherited)
|
||||
role_id=role_id,
|
||||
user_id=user_id,
|
||||
project_id=project_id,
|
||||
inherited_to_projects=inherited,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def put(self, project_id, user_id, role_id):
|
||||
@ -386,12 +402,19 @@ class ProjectUserGrantResource(_ProjectGrantResourceBase):
|
||||
action='identity:create_grant',
|
||||
build_target=functools.partial(
|
||||
self._build_enforcement_target_attr,
|
||||
role_id=role_id, project_id=project_id, user_id=user_id)
|
||||
role_id=role_id,
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
),
|
||||
)
|
||||
inherited = self._check_if_inherited()
|
||||
PROVIDERS.assignment_api.create_grant(
|
||||
role_id=role_id, user_id=user_id, project_id=project_id,
|
||||
inherited_to_projects=inherited, initiator=self.audit_initiator)
|
||||
role_id=role_id,
|
||||
user_id=user_id,
|
||||
project_id=project_id,
|
||||
inherited_to_projects=inherited,
|
||||
initiator=self.audit_initiator,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def delete(self, project_id, user_id, role_id):
|
||||
@ -403,13 +426,20 @@ class ProjectUserGrantResource(_ProjectGrantResourceBase):
|
||||
action='identity:revoke_grant',
|
||||
build_target=functools.partial(
|
||||
self._build_enforcement_target_attr,
|
||||
role_id=role_id, user_id=user_id, project_id=project_id,
|
||||
allow_non_existing=True)
|
||||
role_id=role_id,
|
||||
user_id=user_id,
|
||||
project_id=project_id,
|
||||
allow_non_existing=True,
|
||||
),
|
||||
)
|
||||
inherited = self._check_if_inherited()
|
||||
PROVIDERS.assignment_api.delete_grant(
|
||||
role_id=role_id, user_id=user_id, project_id=project_id,
|
||||
inherited_to_projects=inherited, initiator=self.audit_initiator)
|
||||
role_id=role_id,
|
||||
user_id=user_id,
|
||||
project_id=project_id,
|
||||
inherited_to_projects=inherited,
|
||||
initiator=self.audit_initiator,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -423,12 +453,16 @@ class ProjectUserListGrantResource(_ProjectGrantResourceBase):
|
||||
action='identity:list_grants',
|
||||
build_target=functools.partial(
|
||||
self._build_enforcement_target_attr,
|
||||
project_id=project_id, user_id=user_id)
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
),
|
||||
)
|
||||
inherited = self._check_if_inherited()
|
||||
refs = PROVIDERS.assignment_api.list_grants(
|
||||
user_id=user_id, project_id=project_id,
|
||||
inherited_to_projects=inherited)
|
||||
user_id=user_id,
|
||||
project_id=project_id,
|
||||
inherited_to_projects=inherited,
|
||||
)
|
||||
return self.wrap_collection(refs)
|
||||
|
||||
|
||||
@ -441,13 +475,19 @@ class ProjectGroupGrantResource(_ProjectGrantResourceBase):
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:check_grant',
|
||||
build_target=functools.partial(
|
||||
self._build_enforcement_target_attr, role_id=role_id,
|
||||
project_id=project_id, group_id=group_id)
|
||||
self._build_enforcement_target_attr,
|
||||
role_id=role_id,
|
||||
project_id=project_id,
|
||||
group_id=group_id,
|
||||
),
|
||||
)
|
||||
inherited = self._check_if_inherited()
|
||||
PROVIDERS.assignment_api.get_grant(
|
||||
role_id=role_id, group_id=group_id, project_id=project_id,
|
||||
inherited_to_projects=inherited)
|
||||
role_id=role_id,
|
||||
group_id=group_id,
|
||||
project_id=project_id,
|
||||
inherited_to_projects=inherited,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def put(self, project_id, group_id, role_id):
|
||||
@ -459,12 +499,19 @@ class ProjectGroupGrantResource(_ProjectGrantResourceBase):
|
||||
action='identity:create_grant',
|
||||
build_target=functools.partial(
|
||||
self._build_enforcement_target_attr,
|
||||
role_id=role_id, project_id=project_id, group_id=group_id)
|
||||
role_id=role_id,
|
||||
project_id=project_id,
|
||||
group_id=group_id,
|
||||
),
|
||||
)
|
||||
inherited = self._check_if_inherited()
|
||||
PROVIDERS.assignment_api.create_grant(
|
||||
role_id=role_id, group_id=group_id, project_id=project_id,
|
||||
inherited_to_projects=inherited, initiator=self.audit_initiator)
|
||||
role_id=role_id,
|
||||
group_id=group_id,
|
||||
project_id=project_id,
|
||||
inherited_to_projects=inherited,
|
||||
initiator=self.audit_initiator,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def delete(self, project_id, group_id, role_id):
|
||||
@ -476,13 +523,20 @@ class ProjectGroupGrantResource(_ProjectGrantResourceBase):
|
||||
action='identity:revoke_grant',
|
||||
build_target=functools.partial(
|
||||
self._build_enforcement_target_attr,
|
||||
role_id=role_id, group_id=group_id, project_id=project_id,
|
||||
allow_non_existing=True)
|
||||
role_id=role_id,
|
||||
group_id=group_id,
|
||||
project_id=project_id,
|
||||
allow_non_existing=True,
|
||||
),
|
||||
)
|
||||
inherited = self._check_if_inherited()
|
||||
PROVIDERS.assignment_api.delete_grant(
|
||||
role_id=role_id, group_id=group_id, project_id=project_id,
|
||||
inherited_to_projects=inherited, initiator=self.audit_initiator)
|
||||
role_id=role_id,
|
||||
group_id=group_id,
|
||||
project_id=project_id,
|
||||
inherited_to_projects=inherited,
|
||||
initiator=self.audit_initiator,
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -496,12 +550,16 @@ class ProjectGroupListGrantResource(_ProjectGrantResourceBase):
|
||||
action='identity:list_grants',
|
||||
build_target=functools.partial(
|
||||
self._build_enforcement_target_attr,
|
||||
project_id=project_id, group_id=group_id)
|
||||
project_id=project_id,
|
||||
group_id=group_id,
|
||||
),
|
||||
)
|
||||
inherited = self._check_if_inherited()
|
||||
refs = PROVIDERS.assignment_api.list_grants(
|
||||
group_id=group_id, project_id=project_id,
|
||||
inherited_to_projects=inherited)
|
||||
group_id=group_id,
|
||||
project_id=project_id,
|
||||
inherited_to_projects=inherited,
|
||||
)
|
||||
return self.wrap_collection(refs)
|
||||
|
||||
|
||||
@ -515,8 +573,7 @@ class ProjectAPI(ks_flask.APIBase):
|
||||
url='/projects/<string:project_id>/tags',
|
||||
resource_kwargs={},
|
||||
rel='project_tags',
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID}
|
||||
path_vars={'project_id': json_home.Parameters.PROJECT_ID},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=ProjectTagResource,
|
||||
@ -525,18 +582,21 @@ class ProjectAPI(ks_flask.APIBase):
|
||||
rel='project_tags',
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
'value': json_home.Parameters.TAG_VALUE}
|
||||
'value': json_home.Parameters.TAG_VALUE,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=ProjectUserGrantResource,
|
||||
url=('/projects/<string:project_id>/users/<string:user_id>/'
|
||||
'roles/<string:role_id>'),
|
||||
url=(
|
||||
'/projects/<string:project_id>/users/<string:user_id>/'
|
||||
'roles/<string:role_id>'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='project_user_role',
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
'user_id': json_home.Parameters.USER_ID,
|
||||
'role_id': json_home.Parameters.ROLE_ID
|
||||
'role_id': json_home.Parameters.ROLE_ID,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
@ -546,19 +606,21 @@ class ProjectAPI(ks_flask.APIBase):
|
||||
rel='project_user_roles',
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
'user_id': json_home.Parameters.USER_ID
|
||||
}
|
||||
'user_id': json_home.Parameters.USER_ID,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=ProjectGroupGrantResource,
|
||||
url=('/projects/<string:project_id>/groups/<string:group_id>/'
|
||||
'roles/<string:role_id>'),
|
||||
url=(
|
||||
'/projects/<string:project_id>/groups/<string:group_id>/'
|
||||
'roles/<string:role_id>'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='project_group_role',
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
'group_id': json_home.Parameters.GROUP_ID,
|
||||
'role_id': json_home.Parameters.ROLE_ID
|
||||
'role_id': json_home.Parameters.ROLE_ID,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
@ -568,7 +630,7 @@ class ProjectAPI(ks_flask.APIBase):
|
||||
rel='project_group_roles',
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
'group_id': json_home.Parameters.GROUP_ID
|
||||
'group_id': json_home.Parameters.GROUP_ID,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
@ -58,7 +58,8 @@ class RegionResource(ks_flask.ResourceBase):
|
||||
# both ways.
|
||||
region = self._assign_unique_id(region)
|
||||
ref = PROVIDERS.catalog_api.create_region(
|
||||
region, initiator=self.audit_initiator)
|
||||
region, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref), http.client.CREATED
|
||||
|
||||
def put(self, region_id):
|
||||
@ -70,13 +71,16 @@ class RegionResource(ks_flask.ResourceBase):
|
||||
region['id'] = region_id
|
||||
elif region_id != region.get('id'):
|
||||
raise exception.ValidationError(
|
||||
_('Conflicting region IDs specified: '
|
||||
'"%(url_id)s" != "%(ref_id)s"') % {
|
||||
'url_id': region_id,
|
||||
'ref_id': region['id']})
|
||||
_(
|
||||
'Conflicting region IDs specified: '
|
||||
'"%(url_id)s" != "%(ref_id)s"'
|
||||
)
|
||||
% {'url_id': region_id, 'ref_id': region['id']}
|
||||
)
|
||||
|
||||
ref = PROVIDERS.catalog_api.create_region(
|
||||
region, initiator=self.audit_initiator)
|
||||
region, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref), http.client.CREATED
|
||||
|
||||
def patch(self, region_id):
|
||||
@ -84,13 +88,20 @@ class RegionResource(ks_flask.ResourceBase):
|
||||
region = self.request_body_json.get('region')
|
||||
validation.lazy_validate(schema.region_update, region)
|
||||
self._require_matching_id(region)
|
||||
return self.wrap_member(PROVIDERS.catalog_api.update_region(
|
||||
region_id, region, initiator=self.audit_initiator))
|
||||
return self.wrap_member(
|
||||
PROVIDERS.catalog_api.update_region(
|
||||
region_id, region, initiator=self.audit_initiator
|
||||
)
|
||||
)
|
||||
|
||||
def delete(self, region_id):
|
||||
ENFORCER.enforce_call(action='identity:delete_region')
|
||||
return PROVIDERS.catalog_api.delete_region(
|
||||
region_id, initiator=self.audit_initiator), http.client.NO_CONTENT
|
||||
return (
|
||||
PROVIDERS.catalog_api.delete_region(
|
||||
region_id, initiator=self.audit_initiator
|
||||
),
|
||||
http.client.NO_CONTENT,
|
||||
)
|
||||
|
||||
|
||||
class RegionAPI(ks_flask.APIBase):
|
||||
|
@ -35,13 +35,15 @@ class RegisteredLimitResource(ks_flask.ResourceBase):
|
||||
def _get_registered_limit(self, registered_limit_id):
|
||||
ENFORCER.enforce_call(action='identity:get_registered_limit')
|
||||
ref = PROVIDERS.unified_limit_api.get_registered_limit(
|
||||
registered_limit_id)
|
||||
registered_limit_id
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
def _list_registered_limits(self):
|
||||
filters = ['service_id', 'region_id', 'resource_name']
|
||||
ENFORCER.enforce_call(action='identity:list_registered_limits',
|
||||
filters=filters)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_registered_limits', filters=filters
|
||||
)
|
||||
hints = self.build_driver_hints(filters)
|
||||
refs = PROVIDERS.unified_limit_api.list_registered_limits(hints)
|
||||
return self.wrap_collection(refs, hints=hints)
|
||||
@ -53,32 +55,42 @@ class RegisteredLimitResource(ks_flask.ResourceBase):
|
||||
|
||||
def post(self):
|
||||
ENFORCER.enforce_call(action='identity:create_registered_limits')
|
||||
reg_limits = (flask.request.get_json(
|
||||
silent=True, force=True) or {}).get('registered_limits', {})
|
||||
reg_limits = (
|
||||
flask.request.get_json(silent=True, force=True) or {}
|
||||
).get('registered_limits', {})
|
||||
validation.lazy_validate(schema.registered_limit_create, reg_limits)
|
||||
registered_limits = [self._assign_unique_id(self._normalize_dict(r))
|
||||
for r in reg_limits]
|
||||
registered_limits = [
|
||||
self._assign_unique_id(self._normalize_dict(r)) for r in reg_limits
|
||||
]
|
||||
refs = PROVIDERS.unified_limit_api.create_registered_limits(
|
||||
registered_limits)
|
||||
registered_limits
|
||||
)
|
||||
refs = self.wrap_collection(refs)
|
||||
refs.pop('links')
|
||||
return refs, http.client.CREATED
|
||||
|
||||
def patch(self, registered_limit_id):
|
||||
ENFORCER.enforce_call(action='identity:update_registered_limit')
|
||||
registered_limit = (flask.request.get_json(
|
||||
silent=True, force=True) or {}).get('registered_limit', {})
|
||||
validation.lazy_validate(schema.registered_limit_update,
|
||||
registered_limit)
|
||||
registered_limit = (
|
||||
flask.request.get_json(silent=True, force=True) or {}
|
||||
).get('registered_limit', {})
|
||||
validation.lazy_validate(
|
||||
schema.registered_limit_update, registered_limit
|
||||
)
|
||||
self._require_matching_id(registered_limit)
|
||||
ref = PROVIDERS.unified_limit_api.update_registered_limit(
|
||||
registered_limit_id, registered_limit)
|
||||
registered_limit_id, registered_limit
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
def delete(self, registered_limit_id):
|
||||
ENFORCER.enforce_call(action='identity:delete_registered_limit')
|
||||
return (PROVIDERS.unified_limit_api.delete_registered_limit(
|
||||
registered_limit_id), http.client.NO_CONTENT)
|
||||
return (
|
||||
PROVIDERS.unified_limit_api.delete_registered_limit(
|
||||
registered_limit_id
|
||||
),
|
||||
http.client.NO_CONTENT,
|
||||
)
|
||||
|
||||
|
||||
class RegisteredLimitsAPI(ks_flask.APIBase):
|
||||
|
@ -46,8 +46,13 @@ class RoleAssignmentsResource(ks_flask.ResourceBase):
|
||||
|
||||
def _list_role_assignments(self):
|
||||
filters = [
|
||||
'group.id', 'role.id', 'scope.domain.id', 'scope.project.id',
|
||||
'scope.OS-INHERIT:inherited_to', 'user.id', 'scope.system'
|
||||
'group.id',
|
||||
'role.id',
|
||||
'scope.domain.id',
|
||||
'scope.project.id',
|
||||
'scope.OS-INHERIT:inherited_to',
|
||||
'user.id',
|
||||
'scope.system',
|
||||
]
|
||||
target = None
|
||||
if self.oslo_context.domain_id:
|
||||
@ -58,9 +63,11 @@ class RoleAssignmentsResource(ks_flask.ResourceBase):
|
||||
# so we reflect the domain_id from the context into the target
|
||||
# to validate domain-scoped tokens.
|
||||
target = {'domain_id': self.oslo_context.domain_id}
|
||||
ENFORCER.enforce_call(action='identity:list_role_assignments',
|
||||
filters=filters,
|
||||
target_attr=target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_role_assignments',
|
||||
filters=filters,
|
||||
target_attr=target,
|
||||
)
|
||||
|
||||
assignments = self._build_role_assignments_list()
|
||||
|
||||
@ -83,8 +90,12 @@ class RoleAssignmentsResource(ks_flask.ResourceBase):
|
||||
|
||||
def _list_role_assignments_for_tree(self):
|
||||
filters = [
|
||||
'group.id', 'role.id', 'scope.domain.id', 'scope.project.id',
|
||||
'scope.OS-INHERIT:inherited_to', 'user.id'
|
||||
'group.id',
|
||||
'role.id',
|
||||
'scope.domain.id',
|
||||
'scope.project.id',
|
||||
'scope.OS-INHERIT:inherited_to',
|
||||
'user.id',
|
||||
]
|
||||
project_id = flask.request.args.get('scope.project.id')
|
||||
target = None
|
||||
@ -95,11 +106,16 @@ class RoleAssignmentsResource(ks_flask.ResourceBase):
|
||||
# Add target.domain_id to validate domain-scoped tokens
|
||||
target['domain_id'] = target['project']['domain_id']
|
||||
|
||||
ENFORCER.enforce_call(action='identity:list_role_assignments_for_tree',
|
||||
filters=filters, target_attr=target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_role_assignments_for_tree',
|
||||
filters=filters,
|
||||
target_attr=target,
|
||||
)
|
||||
if not project_id:
|
||||
msg = _('scope.project.id must be specified if include_subtree '
|
||||
'is also specified')
|
||||
msg = _(
|
||||
'scope.project.id must be specified if include_subtree '
|
||||
'is also specified'
|
||||
)
|
||||
raise exception.ValidationError(message=msg)
|
||||
return self._build_role_assignments_list(include_subtree=True)
|
||||
|
||||
@ -144,31 +160,36 @@ class RoleAssignmentsResource(ks_flask.ResourceBase):
|
||||
include_subtree=include_subtree,
|
||||
inherited=self._inherited,
|
||||
effective=self._effective,
|
||||
include_names=include_names)
|
||||
include_names=include_names,
|
||||
)
|
||||
formatted_refs = [self._format_entity(ref) for ref in refs]
|
||||
return self.wrap_collection(formatted_refs)
|
||||
|
||||
def _assert_domain_nand_project(self):
|
||||
if (flask.request.args.get('scope.domain.id') and
|
||||
flask.request.args.get('scope.project.id')):
|
||||
if flask.request.args.get(
|
||||
'scope.domain.id'
|
||||
) and flask.request.args.get('scope.project.id'):
|
||||
msg = _('Specify a domain or project, not both')
|
||||
raise exception.ValidationError(msg)
|
||||
|
||||
def _assert_system_nand_domain(self):
|
||||
if (flask.request.args.get('scope.domain.id') and
|
||||
flask.request.args.get('scope.system')):
|
||||
if flask.request.args.get(
|
||||
'scope.domain.id'
|
||||
) and flask.request.args.get('scope.system'):
|
||||
msg = _('Specify system or domain, not both')
|
||||
raise exception.ValidationError(msg)
|
||||
|
||||
def _assert_system_nand_project(self):
|
||||
if (flask.request.args.get('scope.project.id') and
|
||||
flask.request.args.get('scope.system')):
|
||||
if flask.request.args.get(
|
||||
'scope.project.id'
|
||||
) and flask.request.args.get('scope.system'):
|
||||
msg = _('Specify system or project, not both')
|
||||
raise exception.ValidationError(msg)
|
||||
|
||||
def _assert_user_nand_group(self):
|
||||
if (flask.request.args.get('user.id') and
|
||||
flask.request.args.get('group.id')):
|
||||
if flask.request.args.get('user.id') and flask.request.args.get(
|
||||
'group.id'
|
||||
):
|
||||
msg = _('Specify a user or group, not both')
|
||||
raise exception.ValidationError(msg)
|
||||
|
||||
@ -184,14 +205,17 @@ class RoleAssignmentsResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
if self._effective:
|
||||
if flask.request.args.get('group.id'):
|
||||
msg = _('Combining effective and group filter will always '
|
||||
'result in an empty list.')
|
||||
msg = _(
|
||||
'Combining effective and group filter will always '
|
||||
'result in an empty list.'
|
||||
)
|
||||
raise exception.ValidationError(msg)
|
||||
|
||||
if self._inherited and flask.request.args.get('scope.domain.id'):
|
||||
msg = _(
|
||||
'Combining effective, domain and inherited filters will '
|
||||
'always result in an empty list.')
|
||||
'always result in an empty list.'
|
||||
)
|
||||
raise exception.ValidationError(msg)
|
||||
|
||||
@property
|
||||
@ -275,33 +299,45 @@ class RoleAssignmentsResource(ks_flask.ResourceBase):
|
||||
|
||||
if 'project_id' in entity:
|
||||
if 'project_name' in entity:
|
||||
formatted_entity['scope'] = {'project': {
|
||||
'id': entity['project_id'],
|
||||
'name': entity['project_name'],
|
||||
'domain': {'id': entity['project_domain_id'],
|
||||
'name': entity['project_domain_name']}}}
|
||||
formatted_entity['scope'] = {
|
||||
'project': {
|
||||
'id': entity['project_id'],
|
||||
'name': entity['project_name'],
|
||||
'domain': {
|
||||
'id': entity['project_domain_id'],
|
||||
'name': entity['project_domain_name'],
|
||||
},
|
||||
}
|
||||
}
|
||||
else:
|
||||
formatted_entity['scope'] = {
|
||||
'project': {'id': entity['project_id']}}
|
||||
'project': {'id': entity['project_id']}
|
||||
}
|
||||
|
||||
if 'domain_id' in entity.get('indirect', {}):
|
||||
inherited_assignment = True
|
||||
formatted_link = ('/domains/%s' %
|
||||
entity['indirect']['domain_id'])
|
||||
formatted_link = (
|
||||
'/domains/%s' % entity['indirect']['domain_id']
|
||||
)
|
||||
elif 'project_id' in entity.get('indirect', {}):
|
||||
inherited_assignment = True
|
||||
formatted_link = ('/projects/%s' %
|
||||
entity['indirect']['project_id'])
|
||||
formatted_link = (
|
||||
'/projects/%s' % entity['indirect']['project_id']
|
||||
)
|
||||
else:
|
||||
formatted_link = '/projects/%s' % entity['project_id']
|
||||
elif 'domain_id' in entity:
|
||||
if 'domain_name' in entity:
|
||||
formatted_entity['scope'] = {
|
||||
'domain': {'id': entity['domain_id'],
|
||||
'name': entity['domain_name']}}
|
||||
'domain': {
|
||||
'id': entity['domain_id'],
|
||||
'name': entity['domain_name'],
|
||||
}
|
||||
}
|
||||
else:
|
||||
formatted_entity['scope'] = {
|
||||
'domain': {'id': entity['domain_id']}}
|
||||
'domain': {'id': entity['domain_id']}
|
||||
}
|
||||
formatted_link = '/domains/%s' % entity['domain_id']
|
||||
elif 'system' in entity:
|
||||
formatted_link = '/system'
|
||||
@ -312,14 +348,18 @@ class RoleAssignmentsResource(ks_flask.ResourceBase):
|
||||
formatted_entity['user'] = {
|
||||
'id': entity['user_id'],
|
||||
'name': entity['user_name'],
|
||||
'domain': {'id': entity['user_domain_id'],
|
||||
'name': entity['user_domain_name']}}
|
||||
'domain': {
|
||||
'id': entity['user_domain_id'],
|
||||
'name': entity['user_domain_name'],
|
||||
},
|
||||
}
|
||||
else:
|
||||
formatted_entity['user'] = {'id': entity['user_id']}
|
||||
if 'group_id' in entity.get('indirect', {}):
|
||||
membership_url = (
|
||||
ks_flask.base_url(path='/groups/%s/users/%s' % (
|
||||
entity['indirect']['group_id'], entity['user_id'])))
|
||||
membership_url = ks_flask.base_url(
|
||||
path='/groups/%s/users/%s'
|
||||
% (entity['indirect']['group_id'], entity['user_id'])
|
||||
)
|
||||
formatted_entity['links']['membership'] = membership_url
|
||||
formatted_link += '/groups/%s' % entity['indirect']['group_id']
|
||||
else:
|
||||
@ -329,43 +369,54 @@ class RoleAssignmentsResource(ks_flask.ResourceBase):
|
||||
formatted_entity['group'] = {
|
||||
'id': entity['group_id'],
|
||||
'name': entity['group_name'],
|
||||
'domain': {'id': entity['group_domain_id'],
|
||||
'name': entity['group_domain_name']}}
|
||||
'domain': {
|
||||
'id': entity['group_domain_id'],
|
||||
'name': entity['group_domain_name'],
|
||||
},
|
||||
}
|
||||
else:
|
||||
formatted_entity['group'] = {'id': entity['group_id']}
|
||||
formatted_link += '/groups/%s' % entity['group_id']
|
||||
|
||||
if 'role_name' in entity:
|
||||
formatted_entity['role'] = {'id': entity['role_id'],
|
||||
'name': entity['role_name']}
|
||||
formatted_entity['role'] = {
|
||||
'id': entity['role_id'],
|
||||
'name': entity['role_name'],
|
||||
}
|
||||
if 'role_domain_id' in entity and 'role_domain_name' in entity:
|
||||
formatted_entity['role'].update(
|
||||
{'domain': {'id': entity['role_domain_id'],
|
||||
'name': entity['role_domain_name']}})
|
||||
{
|
||||
'domain': {
|
||||
'id': entity['role_domain_id'],
|
||||
'name': entity['role_domain_name'],
|
||||
}
|
||||
}
|
||||
)
|
||||
else:
|
||||
formatted_entity['role'] = {'id': entity['role_id']}
|
||||
prior_role_link = ''
|
||||
if 'role_id' in entity.get('indirect', {}):
|
||||
formatted_link += '/roles/%s' % entity['indirect']['role_id']
|
||||
prior_role_link = (
|
||||
'/prior_role/%(prior)s/implies/%(implied)s' % {
|
||||
'prior': entity['role_id'],
|
||||
'implied': entity['indirect']['role_id']
|
||||
})
|
||||
prior_role_link = '/prior_role/%(prior)s/implies/%(implied)s' % {
|
||||
'prior': entity['role_id'],
|
||||
'implied': entity['indirect']['role_id'],
|
||||
}
|
||||
else:
|
||||
formatted_link += '/roles/%s' % entity['role_id']
|
||||
|
||||
if inherited_assignment:
|
||||
formatted_entity['scope']['OS-INHERIT:inherited_to'] = (
|
||||
'projects')
|
||||
formatted_link = ('/OS-INHERIT%s/inherited_to_projects' %
|
||||
formatted_link)
|
||||
formatted_entity['scope']['OS-INHERIT:inherited_to'] = 'projects'
|
||||
formatted_link = (
|
||||
'/OS-INHERIT%s/inherited_to_projects' % formatted_link
|
||||
)
|
||||
|
||||
formatted_entity['links']['assignment'] = ks_flask.base_url(
|
||||
path=formatted_link)
|
||||
path=formatted_link
|
||||
)
|
||||
if prior_role_link:
|
||||
formatted_entity['links']['prior_role'] = (
|
||||
ks_flask.base_url(path=prior_role_link))
|
||||
formatted_entity['links']['prior_role'] = ks_flask.base_url(
|
||||
path=prior_role_link
|
||||
)
|
||||
|
||||
return formatted_entity
|
||||
|
||||
@ -379,7 +430,8 @@ class RoleAssignmentsAPI(ks_flask.APIBase):
|
||||
resource=RoleAssignmentsResource,
|
||||
url='/role_assignments',
|
||||
resource_kwargs={},
|
||||
rel='role_assignments')
|
||||
rel='role_assignments',
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
|
@ -32,8 +32,10 @@ class RoleInferencesResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:list_role_inference_rules')
|
||||
refs = PROVIDERS.role_api.list_role_inference_rules()
|
||||
role_dict = {role_ref['id']: role_ref
|
||||
for role_ref in PROVIDERS.role_api.list_roles()}
|
||||
role_dict = {
|
||||
role_ref['id']: role_ref
|
||||
for role_ref in PROVIDERS.role_api.list_roles()
|
||||
}
|
||||
|
||||
rules = dict()
|
||||
for ref in refs:
|
||||
@ -42,15 +44,22 @@ class RoleInferencesResource(flask_restful.Resource):
|
||||
implied = rules.get(prior_role_id, [])
|
||||
implied.append(
|
||||
shared.build_implied_role_response_data(
|
||||
role_dict[implied_role_id]))
|
||||
role_dict[implied_role_id]
|
||||
)
|
||||
)
|
||||
rules[prior_role_id] = implied
|
||||
|
||||
inferences = []
|
||||
for prior_id, implied, in rules.items():
|
||||
for (
|
||||
prior_id,
|
||||
implied,
|
||||
) in rules.items():
|
||||
prior_response = shared.build_prior_role_response_data(
|
||||
prior_id, role_dict[prior_id]['name'])
|
||||
inferences.append({'prior_role': prior_response,
|
||||
'implies': implied})
|
||||
prior_id, role_dict[prior_id]['name']
|
||||
)
|
||||
inferences.append(
|
||||
{'prior_role': prior_response, 'implies': implied}
|
||||
)
|
||||
results = {'role_inferences': inferences}
|
||||
return results
|
||||
|
||||
@ -64,7 +73,8 @@ class RoleInferencesAPI(ks_flask.APIBase):
|
||||
resource=RoleInferencesResource,
|
||||
url='/role_inferences',
|
||||
resource_kwargs={},
|
||||
rel='role_inferences')
|
||||
rel='role_inferences',
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
|
@ -35,7 +35,8 @@ class RoleResource(ks_flask.ResourceBase):
|
||||
collection_key = 'roles'
|
||||
member_key = 'role'
|
||||
get_member_from_driver = PROVIDERS.deferred_provider_lookup(
|
||||
api='role_api', method='get_role')
|
||||
api='role_api', method='get_role'
|
||||
)
|
||||
|
||||
def _is_domain_role(self, role):
|
||||
return bool(role.get('domain_id'))
|
||||
@ -72,20 +73,24 @@ class RoleResource(ks_flask.ResourceBase):
|
||||
# reraise the error after enforcement if needed.
|
||||
raise err
|
||||
else:
|
||||
ENFORCER.enforce_call(action='identity:get_domain_role',
|
||||
member_target_type='role',
|
||||
member_target=role)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:get_domain_role',
|
||||
member_target_type='role',
|
||||
member_target=role,
|
||||
)
|
||||
return self.wrap_member(role)
|
||||
|
||||
def _list_roles(self):
|
||||
filters = ['name', 'domain_id']
|
||||
domain_filter = flask.request.args.get('domain_id')
|
||||
if domain_filter:
|
||||
ENFORCER.enforce_call(action='identity:list_domain_roles',
|
||||
filters=filters)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_domain_roles', filters=filters
|
||||
)
|
||||
else:
|
||||
ENFORCER.enforce_call(action='identity:list_roles',
|
||||
filters=filters)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_roles', filters=filters
|
||||
)
|
||||
|
||||
hints = self.build_driver_hints(filters)
|
||||
if not domain_filter:
|
||||
@ -113,7 +118,8 @@ class RoleResource(ks_flask.ResourceBase):
|
||||
role = self._assign_unique_id(role)
|
||||
role = self._normalize_dict(role)
|
||||
ref = PROVIDERS.role_api.create_role(
|
||||
role['id'], role, initiator=self.audit_initiator)
|
||||
role['id'], role, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref), http.client.CREATED
|
||||
|
||||
def patch(self, role_id):
|
||||
@ -136,14 +142,17 @@ class RoleResource(ks_flask.ResourceBase):
|
||||
if err:
|
||||
raise err
|
||||
else:
|
||||
ENFORCER.enforce_call(action='identity:update_domain_role',
|
||||
member_target_type='role',
|
||||
member_target=role)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:update_domain_role',
|
||||
member_target_type='role',
|
||||
member_target=role,
|
||||
)
|
||||
request_body_role = self.request_body_json.get('role', {})
|
||||
validation.lazy_validate(schema.role_update, request_body_role)
|
||||
self._require_matching_id(request_body_role)
|
||||
ref = PROVIDERS.role_api.update_role(
|
||||
role_id, request_body_role, initiator=self.audit_initiator)
|
||||
role_id, request_body_role, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
def delete(self, role_id):
|
||||
@ -166,9 +175,11 @@ class RoleResource(ks_flask.ResourceBase):
|
||||
if err:
|
||||
raise err
|
||||
else:
|
||||
ENFORCER.enforce_call(action='identity:delete_domain_role',
|
||||
member_target_type='role',
|
||||
member_target=role)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:delete_domain_role',
|
||||
member_target_type='role',
|
||||
member_target=role,
|
||||
)
|
||||
PROVIDERS.role_api.delete_role(role_id, initiator=self.audit_initiator)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
@ -177,10 +188,12 @@ def _build_enforcement_target_ref():
|
||||
ref = {}
|
||||
if flask.request.view_args:
|
||||
ref['prior_role'] = PROVIDERS.role_api.get_role(
|
||||
flask.request.view_args.get('prior_role_id'))
|
||||
flask.request.view_args.get('prior_role_id')
|
||||
)
|
||||
if flask.request.view_args.get('implied_role_id'):
|
||||
ref['implied_role'] = PROVIDERS.role_api.get_role(
|
||||
flask.request.view_args['implied_role_id'])
|
||||
flask.request.view_args['implied_role_id']
|
||||
)
|
||||
return ref
|
||||
|
||||
|
||||
@ -190,8 +203,10 @@ class RoleImplicationListResource(flask_restful.Resource):
|
||||
|
||||
GET/HEAD /v3/roles/{prior_role_id}/implies
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:list_implied_roles',
|
||||
build_target=_build_enforcement_target_ref)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_implied_roles',
|
||||
build_target=_build_enforcement_target_ref,
|
||||
)
|
||||
ref = PROVIDERS.role_api.list_implied_roles(prior_role_id)
|
||||
implied_ids = [r['implied_role_id'] for r in ref]
|
||||
response_json = shared.role_inference_response(prior_role_id)
|
||||
@ -199,10 +214,11 @@ class RoleImplicationListResource(flask_restful.Resource):
|
||||
for implied_id in implied_ids:
|
||||
implied_role = PROVIDERS.role_api.get_role(implied_id)
|
||||
response_json['role_inference']['implies'].append(
|
||||
shared.build_implied_role_response_data(implied_role))
|
||||
shared.build_implied_role_response_data(implied_role)
|
||||
)
|
||||
response_json['links'] = {
|
||||
'self': ks_flask.base_url(
|
||||
path='/roles/%s/implies' % prior_role_id)}
|
||||
'self': ks_flask.base_url(path='/roles/%s/implies' % prior_role_id)
|
||||
}
|
||||
return response_json
|
||||
|
||||
|
||||
@ -215,8 +231,10 @@ class RoleImplicationResource(flask_restful.Resource):
|
||||
# consistent policy enforcement behavior even if it is superfluous.
|
||||
# Alternatively we can keep check_implied_role and reference
|
||||
# ._get_implied_role instead.
|
||||
ENFORCER.enforce_call(action='identity:check_implied_role',
|
||||
build_target=_build_enforcement_target_ref)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:check_implied_role',
|
||||
build_target=_build_enforcement_target_ref,
|
||||
)
|
||||
self.get(prior_role_id, implied_role_id)
|
||||
# NOTE(morgan): Our API here breaks HTTP Spec. This should be evaluated
|
||||
# for a future fix. This should just return the above "get" however,
|
||||
@ -231,22 +249,24 @@ class RoleImplicationResource(flask_restful.Resource):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:get_implied_role',
|
||||
build_target=_build_enforcement_target_ref)
|
||||
build_target=_build_enforcement_target_ref,
|
||||
)
|
||||
return self._get_implied_role(prior_role_id, implied_role_id)
|
||||
|
||||
def _get_implied_role(self, prior_role_id, implied_role_id):
|
||||
# Isolate this logic so it can be re-used without added enforcement
|
||||
PROVIDERS.role_api.get_implied_role(
|
||||
prior_role_id, implied_role_id)
|
||||
PROVIDERS.role_api.get_implied_role(prior_role_id, implied_role_id)
|
||||
implied_role_ref = PROVIDERS.role_api.get_role(implied_role_id)
|
||||
response_json = shared.role_inference_response(prior_role_id)
|
||||
response_json['role_inference'][
|
||||
'implies'] = shared.build_implied_role_response_data(
|
||||
implied_role_ref)
|
||||
response_json['role_inference']['implies'] = (
|
||||
shared.build_implied_role_response_data(implied_role_ref)
|
||||
)
|
||||
response_json['links'] = {
|
||||
'self': ks_flask.base_url(
|
||||
path='/roles/%(prior)s/implies/%(implies)s' % {
|
||||
'prior': prior_role_id, 'implies': implied_role_id})}
|
||||
path='/roles/%(prior)s/implies/%(implies)s'
|
||||
% {'prior': prior_role_id, 'implies': implied_role_id}
|
||||
)
|
||||
}
|
||||
return response_json
|
||||
|
||||
def put(self, prior_role_id, implied_role_id):
|
||||
@ -254,8 +274,10 @@ class RoleImplicationResource(flask_restful.Resource):
|
||||
|
||||
PUT /v3/roles/{prior_role_id}/implies/{implied_role_id}
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:create_implied_role',
|
||||
build_target=_build_enforcement_target_ref)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:create_implied_role',
|
||||
build_target=_build_enforcement_target_ref,
|
||||
)
|
||||
PROVIDERS.role_api.create_implied_role(prior_role_id, implied_role_id)
|
||||
response_json = self._get_implied_role(prior_role_id, implied_role_id)
|
||||
return response_json, http.client.CREATED
|
||||
@ -265,8 +287,10 @@ class RoleImplicationResource(flask_restful.Resource):
|
||||
|
||||
DELETE /v3/roles/{prior_role_id}/implies/{implied_role_id}
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:delete_implied_role',
|
||||
build_target=_build_enforcement_target_ref)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:delete_implied_role',
|
||||
build_target=_build_enforcement_target_ref,
|
||||
)
|
||||
PROVIDERS.role_api.delete_implied_role(prior_role_id, implied_role_id)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
@ -281,16 +305,21 @@ class RoleAPI(ks_flask.APIBase):
|
||||
url='/roles/<string:prior_role_id>/implies',
|
||||
resource_kwargs={},
|
||||
rel='implied_roles',
|
||||
path_vars={'prior_role_id': json_home.Parameters.ROLE_ID}),
|
||||
path_vars={'prior_role_id': json_home.Parameters.ROLE_ID},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=RoleImplicationResource,
|
||||
resource_kwargs={},
|
||||
url=('/roles/<string:prior_role_id>/'
|
||||
'implies/<string:implied_role_id>'),
|
||||
url=(
|
||||
'/roles/<string:prior_role_id>/'
|
||||
'implies/<string:implied_role_id>'
|
||||
),
|
||||
rel='implied_role',
|
||||
path_vars={
|
||||
'prior_role_id': json_home.Parameters.ROLE_ID,
|
||||
'implied_role_id': json_home.Parameters.ROLE_ID})
|
||||
'implied_role_id': json_home.Parameters.ROLE_ID,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -39,8 +39,11 @@ def _calculate_signature_v1(string_to_sign, secret_key):
|
||||
"""
|
||||
key = str(secret_key).encode('utf-8')
|
||||
b64_encode = base64.encodebytes
|
||||
signed = b64_encode(hmac.new(key, string_to_sign, hashlib.sha1)
|
||||
.digest()).decode('utf-8').strip()
|
||||
signed = (
|
||||
b64_encode(hmac.new(key, string_to_sign, hashlib.sha1).digest())
|
||||
.decode('utf-8')
|
||||
.strip()
|
||||
)
|
||||
return signed
|
||||
|
||||
|
||||
@ -80,15 +83,18 @@ class S3Resource(EC2_S3_Resource.ResourceBase):
|
||||
string_to_sign = base64.urlsafe_b64decode(str(credentials['token']))
|
||||
|
||||
if string_to_sign[0:4] != b'AWS4':
|
||||
signature = _calculate_signature_v1(string_to_sign,
|
||||
creds_ref['secret'])
|
||||
signature = _calculate_signature_v1(
|
||||
string_to_sign, creds_ref['secret']
|
||||
)
|
||||
else:
|
||||
signature = _calculate_signature_v4(string_to_sign,
|
||||
creds_ref['secret'])
|
||||
signature = _calculate_signature_v4(
|
||||
string_to_sign, creds_ref['secret']
|
||||
)
|
||||
|
||||
if not utils.auth_str_equal(credentials['signature'], signature):
|
||||
raise exception.Unauthorized(
|
||||
message=_('Credential signature mismatch'))
|
||||
message=_('Credential signature mismatch')
|
||||
)
|
||||
|
||||
@ks_flask.unenforced_api
|
||||
def post(self):
|
||||
@ -115,7 +121,9 @@ class S3Api(ks_flask.APIBase):
|
||||
resource_kwargs={},
|
||||
rel='s3tokens',
|
||||
resource_relation_func=(
|
||||
json_home_relations.s3_token_resource_rel_func))
|
||||
json_home_relations.s3_token_resource_rel_func
|
||||
),
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
|
@ -51,7 +51,8 @@ class ServicesResource(ks_flask.ResourceBase):
|
||||
validation.lazy_validate(schema.service_create, service)
|
||||
service = self._assign_unique_id(self._normalize_dict(service))
|
||||
ref = PROVIDERS.catalog_api.create_service(
|
||||
service['id'], service, initiator=self.audit_initiator)
|
||||
service['id'], service, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref), http.client.CREATED
|
||||
|
||||
def patch(self, service_id):
|
||||
@ -60,13 +61,18 @@ class ServicesResource(ks_flask.ResourceBase):
|
||||
validation.lazy_validate(schema.service_update, service)
|
||||
self._require_matching_id(service)
|
||||
ref = PROVIDERS.catalog_api.update_service(
|
||||
service_id, service, initiator=self.audit_initiator)
|
||||
service_id, service, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
def delete(self, service_id):
|
||||
ENFORCER.enforce_call(action='identity:delete_service')
|
||||
return PROVIDERS.catalog_api.delete_service(
|
||||
service_id, initiator=self.audit_initiator), http.client.NO_CONTENT
|
||||
return (
|
||||
PROVIDERS.catalog_api.delete_service(
|
||||
service_id, initiator=self.audit_initiator
|
||||
),
|
||||
http.client.NO_CONTENT,
|
||||
)
|
||||
|
||||
|
||||
class ServiceAPI(ks_flask.APIBase):
|
||||
|
@ -33,18 +33,21 @@ def _build_enforcement_target(allow_non_existing=False):
|
||||
if flask.request.view_args:
|
||||
if flask.request.view_args.get('role_id'):
|
||||
target['role'] = PROVIDERS.role_api.get_role(
|
||||
flask.request.view_args['role_id'])
|
||||
flask.request.view_args['role_id']
|
||||
)
|
||||
if flask.request.view_args.get('user_id'):
|
||||
try:
|
||||
target['user'] = PROVIDERS.identity_api.get_user(
|
||||
flask.request.view_args['user_id'])
|
||||
flask.request.view_args['user_id']
|
||||
)
|
||||
except exception.UserNotFound:
|
||||
if not allow_non_existing:
|
||||
raise
|
||||
else:
|
||||
try:
|
||||
target['group'] = PROVIDERS.identity_api.get_group(
|
||||
flask.request.view_args.get('group_id'))
|
||||
flask.request.view_args.get('group_id')
|
||||
)
|
||||
except exception.GroupNotFound:
|
||||
if not allow_non_existing:
|
||||
raise
|
||||
@ -57,11 +60,14 @@ class SystemUsersListResource(flask_restful.Resource):
|
||||
|
||||
GET/HEAD /system/users/{user_id}/roles
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:list_system_grants_for_user',
|
||||
build_target=_build_enforcement_target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_system_grants_for_user',
|
||||
build_target=_build_enforcement_target,
|
||||
)
|
||||
refs = PROVIDERS.assignment_api.list_system_grants_for_user(user_id)
|
||||
return ks_flask.ResourceBase.wrap_collection(
|
||||
refs, collection_name='roles')
|
||||
refs, collection_name='roles'
|
||||
)
|
||||
|
||||
|
||||
class SystemUsersResource(flask_restful.Resource):
|
||||
@ -70,8 +76,10 @@ class SystemUsersResource(flask_restful.Resource):
|
||||
|
||||
GET/HEAD /system/users/{user_id}/roles/{role_id}
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:check_system_grant_for_user',
|
||||
build_target=_build_enforcement_target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:check_system_grant_for_user',
|
||||
build_target=_build_enforcement_target,
|
||||
)
|
||||
PROVIDERS.assignment_api.check_system_grant_for_user(user_id, role_id)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
@ -80,8 +88,10 @@ class SystemUsersResource(flask_restful.Resource):
|
||||
|
||||
PUT /system/users/{user_id}/roles/{role_id}
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:create_system_grant_for_user',
|
||||
build_target=_build_enforcement_target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:create_system_grant_for_user',
|
||||
build_target=_build_enforcement_target,
|
||||
)
|
||||
PROVIDERS.assignment_api.create_system_grant_for_user(user_id, role_id)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
@ -93,8 +103,9 @@ class SystemUsersResource(flask_restful.Resource):
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:revoke_system_grant_for_user',
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target,
|
||||
allow_non_existing=True))
|
||||
_build_enforcement_target, allow_non_existing=True
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.delete_system_grant_for_user(user_id, role_id)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
@ -105,11 +116,14 @@ class SystemGroupsRolesListResource(flask_restful.Resource):
|
||||
|
||||
GET/HEAD /system/groups/{group_id}/roles
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:list_system_grants_for_group',
|
||||
build_target=_build_enforcement_target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_system_grants_for_group',
|
||||
build_target=_build_enforcement_target,
|
||||
)
|
||||
refs = PROVIDERS.assignment_api.list_system_grants_for_group(group_id)
|
||||
return ks_flask.ResourceBase.wrap_collection(
|
||||
refs, collection_name='roles')
|
||||
refs, collection_name='roles'
|
||||
)
|
||||
|
||||
|
||||
class SystemGroupsRolestResource(flask_restful.Resource):
|
||||
@ -118,10 +132,13 @@ class SystemGroupsRolestResource(flask_restful.Resource):
|
||||
|
||||
GET/HEAD /system/groups/{group_id}/roles/{role_id}
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:check_system_grant_for_group',
|
||||
build_target=_build_enforcement_target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:check_system_grant_for_group',
|
||||
build_target=_build_enforcement_target,
|
||||
)
|
||||
PROVIDERS.assignment_api.check_system_grant_for_group(
|
||||
group_id, role_id)
|
||||
group_id, role_id
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def put(self, group_id, role_id):
|
||||
@ -129,10 +146,13 @@ class SystemGroupsRolestResource(flask_restful.Resource):
|
||||
|
||||
PUT /system/groups/{group_id}/roles/{role_id}
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:create_system_grant_for_group',
|
||||
build_target=_build_enforcement_target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:create_system_grant_for_group',
|
||||
build_target=_build_enforcement_target,
|
||||
)
|
||||
PROVIDERS.assignment_api.create_system_grant_for_group(
|
||||
group_id, role_id)
|
||||
group_id, role_id
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
def delete(self, group_id, role_id):
|
||||
@ -143,10 +163,12 @@ class SystemGroupsRolestResource(flask_restful.Resource):
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:revoke_system_grant_for_group',
|
||||
build_target=functools.partial(
|
||||
_build_enforcement_target,
|
||||
allow_non_existing=True))
|
||||
_build_enforcement_target, allow_non_existing=True
|
||||
),
|
||||
)
|
||||
PROVIDERS.assignment_api.delete_system_grant_for_group(
|
||||
group_id, role_id)
|
||||
group_id, role_id
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -160,7 +182,8 @@ class SystemAPI(ks_flask.APIBase):
|
||||
url='/system/users/<string:user_id>/roles',
|
||||
resource_kwargs={},
|
||||
rel='system_user_roles',
|
||||
path_vars={'user_id': json_home.Parameters.USER_ID}),
|
||||
path_vars={'user_id': json_home.Parameters.USER_ID},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=SystemUsersResource,
|
||||
url='/system/users/<string:user_id>/roles/<string:role_id>',
|
||||
@ -168,13 +191,16 @@ class SystemAPI(ks_flask.APIBase):
|
||||
rel='system_user_role',
|
||||
path_vars={
|
||||
'role_id': json_home.Parameters.ROLE_ID,
|
||||
'user_id': json_home.Parameters.USER_ID}),
|
||||
'user_id': json_home.Parameters.USER_ID,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=SystemGroupsRolesListResource,
|
||||
url='/system/groups/<string:group_id>/roles',
|
||||
resource_kwargs={},
|
||||
rel='system_group_roles',
|
||||
path_vars={'group_id': json_home.Parameters.GROUP_ID}),
|
||||
path_vars={'group_id': json_home.Parameters.GROUP_ID},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=SystemGroupsRolestResource,
|
||||
url='/system/groups/<string:group_id>/roles/<string:role_id>',
|
||||
@ -182,7 +208,9 @@ class SystemAPI(ks_flask.APIBase):
|
||||
rel='system_group_role',
|
||||
path_vars={
|
||||
'role_id': json_home.Parameters.ROLE_ID,
|
||||
'group_id': json_home.Parameters.GROUP_ID})
|
||||
'group_id': json_home.Parameters.GROUP_ID,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -43,7 +43,8 @@ _build_resource_relation = json_home_relations.os_trust_resource_rel_func
|
||||
_build_parameter_relation = json_home_relations.os_trust_parameter_rel_func
|
||||
|
||||
TRUST_ID_PARAMETER_RELATION = _build_parameter_relation(
|
||||
parameter_name='trust_id')
|
||||
parameter_name='trust_id'
|
||||
)
|
||||
|
||||
|
||||
def _build_trust_target_enforcement():
|
||||
@ -60,17 +61,21 @@ def _build_trust_target_enforcement():
|
||||
|
||||
def _trustor_trustee_only(trust):
|
||||
user_id = flask.request.environ.get(context.REQUEST_CONTEXT_ENV).user_id
|
||||
if user_id not in [trust.get('trustee_user_id'),
|
||||
trust.get('trustor_user_id')]:
|
||||
if user_id not in [
|
||||
trust.get('trustee_user_id'),
|
||||
trust.get('trustor_user_id'),
|
||||
]:
|
||||
raise exception.ForbiddenAction(
|
||||
action=_('Requested user has no relation to this trust'))
|
||||
action=_('Requested user has no relation to this trust')
|
||||
)
|
||||
|
||||
|
||||
def _normalize_trust_expires_at(trust):
|
||||
# correct isotime
|
||||
if trust.get('expires_at') is not None:
|
||||
trust['expires_at'] = utils.isotime(trust['expires_at'],
|
||||
subsecond=True)
|
||||
trust['expires_at'] = utils.isotime(
|
||||
trust['expires_at'], subsecond=True
|
||||
)
|
||||
|
||||
|
||||
def _normalize_trust_roles(trust):
|
||||
@ -81,7 +86,8 @@ def _normalize_trust_roles(trust):
|
||||
try:
|
||||
matching_role = PROVIDERS.role_api.get_role(trust_role)
|
||||
full_role = ks_flask.ResourceBase.wrap_member(
|
||||
matching_role, collection_name='roles', member_name='role')
|
||||
matching_role, collection_name='roles', member_name='role'
|
||||
)
|
||||
trust_full_roles.append(full_role['role'])
|
||||
except exception.RoleNotFound:
|
||||
pass
|
||||
@ -90,7 +96,8 @@ def _normalize_trust_roles(trust):
|
||||
trust['roles_links'] = {
|
||||
'self': ks_flask.base_url(path='/%s/roles' % trust['id']),
|
||||
'next': None,
|
||||
'previous': None}
|
||||
'previous': None,
|
||||
}
|
||||
|
||||
|
||||
class TrustResource(ks_flask.ResourceBase):
|
||||
@ -106,8 +113,10 @@ class TrustResource(ks_flask.ResourceBase):
|
||||
token = self.auth_context['token']
|
||||
if 'application_credential' in token.methods:
|
||||
if not token.application_credential['unrestricted']:
|
||||
action = _("Using method 'application_credential' is not "
|
||||
"allowed for managing trusts.")
|
||||
action = _(
|
||||
"Using method 'application_credential' is not "
|
||||
"allowed for managing trusts."
|
||||
)
|
||||
raise exception.ForbiddenAction(action=action)
|
||||
|
||||
def _find_redelegated_trust(self):
|
||||
@ -130,8 +139,9 @@ class TrustResource(ks_flask.ResourceBase):
|
||||
def _require_trustor_has_role_in_project(self, trust):
|
||||
trustor_roles = self._get_trustor_roles(trust)
|
||||
for trust_role in trust['roles']:
|
||||
matching_roles = [x for x in trustor_roles
|
||||
if x == trust_role['id']]
|
||||
matching_roles = [
|
||||
x for x in trustor_roles if x == trust_role['id']
|
||||
]
|
||||
if not matching_roles:
|
||||
raise exception.RoleNotFound(role_id=trust_role['id'])
|
||||
|
||||
@ -139,7 +149,8 @@ class TrustResource(ks_flask.ResourceBase):
|
||||
original_trust = trust.copy()
|
||||
while original_trust.get('redelegated_trust_id'):
|
||||
original_trust = PROVIDERS.trust_api.get_trust(
|
||||
original_trust['redelegated_trust_id'])
|
||||
original_trust['redelegated_trust_id']
|
||||
)
|
||||
|
||||
if not ((trust.get('project_id')) in [None, '']):
|
||||
# Check project exists.
|
||||
@ -148,7 +159,9 @@ class TrustResource(ks_flask.ResourceBase):
|
||||
assignment_list = PROVIDERS.assignment_api.list_role_assignments(
|
||||
user_id=original_trust['trustor_user_id'],
|
||||
project_id=original_trust['project_id'],
|
||||
effective=True, strip_domain_roles=False)
|
||||
effective=True,
|
||||
strip_domain_roles=False,
|
||||
)
|
||||
return list({x['role_id'] for x in assignment_list})
|
||||
else:
|
||||
return []
|
||||
@ -160,12 +173,15 @@ class TrustResource(ks_flask.ResourceBase):
|
||||
roles.append({'id': role['id']})
|
||||
else:
|
||||
roles.append(
|
||||
PROVIDERS.role_api.get_unique_role_by_name(role['name']))
|
||||
PROVIDERS.role_api.get_unique_role_by_name(role['name'])
|
||||
)
|
||||
return roles
|
||||
|
||||
def _get_trust(self, trust_id):
|
||||
ENFORCER.enforce_call(action='identity:get_trust',
|
||||
build_target=_build_trust_target_enforcement)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:get_trust',
|
||||
build_target=_build_trust_target_enforcement,
|
||||
)
|
||||
|
||||
# NOTE(cmurphy) look up trust before doing is_admin authorization - to
|
||||
# maintain the API contract, we expect a missing trust to raise a 404
|
||||
@ -176,7 +192,8 @@ class TrustResource(ks_flask.ResourceBase):
|
||||
# policies are not loaded for the is_admin context, so need to
|
||||
# block access here
|
||||
raise exception.ForbiddenAction(
|
||||
action=_('Requested user has no relation to this trust'))
|
||||
action=_('Requested user has no relation to this trust')
|
||||
)
|
||||
|
||||
# NOTE(cmurphy) As of Train, the default policies enforce the
|
||||
# identity:get_trust rule. However, in case the
|
||||
@ -189,7 +206,8 @@ class TrustResource(ks_flask.ResourceBase):
|
||||
LOG.warning(
|
||||
"The policy check string for rule \"identity:get_trust\" "
|
||||
"has been overridden to \"always true\". In the next release, "
|
||||
"this will cause the" "\"identity:get_trust\" action to "
|
||||
"this will cause the"
|
||||
"\"identity:get_trust\" action to "
|
||||
"be fully permissive as hardcoded enforcement will be "
|
||||
"removed. To correct this issue, either stop overriding the "
|
||||
"\"identity:get_trust\" rule in config to accept the "
|
||||
@ -206,12 +224,14 @@ class TrustResource(ks_flask.ResourceBase):
|
||||
trustee_user_id = flask.request.args.get('trustee_user_id')
|
||||
if trustor_user_id:
|
||||
target = {'trust': {'trustor_user_id': trustor_user_id}}
|
||||
ENFORCER.enforce_call(action='identity:list_trusts_for_trustor',
|
||||
target_attr=target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_trusts_for_trustor', target_attr=target
|
||||
)
|
||||
elif trustee_user_id:
|
||||
target = {'trust': {'trustee_user_id': trustee_user_id}}
|
||||
ENFORCER.enforce_call(action='identity:list_trusts_for_trustee',
|
||||
target_attr=target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_trusts_for_trustee', target_attr=target
|
||||
)
|
||||
else:
|
||||
ENFORCER.enforce_call(action='identity:list_trusts')
|
||||
|
||||
@ -244,10 +264,12 @@ class TrustResource(ks_flask.ResourceBase):
|
||||
trusts += PROVIDERS.trust_api.list_trusts()
|
||||
elif trustor_user_id:
|
||||
trusts += PROVIDERS.trust_api.list_trusts_for_trustor(
|
||||
trustor_user_id)
|
||||
trustor_user_id
|
||||
)
|
||||
elif trustee_user_id:
|
||||
trusts += PROVIDERS.trust_api.list_trusts_for_trustee(
|
||||
trustee_user_id)
|
||||
trustee_user_id
|
||||
)
|
||||
|
||||
for trust in trusts:
|
||||
# get_trust returns roles, list_trusts does not
|
||||
@ -257,8 +279,9 @@ class TrustResource(ks_flask.ResourceBase):
|
||||
del trust['roles']
|
||||
|
||||
if trust.get('expires_at') is not None:
|
||||
trust['expires_at'] = utils.isotime(trust['expires_at'],
|
||||
subsecond=True)
|
||||
trust['expires_at'] = utils.isotime(
|
||||
trust['expires_at'], subsecond=True
|
||||
)
|
||||
|
||||
return self.wrap_collection(trusts)
|
||||
|
||||
@ -294,7 +317,8 @@ class TrustResource(ks_flask.ResourceBase):
|
||||
trust['roles'] = self._normalize_role_list(trust.get('roles', []))
|
||||
self._require_trustor_has_role_in_project(trust)
|
||||
trust['expires_at'] = self._parse_expiration_date(
|
||||
trust.get('expires_at'))
|
||||
trust.get('expires_at')
|
||||
)
|
||||
trust = self._assign_unique_id(trust)
|
||||
redelegated_trust = self._find_redelegated_trust()
|
||||
return_trust = PROVIDERS.trust_api.create_trust(
|
||||
@ -302,14 +326,17 @@ class TrustResource(ks_flask.ResourceBase):
|
||||
trust=trust,
|
||||
roles=trust['roles'],
|
||||
redelegated_trust=redelegated_trust,
|
||||
initiator=self.audit_initiator)
|
||||
initiator=self.audit_initiator,
|
||||
)
|
||||
_normalize_trust_expires_at(return_trust)
|
||||
_normalize_trust_roles(return_trust)
|
||||
return self.wrap_member(return_trust), http.client.CREATED
|
||||
|
||||
def delete(self, trust_id):
|
||||
ENFORCER.enforce_call(action='identity:delete_trust',
|
||||
build_target=_build_trust_target_enforcement)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:delete_trust',
|
||||
build_target=_build_trust_target_enforcement,
|
||||
)
|
||||
self._check_unrestricted()
|
||||
|
||||
# NOTE(cmurphy) As of Train, the default policies enforce the
|
||||
@ -323,19 +350,23 @@ class TrustResource(ks_flask.ResourceBase):
|
||||
LOG.warning(
|
||||
"The policy check string for rule \"identity:delete_trust\" "
|
||||
"has been overridden to \"always true\". In the next release, "
|
||||
"this will cause the" "\"identity:delete_trust\" action to "
|
||||
"this will cause the"
|
||||
"\"identity:delete_trust\" action to "
|
||||
"be fully permissive as hardcoded enforcement will be "
|
||||
"removed. To correct this issue, either stop overriding the "
|
||||
"\"identity:delete_trust\" rule in config to accept the "
|
||||
"defaults, or explicitly set a rule that is not empty."
|
||||
)
|
||||
trust = PROVIDERS.trust_api.get_trust(trust_id)
|
||||
if (self.oslo_context.user_id != trust.get('trustor_user_id') and
|
||||
not self.oslo_context.is_admin):
|
||||
if (
|
||||
self.oslo_context.user_id != trust.get('trustor_user_id')
|
||||
and not self.oslo_context.is_admin
|
||||
):
|
||||
action = _('Only admin or trustor can delete a trust')
|
||||
raise exception.ForbiddenAction(action=action)
|
||||
PROVIDERS.trust_api.delete_trust(trust_id,
|
||||
initiator=self.audit_initiator)
|
||||
PROVIDERS.trust_api.delete_trust(
|
||||
trust_id, initiator=self.audit_initiator
|
||||
)
|
||||
return '', http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -349,8 +380,10 @@ class RolesForTrustListResource(flask_restful.Resource):
|
||||
return flask.request.environ.get(context.REQUEST_CONTEXT_ENV, None)
|
||||
|
||||
def get(self, trust_id):
|
||||
ENFORCER.enforce_call(action='identity:list_roles_for_trust',
|
||||
build_target=_build_trust_target_enforcement)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_roles_for_trust',
|
||||
build_target=_build_trust_target_enforcement,
|
||||
)
|
||||
|
||||
# NOTE(morgan): This duplicates a little of the .get_trust from the
|
||||
# main resource, as it needs some of the same logic. However, due to
|
||||
@ -360,7 +393,8 @@ class RolesForTrustListResource(flask_restful.Resource):
|
||||
# policies are not loaded for the is_admin context, so need to
|
||||
# block access here
|
||||
raise exception.ForbiddenAction(
|
||||
action=_('Requested user has no relation to this trust'))
|
||||
action=_('Requested user has no relation to this trust')
|
||||
)
|
||||
|
||||
trust = PROVIDERS.trust_api.get_trust(trust_id)
|
||||
|
||||
@ -370,7 +404,8 @@ class RolesForTrustListResource(flask_restful.Resource):
|
||||
# default that would have been produced by the sample config, we need
|
||||
# to enforce it again and warn that the behavior is changing.
|
||||
rules = policy._ENFORCER._enforcer.rules.get(
|
||||
'identity:list_roles_for_trust')
|
||||
'identity:list_roles_for_trust'
|
||||
)
|
||||
# rule check_str is ""
|
||||
if isinstance(rules, op_checks.TrueCheck):
|
||||
LOG.warning(
|
||||
@ -387,8 +422,7 @@ class RolesForTrustListResource(flask_restful.Resource):
|
||||
|
||||
_normalize_trust_expires_at(trust)
|
||||
_normalize_trust_roles(trust)
|
||||
return {'roles': trust['roles'],
|
||||
'links': trust['roles_links']}
|
||||
return {'roles': trust['roles'], 'links': trust['roles_links']}
|
||||
|
||||
|
||||
# NOTE(morgan): Since this Resource is not being used with the automatic
|
||||
@ -402,14 +436,17 @@ class RoleForTrustResource(flask_restful.Resource):
|
||||
|
||||
def get(self, trust_id, role_id):
|
||||
"""Get a role that has been assigned to a trust."""
|
||||
ENFORCER.enforce_call(action='identity:get_role_for_trust',
|
||||
build_target=_build_trust_target_enforcement)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:get_role_for_trust',
|
||||
build_target=_build_trust_target_enforcement,
|
||||
)
|
||||
|
||||
if self.oslo_context.is_admin:
|
||||
# policies are not loaded for the is_admin context, so need to
|
||||
# block access here
|
||||
raise exception.ForbiddenAction(
|
||||
action=_('Requested user has no relation to this trust'))
|
||||
action=_('Requested user has no relation to this trust')
|
||||
)
|
||||
|
||||
trust = PROVIDERS.trust_api.get_trust(trust_id)
|
||||
|
||||
@ -419,7 +456,8 @@ class RoleForTrustResource(flask_restful.Resource):
|
||||
# default that would have been produced by the sample config, we need
|
||||
# to enforce it again and warn that the behavior is changing.
|
||||
rules = policy._ENFORCER._enforcer.rules.get(
|
||||
'identity:get_role_for_trust')
|
||||
'identity:get_role_for_trust'
|
||||
)
|
||||
# rule check_str is ""
|
||||
if isinstance(rules, op_checks.TrueCheck):
|
||||
LOG.warning(
|
||||
@ -438,8 +476,9 @@ class RoleForTrustResource(flask_restful.Resource):
|
||||
raise exception.RoleNotFound(role_id=role_id)
|
||||
|
||||
role = PROVIDERS.role_api.get_role(role_id)
|
||||
return ks_flask.ResourceBase.wrap_member(role, collection_name='roles',
|
||||
member_name='role')
|
||||
return ks_flask.ResourceBase.wrap_member(
|
||||
role, collection_name='roles', member_name='role'
|
||||
)
|
||||
|
||||
|
||||
class TrustAPI(ks_flask.APIBase):
|
||||
@ -452,9 +491,9 @@ class TrustAPI(ks_flask.APIBase):
|
||||
url='/trusts/<string:trust_id>/roles',
|
||||
resource_kwargs={},
|
||||
rel='trust_roles',
|
||||
path_vars={
|
||||
'trust_id': TRUST_ID_PARAMETER_RELATION},
|
||||
resource_relation_func=_build_resource_relation),
|
||||
path_vars={'trust_id': TRUST_ID_PARAMETER_RELATION},
|
||||
resource_relation_func=_build_resource_relation,
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=RoleForTrustResource,
|
||||
url='/trusts/<string:trust_id>/roles/<string:role_id>',
|
||||
@ -462,8 +501,10 @@ class TrustAPI(ks_flask.APIBase):
|
||||
rel='trust_role',
|
||||
path_vars={
|
||||
'trust_id': TRUST_ID_PARAMETER_RELATION,
|
||||
'role_id': json_home.Parameters.ROLE_ID},
|
||||
resource_relation_func=_build_resource_relation),
|
||||
'role_id': json_home.Parameters.ROLE_ID,
|
||||
},
|
||||
resource_relation_func=_build_resource_relation,
|
||||
),
|
||||
]
|
||||
_api_url_prefix = '/OS-TRUST'
|
||||
|
||||
|
@ -43,7 +43,8 @@ PROVIDERS = provider_api.ProviderAPIs
|
||||
|
||||
ACCESS_TOKEN_ID_PARAMETER_RELATION = (
|
||||
json_home_relations.os_oauth1_parameter_rel_func(
|
||||
parameter_name='access_token_id')
|
||||
parameter_name='access_token_id'
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@ -56,11 +57,13 @@ def _convert_v3_to_ec2_credential(credential):
|
||||
blob = jsonutils.loads(credential['blob'])
|
||||
except TypeError:
|
||||
blob = credential['blob']
|
||||
return {'user_id': credential.get('user_id'),
|
||||
'tenant_id': credential.get('project_id'),
|
||||
'access': blob.get('access'),
|
||||
'secret': blob.get('secret'),
|
||||
'trust_id': blob.get('trust_id')}
|
||||
return {
|
||||
'user_id': credential.get('user_id'),
|
||||
'tenant_id': credential.get('project_id'),
|
||||
'access': blob.get('access'),
|
||||
'secret': blob.get('secret'),
|
||||
'trust_id': blob.get('trust_id'),
|
||||
}
|
||||
|
||||
|
||||
def _format_token_entity(entity):
|
||||
@ -73,12 +76,13 @@ def _format_token_entity(entity):
|
||||
if 'access_secret' in entity:
|
||||
formatted_entity.pop('access_secret')
|
||||
|
||||
url = ('/users/%(user_id)s/OS-OAUTH1/access_tokens/%(access_token_id)s'
|
||||
'/roles' % {'user_id': user_id,
|
||||
'access_token_id': access_token_id})
|
||||
url = (
|
||||
'/users/%(user_id)s/OS-OAUTH1/access_tokens/%(access_token_id)s'
|
||||
'/roles' % {'user_id': user_id, 'access_token_id': access_token_id}
|
||||
)
|
||||
|
||||
formatted_entity.setdefault('links', {})
|
||||
formatted_entity['links']['roles'] = (ks_flask.base_url(url))
|
||||
formatted_entity['links']['roles'] = ks_flask.base_url(url)
|
||||
|
||||
return formatted_entity
|
||||
|
||||
@ -86,9 +90,11 @@ def _format_token_entity(entity):
|
||||
def _check_unrestricted_application_credential(token):
|
||||
if 'application_credential' in token.methods:
|
||||
if not token.application_credential['unrestricted']:
|
||||
action = _("Using method 'application_credential' is not "
|
||||
"allowed for managing additional application "
|
||||
"credentials.")
|
||||
action = _(
|
||||
"Using method 'application_credential' is not "
|
||||
"allowed for managing additional application "
|
||||
"credentials."
|
||||
)
|
||||
raise ks_exception.ForbiddenAction(action=action)
|
||||
|
||||
|
||||
@ -117,7 +123,8 @@ def _build_enforcer_target_data_owner_and_user_id_match():
|
||||
if credential_id is not None:
|
||||
hashed_id = utils.hash_access_key(credential_id)
|
||||
ref['credential'] = PROVIDERS.credential_api.get_credential(
|
||||
hashed_id)
|
||||
hashed_id
|
||||
)
|
||||
return ref
|
||||
|
||||
|
||||
@ -170,7 +177,8 @@ class UserResource(ks_flask.ResourceBase):
|
||||
collection_key = 'users'
|
||||
member_key = 'user'
|
||||
get_member_from_driver = PROVIDERS.deferred_provider_lookup(
|
||||
api='identity_api', method='get_user')
|
||||
api='identity_api', method='get_user'
|
||||
)
|
||||
|
||||
def get(self, user_id=None):
|
||||
"""Get a user resource or list users.
|
||||
@ -189,7 +197,7 @@ class UserResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:get_user',
|
||||
build_target=_build_user_target_enforcement
|
||||
build_target=_build_user_target_enforcement,
|
||||
)
|
||||
ref = PROVIDERS.identity_api.get_user(user_id)
|
||||
return self.wrap_member(ref)
|
||||
@ -199,8 +207,15 @@ class UserResource(ks_flask.ResourceBase):
|
||||
|
||||
GET/HEAD /v3/users
|
||||
"""
|
||||
filters = ('domain_id', 'enabled', 'idp_id', 'name', 'protocol_id',
|
||||
'unique_id', 'password_expires_at')
|
||||
filters = (
|
||||
'domain_id',
|
||||
'enabled',
|
||||
'idp_id',
|
||||
'name',
|
||||
'protocol_id',
|
||||
'unique_id',
|
||||
'password_expires_at',
|
||||
)
|
||||
target = None
|
||||
if self.oslo_context.domain_id:
|
||||
target = {'domain_id': self.oslo_context.domain_id}
|
||||
@ -212,7 +227,8 @@ class UserResource(ks_flask.ResourceBase):
|
||||
if domain is None and self.oslo_context.domain_id:
|
||||
domain = self.oslo_context.domain_id
|
||||
refs = PROVIDERS.identity_api.list_users(
|
||||
domain_scope=domain, hints=hints)
|
||||
domain_scope=domain, hints=hints
|
||||
)
|
||||
|
||||
# If the user making the request used a domain-scoped token, let's make
|
||||
# sure we filter out users that are not in that domain. Otherwise, we'd
|
||||
@ -242,8 +258,8 @@ class UserResource(ks_flask.ResourceBase):
|
||||
user_data = self._normalize_dict(user_data)
|
||||
user_data = self._normalize_domain_id(user_data)
|
||||
ref = PROVIDERS.identity_api.create_user(
|
||||
user_data,
|
||||
initiator=self.audit_initiator)
|
||||
user_data, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref), http.client.CREATED
|
||||
|
||||
def patch(self, user_id):
|
||||
@ -253,14 +269,15 @@ class UserResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:update_user',
|
||||
build_target=_build_user_target_enforcement
|
||||
build_target=_build_user_target_enforcement,
|
||||
)
|
||||
PROVIDERS.identity_api.get_user(user_id)
|
||||
user_data = self.request_body_json.get('user', {})
|
||||
validation.lazy_validate(schema.user_update, user_data)
|
||||
self._require_matching_id(user_data)
|
||||
ref = PROVIDERS.identity_api.update_user(
|
||||
user_id, user_data, initiator=self.audit_initiator)
|
||||
user_id, user_data, initiator=self.audit_initiator
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
def delete(self, user_id):
|
||||
@ -270,10 +287,11 @@ class UserResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:delete_user',
|
||||
build_target=_build_user_target_enforcement
|
||||
build_target=_build_user_target_enforcement,
|
||||
)
|
||||
PROVIDERS.identity_api.delete_user(
|
||||
user_id, initiator=self.audit_initiator)
|
||||
user_id, initiator=self.audit_initiator
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -293,7 +311,8 @@ class UserChangePasswordResource(ks_flask.ResourceBase):
|
||||
user_id=user_id,
|
||||
original_password=user_data['original_password'],
|
||||
new_password=user_data['password'],
|
||||
initiator=self.audit_initiator)
|
||||
initiator=self.audit_initiator,
|
||||
)
|
||||
except AssertionError as e:
|
||||
raise ks_exception.Unauthorized(
|
||||
_('Error when changing user password: %s') % e
|
||||
@ -305,13 +324,16 @@ class UserProjectsResource(ks_flask.ResourceBase):
|
||||
collection_key = 'projects'
|
||||
member_key = 'project'
|
||||
get_member_from_driver = PROVIDERS.deferred_provider_lookup(
|
||||
api='resource_api', method='get_project')
|
||||
api='resource_api', method='get_project'
|
||||
)
|
||||
|
||||
def get(self, user_id):
|
||||
filters = ('domain_id', 'enabled', 'name')
|
||||
ENFORCER.enforce_call(action='identity:list_user_projects',
|
||||
filters=filters,
|
||||
build_target=_build_user_target_enforcement)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_user_projects',
|
||||
filters=filters,
|
||||
build_target=_build_user_target_enforcement,
|
||||
)
|
||||
hints = self.build_driver_hints(filters)
|
||||
refs = PROVIDERS.assignment_api.list_projects_for_user(user_id)
|
||||
return self.wrap_collection(refs, hints=hints)
|
||||
@ -321,7 +343,8 @@ class UserGroupsResource(ks_flask.ResourceBase):
|
||||
collection_key = 'groups'
|
||||
member_key = 'group'
|
||||
get_member_from_driver = PROVIDERS.deferred_provider_lookup(
|
||||
api='identity_api', method='get_group')
|
||||
api='identity_api', method='get_group'
|
||||
)
|
||||
|
||||
def get(self, user_id):
|
||||
"""Get groups for a user.
|
||||
@ -330,12 +353,15 @@ class UserGroupsResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
filters = ('name',)
|
||||
hints = self.build_driver_hints(filters)
|
||||
ENFORCER.enforce_call(action='identity:list_groups_for_user',
|
||||
build_target=_build_user_target_enforcement,
|
||||
filters=filters)
|
||||
refs = PROVIDERS.identity_api.list_groups_for_user(user_id=user_id,
|
||||
hints=hints)
|
||||
if (self.oslo_context.domain_id):
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_groups_for_user',
|
||||
build_target=_build_user_target_enforcement,
|
||||
filters=filters,
|
||||
)
|
||||
refs = PROVIDERS.identity_api.list_groups_for_user(
|
||||
user_id=user_id, hints=hints
|
||||
)
|
||||
if self.oslo_context.domain_id:
|
||||
filtered_refs = []
|
||||
for ref in refs:
|
||||
if ref['domain_id'] == self.oslo_context.domain_id:
|
||||
@ -358,7 +384,8 @@ class _UserOSEC2CredBaseResource(ks_flask.ResourceBase):
|
||||
|
||||
url = ks_flask.base_url(path) % {
|
||||
'user_id': ref['user_id'],
|
||||
'credential_id': ref['access']}
|
||||
'credential_id': ref['access'],
|
||||
}
|
||||
ref.setdefault('links', {})
|
||||
ref['links']['self'] = url
|
||||
|
||||
@ -372,10 +399,10 @@ class UserOSEC2CredentialsResourceListCreate(_UserOSEC2CredBaseResource):
|
||||
ENFORCER.enforce_call(action='identity:ec2_list_credentials')
|
||||
PROVIDERS.identity_api.get_user(user_id)
|
||||
credential_refs = PROVIDERS.credential_api.list_credentials_for_user(
|
||||
user_id, type=CRED_TYPE_EC2)
|
||||
user_id, type=CRED_TYPE_EC2
|
||||
)
|
||||
collection_refs = [
|
||||
_convert_v3_to_ec2_credential(cred)
|
||||
for cred in credential_refs
|
||||
_convert_v3_to_ec2_credential(cred) for cred in credential_refs
|
||||
]
|
||||
return self.wrap_collection(collection_refs)
|
||||
|
||||
@ -386,15 +413,16 @@ class UserOSEC2CredentialsResourceListCreate(_UserOSEC2CredBaseResource):
|
||||
"""
|
||||
target = {}
|
||||
target['credential'] = {'user_id': user_id}
|
||||
ENFORCER.enforce_call(action='identity:ec2_create_credential',
|
||||
target_attr=target)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:ec2_create_credential', target_attr=target
|
||||
)
|
||||
PROVIDERS.identity_api.get_user(user_id)
|
||||
tenant_id = self.request_body_json.get('tenant_id')
|
||||
PROVIDERS.resource_api.get_project(tenant_id)
|
||||
blob = dict(
|
||||
access=uuid.uuid4().hex,
|
||||
secret=uuid.uuid4().hex,
|
||||
trust_id=self.oslo_context.trust_id
|
||||
trust_id=self.oslo_context.trust_id,
|
||||
)
|
||||
credential_id = utils.hash_access_key(blob['access'])
|
||||
cred_data = dict(
|
||||
@ -402,7 +430,7 @@ class UserOSEC2CredentialsResourceListCreate(_UserOSEC2CredBaseResource):
|
||||
project_id=tenant_id,
|
||||
blob=jsonutils.dumps(blob),
|
||||
id=credential_id,
|
||||
type=CRED_TYPE_EC2
|
||||
type=CRED_TYPE_EC2,
|
||||
)
|
||||
PROVIDERS.credential_api.create_credential(credential_id, cred_data)
|
||||
ref = _convert_v3_to_ec2_credential(cred_data)
|
||||
@ -415,7 +443,8 @@ class UserOSEC2CredentialsResourceGetDelete(_UserOSEC2CredBaseResource):
|
||||
cred = PROVIDERS.credential_api.get_credential(credential_id)
|
||||
if not cred or cred['type'] != CRED_TYPE_EC2:
|
||||
raise ks_exception.Unauthorized(
|
||||
message=_('EC2 access key not found.'))
|
||||
message=_('EC2 access key not found.')
|
||||
)
|
||||
return _convert_v3_to_ec2_credential(cred)
|
||||
|
||||
def get(self, user_id, credential_id):
|
||||
@ -425,8 +454,8 @@ class UserOSEC2CredentialsResourceGetDelete(_UserOSEC2CredBaseResource):
|
||||
"""
|
||||
func = _build_enforcer_target_data_owner_and_user_id_match
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:ec2_get_credential',
|
||||
build_target=func)
|
||||
action='identity:ec2_get_credential', build_target=func
|
||||
)
|
||||
PROVIDERS.identity_api.get_user(user_id)
|
||||
ec2_cred_id = utils.hash_access_key(credential_id)
|
||||
cred_data = self._get_cred_data(ec2_cred_id)
|
||||
@ -438,8 +467,9 @@ class UserOSEC2CredentialsResourceGetDelete(_UserOSEC2CredBaseResource):
|
||||
DELETE /users/{user_id}/credentials/OS-EC2/{credential_id}
|
||||
"""
|
||||
func = _build_enforcer_target_data_owner_and_user_id_match
|
||||
ENFORCER.enforce_call(action='identity:ec2_delete_credential',
|
||||
build_target=func)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:ec2_delete_credential', build_target=func
|
||||
)
|
||||
PROVIDERS.identity_api.get_user(user_id)
|
||||
ec2_cred_id = utils.hash_access_key(credential_id)
|
||||
self._get_cred_data(ec2_cred_id)
|
||||
@ -473,10 +503,13 @@ class OAuth1ListAccessTokensResource(_OAuth1ResourceBase):
|
||||
ENFORCER.enforce_call(action='identity:list_access_tokens')
|
||||
if self.oslo_context.is_delegated_auth:
|
||||
raise ks_exception.Forbidden(
|
||||
_('Cannot list request tokens with a token '
|
||||
'issued via delegation.'))
|
||||
_(
|
||||
'Cannot list request tokens with a token '
|
||||
'issued via delegation.'
|
||||
)
|
||||
)
|
||||
refs = PROVIDERS.oauth_api.list_access_tokens(user_id)
|
||||
formatted_refs = ([_format_token_entity(x) for x in refs])
|
||||
formatted_refs = [_format_token_entity(x) for x in refs]
|
||||
return self.wrap_collection(formatted_refs)
|
||||
|
||||
|
||||
@ -500,7 +533,8 @@ class OAuth1AccessTokenCRUDResource(_OAuth1ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:ec2_delete_credential',
|
||||
build_target=_build_enforcer_target_data_owner_and_user_id_match)
|
||||
build_target=_build_enforcer_target_data_owner_and_user_id_match,
|
||||
)
|
||||
access_token = PROVIDERS.oauth_api.get_access_token(access_token_id)
|
||||
reason = (
|
||||
'Invalidating the token cache because an access token for '
|
||||
@ -511,7 +545,8 @@ class OAuth1AccessTokenCRUDResource(_OAuth1ResourceBase):
|
||||
)
|
||||
notifications.invalidate_token_cache_notification(reason)
|
||||
PROVIDERS.oauth_api.delete_access_token(
|
||||
user_id, access_token_id, initiator=self.audit_initiator)
|
||||
user_id, access_token_id, initiator=self.audit_initiator
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -531,7 +566,7 @@ class OAuth1AccessTokenRoleListResource(ks_flask.ResourceBase):
|
||||
raise ks_exception.NotFound()
|
||||
authed_role_ids = access_token['role_ids']
|
||||
authed_role_ids = jsonutils.loads(authed_role_ids)
|
||||
refs = ([_format_role_entity(x) for x in authed_role_ids])
|
||||
refs = [_format_role_entity(x) for x in authed_role_ids]
|
||||
return self.wrap_collection(refs)
|
||||
|
||||
|
||||
@ -561,19 +596,21 @@ class OAuth1AccessTokenRoleResource(ks_flask.ResourceBase):
|
||||
class UserAppCredListCreateResource(ks_flask.ResourceBase):
|
||||
collection_key = 'application_credentials'
|
||||
member_key = 'application_credential'
|
||||
_public_parameters = frozenset([
|
||||
'id',
|
||||
'name',
|
||||
'description',
|
||||
'expires_at',
|
||||
'project_id',
|
||||
'roles',
|
||||
# secret is only exposed after create, it is not stored
|
||||
'secret',
|
||||
'links',
|
||||
'unrestricted',
|
||||
'access_rules'
|
||||
])
|
||||
_public_parameters = frozenset(
|
||||
[
|
||||
'id',
|
||||
'name',
|
||||
'description',
|
||||
'expires_at',
|
||||
'project_id',
|
||||
'roles',
|
||||
# secret is only exposed after create, it is not stored
|
||||
'secret',
|
||||
'links',
|
||||
'unrestricted',
|
||||
'access_rules',
|
||||
]
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _generate_secret():
|
||||
@ -591,8 +628,9 @@ class UserAppCredListCreateResource(ks_flask.ResourceBase):
|
||||
if role.get('id'):
|
||||
roles.append(role)
|
||||
else:
|
||||
roles.append(PROVIDERS.role_api.get_unique_role_by_name(
|
||||
role['name']))
|
||||
roles.append(
|
||||
PROVIDERS.role_api.get_unique_role_by_name(role['name'])
|
||||
)
|
||||
return roles
|
||||
|
||||
def _get_roles(self, app_cred_data, token):
|
||||
@ -606,10 +644,13 @@ class UserAppCredListCreateResource(ks_flask.ResourceBase):
|
||||
token_roles = [r['id'] for r in token.roles]
|
||||
for role in roles:
|
||||
if role['id'] not in token_roles:
|
||||
detail = _('Cannot create an application credential with '
|
||||
'unassigned role')
|
||||
detail = _(
|
||||
'Cannot create an application credential with '
|
||||
'unassigned role'
|
||||
)
|
||||
raise ks_exception.ApplicationCredentialValidationError(
|
||||
detail=detail)
|
||||
detail=detail
|
||||
)
|
||||
else:
|
||||
roles = token.roles
|
||||
return roles
|
||||
@ -620,8 +661,9 @@ class UserAppCredListCreateResource(ks_flask.ResourceBase):
|
||||
GET/HEAD /v3/users/{user_id}/application_credentials
|
||||
"""
|
||||
filters = ('name',)
|
||||
ENFORCER.enforce_call(action='identity:list_application_credentials',
|
||||
filters=filters)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_application_credentials', filters=filters
|
||||
)
|
||||
app_cred_api = PROVIDERS.application_credential_api
|
||||
hints = self.build_driver_hints(filters)
|
||||
refs = app_cred_api.list_application_credentials(user_id, hints=hints)
|
||||
@ -634,14 +676,17 @@ class UserAppCredListCreateResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:create_application_credential')
|
||||
app_cred_data = self.request_body_json.get(
|
||||
'application_credential', {})
|
||||
validation.lazy_validate(app_cred_schema.application_credential_create,
|
||||
app_cred_data)
|
||||
'application_credential', {}
|
||||
)
|
||||
validation.lazy_validate(
|
||||
app_cred_schema.application_credential_create, app_cred_data
|
||||
)
|
||||
token = self.auth_context['token']
|
||||
_check_unrestricted_application_credential(token)
|
||||
if self.oslo_context.user_id != user_id:
|
||||
action = _('Cannot create an application credential for another '
|
||||
'user.')
|
||||
action = _(
|
||||
'Cannot create an application credential for another ' 'user.'
|
||||
)
|
||||
raise ks_exception.ForbiddenAction(action=action)
|
||||
project_id = self.oslo_context.project_id
|
||||
app_cred_data = self._assign_unique_id(app_cred_data)
|
||||
@ -652,7 +697,8 @@ class UserAppCredListCreateResource(ks_flask.ResourceBase):
|
||||
app_cred_data['roles'] = self._get_roles(app_cred_data, token)
|
||||
if app_cred_data.get('expires_at'):
|
||||
app_cred_data['expires_at'] = utils.parse_expiration_date(
|
||||
app_cred_data['expires_at'])
|
||||
app_cred_data['expires_at']
|
||||
)
|
||||
if app_cred_data.get('access_rules'):
|
||||
for access_rule in app_cred_data['access_rules']:
|
||||
# If user provides an access rule by ID, it will be looked up
|
||||
@ -668,13 +714,15 @@ class UserAppCredListCreateResource(ks_flask.ResourceBase):
|
||||
|
||||
try:
|
||||
ref = app_cred_api.create_application_credential(
|
||||
app_cred_data, initiator=self.audit_initiator)
|
||||
app_cred_data, initiator=self.audit_initiator
|
||||
)
|
||||
except ks_exception.RoleAssignmentNotFound as e:
|
||||
# Raise a Bad Request, not a Not Found, in accordance with the
|
||||
# API-SIG recommendations:
|
||||
# https://specs.openstack.org/openstack/api-wg/guidelines/http.html#failure-code-clarifications
|
||||
raise ks_exception.ApplicationCredentialValidationError(
|
||||
detail=str(e))
|
||||
detail=str(e)
|
||||
)
|
||||
return self.wrap_member(ref), http.client.CREATED
|
||||
|
||||
|
||||
@ -694,7 +742,8 @@ class UserAppCredGetDeleteResource(ks_flask.ResourceBase):
|
||||
target_attr=target,
|
||||
)
|
||||
ref = PROVIDERS.application_credential_api.get_application_credential(
|
||||
application_credential_id)
|
||||
application_credential_id
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
def delete(self, user_id, application_credential_id):
|
||||
@ -705,13 +754,13 @@ class UserAppCredGetDeleteResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
target = _update_request_user_id_attribute()
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:delete_application_credential',
|
||||
target_attr=target
|
||||
action='identity:delete_application_credential', target_attr=target
|
||||
)
|
||||
token = self.auth_context['token']
|
||||
_check_unrestricted_application_credential(token)
|
||||
PROVIDERS.application_credential_api.delete_application_credential(
|
||||
application_credential_id, initiator=self.audit_initiator)
|
||||
application_credential_id, initiator=self.audit_initiator
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -724,10 +773,16 @@ class UserAccessRuleListResource(ks_flask.ResourceBase):
|
||||
|
||||
GET/HEAD /v3/users/{user_id}/access_rules
|
||||
"""
|
||||
filters = ('service', 'path', 'method',)
|
||||
ENFORCER.enforce_call(action='identity:list_access_rules',
|
||||
filters=filters,
|
||||
build_target=_build_user_target_enforcement)
|
||||
filters = (
|
||||
'service',
|
||||
'path',
|
||||
'method',
|
||||
)
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:list_access_rules',
|
||||
filters=filters,
|
||||
build_target=_build_user_target_enforcement,
|
||||
)
|
||||
app_cred_api = PROVIDERS.application_credential_api
|
||||
hints = self.build_driver_hints(filters)
|
||||
refs = app_cred_api.list_access_rules_for_user(user_id, hints=hints)
|
||||
@ -746,10 +801,11 @@ class UserAccessRuleGetDeleteResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:get_access_rule',
|
||||
build_target=_build_user_target_enforcement
|
||||
build_target=_build_user_target_enforcement,
|
||||
)
|
||||
ref = PROVIDERS.application_credential_api.get_access_rule(
|
||||
access_rule_id)
|
||||
access_rule_id
|
||||
)
|
||||
return self.wrap_member(ref)
|
||||
|
||||
def delete(self, user_id, access_rule_id):
|
||||
@ -759,10 +815,11 @@ class UserAccessRuleGetDeleteResource(ks_flask.ResourceBase):
|
||||
"""
|
||||
ENFORCER.enforce_call(
|
||||
action='identity:delete_access_rule',
|
||||
build_target=_build_user_target_enforcement
|
||||
build_target=_build_user_target_enforcement,
|
||||
)
|
||||
PROVIDERS.application_credential_api.delete_access_rule(
|
||||
access_rule_id, initiator=self.audit_initiator)
|
||||
access_rule_id, initiator=self.audit_initiator
|
||||
)
|
||||
return None, http.client.NO_CONTENT
|
||||
|
||||
|
||||
@ -776,21 +833,21 @@ class UserAPI(ks_flask.APIBase):
|
||||
url='/users/<string:user_id>/password',
|
||||
resource_kwargs={},
|
||||
rel='user_change_password',
|
||||
path_vars={'user_id': json_home.Parameters.USER_ID}
|
||||
path_vars={'user_id': json_home.Parameters.USER_ID},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=UserGroupsResource,
|
||||
url='/users/<string:user_id>/groups',
|
||||
resource_kwargs={},
|
||||
rel='user_groups',
|
||||
path_vars={'user_id': json_home.Parameters.USER_ID}
|
||||
path_vars={'user_id': json_home.Parameters.USER_ID},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=UserProjectsResource,
|
||||
url='/users/<string:user_id>/projects',
|
||||
resource_kwargs={},
|
||||
rel='user_projects',
|
||||
path_vars={'user_id': json_home.Parameters.USER_ID}
|
||||
path_vars={'user_id': json_home.Parameters.USER_ID},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=UserOSEC2CredentialsResourceListCreate,
|
||||
@ -798,21 +855,27 @@ class UserAPI(ks_flask.APIBase):
|
||||
resource_kwargs={},
|
||||
rel='user_credentials',
|
||||
resource_relation_func=(
|
||||
json_home_relations.os_ec2_resource_rel_func),
|
||||
path_vars={'user_id': json_home.Parameters.USER_ID}
|
||||
json_home_relations.os_ec2_resource_rel_func
|
||||
),
|
||||
path_vars={'user_id': json_home.Parameters.USER_ID},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=UserOSEC2CredentialsResourceGetDelete,
|
||||
url=('/users/<string:user_id>/credentials/OS-EC2/'
|
||||
'<string:credential_id>'),
|
||||
url=(
|
||||
'/users/<string:user_id>/credentials/OS-EC2/'
|
||||
'<string:credential_id>'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='user_credential',
|
||||
resource_relation_func=(
|
||||
json_home_relations.os_ec2_resource_rel_func),
|
||||
json_home_relations.os_ec2_resource_rel_func
|
||||
),
|
||||
path_vars={
|
||||
'credential_id': json_home.build_v3_parameter_relation(
|
||||
'credential_id'),
|
||||
'user_id': json_home.Parameters.USER_ID}
|
||||
'credential_id'
|
||||
),
|
||||
'user_id': json_home.Parameters.USER_ID,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=OAuth1ListAccessTokensResource,
|
||||
@ -820,80 +883,99 @@ class UserAPI(ks_flask.APIBase):
|
||||
resource_kwargs={},
|
||||
rel='user_access_tokens',
|
||||
resource_relation_func=(
|
||||
json_home_relations.os_oauth1_resource_rel_func),
|
||||
path_vars={'user_id': json_home.Parameters.USER_ID}
|
||||
json_home_relations.os_oauth1_resource_rel_func
|
||||
),
|
||||
path_vars={'user_id': json_home.Parameters.USER_ID},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=OAuth1AccessTokenCRUDResource,
|
||||
url=('/users/<string:user_id>/OS-OAUTH1/'
|
||||
'access_tokens/<string:access_token_id>'),
|
||||
url=(
|
||||
'/users/<string:user_id>/OS-OAUTH1/'
|
||||
'access_tokens/<string:access_token_id>'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='user_access_token',
|
||||
resource_relation_func=(
|
||||
json_home_relations.os_oauth1_resource_rel_func),
|
||||
json_home_relations.os_oauth1_resource_rel_func
|
||||
),
|
||||
path_vars={
|
||||
'access_token_id': ACCESS_TOKEN_ID_PARAMETER_RELATION,
|
||||
'user_id': json_home.Parameters.USER_ID}
|
||||
'user_id': json_home.Parameters.USER_ID,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=OAuth1AccessTokenRoleListResource,
|
||||
url=('/users/<string:user_id>/OS-OAUTH1/access_tokens/'
|
||||
'<string:access_token_id>/roles'),
|
||||
url=(
|
||||
'/users/<string:user_id>/OS-OAUTH1/access_tokens/'
|
||||
'<string:access_token_id>/roles'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel='user_access_token_roles',
|
||||
resource_relation_func=(
|
||||
json_home_relations.os_oauth1_resource_rel_func),
|
||||
path_vars={'access_token_id': ACCESS_TOKEN_ID_PARAMETER_RELATION,
|
||||
'user_id': json_home.Parameters.USER_ID}
|
||||
json_home_relations.os_oauth1_resource_rel_func
|
||||
),
|
||||
path_vars={
|
||||
'access_token_id': ACCESS_TOKEN_ID_PARAMETER_RELATION,
|
||||
'user_id': json_home.Parameters.USER_ID,
|
||||
},
|
||||
),
|
||||
ks_flask.construct_resource_map(
|
||||
resource=OAuth1AccessTokenRoleResource,
|
||||
url=('/users/<string:user_id>/OS-OAUTH1/access_tokens/'
|
||||
'<string:access_token_id>/roles/<string:role_id>'),
|
||||
url=(
|
||||
'/users/<string:user_id>/OS-OAUTH1/access_tokens/'
|
||||
'<string:access_token_id>/roles/<string:role_id>'
|
||||
),
|
||||
resource_kwargs={},
|
||||
rel< |