def __init__(self, proxy_auth=False): """ Initialise a security policy. :param proxy_auth: Replace the default `CookiePolicy` for the UI with the `RemoteUserPolicy`. """ self._bearer_token_policy = BearerTokenPolicy() self._http_basic_auth_policy = AuthClientPolicy() self._identity_cache = RequestLocalCache(self._load_identity) self._ui_policy = RemoteUserPolicy() if proxy_auth else CookiePolicy()
def test_identify_without_forwarded_user(self, pyramid_request, auth_client): pyramid_request.headers["X-Forwarded-User"] = None identity = AuthClientPolicy().identity(pyramid_request) assert identity == Identity.from_models(auth_client=auth_client)
def test_identity(self, pyramid_request, auth_client, user_service): pyramid_request.headers["X-Forwarded-User"] = sentinel.forwarded_user identity = AuthClientPolicy().identity(pyramid_request) user_service.fetch.assert_called_once_with(sentinel.forwarded_user) assert identity == Identity.from_models( auth_client=auth_client, user=user_service.fetch.return_value)
def test_identify_returns_None_if_forwarded_userid_is_invalid( self, user_service, pyramid_request): user_service.fetch.side_effect = InvalidUserId(sentinel.invalid_id) assert AuthClientPolicy().identity(pyramid_request) is None
def test_identify_returns_None_if_forwarded_user_is_not_found( self, user_service, pyramid_request): user_service.fetch.return_value = None assert AuthClientPolicy().identity(pyramid_request) is None
def test_identify_returns_None_if_auth_client_secrets_do_not_match( self, auth_client, pyramid_request): self.set_http_credentials(pyramid_request, auth_client.id, "WRONG SECRET") assert AuthClientPolicy().identity(pyramid_request) is None
def test_identify_returns_None_if_auth_client_secret_is_None( self, auth_client, pyramid_request): auth_client.secret = None assert AuthClientPolicy().identity(pyramid_request) is None
def test_identify_returns_None_if_auth_client_not_client_type( self, auth_client, pyramid_request): auth_client.grant_type = None assert AuthClientPolicy().identity(pyramid_request) is None
def test_identify_returns_None_if_auth_client_not_secret( self, auth_client, pyramid_request): self.set_http_credentials(pyramid_request, "NOT A UUID", auth_client.secret) assert AuthClientPolicy().identity(pyramid_request) is None
def test_identity_returns_None_if_auth_client_missing( self, pyramid_request, auth_client, db_session): db_session.delete(auth_client) db_session.flush() assert AuthClientPolicy().identity(pyramid_request) is None
def test_identity_returns_None_without_credentials(self, pyramid_request): pyramid_request.headers["Authorization"] = None assert AuthClientPolicy().identity(pyramid_request) is None
def test_handles_rejects_no_route(self, pyramid_request): pyramid_request.matched_route = None assert not AuthClientPolicy.handles(pyramid_request)
def test_handles_rejects_unknown_routes(self, pyramid_request): pyramid_request.matched_route.name = "not.recognised" assert not AuthClientPolicy.handles(pyramid_request)
def test_handles(self, pyramid_request, route_name, method): pyramid_request.matched_route.name = route_name pyramid_request.method = method assert AuthClientPolicy.handles(pyramid_request)
def test_identify_returns_None_on_forwarded_userid_authority_mismatch( self, user, auth_client, pyramid_request): user.authority = "not" + auth_client.authority assert AuthClientPolicy().identity(pyramid_request) is None
class SecurityPolicy(IdentityBasedPolicy): """ The security policy for `h`. This delegates to various different policies depending on the situation. """ def __init__(self, proxy_auth=False): """ Initialise a security policy. :param proxy_auth: Replace the default `CookiePolicy` for the UI with the `RemoteUserPolicy`. """ self._bearer_token_policy = BearerTokenPolicy() self._http_basic_auth_policy = AuthClientPolicy() self._identity_cache = RequestLocalCache(self._load_identity) self._ui_policy = RemoteUserPolicy() if proxy_auth else CookiePolicy() def remember(self, request, userid, **kw): """Get the correct headers to remember the given user.""" self._identity_cache.clear(request) return self._call_sub_policies("remember", request, userid, **kw) def forget(self, request): """Get the correct headers to forget the current login.""" self._identity_cache.clear(request) return self._call_sub_policies("forget", request) def identity(self, request) -> Optional[Identity]: """ Get an Identity object for valid credentials. :param request: Pyramid request to inspect """ return self._identity_cache.get_or_create(request) def _load_identity(self, request): return self._call_sub_policies("identity", request) def _call_sub_policies(self, method, request, *args, **kwargs): """ Delegate calls to the correct set of security policies. :param method: Method to call (like `identity()` or `forget()`) :param request: Pyramid request object :param args: Args to pass to the method :param kwargs: Kwargs to pass to the method :return: The response from the correct sub-policy """ if not self._is_api_request(request): # This is usually the cookie policy for UI things return getattr(self._ui_policy, method)(request, *args, **kwargs) # Then we try the bearer header (or `access_token` GET param) result = getattr(self._bearer_token_policy, method)(request, *args, **kwargs) if not result and self._http_basic_auth_policy.handles(request): # Only then do we look for auth clients authenticating with basic # HTTP auth credentials return getattr(self._http_basic_auth_policy, method)(request, *args, **kwargs) return result @staticmethod def _is_api_request(request): return request.path.startswith("/api") and request.path not in [ "/api/token", "/api/badge", ]