Refactor the code into modules, it was getting unweildy.
This commit is contained in:
parent
2611d70185
commit
ee5ea51532
12 changed files with 73 additions and 70 deletions
0
auth/__init__.py
Normal file
0
auth/__init__.py
Normal file
120
auth/auth.py
Normal file
120
auth/auth.py
Normal file
|
@ -0,0 +1,120 @@
|
|||
import logging
|
||||
|
||||
from functools import wraps
|
||||
from flask import request, make_response, _request_ctx_stack, abort
|
||||
from flask.ext.principal import identity_changed, Identity
|
||||
from flask.ext.login import UserMixin
|
||||
from base64 import b64decode
|
||||
|
||||
from data import model
|
||||
from app import app, login_manager
|
||||
|
||||
from util import parse_namespace_repository
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class _LoginWrappedDBUser(UserMixin):
|
||||
def __init__(self, db_user):
|
||||
self.db_user = db_user
|
||||
|
||||
def is_active(self):
|
||||
return self.db_user.verified
|
||||
|
||||
def get_id(self):
|
||||
return unicode(self.db_user.username)
|
||||
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(username):
|
||||
db_user = model.get_user(username)
|
||||
if db_user:
|
||||
return _LoginWrappedDBUser(db_user)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def get_authenticated_user():
|
||||
return getattr(_request_ctx_stack.top, 'authenticated_user', None)
|
||||
|
||||
|
||||
def get_validated_token():
|
||||
return getattr(_request_ctx_stack.top, 'validated_token', None)
|
||||
|
||||
|
||||
def process_basic_auth():
|
||||
auth = request.headers.get('authorization', '')
|
||||
normalized = [part.strip() for part in auth.split(' ') if part]
|
||||
if normalized[0].lower() != 'basic' or len(normalized) != 2:
|
||||
logger.debug('Invalid basic auth format.')
|
||||
return False
|
||||
|
||||
credentials = b64decode(normalized[1]).split(':')
|
||||
|
||||
if len(credentials) != 2:
|
||||
logger.debug('Invalid basic auth credential formet.')
|
||||
|
||||
authenticated = model.verify_user(credentials[0], credentials[1])
|
||||
|
||||
if authenticated:
|
||||
logger.debug('Successfully validated user: %s' % authenticated.username)
|
||||
ctx = _request_ctx_stack.top
|
||||
ctx.authenticated_user = authenticated
|
||||
|
||||
identity_changed.send(app, identity=Identity(authenticated.username))
|
||||
|
||||
return True
|
||||
|
||||
# We weren't able to authenticate via basic auth.
|
||||
return False
|
||||
|
||||
|
||||
def process_token():
|
||||
auth = request.headers.get('authorization', '')
|
||||
logger.debug('Validating auth token: %s' % auth)
|
||||
|
||||
normalized = [part.strip() for part in auth.split(' ') if part]
|
||||
if normalized[0].lower() != 'token' or len(normalized) != 3:
|
||||
logger.debug('Invalid token format.')
|
||||
return False
|
||||
|
||||
token_details = normalized[2].split(',')
|
||||
|
||||
if len(token_details) != 3:
|
||||
logger.debug('Invalid token format.')
|
||||
return False
|
||||
|
||||
token_vals = {val[0]: val[1] for val in
|
||||
(detail.split('=') for detail in token_details)}
|
||||
if ('signature' not in token_vals or 'access' not in token_vals or
|
||||
'repository' not in token_vals):
|
||||
logger.debug('Invalid token components.')
|
||||
return False
|
||||
|
||||
unquoted = token_vals['repository'][1:-1]
|
||||
namespace, repository = parse_namespace_repository(unquoted)
|
||||
logger.debug('Validing signature: %s' % token_vals['signature'])
|
||||
validated = model.verify_token(token_vals['signature'])
|
||||
|
||||
if validated:
|
||||
logger.debug('Successfully validated token: %s' % validated.code)
|
||||
ctx = _request_ctx_stack.top
|
||||
ctx.validated_token = validated
|
||||
|
||||
identity_changed.send(app, identity=Identity(validated.code))
|
||||
|
||||
return True
|
||||
|
||||
# WE weren't able to authenticate the token
|
||||
logger.debug('Token could not be validated.')
|
||||
return False
|
||||
|
||||
|
||||
def process_auth(f):
|
||||
@wraps(f)
|
||||
def wrapper(*args, **kwargs):
|
||||
process_token()
|
||||
process_basic_auth()
|
||||
return f(*args, **kwargs)
|
||||
return wrapper
|
60
auth/permissions.py
Normal file
60
auth/permissions.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
import logging
|
||||
|
||||
from flask.ext.principal import identity_loaded, UserNeed, Permission
|
||||
from collections import namedtuple
|
||||
|
||||
from data import model
|
||||
from app import app
|
||||
from auth import get_authenticated_user, get_validated_token
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
_RepositoryNeed = namedtuple('repository', ['namespace', 'name', 'role'])
|
||||
|
||||
|
||||
class ModifyRepositoryPermission(Permission):
|
||||
def __init__(self, namespace, name):
|
||||
admin_need = _RepositoryNeed(namespace, name, 'admin')
|
||||
write_need = _RepositoryNeed(namespace, name, 'write')
|
||||
super(ModifyRepositoryPermission, self).__init__(admin_need, write_need)
|
||||
|
||||
|
||||
class ReadRepositoryPermission(Permission):
|
||||
def __init__(self, namespace, name):
|
||||
admin_need = _RepositoryNeed(namespace, name, 'admin')
|
||||
write_need = _RepositoryNeed(namespace, name, 'write')
|
||||
read_need = _RepositoryNeed(namespace, name, 'read')
|
||||
super(ReadRepositoryPermission, self).__init__(admin_need, write_need,
|
||||
read_need)
|
||||
|
||||
|
||||
class UserPermission(Permission):
|
||||
def __init__(self, username):
|
||||
user_need = UserNeed(username)
|
||||
super(UserPermission, self).__init__(user_need)
|
||||
|
||||
|
||||
@identity_loaded.connect_via(app)
|
||||
def on_identity_loaded(sender, identity):
|
||||
# We have verified an identity, load in all of the permissions
|
||||
if get_authenticated_user():
|
||||
identity.provides.add(UserNeed(get_authenticated_user().username))
|
||||
|
||||
for user in model.get_all_repo_permissions(get_authenticated_user()):
|
||||
grant = _RepositoryNeed(user.repositorypermission.repository.namespace,
|
||||
user.repositorypermission.repository.name,
|
||||
user.repositorypermission.role.name)
|
||||
logger.debug('User added permission: {0}'.format(grant))
|
||||
identity.provides.add(grant)
|
||||
|
||||
if get_validated_token():
|
||||
query = model.get_user_repo_permissions(get_validated_token().user,
|
||||
get_validated_token().repository)
|
||||
for permission in query:
|
||||
t_grant = _RepositoryNeed(get_validated_token().repository.namespace,
|
||||
get_validated_token().repository.name,
|
||||
permission.role.name)
|
||||
logger.debug('Token added permission: {0}'.format(t_grant))
|
||||
identity.provides.add(t_grant)
|
Reference in a new issue