Fix getting token from application credentials token

When user tries to get token from token that was initially issued using
application credentials it is necessary to restore the initial
application credential is to enforce it's scope, roles and access rules.

Closes-bug: #2111836
Change-Id: Ie94f7e18106b50087284bd8c81b50aa50ab104cb
Signed-off-by: Artem Goncharov <artem.goncharov@gmail.com>
This commit is contained in:
Artem Goncharov
2025-05-30 12:47:29 +02:00
parent 069fa4566b
commit 2323c474f8
2 changed files with 32 additions and 3 deletions

View File

@@ -178,6 +178,13 @@ def authenticate(auth_info, auth_context):
resp_method_names = resp.response_data.pop('method_names', [])
auth_context['method_names'].extend(resp_method_names)
auth_context.update(resp.response_data or {})
# NOTE(gtema): When trying to get token from
# application_credential based token we need to restore
# application_credential_id to prevent escaping its bounds.
if "application_credential_id" in resp:
auth_context["application_credential_id"] = resp[
"application_credential_id"
]
elif resp.response_body:
auth_response['methods'].append(method_name)
auth_response[method_name] = resp.response_body
@@ -226,7 +233,14 @@ def authenticate_for_token(auth=None):
app_cred_id = None
if 'application_credential' in method_names:
token_auth = auth_info.auth['identity']
app_cred_id = token_auth['application_credential']['id']
if "application_credential" in token_auth:
app_cred_id = token_auth['application_credential']['id']
elif "application_credential_id" in auth_context:
app_cred_id = auth_context["application_credential_id"]
else:
raise exception.MissingApplicationCredentialId(
user_id=auth_context['user_id']
)
# Do MFA Rule Validation for the user
if not core.UserMFARulesValidator.check_auth_methods_against_rules(

View File

@@ -14,6 +14,7 @@
import flask
from oslo_log import log
import typing as ty
from keystone.auth.plugins import base
from keystone.auth.plugins import mapped
@@ -21,6 +22,7 @@ from keystone.common import provider_api
import keystone.conf
from keystone import exception
from keystone.i18n import _
from keystone.models.token_model import TokenModel
LOG = log.getLogger(__name__)
@@ -49,13 +51,12 @@ class Token(base.AuthMethodHandler):
# for re-scoping and we want to maintain the values. Most
# AuthMethodHandlers do no such thing and this is not required.
response_data.setdefault('method_names', []).extend(token.methods)
return base.AuthHandlerResponse(
status=True, response_body=None, response_data=response_data
)
def token_authenticate(token):
def token_authenticate(token: TokenModel) -> dict[str, ty.Any]:
response_data = {}
try:
# Do not allow tokens used for delegation to
@@ -88,6 +89,20 @@ def token_authenticate(token):
'or domain-scoped token is not allowed.'
)
)
elif token.application_credential:
# NOTE(gtema): when getting token from token (initially issued by
# application credential) it is necessary to ensure scope is not
# requested.
if project_scoped or domain_scoped:
raise exception.ForbiddenAction(
action=_(
"Using an application credential token to create a "
"project-scoped or domain-scoped token is not allowed."
)
)
response_data["application_credential_id"] = (
token.application_credential["id"]
)
if not CONF.token.allow_rescope_scoped_token:
# Do not allow conversion from scoped tokens.