Switch our temporary token lookups for signed grants which will not require DB access.
This commit is contained in:
parent
4e5d671349
commit
78c8354174
4 changed files with 81 additions and 54 deletions
|
@ -9,12 +9,13 @@ from collections import OrderedDict
|
|||
from data import model
|
||||
from data.model import oauth
|
||||
from app import app, authentication, userevents, storage
|
||||
from auth.auth import process_auth
|
||||
from auth.auth import process_auth, generate_signed_token
|
||||
from auth.auth_context import get_authenticated_user, get_validated_token, get_validated_oauth_token
|
||||
from util.names import parse_repository_name
|
||||
from util.useremails import send_confirmation_email
|
||||
from auth.permissions import (ModifyRepositoryPermission, UserAdminPermission,
|
||||
ReadRepositoryPermission, CreateRepositoryPermission)
|
||||
ReadRepositoryPermission, CreateRepositoryPermission,
|
||||
AlwaysFailPermission, repository_read_grant, repository_write_grant)
|
||||
|
||||
from util.http import abort
|
||||
from endpoints.trackhelper import track_and_log
|
||||
|
@ -26,7 +27,13 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
index = Blueprint('index', __name__)
|
||||
|
||||
def generate_headers(role='read'):
|
||||
|
||||
class GrantType(object):
|
||||
READ_REPOSITORY = 'read'
|
||||
WRITE_REPOSITORY = 'write'
|
||||
|
||||
|
||||
def generate_headers(scope=GrantType.READ_REPOSITORY):
|
||||
def decorator_method(f):
|
||||
@wraps(f)
|
||||
def wrapper(namespace, repository, *args, **kwargs):
|
||||
|
@ -35,12 +42,6 @@ def generate_headers(role='read'):
|
|||
# Setting session namespace and repository
|
||||
session['namespace'] = namespace
|
||||
session['repository'] = repository
|
||||
|
||||
if get_authenticated_user():
|
||||
session['username'] = get_authenticated_user().username
|
||||
else:
|
||||
session.pop('username', None)
|
||||
|
||||
# We run our index and registry on the same hosts for now
|
||||
registry_server = urlparse.urlparse(request.url).netloc
|
||||
response.headers['X-Docker-Endpoints'] = registry_server
|
||||
|
@ -48,16 +49,23 @@ def generate_headers(role='read'):
|
|||
has_token_request = request.headers.get('X-Docker-Token', '')
|
||||
|
||||
if has_token_request:
|
||||
repo = model.get_repository(namespace, repository)
|
||||
if repo:
|
||||
token = model.create_access_token(repo, role, 'pushpull-token')
|
||||
token_str = 'signature=%s' % token.code
|
||||
response.headers['WWW-Authenticate'] = token_str
|
||||
response.headers['X-Docker-Token'] = token_str
|
||||
else:
|
||||
logger.info('Token request in non-existing repo: %s/%s' %
|
||||
(namespace, repository))
|
||||
permission = AlwaysFailPermission()
|
||||
grants = []
|
||||
if scope == GrantType.READ_REPOSITORY:
|
||||
permission = ReadRepositoryPermission(namespace, repository)
|
||||
grants.append(repository_read_grant(namespace, repository))
|
||||
elif scope == GrantType.WRITE_REPOSITORY:
|
||||
permission = ModifyRepositoryPermission(namespace, repository)
|
||||
grants.append(repository_write_grant(namespace, repository))
|
||||
|
||||
if permission.can():
|
||||
# Generate a signed grant which expires here
|
||||
signature = generate_signed_token(grants)
|
||||
response.headers['WWW-Authenticate'] = signature
|
||||
response.headers['X-Docker-Token'] = signature
|
||||
else:
|
||||
logger.warning('Registry request with invalid credentials on repository: %s/%s',
|
||||
namespace, repository)
|
||||
return response
|
||||
return wrapper
|
||||
return decorator_method
|
||||
|
@ -186,7 +194,7 @@ def update_user(username):
|
|||
@index.route('/repositories/<path:repository>', methods=['PUT'])
|
||||
@process_auth
|
||||
@parse_repository_name
|
||||
@generate_headers(role='write')
|
||||
@generate_headers(scope=GrantType.WRITE_REPOSITORY)
|
||||
def create_repository(namespace, repository):
|
||||
logger.debug('Parsing image descriptions')
|
||||
image_descriptions = json.loads(request.data.decode('utf8'))
|
||||
|
@ -228,7 +236,7 @@ def create_repository(namespace, repository):
|
|||
@index.route('/repositories/<path:repository>/images', methods=['PUT'])
|
||||
@process_auth
|
||||
@parse_repository_name
|
||||
@generate_headers(role='write')
|
||||
@generate_headers(scope=GrantType.WRITE_REPOSITORY)
|
||||
def update_images(namespace, repository):
|
||||
permission = ModifyRepositoryPermission(namespace, repository)
|
||||
|
||||
|
@ -273,7 +281,7 @@ def update_images(namespace, repository):
|
|||
@index.route('/repositories/<path:repository>/images', methods=['GET'])
|
||||
@process_auth
|
||||
@parse_repository_name
|
||||
@generate_headers(role='read')
|
||||
@generate_headers(scope=GrantType.READ_REPOSITORY)
|
||||
def get_repository_images(namespace, repository):
|
||||
permission = ReadRepositoryPermission(namespace, repository)
|
||||
|
||||
|
@ -307,7 +315,7 @@ def get_repository_images(namespace, repository):
|
|||
@index.route('/repositories/<path:repository>/images', methods=['DELETE'])
|
||||
@process_auth
|
||||
@parse_repository_name
|
||||
@generate_headers(role='write')
|
||||
@generate_headers(scope=GrantType.WRITE_REPOSITORY)
|
||||
def delete_repository_images(namespace, repository):
|
||||
abort(501, 'Not Implemented', issue='not-implemented')
|
||||
|
||||
|
|
Reference in a new issue