diff --git a/auth/auth.py b/auth/auth.py index 61c6b9a2c..b8d9065e6 100644 --- a/auth/auth.py +++ b/auth/auth.py @@ -15,7 +15,7 @@ from data import model from data.model import oauth from app import app, authentication from permissions import QuayDeferredPermissionUser -from auth_context import (set_authenticated_user, set_validated_token, +from auth_context import (set_authenticated_user, set_validated_token, set_grant_user_context, set_authenticated_user_deferred, set_validated_oauth_token) from util.http import abort @@ -131,10 +131,11 @@ def _process_basic_auth(auth): logger.debug('Basic auth present but could not be validated.') -def generate_signed_token(grants): +def generate_signed_token(grants, user_context): ser = SecureCookieSessionInterface().get_signing_serializer(app) data_to_sign = { 'grants': grants, + 'user_context': user_context, } encrypted = ser.dumps(data_to_sign) @@ -164,6 +165,7 @@ def _process_signed_grant(auth): logger.debug('Successfully validated signed grant with data: %s', token_data) loaded_identity = Identity(None, 'signed_grant') + set_grant_user_context(token_data['user_context']) loaded_identity.provides.update(token_data['grants']) identity_changed.send(app, identity=loaded_identity) diff --git a/auth/auth_context.py b/auth/auth_context.py index cfc6c7b5d..d4ae381be 100644 --- a/auth/auth_context.py +++ b/auth/auth_context.py @@ -30,6 +30,15 @@ def set_authenticated_user(user_or_robot): ctx.authenticated_user = user_or_robot +def get_grant_user_context(): + return getattr(_request_ctx_stack.top, 'grant_user_context', None) + + +def set_grant_user_context(username_or_robotname): + ctx = _request_ctx_stack.top + ctx.grant_user_context = username_or_robotname + + def set_authenticated_user_deferred(user_or_robot_db_uuid): logger.debug('Deferring loading of authenticated user object with uuid: %s', user_or_robot_db_uuid) ctx = _request_ctx_stack.top diff --git a/endpoints/index.py b/endpoints/index.py index a20c492d6..ca4b73362 100644 --- a/endpoints/index.py +++ b/endpoints/index.py @@ -60,7 +60,8 @@ def generate_headers(scope=GrantType.READ_REPOSITORY): if permission.can(): # Generate a signed grant which expires here - signature = generate_signed_token(grants) + user_context = get_authenticated_user() and get_authenticated_user().username + signature = generate_signed_token(grants, user_context) response.headers['WWW-Authenticate'] = signature response.headers['X-Docker-Token'] = signature else: diff --git a/endpoints/registry.py b/endpoints/registry.py index 07a33c4d9..73610910e 100644 --- a/endpoints/registry.py +++ b/endpoints/registry.py @@ -9,7 +9,7 @@ from time import time from app import storage as store, image_diff_queue, app from auth.auth import process_auth, extract_namespace_repo_from_session -from auth.auth_context import get_authenticated_user +from auth.auth_context import get_authenticated_user, get_grant_user_context from util import checksums, changes from util.http import abort, exact_abort from auth.permissions import (ReadRepositoryPermission, @@ -463,8 +463,9 @@ def put_image_json(namespace, repository, image_id): repo_image = model.get_repo_image_extended(namespace, repository, image_id) if not repo_image: - logger.debug('Image not found, creating image') - username = get_authenticated_user() and get_authenticated_user().username + username = (get_authenticated_user() and get_authenticated_user().username or + get_grant_user_context()) + logger.debug('Image not found, creating image with initiating user context: %s', username) repo_image = model.find_create_or_link_image(image_id, repo, username, {}, store.preferred_locations[0])