Make our JWT subjects better and log using the info

Fixes #1039
This commit is contained in:
Joseph Schorr 2015-12-09 16:10:39 -05:00
parent 35437c9f55
commit 4a4eee5e05
10 changed files with 199 additions and 35 deletions

View file

@ -3,7 +3,7 @@
import features
from flask import abort
from auth.auth_context import (get_validated_oauth_token, get_authenticated_user,
get_validated_token, get_grant_user_context)
get_validated_token, get_grant_context)
from functools import wraps
@ -29,7 +29,7 @@ def check_anon_protection(func):
# Check for validated context. If none exists, fail with a 401.
if (get_authenticated_user() or get_validated_oauth_token() or get_validated_token() or
get_grant_user_context()):
get_grant_context()):
return func(*args, **kwargs)
abort(401)

View file

@ -4,8 +4,9 @@ import random
from app import analytics, app, userevents
from data import model
from flask import request
from auth.jwt_auth import get_granted_entity
from auth.auth_context import (get_authenticated_user, get_validated_token,
get_validated_oauth_token, get_grant_user_context)
get_validated_oauth_token)
logger = logging.getLogger(__name__)
@ -23,11 +24,13 @@ def track_and_log(event_name, repo, analytics_name=None, analytics_sample=1, **k
authenticated_oauth_token = get_validated_oauth_token()
authenticated_user = get_authenticated_user()
authenticated_token = get_validated_token() if not authenticated_user else None
granted_username = get_grant_user_context()
# TODO: Fix this to support OAuth tokens as well.
if granted_username is not None:
authenticated_user = model.user.get_user(granted_username)
if not authenticated_user and not authenticated_token and not authenticated_oauth_token:
entity = get_granted_entity()
if entity:
authenticated_user = entity.user
authenticated_token = entity.token
authenticated_oauth_token = entity.oauth
logger.debug('Logging the %s to Mixpanel and the log system', event_name)
if authenticated_oauth_token:

View file

@ -9,7 +9,8 @@ from time import time
from app import storage as store, image_replication_queue, app
from auth.auth import process_auth, extract_namespace_repo_from_session
from auth.auth_context import get_authenticated_user, get_grant_user_context
from auth.auth_context import get_authenticated_user
from auth.jwt_auth import get_granted_username
from digest import checksums
from util.registry import changes
from util.http import abort, exact_abort
@ -436,8 +437,10 @@ def put_image_json(namespace, repository, image_id):
repo_image = model.image.get_repo_image_extended(namespace, repository, image_id)
if not repo_image:
username = (get_authenticated_user() and get_authenticated_user().username or
get_grant_user_context())
username = get_authenticated_user() and get_authenticated_user().username
if not username:
username = get_granted_username()
logger.debug('Image not found, creating image with initiating user context: %s', username)
repo_image = model.image.find_create_or_link_image(image_id, repo, username, {},
store.preferred_locations[0])

View file

@ -10,7 +10,7 @@ from app import metric_queue
from endpoints.decorators import anon_protect, anon_allowed
from endpoints.v2.errors import V2RegistryException
from auth.jwt_auth import process_jwt_auth
from auth.auth_context import get_grant_user_context
from auth.auth_context import get_grant_context
from auth.permissions import (ReadRepositoryPermission, ModifyRepositoryPermission,
AdministerRepositoryPermission)
from data import model
@ -80,7 +80,7 @@ def route_show_if(value):
def v2_support_enabled():
response = make_response('true', 200)
if get_grant_user_context() is None:
if get_grant_context() is None:
response = make_response('true', 401)
realm_auth_path = url_for('v2.generate_registry_jwt')

View file

@ -9,7 +9,8 @@ from cachetools import lru_cache
from app import app
from data import model
from auth.auth import process_auth
from auth.auth_context import get_authenticated_user, get_validated_token
from auth.jwt_auth import build_context_and_subject
from auth.auth_context import get_authenticated_user, get_validated_token, get_validated_oauth_token
from auth.permissions import (ModifyRepositoryPermission, ReadRepositoryPermission,
CreateRepositoryPermission)
from endpoints.v2 import v2_bp
@ -24,8 +25,6 @@ TOKEN_VALIDITY_LIFETIME_S = 60 * 60 # 1 hour
SCOPE_REGEX = re.compile(
r'^repository:([\.a-zA-Z0-9_\-]+/[\.a-zA-Z0-9_\-]+):(((push|pull|\*),)*(push|pull|\*))$'
)
ANONYMOUS_SUB = '(anonymous)'
@lru_cache(maxsize=1)
def load_certificate_bytes(certificate_file_path):
@ -58,6 +57,10 @@ def generate_registry_jwt():
token = get_validated_token()
logger.debug('Authenticated token: %s', token)
oauthtoken = get_validated_oauth_token()
logger.debug('Authenticated OAuth token: %s', oauthtoken)
access = []
if scope_param is not None:
match = SCOPE_REGEX.match(scope_param)
@ -123,14 +126,16 @@ def generate_registry_jwt():
# In this case, we are doing an auth flow, and it's not an anonymous pull
return abort(401)
context, subject = build_context_and_subject(user, token, oauthtoken)
token_data = {
'iss': app.config['JWT_AUTH_TOKEN_ISSUER'],
'aud': audience_param,
'nbf': int(time.time()),
'iat': int(time.time()),
'exp': int(time.time() + TOKEN_VALIDITY_LIFETIME_S),
'sub': user.username if user else ANONYMOUS_SUB,
'sub': subject,
'access': access,
'context': context,
}
certificate = load_certificate_bytes(app.config['JWT_AUTH_CERTIFICATE_PATH'])