import logging from flask.sessions import BadSignature, SecureCookieSessionInterface 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)