def test_token_generation(default_user, default_repo, default_repo_access): tenant = auth.Tenant.from_user(default_user) token = auth.generate_token(tenant) assert isinstance(token, bytes) result = auth.parse_token(token) assert result["access"] == {str(default_repo.id): Permission.admin} assert result["uid"] == str(default_user.id)
def request( self, path: str, method: str, params: Optional[dict] = None, tenant: Optional[Union[bool, auth.Tenant]] = True, raise_errors: Optional[bool] = True, ): if tenant is True: tenant = auth.get_current_tenant() elif tenant is False: tenant = None url = "{}/{}".format(current_app.config["VCS_SERVER_ENDPOINT"], path.lstrip("/")) hub = Hub.current with hub.start_span(op="vcs-server", description=f"{method} {path}"): response = requests.request( method=method, url=url, params=({k: v for k, v in params.items() if v is not None} if params else None), headers={ "Authorization": "Bearer zeus-t-{}".format( auth.generate_token(tenant).decode("utf-8")) }, ) if raise_errors and not (200 <= response.status_code < 300): text = response.text data = {} try: data = json.loads(text) except ValueError: pass # XXX(dcramer): this feels a bit hacky, and ideally would be handled # in the vcs implementation if data.get("error") == "invalid_pubkey" and params: from zeus.tasks import deactivate_repo, DeactivationReason deactivate_repo.delay(params["repo_id"], DeactivationReason.invalid_pubkey) if data.get("error") == "invalid_ref": raise UnknownRevision(ref=data.get("ref")) raise ApiError(text=text, code=response.status_code) if raise_errors and not response.headers["Content-Type"].startswith( "application/json"): raise ApiError( text="Request returned invalid content type: {}".format( response.headers["Content-Type"]), code=response.status_code, ) return response.json()
def test_token_generation(default_user, default_repo, default_repo_access): tenant = auth.Tenant.from_user(default_user) token = auth.generate_token(tenant) assert isinstance(token, bytes) result = auth.parse_token(token) assert result['repo_ids'] == [str(default_repo.id)] assert result['uid'] == str(default_user.id)
def test_get_tenant_from_signed_token_user(default_user, default_repo, default_repo_access): # TODO(dcramer): we'd prefer to not generate a dynamic token tenant = auth.Tenant.from_user(default_user) token = auth.generate_token(tenant) tenant = auth.get_tenant_from_signed_token(token) assert tenant.user_id == default_user.id assert tenant.access == {default_repo.id: Permission.admin}
def test_get_tenant_from_headers_token(default_user, default_repo, default_repo_access): # TODO(dcramer): we'd prefer to not generate a dynamic token tenant = auth.Tenant.from_user(default_user) token = auth.generate_token(tenant).decode("utf-8") tenant = auth.get_tenant_from_headers( {"Authorization": f"Bearer zeus-t-{token}"}) assert tenant.user_id == default_user.id assert tenant.access == {default_repo.id: Permission.admin}
def dispatch_request(self, *args, **kwargs) -> Response: delay = current_app.config.get("API_DELAY", 0) if delay: sleep(delay / 1000) tenant = request.environ.get("zeus.tenant") if self.authentication_classes: for auth_cls in self.authentication_classes: try: _tenant = auth_cls().authenticate() if _tenant: tenant = _tenant break except auth.AuthenticationFailed: return self.respond({"error": "invalid_auth"}, 401) if tenant: auth.set_current_tenant(tenant) elif self.auth_required: return self.respond({"error": "auth_required"}, 401) try: method = getattr(self, request.method.lower()) except AttributeError: return self.respond({"message": "resource not found"}, 405) try: resp = method(*args, **kwargs) if not isinstance(resp, Response): resp = self.respond(resp) if tenant: resp.headers["X-Stream-Token"] = auth.generate_token(tenant) return resp except ValidationError as e: return self.respond(e.messages, 403) except ConnectionError as exc: current_app.logger.exception("failed to handle api request") return self.respond( {"error": "connection_error", "url": exc.request.url}, 502 ) except ApiUnauthorized: return self.respond({"error": "auth_required"}, 401) except Exception: current_app.logger.exception("failed to handle api request") return self.error("internal server error", 500)
def get(self, path: str, repo_id: UUID, **params): if "tenant" not in params: tenant = auth.RepositoryTenant(repository_id=repo_id) else: tenant = params.pop("tenant", None) headers = {} if tenant: headers["Authorization"] = "Bearer zeus-t-{}".format( auth.generate_token(tenant).decode("utf-8")) return self.client.get( f"{path}?repo_id={repo_id}&{'&'.join('{}={}'.format(k, v) for k, v in params.items())}", headers=headers, )
def dispatch_request(self, *args, **kwargs) -> Response: delay = current_app.config.get('API_DELAY', 0) if delay: sleep(delay / 1000) tenant = request.environ.get('zeus.tenant') if self.authentication_classes: for auth_cls in self.authentication_classes: try: _tenant = auth_cls().authenticate() if _tenant: tenant = _tenant break except auth.AuthenticationFailed: return self.respond({ 'error': 'invalid_auth', }, 401) if tenant: auth.set_current_tenant(tenant) elif self.auth_required: return self.respond({ 'error': 'auth_required', }, 401) try: method = getattr(self, request.method.lower()) except AttributeError: return self.respond({'message': 'resource not found'}, 405) try: resp = method(*args, **kwargs) if not isinstance(resp, Response): resp = self.respond(resp) if tenant: resp.headers['X-Stream-Token'] = auth.generate_token(tenant) return resp except ApiUnauthorized: return self.respond({ 'error': 'auth_required', }, 401) except Exception: current_app.logger.exception('failed to handle api request') return self.error('internal server error', 500)