import logging from flask.sessions import SecureCookieSessionInterface, BadSignature from app import app from auth.validateresult import AuthKind, ValidateResult logger = logging.getLogger(__name__) # The prefix for all signatures of signed granted. SIGNATURE_PREFIX = 'sigv2=' def generate_signed_token(grants, user_context): """ Generates a signed session token with the given grants and user context. """ ser = SecureCookieSessionInterface().get_signing_serializer(app) data_to_sign = { 'grants': grants, 'user_context': user_context, } encrypted = ser.dumps(data_to_sign) return '{0}{1}'.format(SIGNATURE_PREFIX, encrypted) def validate_signed_grant(auth_header): """ Validates a signed grant as found inside an auth header and returns whether it points to a valid grant. """ if not auth_header: return ValidateResult(AuthKind.signed_grant, missing=True) # Try to parse the token from the header. normalized = [part.strip() for part in auth_header.split(' ') if part] if normalized[0].lower() != 'token' or len(normalized) != 2: logger.debug('Not a token: %s', auth_header) return ValidateResult(AuthKind.signed_grant, missing=True) # Check that it starts with the expected prefix. if not normalized[1].startswith(SIGNATURE_PREFIX): logger.debug('Not a signed grant token: %s', auth_header) return ValidateResult(AuthKind.signed_grant, missing=True) # Decrypt the grant. encrypted = normalized[1][len(SIGNATURE_PREFIX):] ser = SecureCookieSessionInterface().get_signing_serializer(app) try: token_data = ser.loads(encrypted, max_age=app.config['SIGNED_GRANT_EXPIRATION_SEC']) except BadSignature: logger.warning('Signed grant could not be validated: %s', encrypted) return ValidateResult(AuthKind.signed_grant, error_message='Signed grant could not be validated') logger.debug('Successfully validated signed grant with data: %s', token_data) return ValidateResult(AuthKind.signed_grant, signed_data=token_data)