class MySecurityPolicy: def __init__(self, secret): self.authtkt = AuthTktCookieHelper(secret) self.identity_cache = RequestLocalCache(self.load_identity) def load_identity(self, request): identity = self.authtkt.identify(request) if identity is None: return None userid = identity['userid'] user = request.dbsession.query(models.User).get(userid) return user def identity(self, request): return self.identity_cache.get_or_create(request) def authenticated_userid(self, request): user = self.identity(request) if user is not None: return user.id def remember(self, request, userid, **kw): return self.authtkt.remember(request, userid, **kw) def forget(self, request, **kw): return self.authtkt.forget(request, **kw)
class BearerTokenPolicy(IdentityBasedPolicy): """ A Bearer token authentication policy. This policy uses a bearer token which is validated against Token objects in the DB. This can come from the Bearer token header or in the case of Websocket requests with the GET parameter `access_token`. We use this for our API and Websocket requests. """ def __init__(self): self._identity_cache = RequestLocalCache(self._load_identity) def identity(self, request): """ Get an Identity object for valid credentials. Validate the token from the request by matching them to Token records in the DB. :param request: Pyramid request to inspect :returns: An `Identity` object if the login is authenticated or None """ return self._identity_cache.get_or_create(request) def _load_identity(self, request): token_svc = request.find_service(name="auth_token") token_str = None # We only ever want to read the access token from GET parameters for # websocket requests if self._is_ws_request(request): token_str = request.GET.get("access_token", None) # We currently only accept a real bearer token in our API calls, but # it's conceivable the WS spec will one day change to accept this: # See: https://github.com/whatwg/html/issues/3062 if token_str is None: token_str = token_svc.get_bearer_token(request) if token_str is None: return None token = token_svc.validate(token_str) if token is None: return None user = request.find_service(name="user").fetch(token.userid) if user is None: return None return Identity.from_models(user=user) @staticmethod def _is_ws_request(request): return request.path == "/ws"
class MySecurityPolicy: def __init__(self, secret): self.authtkt = AuthTktCookieHelper(secret) self.identity_cache = RequestLocalCache(self.load_identity) self.acl = ACLHelper() def load_identity(self, request): identity = self.authtkt.identify(request) if identity is None: return None userid = identity['userid'] user = request.dbsession.query(models.User).get(userid) return user def identity(self, request): return self.identity_cache.get_or_create(request) def authenticated_userid(self, request): user = self.identity(request) if user is not None: return user.id def remember(self, request, userid, **kw): return self.authtkt.remember(request, userid, **kw) def forget(self, request, **kw): return self.authtkt.forget(request, **kw) def permits(self, request, context, permission): principals = self.effective_principals(request) return self.acl.permits(context, principals, permission) def effective_principals(self, request): principals = [Everyone] user = self.identity(request) if user is not None: principals.append(Authenticated) principals.append('u:' + str(user.id)) principals.append('role:' + user.role) return principals
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", ]