from functools import wraps from jwt.exceptions import InvalidIssuerError, InvalidTokenError from .asap import _process_asap_token, _verify_issuers from .utils import SettingsDict def _with_asap(func=None, backend=None, issuers=None, required=True, subject_should_match_issuer=None): if backend is None: raise ValueError( 'Invalid value for backend. Use a subclass instead.' ) def with_asap_decorator(func): @wraps(func) def with_asap_wrapper(*args, **kwargs): settings = _update_settings_from_kwargs( backend.settings, issuers=issuers, required=required, subject_should_match_issuer=subject_should_match_issuer ) request = None if len(args) > 0: request = args[0] error_response = _process_asap_token( request, backend, settings ) if error_response is not None: return error_response return func(*args, **kwargs) return with_asap_wrapper if callable(func): return with_asap_decorator(func) return with_asap_decorator def _restrict_asap(func=None, backend=None, issuers=None, required=True, subject_should_match_issuer=None): """Decorator to allow endpoint-specific ASAP authorization, assuming ASAP authentication has already occurred. """ def restrict_asap_decorator(func): @wraps(func) def restrict_asap_wrapper(request, *args, **kwargs): settings = _update_settings_from_kwargs( backend.settings, issuers=issuers, required=required, subject_should_match_issuer=subject_should_match_issuer ) asap_claims = getattr(request, 'asap_claims', None) error_response = None if required and not asap_claims: return backend.get_401_response( 'Unauthorized', request=request ) try: _verify_issuers(asap_claims, settings.ASAP_VALID_ISSUERS) except InvalidIssuerError: error_response = backend.get_403_response( 'Forbidden: Invalid token issuer', request=request ) except InvalidTokenError: error_response = backend.get_401_response( 'Unauthorized: Invalid token', request=request ) if error_response and required: return error_response return func(request, *args, **kwargs) return restrict_asap_wrapper if callable(func): return restrict_asap_decorator(func) return restrict_asap_decorator def _update_settings_from_kwargs(settings, issuers=None, required=True, subject_should_match_issuer=None): settings = settings.copy() if issuers is not None: settings['ASAP_VALID_ISSUERS'] = set(issuers) if required is not None: settings['ASAP_REQUIRED'] = required if subject_should_match_issuer is not None: settings['ASAP_SUBJECT_SHOULD_MATCH_ISSUER'] = ( subject_should_match_issuer ) return SettingsDict(settings)