From f5fc3f2b3276be1a17558049b7fb85308a8659e1 Mon Sep 17 00:00:00 2001 From: Trayan Azarov Date: Thu, 10 Aug 2023 15:57:59 +0300 Subject: [PATCH 01/13] feat: Simple Pluggable Auth token based plugin for static tokens - WIP --- .pre-commit-config.yaml | 2 +- chromadb/config.py | 8 +++-- chromadb/server/fastapi/__init__.py | 11 ++++++- chromadb/server/middlewares/README.md | 39 +++++++++++++++++++++++ chromadb/server/middlewares/__init__.py | 34 ++++++++++++++++++++ chromadb/test/conftest.py | 42 +++++++++++++++++++++---- 6 files changed, 125 insertions(+), 11 deletions(-) create mode 100644 chromadb/server/middlewares/README.md create mode 100644 chromadb/server/middlewares/__init__.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6b8fbca9079..c93f1305691 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,5 +31,5 @@ repos: rev: "v1.2.0" hooks: - id: mypy - args: [--strict, --ignore-missing-imports, --follow-imports=silent, --disable-error-code=type-abstract] + args: [--strict, --ignore-missing-imports, --follow-imports=silent, --disable-error-code=type-abstract,--exclude=^chromadb/server/fastapi/__init__.py$] additional_dependencies: ["types-requests", "pydantic", "overrides", "hypothesis", "pytest", "pypika", "numpy"] \ No newline at end of file diff --git a/chromadb/config.py b/chromadb/config.py index 93b4f0342b4..2bd28dd451a 100644 --- a/chromadb/config.py +++ b/chromadb/config.py @@ -15,10 +15,8 @@ except ImportError: is_thin_client = False - logger = logging.getLogger(__name__) - LEGACY_ERROR = """\033[91mYou are using a deprecated configuration of Chroma. \033[94mIf you do not have data you wish to migrate, you only need to change how you construct @@ -59,7 +57,7 @@ } -class Settings(BaseSettings): +class Settings(BaseSettings): # type: ignore environment: str = "" # Legacy config has to be kept around because pydantic will error on nonexisting keys @@ -88,7 +86,11 @@ class Settings(BaseSettings): chroma_server_ssl_enabled: Optional[bool] = False chroma_server_grpc_port: Optional[str] = None chroma_server_cors_allow_origins: List[str] = [] # eg ["http://localhost:3000"] + # eg ["chromadb.api.fastapi.middlewares.auth.AuthMiddleware"] + chroma_server_middlewares: List[str] = [] + chroma_server_middleware_token_auth_enabled: bool = False + chroma_server_middleware_token_auth_token: Optional[str] = None anonymized_telemetry: bool = True allow_reset: bool = False diff --git a/chromadb/server/fastapi/__init__.py b/chromadb/server/fastapi/__init__.py index 249bcae167d..bd366d4b00b 100644 --- a/chromadb/server/fastapi/__init__.py +++ b/chromadb/server/fastapi/__init__.py @@ -8,11 +8,12 @@ from fastapi import HTTPException, status from uuid import UUID +from starlette.middleware.base import BaseHTTPMiddleware import chromadb from chromadb.api.models.Collection import Collection from chromadb.api.types import GetResult, QueryResult -from chromadb.config import Settings +from chromadb.config import Settings, get_class import chromadb.server import chromadb.api from chromadb.errors import ( @@ -111,6 +112,14 @@ def __init__(self, settings: Settings): allow_methods=["*"], ) + if ( + settings.chroma_server_middlewares is not None + and len(settings.chroma_server_middlewares) > 0 + ): + for middleware in settings.chroma_server_middlewares: + _cls = get_class(middleware, BaseHTTPMiddleware) + self._app.add_middleware(_cls, settings=settings) + self.router = ChromaAPIRouter() self.router.add_api_route("/api/v1", self.root, methods=["GET"]) diff --git a/chromadb/server/middlewares/README.md b/chromadb/server/middlewares/README.md new file mode 100644 index 00000000000..b6c5848c5ed --- /dev/null +++ b/chromadb/server/middlewares/README.md @@ -0,0 +1,39 @@ +# Chroma Server Middlewares + + +## Simple Token Auth Middleware + +This is very rudimentary security middleware that checks Authorization headers for a static token. + +The static token is configure on the server side using `CHROMA_SERVER_MIDDLEWARE_TOKEN_AUTH_TOKEN` + +### Usage + +Start the server: + +```bash +ALLOW_RESET=1 \ +IS_PERSISTENT=1 \ +CHROMA_SERVER_MIDDLEWARES='["chromadb.server.middlewares.SimpleTokenAuthMiddleware"]' \ +CHROMA_SERVER_MIDDLEWARE_TOKEN_AUTH_ENABLED=true \ +CHROMA_SERVER_MIDDLEWARE_TOKEN_AUTH_TOKEN=test \ +uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 \ +--proxy-headers --log-config log_config.yml --reload +``` + +Test request with `curl`: + +```bash +curl http://localhost:8000/api/v1 -v -H "Authorization: Token test" +``` + +> **Note**: The authorization header should contain at least two parts Token + the actual token + +Test with http client: + +```python +import chromadb + +client = chromadb.HttpClient(host="localhost", port="8000", headers={"Authorization": "Token test"}) +client.heartbeat() +``` diff --git a/chromadb/server/middlewares/__init__.py b/chromadb/server/middlewares/__init__.py new file mode 100644 index 00000000000..7ed34884c7d --- /dev/null +++ b/chromadb/server/middlewares/__init__.py @@ -0,0 +1,34 @@ +from typing import Callable + +from starlette.middleware.base import BaseHTTPMiddleware +from starlette.requests import Request +from starlette.responses import JSONResponse, Response +from starlette.types import ASGIApp + +from chromadb.config import Settings + + +class SimpleTokenAuthMiddleware(BaseHTTPMiddleware): # type: ignore + """ + Very basic security middleware that checks for a token in the Authorization header + """ + + def __init__(self, app: ASGIApp, settings: Settings) -> None: + super().__init__(app) + self.settings = settings + if settings.chroma_server_middleware_token_auth_enabled: + settings.require("chroma_server_middleware_token_auth_token") + self.token = settings.chroma_server_middleware_token_auth_token + + async def dispatch( + self, request: Request, call_next: Callable[[Request], Response] + ) -> Response: + # Extract the Authorization header + auth_header = request.headers.get("Authorization", "").split() + # Check if the header exists and the token is correct + if len(auth_header) != 2 or auth_header[1] != self.token: + return JSONResponse({"error": "Unauthorized"}, status_code=401) + + # If token is correct, continue to the next middleware or route handler + response = await call_next(request) + return response diff --git a/chromadb/test/conftest.py b/chromadb/test/conftest.py index 526e1a0cb0a..49631ca1af4 100644 --- a/chromadb/test/conftest.py +++ b/chromadb/test/conftest.py @@ -8,7 +8,7 @@ import uvicorn import time import pytest -from typing import Generator, List, Callable, Optional, Tuple +from typing import Generator, List, Callable, Optional, Tuple, Any, Dict, Union import shutil import logging import socket @@ -17,7 +17,6 @@ root_logger = logging.getLogger() root_logger.setLevel(logging.DEBUG) # This will only run when testing - logger = logging.getLogger(__name__) hypothesis.settings.register_profile( @@ -40,7 +39,10 @@ def find_free_port() -> int: def _run_server( - port: int, is_persistent: bool = False, persist_directory: Optional[str] = None + port: int, + is_persistent: bool = False, + persist_directory: Optional[str] = None, + **additional_settings: Optional[dict[Any, Any]], ) -> None: """Run a Chroma server locally""" if is_persistent and persist_directory: @@ -53,6 +55,7 @@ def _run_server( is_persistent=is_persistent, persist_directory=persist_directory, allow_reset=True, + **additional_settings, ) else: settings = Settings( @@ -63,6 +66,7 @@ def _run_server( chroma_segment_manager_impl="chromadb.segment.impl.manager.local.LocalSegmentManager", is_persistent=False, allow_reset=True, + **additional_settings, ) server = chromadb.server.fastapi.FastAPI(settings) uvicorn.run(server.app(), host="0.0.0.0", port=port, log_level="error") @@ -81,7 +85,11 @@ def _await_server(api: API, attempts: int = 0) -> None: _await_server(api, attempts + 1) -def _fastapi_fixture(is_persistent: bool = False) -> Generator[System, None, None]: +def _fastapi_fixture( + is_persistent: bool = False, + client_headers: Optional[dict[str, str]] = None, + additional_args: Optional[Dict[str, Union[bool, List[str], str]]] = None, +) -> Generator[System, None, None]: """Fixture generator that launches a server in a separate process, and yields a fastapi client connect to it""" @@ -90,16 +98,25 @@ def _fastapi_fixture(is_persistent: bool = False) -> Generator[System, None, Non ctx = multiprocessing.get_context("spawn") args: Tuple[int, bool, Optional[str]] = (port, False, None) persist_directory = None + if additional_args is None: + additional_args = {} if is_persistent: persist_directory = tempfile.mkdtemp() - args = (port, is_persistent, persist_directory) - proc = ctx.Process(target=_run_server, args=args, daemon=True) + args = ( + port, + is_persistent, + persist_directory, + ) + proc = ctx.Process( + target=_run_server, args=args, kwargs=additional_args, daemon=True + ) proc.start() settings = Settings( chroma_api_impl="chromadb.api.fastapi.FastAPI", chroma_server_host="localhost", chroma_server_http_port=str(port), allow_reset=True, + chroma_server_headers=client_headers, ) system = System(settings) api = system.instance(API) @@ -121,6 +138,19 @@ def fastapi_persistent() -> Generator[System, None, None]: return _fastapi_fixture(is_persistent=True) +def fastapi_persistent_w_middleware() -> Generator[System, None, None]: + return _fastapi_fixture( + is_persistent=True, + additional_args={ + "chroma_middleware_impl": [ + "chromadb.server.middlewares.SimpleTokenAuthMiddleware" + ], + "chroma_server_middleware_token_auth_enabled": True, + "chroma_server_middleware_token_auth_token": "test", + }, + ) + + def integration() -> Generator[System, None, None]: """Fixture generator for returning a client configured via environmenet variables, intended for externally configured integration tests From 394416ce2a3a309fab5fb92e9588eec74509185e Mon Sep 17 00:00:00 2001 From: Trayan Azarov Date: Thu, 10 Aug 2023 15:58:59 +0300 Subject: [PATCH 02/13] chore: reverted pre-commit-config to original settings --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c93f1305691..6b8fbca9079 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,5 +31,5 @@ repos: rev: "v1.2.0" hooks: - id: mypy - args: [--strict, --ignore-missing-imports, --follow-imports=silent, --disable-error-code=type-abstract,--exclude=^chromadb/server/fastapi/__init__.py$] + args: [--strict, --ignore-missing-imports, --follow-imports=silent, --disable-error-code=type-abstract] additional_dependencies: ["types-requests", "pydantic", "overrides", "hypothesis", "pytest", "pypika", "numpy"] \ No newline at end of file From 30c5ee0f9ea71d9914e22b9dacc1240e5c8a4e7b Mon Sep 17 00:00:00 2001 From: Trayan Azarov Date: Fri, 11 Aug 2023 19:34:25 +0300 Subject: [PATCH 03/13] feat: Client and Server Side Auth provider abstractions - Basic Auth provider for both server and client implemented --- chromadb/api/fastapi.py | 2 + chromadb/auth/README.md | 46 +++++++ chromadb/config.py | 117 ++++++++++++++++-- chromadb/server/fastapi/__init__.py | 15 +-- chromadb/server/middlewares/README.md | 39 ------ chromadb/server/middlewares/__init__.py | 34 ----- .../basic_functionality/client_auth.ipynb | 112 +++++++++++++++++ 7 files changed, 272 insertions(+), 93 deletions(-) create mode 100644 chromadb/auth/README.md delete mode 100644 chromadb/server/middlewares/README.md delete mode 100644 chromadb/server/middlewares/__init__.py create mode 100644 examples/basic_functionality/client_auth.ipynb diff --git a/chromadb/api/fastapi.py b/chromadb/api/fastapi.py index bb191cd59f3..d6fd54d2268 100644 --- a/chromadb/api/fastapi.py +++ b/chromadb/api/fastapi.py @@ -50,6 +50,8 @@ def __init__(self, system: System): self._session = requests.Session() if self._header is not None: self._session.headers.update(self._header) + if system.auth_provider is not None: + system.auth_provider.authenticate(self._session) @override def heartbeat(self) -> int: diff --git a/chromadb/auth/README.md b/chromadb/auth/README.md new file mode 100644 index 00000000000..309b29d1410 --- /dev/null +++ b/chromadb/auth/README.md @@ -0,0 +1,46 @@ +# Chroma Server Middlewares + +## Basic Auth + +This is very rudimentary security middleware that checks Authorization headers for basic auth credentials. + +The basic auth user and pass are configured on the server side using `CHROMA_SERVER_AUTH_PROVIDER_CONFIG`. Make sure to +also define the auth provider `CHROMA_SERVER_AUTH_PROVIDER="chromadb.auth.BasicAuthServerProvider"`. + +### Usage + +Start the server: + +```bash +CHROMA_SERVER_AUTH_PROVIDER="chromadb.BasicAuthServerProvider" \ +CHROMA_SERVER_AUTH_PROVIDER_CONFIG='{"username":"admin","password":"admin"}' \ +ALLOW_RESET=1 \ +IS_PERSISTENT=1 \ +uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 --proxy-headers --log-config log_config.yml --reload +``` + +Test request with `curl`: + +```bash +curl http://localhost:8000/api/v1 -v -H "Authorization: Basic YWRtaW46YWRtaW4=" +``` + +Test with client side auth provider: + +```python +import chromadb +from chromadb import Settings + +client = chromadb.HttpClient(settings=Settings(chroma_client_auth_provider="chromadb.auth.BasicAuthClientProvider", + chroma_client_auth_provider_config={"username": "admin", "password": "admin"})) +client.heartbeat() +``` + +Test with Http Client and basic auth header: + +```python +import chromadb + +client = chromadb.HttpClient(host="localhost", port="8000", headers={"Authorization": "Basic YWRtaW46YWRtaW4="}) +client.heartbeat() +``` diff --git a/chromadb/config.py b/chromadb/config.py index 2bd28dd451a..027134f232b 100644 --- a/chromadb/config.py +++ b/chromadb/config.py @@ -1,12 +1,21 @@ -from pydantic import BaseSettings -from typing import Optional, List, Any, Dict, TypeVar, Set, cast, Iterable, Type -from typing_extensions import Literal -from abc import ABC +import base64 import importlib +import inspect import logging -from overrides import EnforceOverrides, override +from abc import ABC, abstractmethod from graphlib import TopologicalSorter -import inspect +from typing import Optional, List, Any, Dict, Set, Iterable +from typing import Type, TypeVar, cast + +import requests +from overrides import override +from overrides import overrides, EnforceOverrides +from pydantic import BaseSettings, SecretStr +from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint +from starlette.requests import Request +from starlette.responses import Response, JSONResponse +from starlette.types import ASGIApp +from typing_extensions import Literal # The thin client will have a flag to control which implementations to use is_thin_client = False @@ -57,6 +66,24 @@ } +class ClientAuthProvider(ABC, EnforceOverrides): + def __init__(self, settings: "Settings") -> None: + self._settings = settings + + @abstractmethod + def authenticate(self, session: requests.Session) -> None: + pass + + +class ServerAuthProvider(ABC, EnforceOverrides): + def __init__(self, settings: "Settings") -> None: + self._settings = settings + + @abstractmethod + def authenticate(self, request: Request) -> Response | None: + pass + + class Settings(BaseSettings): # type: ignore environment: str = "" @@ -89,8 +116,10 @@ class Settings(BaseSettings): # type: ignore # eg ["chromadb.api.fastapi.middlewares.auth.AuthMiddleware"] chroma_server_middlewares: List[str] = [] - chroma_server_middleware_token_auth_enabled: bool = False - chroma_server_middleware_token_auth_token: Optional[str] = None + chroma_server_auth_provider: Optional[str] = None + chroma_server_auth_provider_config: Optional[Dict[str, Any]] = None + chroma_client_auth_provider: Optional[str] = None + chroma_client_auth_provider_config: Optional[Dict[str, Any]] = None anonymized_telemetry: bool = True allow_reset: bool = False @@ -108,7 +137,7 @@ def require(self, key: str) -> Any: def __getitem__(self, key: str) -> Any: val = getattr(self, key) # Error on legacy config values - if val in _legacy_config_values: + if isinstance(val, str) and val in _legacy_config_values: raise ValueError(LEGACY_ERROR) return val @@ -160,7 +189,7 @@ def reset_state(self) -> None: class System(Component): settings: Settings - + auth_provider: Optional["ClientAuthProvider"] _instances: Dict[Type[Component], Component] def __init__(self, settings: Settings): @@ -171,6 +200,11 @@ def __init__(self, settings: Settings): "Chroma is running in http-only client mode, and can only be run with 'chromadb.api.fastapi.FastAPI' as the chroma_api_impl. \ see https://docs.trychroma.com/usage-guide?lang=py#using-the-python-http-only-client for more information." ) + if settings.chroma_client_auth_provider is not None: + print("provider: ", settings.chroma_client_auth_provider) + self.auth_provider = get_class( + settings.chroma_client_auth_provider, ClientAuthProvider + )(settings) # Validate settings don't contain any legacy config values for key in _legacy_config_keys: @@ -232,6 +266,69 @@ def reset_state(self) -> None: component.reset_state() +class BasicAuthClientProvider(ClientAuthProvider): + def __init__(self, settings: "Settings") -> None: + super().__init__(settings) + self._settings = settings + self._settings.require("chroma_client_auth_provider_config") + if self._settings.chroma_client_auth_provider_config: + self._basic_auth_token = SecretStr( + base64.b64encode( + f"{self._settings.chroma_client_auth_provider_config['username']}:" + f"{self._settings.chroma_client_auth_provider_config['password']}".encode( + "utf-8" + ) + ).decode("utf-8") + ) + + @overrides + def authenticate(self, session: requests.Session) -> None: + session.headers.update({"Authorization": f"Basic {self._basic_auth_token}"}) + + +class ChromaAuthMiddleware(BaseHTTPMiddleware): # type: ignore + def __init__(self, app: ASGIApp, settings: "Settings") -> None: + super().__init__(app) + self._settings = settings + self._settings.require("chroma_server_auth_provider") + if settings.chroma_server_auth_provider: + _cls = get_class(settings.chroma_server_auth_provider, ServerAuthProvider) + self._auth_provider = _cls(settings) + + async def dispatch( + self, request: Request, call_next: RequestResponseEndpoint + ) -> Response: + response = self._auth_provider.authenticate(request) + if response is not None: + return response + return await call_next(request) + + +class BasicAuthServerProvider(ServerAuthProvider): + def __init__(self, settings: "Settings") -> None: + super().__init__(settings) + self._settings = settings + self._settings.require("chroma_server_auth_provider_config") + if self._settings.chroma_server_auth_provider_config: + # encode the username and password base64 + self._basic_auth_token = SecretStr( + base64.b64encode( + f"{self._settings.chroma_server_auth_provider_config['username']}:" + f"{self._settings.chroma_server_auth_provider_config['password']}".encode( + "utf-8" + ) + ).decode("utf-8") + ) + + @overrides + def authenticate(self, request: Request) -> Response | None: + auth_header = request.headers.get("Authorization", "").split() + # Check if the header exists and the token is correct + if len(auth_header) != 2 or auth_header[1] != self._basic_auth_token: + return JSONResponse({"error": "Unauthorized"}, status_code=401) + return None + + C = TypeVar("C") diff --git a/chromadb/server/fastapi/__init__.py b/chromadb/server/fastapi/__init__.py index bd366d4b00b..709570ab340 100644 --- a/chromadb/server/fastapi/__init__.py +++ b/chromadb/server/fastapi/__init__.py @@ -8,12 +8,10 @@ from fastapi import HTTPException, status from uuid import UUID -from starlette.middleware.base import BaseHTTPMiddleware - import chromadb from chromadb.api.models.Collection import Collection from chromadb.api.types import GetResult, QueryResult -from chromadb.config import Settings, get_class +from chromadb.config import Settings import chromadb.server import chromadb.api from chromadb.errors import ( @@ -112,13 +110,10 @@ def __init__(self, settings: Settings): allow_methods=["*"], ) - if ( - settings.chroma_server_middlewares is not None - and len(settings.chroma_server_middlewares) > 0 - ): - for middleware in settings.chroma_server_middlewares: - _cls = get_class(middleware, BaseHTTPMiddleware) - self._app.add_middleware(_cls, settings=settings) + if settings.chroma_server_auth_provider is not None: + self._app.add_middleware( + chromadb.config.ChromaAuthMiddleware, settings=settings + ) self.router = ChromaAPIRouter() diff --git a/chromadb/server/middlewares/README.md b/chromadb/server/middlewares/README.md deleted file mode 100644 index b6c5848c5ed..00000000000 --- a/chromadb/server/middlewares/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Chroma Server Middlewares - - -## Simple Token Auth Middleware - -This is very rudimentary security middleware that checks Authorization headers for a static token. - -The static token is configure on the server side using `CHROMA_SERVER_MIDDLEWARE_TOKEN_AUTH_TOKEN` - -### Usage - -Start the server: - -```bash -ALLOW_RESET=1 \ -IS_PERSISTENT=1 \ -CHROMA_SERVER_MIDDLEWARES='["chromadb.server.middlewares.SimpleTokenAuthMiddleware"]' \ -CHROMA_SERVER_MIDDLEWARE_TOKEN_AUTH_ENABLED=true \ -CHROMA_SERVER_MIDDLEWARE_TOKEN_AUTH_TOKEN=test \ -uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 \ ---proxy-headers --log-config log_config.yml --reload -``` - -Test request with `curl`: - -```bash -curl http://localhost:8000/api/v1 -v -H "Authorization: Token test" -``` - -> **Note**: The authorization header should contain at least two parts Token + the actual token - -Test with http client: - -```python -import chromadb - -client = chromadb.HttpClient(host="localhost", port="8000", headers={"Authorization": "Token test"}) -client.heartbeat() -``` diff --git a/chromadb/server/middlewares/__init__.py b/chromadb/server/middlewares/__init__.py deleted file mode 100644 index 7ed34884c7d..00000000000 --- a/chromadb/server/middlewares/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import Callable - -from starlette.middleware.base import BaseHTTPMiddleware -from starlette.requests import Request -from starlette.responses import JSONResponse, Response -from starlette.types import ASGIApp - -from chromadb.config import Settings - - -class SimpleTokenAuthMiddleware(BaseHTTPMiddleware): # type: ignore - """ - Very basic security middleware that checks for a token in the Authorization header - """ - - def __init__(self, app: ASGIApp, settings: Settings) -> None: - super().__init__(app) - self.settings = settings - if settings.chroma_server_middleware_token_auth_enabled: - settings.require("chroma_server_middleware_token_auth_token") - self.token = settings.chroma_server_middleware_token_auth_token - - async def dispatch( - self, request: Request, call_next: Callable[[Request], Response] - ) -> Response: - # Extract the Authorization header - auth_header = request.headers.get("Authorization", "").split() - # Check if the header exists and the token is correct - if len(auth_header) != 2 or auth_header[1] != self.token: - return JSONResponse({"error": "Unauthorized"}, status_code=401) - - # If token is correct, continue to the next middleware or route handler - response = await call_next(request) - return response diff --git a/examples/basic_functionality/client_auth.ipynb b/examples/basic_functionality/client_auth.ipynb new file mode 100644 index 00000000000..5fa612893ac --- /dev/null +++ b/examples/basic_functionality/client_auth.ipynb @@ -0,0 +1,112 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "initial_id", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2023-08-11T15:58:07.061237Z", + "start_time": "2023-08-11T15:58:07.058628Z" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 2, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "provider: chromadb.config.BasicAuthClientProvider\n" + ] + }, + { + "ename": "Exception", + "evalue": "{\"error\":\"Unauthorized\"}", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mHTTPError\u001B[0m Traceback (most recent call last)", + "File \u001B[0;32m~/PycharmProjects/chroma-core/chromadb/api/fastapi.py:385\u001B[0m, in \u001B[0;36mraise_chroma_error\u001B[0;34m(resp)\u001B[0m\n\u001B[1;32m 384\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m--> 385\u001B[0m \u001B[43mresp\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mraise_for_status\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 386\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m requests\u001B[38;5;241m.\u001B[39mHTTPError:\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/requests/models.py:1021\u001B[0m, in \u001B[0;36mResponse.raise_for_status\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 1020\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m http_error_msg:\n\u001B[0;32m-> 1021\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m HTTPError(http_error_msg, response\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m)\n", + "\u001B[0;31mHTTPError\u001B[0m: 401 Client Error: Unauthorized for url: http://localhost:8000/api/v1", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001B[0;31mException\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[2], line 5\u001B[0m\n\u001B[1;32m 2\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mchromadb\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m Settings\n\u001B[1;32m 4\u001B[0m client \u001B[38;5;241m=\u001B[39m chromadb\u001B[38;5;241m.\u001B[39mHttpClient(settings\u001B[38;5;241m=\u001B[39mSettings(chroma_client_auth_provider\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mchromadb.config.BasicAuthClientProvider\u001B[39m\u001B[38;5;124m\"\u001B[39m, chroma_client_auth_provider_config\u001B[38;5;241m=\u001B[39m{\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124musername\u001B[39m\u001B[38;5;124m\"\u001B[39m: \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124madmi1n\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mpassword\u001B[39m\u001B[38;5;124m\"\u001B[39m: \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124madmin\u001B[39m\u001B[38;5;124m\"\u001B[39m}))\n\u001B[0;32m----> 5\u001B[0m \u001B[43mclient\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mheartbeat\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/chromadb/api/fastapi.py:60\u001B[0m, in \u001B[0;36mFastAPI.heartbeat\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 58\u001B[0m \u001B[38;5;250m\u001B[39m\u001B[38;5;124;03m\"\"\"Returns the current server time in nanoseconds to check if the server is alive\"\"\"\u001B[39;00m\n\u001B[1;32m 59\u001B[0m resp \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_session\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_api_url)\n\u001B[0;32m---> 60\u001B[0m \u001B[43mraise_chroma_error\u001B[49m\u001B[43m(\u001B[49m\u001B[43mresp\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 61\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mint\u001B[39m(resp\u001B[38;5;241m.\u001B[39mjson()[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mnanosecond heartbeat\u001B[39m\u001B[38;5;124m\"\u001B[39m])\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/chromadb/api/fastapi.py:387\u001B[0m, in \u001B[0;36mraise_chroma_error\u001B[0;34m(resp)\u001B[0m\n\u001B[1;32m 385\u001B[0m resp\u001B[38;5;241m.\u001B[39mraise_for_status()\n\u001B[1;32m 386\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m requests\u001B[38;5;241m.\u001B[39mHTTPError:\n\u001B[0;32m--> 387\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m (\u001B[38;5;167;01mException\u001B[39;00m(resp\u001B[38;5;241m.\u001B[39mtext))\n", + "\u001B[0;31mException\u001B[0m: {\"error\":\"Unauthorized\"}" + ] + } + ], + "source": [ + "import chromadb\n", + "from chromadb import Settings\n", + "\n", + "client = chromadb.HttpClient(settings=Settings(chroma_client_auth_provider=\"chromadb.config.BasicAuthClientProvider\", chroma_client_auth_provider_config={\"username\": \"admin\", \"password\": \"admin\"}))\n", + "client.heartbeat()\n" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-08-11T16:25:06.501154Z", + "start_time": "2023-08-11T16:25:06.299634Z" + } + }, + "id": "8f9307acce25f672" + }, + { + "cell_type": "code", + "execution_count": 2, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-08-11T16:00:53.461947Z", + "start_time": "2023-08-11T16:00:53.458763Z" + } + }, + "id": "c0c3240ed4d70a79" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "start_time": "2023-08-11T15:58:07.272237Z" + } + }, + "id": "ab8b90d83f02eda" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From b90a5256f4bf6339ee0e460be0a6cc7ab7b74d5a Mon Sep 17 00:00:00 2001 From: Trayan Azarov Date: Tue, 15 Aug 2023 01:02:33 +0300 Subject: [PATCH 04/13] feat: CIP-2 Auth Providers added in `/docs` - Updated Basic Auth Provider to also load credentials from file or from env vars (CHROMA_BASIC_AUTH_USERNAME and CHROMA_BASIC_AUTH_PASSWORD) --- chromadb/config.py | 48 +++++++++++---- docs/CIP_2_Auth_Providers_Proposal.md | 84 ++++++++++++++++++++++++++ docs/assets/cip-2-arch.png | Bin 0 -> 46879 bytes docs/assets/cip-2-seq.png | Bin 0 -> 161310 bytes 4 files changed, 120 insertions(+), 12 deletions(-) create mode 100644 docs/CIP_2_Auth_Providers_Proposal.md create mode 100644 docs/assets/cip-2-arch.png create mode 100644 docs/assets/cip-2-seq.png diff --git a/chromadb/config.py b/chromadb/config.py index 027134f232b..12a63ceb9a4 100644 --- a/chromadb/config.py +++ b/chromadb/config.py @@ -1,10 +1,12 @@ import base64 import importlib import inspect +import json import logging +import os from abc import ABC, abstractmethod from graphlib import TopologicalSorter -from typing import Optional, List, Any, Dict, Set, Iterable +from typing import Optional, List, Any, Dict, Set, Iterable, Union from typing import Type, TypeVar, cast import requests @@ -117,7 +119,7 @@ class Settings(BaseSettings): # type: ignore chroma_server_middlewares: List[str] = [] chroma_server_auth_provider: Optional[str] = None - chroma_server_auth_provider_config: Optional[Dict[str, Any]] = None + chroma_server_auth_provider_config: Optional[Union[str, Dict[str, Any]]] = None chroma_client_auth_provider: Optional[str] = None chroma_client_auth_provider_config: Optional[Dict[str, Any]] = None anonymized_telemetry: bool = True @@ -305,20 +307,42 @@ async def dispatch( class BasicAuthServerProvider(ServerAuthProvider): + @staticmethod + def _create_token(username: str, password: str) -> SecretStr: + return SecretStr( + base64.b64encode(f"{username}:{password}".encode("utf-8")).decode("utf-8") + ) + def __init__(self, settings: "Settings") -> None: super().__init__(settings) self._settings = settings - self._settings.require("chroma_server_auth_provider_config") - if self._settings.chroma_server_auth_provider_config: - # encode the username and password base64 - self._basic_auth_token = SecretStr( - base64.b64encode( - f"{self._settings.chroma_server_auth_provider_config['username']}:" - f"{self._settings.chroma_server_auth_provider_config['password']}".encode( - "utf-8" + # self._settings.require("chroma_server_auth_provider_config") + if self._settings.chroma_server_auth_provider_config and isinstance( + self._settings.chroma_server_auth_provider_config, str + ): + if os.path.exists(self._settings.chroma_server_auth_provider_config): + with open(self._settings.chroma_server_auth_provider_config) as f: + _auth_data = json.loads(f.read()) + self._basic_auth_token = self._create_token( + _auth_data["username"], _auth_data["password"] ) - ).decode("utf-8") - ) + elif self._settings.chroma_server_auth_provider_config and isinstance( + self._settings.chroma_server_auth_provider_config, dict + ): + # encode the username and password base64 + self._basic_auth_token = self._create_token( + self._settings.chroma_server_auth_provider_config["username"], + self._settings.chroma_server_auth_provider_config["password"], + ) + elif os.environ.get("CHROMA_BASIC_AUTH_USERNAME") and os.environ.get( + "CHROMA_BASIC_AUTH_PASSWORD" + ): + self._basic_auth_token = self._create_token( + os.environ.get("CHROMA_BASIC_AUTH_USERNAME", ""), + os.environ.get("CHROMA_BASIC_AUTH_PASSWORD", ""), + ) + else: + raise ValueError("Basic auth credentials not found") @overrides def authenticate(self, request: Request) -> Response | None: diff --git a/docs/CIP_2_Auth_Providers_Proposal.md b/docs/CIP_2_Auth_Providers_Proposal.md new file mode 100644 index 00000000000..81bb098bfc1 --- /dev/null +++ b/docs/CIP_2_Auth_Providers_Proposal.md @@ -0,0 +1,84 @@ +# CIP-2: Auth Providers Proposal + +## Status + +Current Status: `Under Discussion` + +## **Motivation** + +Currently, Chroma does not provide any authentication mechanism. This CIP proposes to +to add authentication abstractions and basic authentication mechanisms to Chroma. + +There are intrinsic and extrinsic motivations for this CIP. The intrinsic motivation +is to provide a secure way to access Chroma as adoption grows and the team is gearing up to release a cloud offering. +The extrinsic motivation is driven by the community which is deploying Chroma in both public and private clouds and +in test and production environments. The community has expressed the need for authentication and authorization. + +> Observation: We consider the Auth to be applicable to client-server mode. + +## **Public Interfaces** + +Changes to the public interface are related to the `Settings` class where we introduce new optional attributes to control server and client-side auth providers. + +## **Proposed Changes** + +We propose two abstractions, one for the server-side and another for the [client-side.](http://client-side.In) In addition we also introduce a FastAPI/startlette middleware adapter which will allow using the server-side abstractions in the context of FastAPI. + +Architecture Overview: + +![cip-2-arch.png](assets/cip-2-arch.png) + +Request Sequence: + +![cip-2-seq.png](assets/cip-2-seq.png) + +Reasoning: + +- Server-side abstraction - it is very useful as the intention is to support a variety of auth providers. +- Client-side abstraction - similar reasoning but from client's perspective. It will allow for both standard and non-standard auth provider plugins to be added without further impacting the client side +- Backend (fastAPI) adapter - this is a backend-specific way of loading server-side auth provider plugins. It will also serve as a template/blueprint when it comes to introducing the auth plugins to another backend framework (e.g. Flask) + +We also propose that each auth provider on either side must be configurable via three main methods depending on developer preference: + +- File-base - a configuration file that provides the requisite config and credentials (recommended for production) +- Env - configuration through environment variables (this can also apply for the file-based config, which can be specified in env var) +- Programmatically - provide requisite configuration through CLI or directly in code (it is left for the developer to decide how such configuration is loaded and made available to the auth provider) - this is possibly the least secure and should be used for testing + +The intention is to start with two minimal but useful Auth providers: + +- Basic Auth - base64 encoded user and password credentials. The credentials will be static in nature and defined via auth provider config +- Token - A simple static token implementation + +Both of the above providers will rely on the `Authorization` header to achieve their functionality. + +> Both initial providers are there to help introduce a bear minimum security but are not recommended for production use + +Further work: + +- Introduction of JWT and mTLS auth providers +- API Keys +- Chroma managed user store - this would be similar to what standard DBMS’ are doing today - maintain a table with users and salted password hashes +- K8s RBAC integration (for cloud-native deployments) +- GCP service accounts? +- SPIFFE and SPIRE integrations +- Go and Java client-side auth providers (for other impl like Rust and Ruby, we need to discuss with respective maintainers) + +> Note: this CIP intentionally does not tackle authZ but acknowledges that authN and authZ must work in tandem in future releases + +## **Compatibility, Deprecation, and Migration Plan** + +This change, introducing a pluggable auth framework is no impacting compatibility of existing deployments and users can upgrade and use the new framework without the need for migration. + +No deprecations. + +## **Test Plan** + +We will introduce a new set of tests to verify both client and server-side auth providers. + +## **Rejected Alternatives** + +We have considered direct middleware Auth or existing third-party libraries for FastAPI integration with auth providers, but that will create a dependency for Chroma on FastAPI itself. + +We have also considered using OAuth 2.0 or OIDC however the challenge there is that both of these protocols are generally intended for User (human) auth whereas in our case we have a system-to-system auth. That said there still might be room for either of these protocols, but further more in-depth use case analysis is required. + +Relying entirely on external providers, while this is possible not providing out-of-the-box integrated auth capabilities is a non-starter for many enterprise customers. diff --git a/docs/assets/cip-2-arch.png b/docs/assets/cip-2-arch.png new file mode 100644 index 0000000000000000000000000000000000000000..68f30ac6c5cd5b2209c0f1529b2d7235c831034c GIT binary patch literal 46879 zcmaI81z40@*FQWnASIG29nuJrBGN4#BHbY%9nuUigaQ^_2Bm;>O2<%Aqo4>#hjb3z z@ZaM(=Q;2DK7QZja5)ab?0es9ueE-$CQ3^~@d^Po0R#fMqO2sZ4S`^7K_JjsJRI;! z2CZ5Y_zU`2TTvEL{FQbY{6pTxK-pGZ9dZ*q$Ads4>>=2g{{p_K!58@P3@8K({0+st zmI3?cyI5NpSpPhS&SL(feI-{B1R@PlmY31-g|5BBO}W~!zfa7>$OxT&_%1 zRMf}k`Y#kMj=bAQTUmL~T%5P@!0Rg~DH|Ch^uHg9BwexZ68gk<)XsW&>enuc8@79J z*frkPR9Uoy+D8!4-AtbFJ59q@Lj2c*(GjL^9=P|_y7Lw5RSqqScdCmTBEjdU?Urp% z&k{xq4R3A*p6tJSoswcu?J$_HJZu)QK2O18LXs@N%cEeHc(9lrtm5x4de9xV-lBkL z#@)wVBR&$J-ih7B^<~`lLoPzoapCl6@Fb+U4@+E(i1seyn>)^;&31ihSb2GQ1s6N% z7oPGWY0DmcSU)$1OUxtU*)=s>M#^nAM7>rXYJG2f*JjNk4g2rMIeE=We!&lAg=bg0 zm#MLDmcfs<$vUGMq*g_PIuTH;979zUAGs9#5FMbIE_wDXUQ;ra*LAXCs9~J#54%Vf z2?=RFKUTf>g3^8E8CS9ITwZS4v8=g3?j$l-wXK;|@fGba|Gkw&Uj1T|p^_T)KP-ub zt>aAV6XANv;V&y5)rN zs))}ee=?LxSp>VqLQdrNBi4vV7|Nv{2IIjnJ4fp2^2Wp>b3~51b;F$+0z*)@JqqY|7XpNzXNzCh(6=pNP;h| z1=F84oG%`+9ku!Gz2Y%?rtM2YjCSmQ?-&HX>w%_3N2+fX)*mj@jR5*aL?ZC+QX8oY z15uJ@y3B+~d9!73+d1M4dJ^^=`{(a~_BG0Fpp#L7xu5%LXLy+zm$NR7<1>cZGW2yb&YNcVe zWEq+bsRvK~6dH(^V2RFmYvlfrP;ALdQwRP!TKh8=N4r!%Oqot-_J#jHZi{&uZkOGI zS$9O#AFfsjsRrAP65eUjy7`9-E+qvkyn^fVhloNt!R|cvH+MoWSIDK)O?((JTWah4 zb7W5MAo{}Gq=@^!I;n^g@%`~2q$ndKw`?aVR22Sj!FRwCt7oQ({t!_q>PTA+O$MT4 zxA3uuu=xQyEuW}0*Pm0E%=w4g0{5e5OjnQUg#Ni`3gY*(Pohp_^ZslPVlo$--)SyX4?~ zA;k~6y>5Cve;6>m83M8$IOTsO;YUWnhf2}s+N*Upx2-l6_xcjj|2kViB#$PtG7B|R znTkX`lLhVi@&(_a8zM69uuevc3Ud9sT`|&E@zhd96;-bC-aHr|xj~@6$cm{4j8%BZ z59g_paHsf&VxeQakR@nkmGW8NzVn{wufVXlIe`zSkR( zMsherZAbaN_%78@v*&rxl3?$@2kB|9lu4O?7_F4Mwn`F5{u^p3Wkwe4JIcI)*} zd`GWdJ!*x9ntNX18_1ETx3Uob<~7Fc=##YA^NUUQ+A4q6S;mkU(i8!kXAKwUC*R*I z5-gZkTJ zuFcA2RvmN2^&4^2LJl>3TY5nU8xz^y>!Tau`$N|tJ~i|2oAp|_c`1wEd(D7K!oO0W z;DDR*nWXJS)5(Syr%~lc>CB7iFyguAyiIO)Pso}cePg1!{U}E5?cMtxi(hX=MMd@8 zzNqMvthj_4tM@5^?|c#7NDU$+M6w63kABk5(`F5c4%(b-wCQ|BXPA^OXs2;-fLSj- zSTEUbMNV@`M%o=#$)C@5;Qxd(NMIpo5+%c09`Q>RKWf;t8hqXTwmK+SHPgf$*iJJe z=;H8Fd)Sv0V2hBN8>oyAd@>)ouc|j5% zTLA)g#3qz7R;O9K?35ErM8oVY{Za@nDjRSR9S0 zqqOY^K0mUvISv}s)z7nzXH$>6Wn6`4JHjtU+(F-&(O~>#+Gk^&Gg|Waqd;!(M(tw4 z_uxK>1EnZ3)`ve!Ej>;T-IvE}D=heCT5uV3Y^+o3_09YgZt53vZ#JD2izXQ!t*D+e zhmerE$x5lFACgQsUH{+3Sc6Tg%E{0V+>pUFQPc|mo5?JN%bX8#Uc6RToT!v_E?NZL zALuBfuW@KeyXNQt?yxq;7SaKQ*(uUxN+r+-NRS$C(Bu6DpJaB^aktP`J)-xLA)!Ak z^=Ktq$l26lSXGlaSm~SAPYyPd`K>>Hr1A{Tme&$XLABWhfd)HHDmch~s4(>=+l?8k zx40a~CT}Lq%TWwOutyhc%@UXnbv}d3Y^&_o9bN4*U8IbJGMoo zkZQd&s&e8?HV>+O!60R(S8S4ZItT7NHfxhoEYnTVvnuB?*v)kISm_4PNWdE=+=r6? z$&bib?6=be%Sxs0JiFlV-D1~FyUI<4JGKAijWE{(e-3n{LAtQ3*?cuou$O$c>-P^) z(wrBoCCxgMVw(*Qikprdsx`%vUWMT|*-`UZAdEtZI?H$hpAcLdH@wbk#*Kwbr1NcU ztkV8HY<7L5Lh<|e??2+ax;_TZ3UW=EQVJ_E;=weQ?5sbtgALgc_|>UU{&2)$q|~o| z6*pK7)aC2<+^=L^+R-6%;|sy@a_o6E6_jiwRG_k~t&pwz{Hb=ew-@ekWY*usQrZ^} zSsA#$Hd1cU0z0@w@~{{{S(T7ZnZwNHov&gyAJL&^7Qej79g5&JEdMYbbh5r8-e}fP zPZE74<%jhbU+x=ry3?^&u&~aK_Z}?l^8M;$uw7XlDq7`Xt>2!Ys+EDcOC#@)Z_1~4 z8a__$Zg;g)%_CFzpiptFEmB+9%blCS!glpp*jVRHPB7M+CRwq5aYaS2&;Kb|zceNn!Jda4V#=EIBd;n@=k(V z8qm0v*Orchne~J;-xZDOQ4dowtp!pa7G{2-_3GSD_G!~;VM#6@1E%az${_KZUf)Ax zkzit)gb~WVTY--9G4b?AA*($((W}}yS|P-x?%TJ?BJE(j`$0Mm=K8wy!TuKil=^=F zBdrQDr@c+_>gw$B!`br(eT_`6^|sT$-QTfZAtV%$jNV7v^Yeu8$lCI|WRZ$6EHhtO$v1rJ zK^MQI#r4v?{wFix#sTd-#Gv;RdVjOe(Uv4)5miFX?M-eop%#JKeY<+$3A64cTR?FZ^sbNo%tLe1@dTO))1mZ?iN~N`ymzW|9eMNFo%KelZNobjfwjCA9)Y7KPZuM-p>k8;59d+_nRYSU9X-BS}p(F zwWv4ivp&koeD6gJXio5k7;KoJ!FUOtx73doqsYrW_U`2wN33?8w7v5CPo4*NEK3e~ zXVAV}bLsnh!JsJmTT6Sv(|Ba2T*O=yds+-=adghlPh2tGgZ3yW^&Anz3`q>Zr~CuG z>5_p)cU;CfaEa+rw>A09oyMxvwY9ZFIYSqzH8M=!
    zYV+4#V9EB_1);7F1TJxy zuN`*LOcrU2W5UesHn<7Nh}9IY*o}99$`6Gmi!sz%CWp0ChKYzma7RXx^da|zgDwN->}6A z+I=-BxVcK+iB0>9JXmfuz-FcWfQ3I(i*~B`XTkCQ`q&^hTw6QtbyP%ifZlRiz{dTB z-S_uiYL9@05+BXQYkmN2+xG^)#|L>F6bna`v>bYcDdS$lrrPiCT{$?|Y}k1<*B!4| z=ef*;t}w6nF0zn@VBu%0ChHwd25d^C3OObre>BU4;jB=?wFs_rFY!dsd}S}akj@|9 zLspbqEaZMIA#}u?q5*8Rox!(TZL(CtLHP+DwQQdr>6zbTPu6`#J~e1nMGKaAMaT`!Q=`?6YQ^V zCAj)_sb;AO`)-kc7MOOcxmz)g1T+@Xykkzl!|^03KLZ1E25fm^EQ_=Acjms*`Ob*P zV-qq?Q>OdAwxQ}bYGs7kevjodrq93aF{dQs8Gsr(SQ%7(N<^1`bqlluKY85ex=1;7 zKE}L`>J(9beLL1X_)ND_O(I}lr)4iD*LA9CCAtEAC!D_`?EH!3;;u+_-A1WIsYJ>+ zeb&fPPEL+;V~&sV;@D_c>F}}qgR5q5uuqu~`_H_MhX;ecy-HPL6oj!IT=+`Kc)ZYr z+s62fkAMpkd4DtJ9aUq=C-I=u8Vm1c->unl+b`5!M*jYF$Km#kLaZz-UC0oudBAFF zMf4`!;(AWOd!6F|^bVD_^LPFR3+)n6kRjLlO^0%S;&%L^CxqU8D!qFBitb6#NJf02 z!R|G?Il9M-93R=CZ^(i{CpOX~>^#Lr>thuPNs5sJjg7g|3f6$H>Ev`vn6r(nNOcZZ zNrU$G!k1Oab_Bc2Rrgv;qhLipR1p2vIr`i{tVgLDcl8rjdNupLqiL=N zT?o}lv1xsRYh5+9;}o&$lplQB!{?i zS<)?m*L%p1xT-nI)AgBjX}Wrf3d5mN*y3KR3Pf_-z!bXvCJMU{TP=7}R_|-O@g`+8 zv&M9JFHd~%*{b<=>t)`L*|QnG!p@^VKFO~u zWz|gp3OL+yUs87c8;?dn$Hfiq`;HOO_<@Ha-{?`y4LOsL5$$<^k0=^fUg?$wogH_B zV9h3K(Jhq@foa!!JKK+xXOF!kfd-J0FLh9uSEf<>jIlmr?M98Le!xmjdtM)~xl1sX z;A`%T_R3~{XKtRHUZyZzw_5xlXS40;l?S$acs#k}aP845=K`Ng#LNX`FJ&No;T$`@ zh?ciOt>O49#Ez|UH-@__Xai}}hXh=kj%*E^gBq#jkB*AM-fgwHI=H z)z{uGj{$i8KbN?I_ebpf9|VF9*)ZsIOL2^UO*$5|cvD-9aw2;3Qx&vtA8$4u zpO7$Td~d;n8zgVB9_#&`$b*OjcIr*lZz~o9-(S^^j}zQm-F{WO@$4Gc55j|mFK-f= zCO_V1u3fJh!zTEok;2+pc-OXdXTFzxZ*@2s=nKYyXQ1+Qw}j!&1O7_jQ9q*>q2T&) zBQ4vu)_4KH8skLCJf=4eu{3fJMqoqBLzQ?6#MT(c-fb=$kwpbN_{sb6$KG}RU zbl*y3VzM!ywKHWy(uujYZvV10V>Io zfuI}E5QAHe#kFj02U~DP&axOC4t>!y($WngR*N@L!h;J_nNFM_qawoaQYJ6%OCGBk z2WvPHZ%xn_I^Q50hipummchZH~?! zltLAmi$$pmPJoc~I}0!T_t)|goKdGY&~NQRIRhsf{03|JGMkTA3N8tr0H&pWi8WwP z1f$DwY*O+e#%2IAFM^%CN1 z+SjV;d_lzw5=D+SGGK2dTWz)IsKFVid!}@s<7!j36lMEOF-=h(t0!;s>32toq{P+9 z#`@Pqyry-PW3tlkkilRbhJcKRC;1+-{;!C+n~q!=ESMkEH`nbs0kO(86?9TWz_w^8 zh^8UUR+^o$71QKiyY{x~10;k}f`!oPO6mtI)9Go=eRP&J)s#Wsuf& zB-ciN(0^NVCyZUO)NoY?l|2bGM>pgBxr=(`LF*$AdKQZD7!UUQ0NBoqbsr&R5 z>52_f4N~9W<^*0Bo!jN?8Ft_Iau=xpLG++v*>Sj7*LDv`toKP59xtFc&rS{~4$Bw& z(#<*d!8z2Ok_o{OJ1qSC-%M#k2QAfoQ2kP8y94Dmz1J}vAb}b#xnEy+>Ipz3A4h_? zT_eJ&&QWte7MY39F)En=S)}d7M(@cbma5bNyFys>zng(sBb*$$?RwbDEt5(Q7zRdx zGeFo5s)=oDr0~hCv$L?^!BCbjeK-!aGK$#h>&D4gRX!rU@Qfm$5LCH!R88S`IbsQx z!-3^Du1(+Gqz1KGVH6l-Ew+dBF1>{R2Vw@v@g*aj;t83m;#$hofk!f&v>-|R!Yd7S zAHVe;$wHEhoi(Vhuv+Kt7jL*6Np5lS>aNFo-lgz;#35znd;U7A`*;5brw3r&??;V1 zfT$-{VGQaFA*xo7pJNyoS=HZB^$l0-b)R{aRK=+IqX4O-d%v|73s#Hco$KYJ3BCpB zKa1de&oO#g9YexX&@~eP-sa-!CGG|muvp8#SNL=$_b$H*VqNT>s}o|-LpA^$CWLTu z?!RR2e7)|H_IL@HjsyU#YBRK`Mqu0Y_!b+P>W&`Eovy zd~jK-jB^Wv4gXJq`s;oj$^vDkNy~~J;Mx?nY3z&KlqP5)W-m4WUY?|kB^w!D9AwNV z24cPD$zF+j+}>&M-r5U;1OE5J>Tiwj^wBY1`+kwdI{1E;^8ekv+b1fZ4F}({0?De+ z7+uY|RTd;?AoYja0h%r#Cme0u_Xf+0A#n@6c%XE%M;81ntvaJopl)UH>e3s989F({ z`WS!pO{P%MOo@JWNhb9Wia$tAA^jvk{Cl&pbN%(rimRBn>r(o?xYYT0)Je+;sd{?% z3kk}>SbIT=uF@NUESekRBiC9sl^IoG=qO=bhR-LsWP!644Np$v z{zv>U8o=`M?6pglO}`&i-4Or^SIhOz9cAP_h%uF>%t}}7iAz!h{iMS+ViGuzk8BD_vy~4AB1X= zxyc4hi*98${Nnz7y#J12Ml5JbfAhM)V_T*WB@%?P#3(H}e!Bq1M&PujZU(A=EA}cl z^dzRRoP*$mzO_a2P2x>WmZ|itG2>$&FYK}~VmLr|XJWCn%8b&mM~;skKMGJ|A;Ak# z+FuN5kjl^iQbLT%_WuqeGz-FJ4)9fjq>^Z0Lx}^FbJuGjNAUvEy)%q?rn~CVw=8a( ztt8j^p2U^$_lnWBelCT9_zZr92*jN(d03ee^7^~;{DR{0!Ecp;Z`^)stRW<1d_~Rg z#cidceS>|23nw%`jD_uuvbkE*9maJ$4_9lyA@{Tm!RUe3a_*u zxCcyK zw5k=$ki0*3IhO1DS$)ZH1?QHbe#BIqv?spB?Q6W)s!2sjSKd??2+79(CH7`27 z{^peT>FNjlkrUe zyxJ4-agZ+uyZo*<|Zv!Stjl3?SHUIP@muKjb_Oy-(OeuzCIt>(#i$A zLlSH<@sv(}wd+YRe5)=Z_=~!kD%4tVF0JTs+*Kpx0_xro+8vomJo_ldO89 zk6;E#IHdPTGcZK+ywLO?d)d-4cLZto_X9RHCm~e#=Z37zNHB~rbZjh7eNOzpnt?q zSi<1+mGOhg08Ju#agG!^2B6gSEQ%B~Tejh(N(R=Qo}X-fFEkWf?#~PZ4y8U*TU#1% zVF^;_hjJNRZE#ceu8ih^PIOd5I($2-?%vMAmkD#{i8|e;qXn9g#(?U4V$^ygtND(f z*a5&7$w2tQgU`3@VH7IcHh?YPzyXl-0EkZoaDG4XN-2>@MPMqsrf50|cvvoQ+6u%^ z)+#W>K!+ay_b}lQfWuUPHkfVn$w9Qf0f-R}Zod}Zxa#eN(X@gC@UaQgs=ffdEK(9Q z@jcENf9a@3SH?`AO3^4sJz?ELlLl*8nvuB?f;78XaHXl(^ux~T>b9UH-Uq-=6%b7% zT6KP`Dhuo*Mc95lop+#{@f%Q7)z+46=b~Lce=+=C^V6r;3P5Qc4$v3+sZT!bHRj-6 zSm;aV)tbvxlZy=}BWC^apw_g(x9rEq`)yCLRajxIUYnDqbP*WzHTY_t0oD?Dwl};Y zdiNBt69v( zlC0T(&q3%B?8z~}r@BphrSK5eu>Fe&1?V^}AXiuczZ4o!7Ify{A;&e#$;s(4BqS0B zrA#PUz0!M$@Wa|fy}l`V7&`+T9U@(ZTP^)S+v-N1RlwDZ%M+0_RiZd+x0Y5GtUlDsa-p9Ni^#zD1nvHVKp`htH!F ztW8cM*EA2e=!(KpV(!q8IZngo8vA3Vi{Lka;6J>A~lQ-B5;eo8F{6xYjsn zV>5VGZa=`5>}c}3oC%pc{bU4=%3`*Zw&+RVggHV{yQ|n6K+KK@0C-fQ_Z3y30p01z z)Wvnwcjip)t`R^^XUr~y=U;I+I#Pz^kd)ryk6=jZUY$*az4QoAho~)0d8g_Lb}&Fw ze*8LD6ivl|?22?v46=xY2S4+?p!~AB{w?n6oUNf>McpDHieo2!sb{Hz;RCs<}_r&ll>=P8#ZKYLy7R3^xZjApDIA>)88A`dMh!j8VQyLU2hz3!O>fJM zmf;2f#j7GWSDrJTU*ohgC*uWXouI_0hATjk=LAqtH$v$UO?AM!K31)16PEQxcUvgE zS|G!M`O7;o{WHUzr4|B?1?$f*?z=!z3?pR2TJR6+tl8-CgD$!vLawnG2w3dX6=P|g z?z!(}&ofwE_7!;23;7N}vSYWOJNfl1O@xStcVlst7(e6xOz?f+d~SV8U+RAyMoD+> z)T%=z^;Bk!+hEp(Tyopzq9S?R)A|=7@rhdtU*pAl_-<-dRbW-bp$qX)6-nk#%qA~wU}ADAqVY5iP<*HU`3BOV0Z4Y+Ry88 zEvLTw zr^!J2W{6Y|VhP0IiTYAxz*_2g^i?HE z*O5t-i)+Y%=T}j36*^S8*9V`1T`fk^Jo<_bBln0|{0bNDu{%Kez*tBoLWT+#hl-5# zi{>SVuJvDmjtV@mEm}ORxT0|Vd{+rwb|3^c*-K$=AJcm&1Tz3&O<-krtL?8#9LjP1 zmi5G9#0%I6)D3_oaDc-$>)^mDm;DNGay8bFEcY+N$~q)K83bfW{n z4BeOpVD(UX7iK-WXhw(LCT>~f+ld0Yd=>600XBBK#E*laUVCwQm?bj??p_0k&62q# zR2iuV!?Y+p-8O-!FHU7@8QL8l|M5-yr&q$?B=a=579P20% zj%oj@#>b0awTn$evQJyh>3eR#f5aAs{2-w$0a?%?RfwaUva*%1ruv~o-`K(31wR)+ zAKDzEXSVmpTrZ!_3aX|p-k7qEmdLsKkYj}M1%kmJWC&eSJwx~xI|;?!t?|cw_y&Mp zNNHeJkxGgP^C%`y@Jv~^MncAvI8=vo?FVv13tsz0*h}Crkmxdm@lr~+^gy*%*wtTu z*v=An-A02WZvx!7=i>3 zPrjgpV7D$Lje`3o>a%0~PGOHMLYyNh<(u#=OEwY$CvTYz_?N|^AU;1_E{<<{3>L0_ zfg(7p^lB~i_$NTQO_=R?9-s@9yePu}Zqo>VYsihCbE-7EteT}BX!s%tz&Qx9*juIV z9;3Ct8?eThG~K>-XwX<2G{p56&pO&yk@D_024kGWKcuF;C3Z>VHEp17ejs>To>FY2 zlix?OLT12T3Y2ZGHueiJ21$3vvF`Cm0dy#E!=i#tU;>vXUKH&{NQ!YpJ#}cy$5v&G z1EeEh;ZoP%qfXjR$dws-EKc;&G=E1!jL6?;NZR8KS-PL@;g$bEqWw#ARN`Z34s)M7 zqouxq089U5weY`CJemzKb(;*Hy!g2uXefxu+hDD3#u_&eA6G%@ zE-UKTxH`hgj^9obqO?*SA|CA~<)i|PIE?=>;=pc{g0T*1jh)rEiCp^m$>*T>AA6a7 z5C{epUcja&ft$A)P<-6Yi^(k0@-U3MYjO2+q$}~KJAA-=3GDG5^Y0+L*c|UJZ$}58wk5AoZNCLp13s}p^t8-@ z&w0Gc8l=)(UK`uuJn>B7*duCTWxhyEgn~LtL!dKG{qG7 zojQPf&9N;lcj!wAWB}&DN|y;E(3qs^4yiR40DOc>;cwe-loI%<@uL4LjcY?DjtJk$ zl51#33&@D`z?zYS5d$~IYjsI;KDp+0{o)N?AeMlpd|&K}l>=&F4$jBY;I=Em4{Q2C z(w+xIWh@ZRRF}VJC+@wp%K=D$li>)+4VQ6xw-@_LxLtvyw)j=l?kg<@DS3hp9q2pk zZWXm_<-H%2G+m(=IgNuLU^NDM|jA z`r`ngt+Dl_Ys^6JH{szHhCLevfzPTBMr<|6mUC`xc|JDK#{?B4^a2ml_OE1r0x-;D zruEWZxjx2vHy5j@BQw&-!88EC`w!LCD021$CX*r~p;W2hCeP*X3UTrAx*`{6o541K zuigeJRT-m_@TU~b&R@-$e@P>(*NGQlqv?DIG-4tJeAedH8eb;B>Eg|)7rFX|a9%$B@ySPDk#n92ejT zR4zA#m4^jvZw6l&8;WOqRU08kWGe!AI45;+q`9A(%4~(*KeQ#*aDKdcNso=3T_XYb zd6XO+@>y6}Yv&Q4)Pa*`u7|5c=WGy&1asNRW*)&M!sszL@D=M!MVw#m5yZLrtpuD% zT^qUPI$%&0I*EpcfZV`QaRfBHf|gIX^uE%2omy+L{ld&M)e+%`bbV464IY7c`Xy;A z6#fSrMdSWG$-E`oOO6qEbhf&OFFB zKkSy4wo2m7Y#bUONqpD{`TE>DG~7_WsQt}QlX^UEbFO*NkwX7xzz!(;%{-yFDtG>z z2Ws$Ty1E}|jzT1nBO4&+UVb(8xKF}mrhoVb!&T2Su?|--0u{0${uAj+9hmjX4?2I5 zYL|9DFkEkT4}U4F`Ed5K5aMYN_B!lr@#1XiBG1sLW(k>(7iPO;?nN!)@nOXdWaDg{ zyY3s9h9q=b0#FE|Z;rz|t`�D6?TaasJoo3Dp85ANhguAwI=D^jFPA3d6Lfw**Fk zrhb4A4&v-3a^AP#6|2khN5EDId*IB`dd`NToSCN*v;sIaUzG0IE!$T9y9g?FjwCG( z;A6#2 zC$@L5gmLj*3p$wa`E7YwhxHH?-cd>7&fB)0eh=IYJxq*pQ1KW}Xk#JsRX=RG@b90m zn!+eK!b1zb{IJ}A6@cxWft3X5(w`nzFfuc1h>sJGA$@LwdKFKwWRO15liVTl=xpaeK*}H#ZeH$z}qG|L#?DW zXLWpOZ52LGEot5qo_`I4nZS(1P$!m^ZVMaq|`cgrNG5EMTYKL&oRe063hp{ z?lQzjDIWfY5U0p9^f?MxRubb(fUm}b{AcH`lS zp{Zp}!iP*Z;v@^>3cHONLR;8axL8K;Dl@55NhCODnXSUpB5dI!3 z;NHm%m;%f;MJbKfA0&ubRx)L-WC!-hU|;)tvV81x{mK-%<{DeyFH5-`UTY(ONKPM2 z1ve9{e845!6&VR!p>j?^tzxrY>)}lBMY*)#(rv-qXbB|XGnxHXIadU?LfF=gqjxg- z4&(MWCJJn)J~=N-KR2g1~}6u&U7D63=Afh!kehBD^q$R zGni&0FjHd>HKmD5nR4y>aBuZ>XeEsdKN0!6S4MI{`zRD#Q+H8J@E=~Ss+_jZB;wPY zhaB_LflZ6g+D2V;iQKliGCFrJVD*meH`2SBipLtt%I?AI>m9>q*_}9M2noC4N@WS# z+KeUUeukB26n?04x!A8?6DAp`#O1f^F3&@4nK)<%-T1dl4{88hb zXe};2pFw1JYG4gbOD8?P%vwz8(^KH3$iktpObnM%$9UZq$x1o5C}n=UM|_O4Kl$3B z)(w!38oPy2u-$9%Awx#j1A%%9g~InQVx3X8mQmGPzd8$~P4QkYq*hwJpwMW5SSt%U zOP1_dJ#7U1mr7pH@p3Mv8-~r(ej9eb!h)T(I#`fwbWT_?>+7yiUL5##QtE!mo3JJS3*Bo9=gtZpJi-bGy)ncxcfN$EWGlNVCBRTA}W%zo_`7R^g ztL2~2CbxS>F~ocKrlkp69|}L3<&3AVsonZaGhv?kJH%A?0quU#laPFJ*+o7alGXSA zqBSF>`opl7q9n_1#HbYg8D&yj7}?8*d(Mh{;_dy?!FS<@ZiD)a9IVG;yYWNVTnyMB z+dW>Uv|#L6^MK9uvJ2@x{USV7$PMY=Tn-`;I9MIlG^IG>v~pt9mN-^?S17P-eaZp` zzbwinUo2jW`|?&Y&Gq`K#$O0fD5UVTYwtOe?T4+bNGXmuBbg^tx6Q0T@wO2*MM(Sl9Bok`#g%xW@~PQLk?{^A0}eB(C;4>>x3+I(!WkLHU;JVzDmDxl8GOz_jatJl+%NU9|do z!$^;f#p_NjiT=ZN&tzD_2Ei!#HGbwndM2-TAEjTkDwvY?51866F7tGVv<~lrW^?skGo@vJ!o_U!;<;70Pp8+1|#ERYq;fZYQrCIo~X9u&A&ll~S z&GFiS+*4G7P{^Y_-4HY3{+;q167#7#91@-M9Wcw%q2D2=V{AT}!Rsf>LiF4ng3-N~ zHr_`0{6t*t*n5ctMoXO-&KF9?!(RLAYio~h#OOA`kA8Id?$`3pBTDk`ICk8}ZfL=i zK!x(F+R#xod+IG!^U2)}K8Lrcp6bsMN`pa_(>CGVB@21Kw$8`(73nSrR^r9!jw<9gL*Sl4P5Z5kYyBP z3jVHi^JQ4c+dZc&p1x$w;f#o93R**-c7cNYw<|{a5gza*+@>{rCWB2vg0rf@T-pn8 zS7;oejbWI@CEb+OhlgFVJo05vySYw{EGC~>+(C!D(2;fH;aD0u5>Zs4Coi^styyTl z9bR7~?*QSt>U?Ek9-wtXh5P*GpCS6vyz2q3MTPe3WA@tyh8|*7_(%yn7j8iRzgmA* z?#*IB0%bpJ2jpuoKkpr9;Tz^o&=)-2feC?Lt-PQ zy$pugwC}qdX_Iiyer+bodTku6`jeO0~9f3dNnD=unAuK4DZEb(gp%m6U)>TV6M-DN5(k| zNpvXD+4l3-zkW(}s^&l?1-0MxEG+^S$AS#Xm?zryy54j)g~r3X56o;a$CweW4s zoZn46qT&EB%f?Ylg2s{gK*EQjZn!)@dpF5XcACfFCgKXy(uz<~EN;?eKJw3T!gxcM z6grGs5m-a-K9k+Cc=@TW=&!;8W*b7c$;!pHPTqwpB3%dnB zYV)0>EzXLjb=J5NTg`jYp9YQuo1br&o?oy1>%$^Qj9^1Pfx#z>O7n|q@JE{>s?P!EDY|1CBZ+t;wQvht6%{oGmn`;zK9>4352{ zm4Xr@kHac_8*1ggXKjV#&vt>;zc_2GE;PJ0(Vlw{TPpZ%*rS?ZlgBT$8#1Tc*-BMO3iqNgr8~_+C}8_&i-Sx{X5tZ!PsERNQ)jlTcXIIHg-_rfTD}W zwor+l*235?1^rTNCQB{DEcQhUkouDbEsNI(_=9l4$D(|RxumKuv-MP295sPMM9V=* zi&XOmjHBROH9f*!VCdzO@{S-^m(~vX^<-)p z)2xvh78!lgCJ@8n1T(3kUN^5gpH}S|Rn>`~;XlXHPjJiAD|&6Ad=r}>?1dXUvanHO zdg)mYuYsg0v4O?Hq z2*PZyRC0&y2qU0rL!$_^eT6XpJ2!P zuy7oVuyV8-9QXshcGk#2b^85AUON~EExL1wUT`YX#T*QqRKucIk^CdSS!DlaF69RCWxM zz7{goOcgXmHIMS8?BQV@fI)lW6P|A<=`nb}yTQ+Y9}JTi z9{)3`nT(m#v>D9Tb+CY9T}ow@FHn>fF=V~f27Jnwf`{fre4z{u!6^p4&puaS_80%F zUCL=!-)MBZQ9$X?%P|a3D-FwJ&9IxfpP$zk-EV(8)28#g5|S5&{`FKFzk?!ZQtOe| zP2i~|Kt9dz0(#cB2tjyjiG+5Z>=S|ws>kLfd16;l;{j~6ZPJK+KSiy2Fg1Epf!-a4 zri0DfBvqCdB_5%+?O7Q@);7RIF{*s)?mzkZFDhC(1!K3fw07OD^R=`>T3I6?sJhH9 zt17zl*&(SEPi8~)mCQAIQO_>Z$A@2-N#5ACq9l4c2z@HaQ3L$cOSMg6a5TT%D=Oc2 zVAeCQkmz$XLkWCvhJBOji_v0-9T=zm!2?@d4iAY1w9=C49vHXQ-OCGHb2b-+cm5{P z&)~n!S92%vZS}^_ev|0;$Ri&H(|4Urlk$+knC6+qPur151F?xV;pB74nRtvd|8)UTK>+Pf&?uhfH%=KIsZD1eDIV zdwAb6sw6>eFk8^sp7Pg}0y6p-NLLFo2mVyu3b(cv)NC)`C-~;Ny zQHw@H9~o>1NY}2c)>>CJswVS%uYGKHtqe2M(DQ?~Gh^Di_HIGkE2Qu0a7i*?D(fyX z)>==;U-$Lg$9-BsKQLw(xTs2xT`y-L!hQC%YhQ`a9enapx)@m_4=zEK*)yVrlc70I zG586X>Mg;+hhQzyc*Zhc>1ro9_dH;k0|sK99DMj;D)dM{TVf7_D=sOL2jvKvf8B?`0~e+)@PpB z$-Nr2_kgUEqxJt7dkdf_*RTzkQb3d?R8(Y_P(oS+5f)ekL_knp#fP8m8}iJ}DG;GJ z<(r`tm8d%Ebs@&r<&>|nf{BtTc^KOJWxdQ`9Yc$^8MSMPh7``VK; zS`iei103s(6sC#tVdtWV0*s_@pP3AKThe}UMs(Knep%&~T0r8MN9ijok3U{*8nA4% z;%dOS+BAtOz^?XKr!+M?Z6zZApGARjw&iHDaKO3;> zTl&WvFx>#~99X6dQQ!YJF&-K+egIB*U19fS0k}RZ;ZvvBJBk2{H5j?P-n2tC zwo*NK`LECv2*FD0J^;%6nklXT{`6_H{Pd?=2MtIU%Ubs=g1FR*)P;;kdEUKixbXx1 zP7a`41$3|9z52sJ#15@JN!NSMp_!IaVA!d=*qa3{TFTX-@fIWkVnX5(K+ zAh?$S0blAK9;ILp7-(l1g^gki%6KEY-aJ4CUzOkr1)3J}e_6@D%Z>Eq9&f@Pk>9LwHTE>*B$9x<;UF|xHz$^+ z_jJ-Dg%b%Fk-;91`%6ENna+aD%ST~cL$qUh3H!#{G||5dsUZpY%es! zCZNZJi)DA``jaHb^8T|oQPb20H9il%(wV*iZebBkr1qhZU zfT`GJL{nZbjaC7Yt-4n$2!HgK4BZ;9nI5E&2a}eB+VOu#%fDUQ z=X`FA^8$KuaY}%q&u+1M>wiBE$S7EIoV#pOqcw!aU-xCGv4G6?>0EMRqMW?Ee3kCe z-c-QvN*5QvZbDY+zO|i{0yG4VvloK#fMQnVu>*i!J^_4?Eq|FwOzVfGZY2Mk55r)f zj*0tjw`Wg^*5lrc5t_xf%y(PbX{ zZt*5jx%LK(ya7Apv2S1dA)+@O@S5=GD@d3D6@cJ_7YUdtV<{eWNPm{?+&O*ywiL9x5)8(za=t-K z0r8L!fON=#jP6pD-mfom`1wowBGZvu_%f(UJq}=oX%(xy-1NyxF~Oi0*97oaJhiD= z8;T`Vrc20}F1{GDqQ|cidT>PgH2+t_`5RQX@Gck>Kq;$2E#&0*x!w;6*Dur1lk`Jh zPl@MU#+%(ZuiNxS;!S?0932ZjPfsG>$d$GjQ3W@mGjD%>ycGP!P=(~K*(etXcENzS zHN-s%vb=77u_b4KbpmYFH@l_(!EgCAadLTnbj#OAZk`IkM@>*z8Kmx#%BA=jN%i-GAAVK=iMpF(PP;J|xz(S=b+`a}{03lt ze&5t%1=&;p{m+lAa*;;Nv}{$fL7)9dzTuPd0GPl7+UOdLR}jBzYCK@ZyWEk8tl3=C9a9C-yHCYL}L}@UzqA!?-4ak z?1}9TPpSM6rW2Urv%^2hh`>niednWXm8$^8!UJ;nq0;QKjgMTaIS9aUfBkFLhW^~W zM<)@y+C1L27+!60-7`AB&U;>Mw!q`IulDw8y^b*_xa3lCHjU~r#xYQ|XJ-%qkUcfj zsP)5}9VjuiK|WyRKg-_%*XHTR%59N;z}_i%z1#cJ><95Ow^o@dsPhb34nX0a7U^*Q z`Y_PwSrpZPML#xEy)i${Q7OLKuFtnpjalO3C3ht_ON2+bkKO7bQJ!umkC+I$?tSh6 zynw|Cmf%nn*3Rgc zG8-frQoy+1^dxMzM;Ma0PbG={8MV*)g5Bw2F3(B zx0S+@&XNW~+_rR>T&pjbk>{`S`8Av`6TI&X=HhR^^%{_%$+*I&<0jGQT1|rVB}MKF zT&yPsSJ|01=NHIz-ptvppxmd(o@EDfMHR0Eer(dc&L(<>lG}|t%T_tl@Mp*6FEa1& z`6q9MQ=I*Y{Yn0O#a@^vLF<6a$&sBP#Ss|bD5?B`+i1}Rb5HVwSx=Mw4^iwwI!alz zSyRZ8!`0G6Fp~QOND~QCjlW9^$Q!5BQ6%g4TAGi%f20W%5C)~i_`4`MiCV{NiM|4+ z@-1(MM;l*<9Th~V;&>WfLYS=GgEYyR<1?KQ{d>;O>oKDw!MWDYdeSHDDL32HIIKQYC#*IW(d)^D zis_A0vjKjve$q1|T2yB1l4ZG5%^cL@41P-I*Pvrd3trFkD;p47^zthQ;or03fUENk z(aPYRAc-A@+lpMxv}cHXeg^B}A|i;URb^6M7H8?~Fo!n%?-J`N`=NMOv%_+3LxOHg z)!7Z8e40g6SPi>gJqte>H}fC2*ehpVP_tsV0F_^tg*k;1`n)iG^~LnQ`N^|-b$y36FvdF_s7H}!XHR5sCE)s$M38<9q)a>oDbs0 z;U;1fRyCAV*D!cN$0=Ht0MeYLDbfr$G#0Vzp~7!T%um)TOW!2r(|Uh6tfNJu%Aw)? zZUIbxnu}lrVAOst=Fy=!d!)A|^kL0yV`bIMipi2_&aChEFHnvj0$-M13zQ$8VpQEt zK}B_IP(&|6jP|U5(0DOrrR8T|S%Ftn^aAVS-t!v(RHh;M<}pLK=&xoOlVhzB3%7qp zCBh}>Md;s3vr!1ds?HQS?oD`IqLm($%@J*XKW_6GOBwxM6o{0pCD*2B%OS9pyEpYmCe1%)Gde}d+jr^T;ooOY&VD&HZm;`tdsm~0!K zvBOVAZ{WUm_o6~Z@hUe{)yURDS6ILvgWd2~qOn&id!eBh)c_QZNcGzIIOi>RlZ`E% zY+3mUAidrM!+e4M45E6fhHVc1cgJka#`ME@^Vh~b@NuyP4EAuSI#ZG_6}-78mO){r zm?Ms0U@E0tPp<4!m|Ji{*U%7MCLMRH_6xqLAP)?3#*o+s;I$v*^*U!v7 z2ZX3R9$k3@3cYvrwBL&)+0=f_b2h!fZc>DGd=5g?>5z!$vF`A`xQ1sR@`WJ^4$=@= zjv(YTO@{hy4Dr&jq#m~12{bxzybuFR%IC{$$4FF)PjAz94h0nhp{dovsdBwfgYli<%bElO^(srH+*Hiv$P zE@A7@gagzCyrJjdH)MWPu!Dk@=d&9m0@Sm7L5LgVpO4GVQXJID=E*%>yDiIolM@aTj5~|bv0R) z_nAtFe0?su0hK#E=c8I=oq{eqwEXbtbH3UP^mr{d{iEcH>w?N>uvbN_4Zia>Y~V{| zpljWEd-FVg3Y1j%Zb5}gk`fw8L%SCZNy)A2kUNAVG;2cOoD_P_i*}i(l|S~d240;@ z65RpSQ8J@2o>LvX2%jZKRF^K)*Wb3-TQ@z+Lgngk=2@Mz=b7x8FNK1mG{*u9O*NrXuA*D45k3zJ?G-)9GKO-V8}?-A1xjDM*-KuI(-xGyF{v%+zq-vn6*}t{IVm?_`Z?7&~!_pk_}cAu&31^HoPl=6MMat-I1k8yN|9Zn5Vc;{!M;7pqw;8 z$BlF5V6Z3t7AY@On`Da%Zpg5D4DZ;uM+?(72`&_jc8&G)`W)?dcS&!=qJcq=T>9N< zU->CWj`*E6g7>o`ldjN-WNcD5Ge|Nb%IoLzkrzRMLtU zF+s}>!lz{OYN&KL=ma=?8k%4N!1cfSFmV^=FD~rFWz(m%1GaS|NO!KMP2PV&={^{H z&+5f&t2Q+6wpySS*?E+10(=Xh&+$Aj#p-=h0>32Vm!neNc3MOc2lk%jG!<^)?H>S# z%9rFak4B2#Sf)*_G2CCk6XW`ygw#VQ?kQj$R+y%UgF=H-(6F2AxdjuqKIj8%Ji;(B zaff(DBF9^Nx@M}XpDkGGlWuw@zUP>-jk`aje1iYZ z{mPq-%`)0e2`6pe0?>~})Esp$^SD30gAC0|UsSnPAR{sZ-JK(T9S zeC4ED51~j@DAsyXW)NIppss!EITt4&l4-hlGIP^p)7^0M@cMmYrI8=s48j!{#%O#G zoHrP6 zn{nrW=&s`wj_XeacRh}F;|{O7NECyT4%Bub4N%9{v8R4bK#Jh*NWZFHNiU`L;+G!` zVy3|fP;urz?q%sykiawd=to1h_Gxc0B+Fg;A7Ha#eOk$@))6$8X zhef~j!bdB~jP~nGLOGxFkeEGTvxJNayrwm5;BXQU&l_nbdcgMvlv!i#=YSgkCW?J^ zW@ufW#Pwa+g1fx+ohef-oCSo{a6JD(3pL@Xnq}C(ID6VY>L+NFhOm-{dC zS(3hkRe`=iLl;)+*pgL^Y7Ls~6dyPju1Y$rLA+u zVFb~>DU+ny7Vk9iwQTAA0P3LL=vsx#!SAz9O;d-LBD)sw5o4Uz%vWj6dOj3`zw3{f zIsnG=RQl_6{LMfRQ8MS4Puv$gG`)27oS45rRZQ5qVmU@<{3O0pZgoI-073Y-Q@M6G zb1KBiYs(Wak*DGZI3Ifm=fU z0{gPACLI!5txiFB*8jtIQ9i|kCsPU`JH>$e4#dvnU*Bi)t_MK{LBzy_*GyX;%#si;i)gh2;#b&JXf?LkFz4tRdUrs)RK_p zmpn6pIX+oNdHe;SCFwQkzg1}X!q=xHhX((Nb!Z4HN+YfBP9np(dCI@4 z_k6^vSo8|>kbyDA5GS4}p$e^8UK|IH={ZgSpi|u=l4#XpHc=NmpWeQYmuCY*#EaKT z^jLR`1A{g?Nyn@)Rj6>}E=!WjH{EE0$ z(2N#3ej(}-vNKfpj@e~d^h(>|&peQTOn$0@IYJ&*6R9+B7pA9I@M;`s1Ff7yK$XUK z+e*lzx-0LqH@{ik4A}Kr>Dt^~SbcbY?EBuTZKF8{hgJrSYw7T>yF&gwi@92_Zct_I zN_sC3U`X?_o2x7T%5+?hdXS87aI0;GHvtW{E8J|JzzLC?$L#5lAJ{rCy@ZA$CD1^; zfNODxy!BMU{P7K{%xzzfA3S3t?nZoQ7}=*Wyr6&(H@)0p)EC{C2)-53p_<5Q3;d&83M<_wuhiZP4L?%wNsHYC8dDVOQPPhoU|S&U2`ok z8>-{}LVF<54X+NC0?zq!UBol)dHLZ0XDH`G$5+ zeq!yeL|CiU0=a<|aHi~pU1N8ZdBKR-MGR`m4-W%e>-iPJcGqb-Q|CJaEy+AF-NDdz z)PSM=s^`~#TK`fmgy9eIwg{+5+}gjgASV)6cd_Y`eg12v$1Kx_u4b*{#1LAb0eYBT z<(1}i$jV_Asl=#$lp&!pPV4eRg6(rCokT}a?ZG*sB3$n@SOPl|<&qfo%O{hH3qC0F0_9FPmZBput2 z#kBdB;Kw4+Q*94Xw-r&_mWhJ+;LlXUrI*G=mNkCRUHMM}uKK`q?f6;WIJ&_VJ^r{i zThxw}m8_lFjU7MaH+WnLcDcykU|YUxii#PYRu_MrWRy8~#`nqeR4#3gucN1B;!V&= zWB)djD90#FbcOuwxlag>5<%StGsgryKlvvW!-5;Am3#PXd-a=d@=!bgmJV1^4X<<&2Z*GIwSt||97>sQ~P;wCzzOt@u* zGtk8J-E>2o!ayLT)5^FFvq6fy<}(h5fyo~q_rr1}Yzqlv_TZD7-tF-Um83_d9T-&@ zm~h{5xI2yEbCMnBlP1t-c2i|?-9ZDnP2!#8fJ>AavJZ%oB+M8s9_`f`Z6)ooE64hh zpd@gc76lss*N@~EziZrX+|H{x8BY^&DpNaSaWDp>fs#=_1$d}66f%AzYc*PpxLlXUfV5KN2 z{iw~V@J)d}E6w^1sukznr?IU&3$#d#g56MDJBO2!;x6Gw!F|h8Eyms~&2(oE+!1z{ z&S)iS`^R)GG;M6xtn?(1m=scq8S3mmEyF+mDZ@Lz6PD>!k&F`u*p}7^f}gF@M6svz zNMOfTVIgFeU2LP4yN|FI9n6no=MSz2OYAR=F^dmC`@w%az{xU+RC;}rp$Vf2KqkPP z_au`ZMKS|{fa=63S~u=i9sldSDtfpalb?CPp{o7cD(pm0)@g18 z-Xmmxlj;>f*6XJI9hJB|f=P21_)RKqrH6a)EK2SX`&-93fo=Qb*!y^bCrlhIyv6`< zTPENm^&9=-uAGK(Dz|DWiQwCP7b6Zes0)Jt%)ttD%R)dtBBR*6IoI9-^c>$V-lB7 zR31bBKq;P!PcrTvkxQA`>(ElYf&F--;i^%j3o8=6sDz%q`Hg_em4JkifRGG9K%_{s zXM3W#@=<&2iE&-P75;BcYtJ_o1wWmAAckHFNX3y@KXz%$r){o$-AhJD#wCS7nry8N zIY#bEp^1_3*u8H&Ei(g~oNt{_Xlz~h7_9>O5?P>jBd>icuc+x*ZLh`~o5Mp#*xs|M zvNrOqRZaQ}A4Rgy+VZlI9P``7Zja`Y#_lPLk!X2^^3o$=I0}*u*uiElqi7eaF})=1=}8@^+&CuD_-SLYSl*JJHdYRQEej?FcKZ2dx$P5*fBp{+{7h+OVFSn6C zZ|jyi`6|Ad?QZxDjUu9uXUEAx<_X2>NW4iWnO+b#w7~0XK|ERBdg}5zyE4DZcERzz z=0*$Vfz&$_OekT?>4_`5yTaE2qV+>D+FUc2Fgv@q8B2^r`+S@+A$u!F0MQ8F8V~{x z;Wh|rhR)Zb+xm1v@|>A(MRyn9Ien`~&naCfS`~>gG?HasxlJMrQ$0&=hKTDSnf;~x zc5{}uAVS-I^R4HZ*~E72w1G$ zXn5i^Y~duKc_i0?tUcD%f!n|z+98#>^c9E{vtl?MSYw;?r}Nd@^+P3C5pde}+-t%W z)Q}k;(&EeYKFAN3Tc{di383GXmt1Lpx#7P<9&6P;qF1nLhlvVGSnmVLR${0A#~i5) z!mGf1t|8d%X1XJa1||po(zb%D#U%KUDW>-GWdTZN8`q%oZWj4Y?u@WNNF(XQvvqFEYjK#}`{>-sJ4Y9-ZQ+~dJJzNGLjrpLXnaoJLqa6rw3sTgA?e>N@N9L1u)d65uqXdX?AKIhz)b7HNb z7c(zYXeJa3?eJ*1hMIh;K5>TRHk&Ic&*rVTQzz(t!@QXzSrzQ!SoUV|C(A=$Oe+Hy zo1GWgd)Cc?(Uq+NY8d47kGEvJi^pUb4(sn$1VtU`%AUTZjv7&F!vZ#ATrEg?JtMR) zp9qP%mDQL%t+K({5Mg;8a=h*(ak0UZx8a}>Ij!%Hyp9nT?-|8%^msRfyl0b>TxQ#H zg_ix#p`04@eh`Wg>h1NJ0E>Xv8Kw+ls~^|XVx)iFCdtD;|Di}@2?@{+&Ifv5{o;qq zAvTZu#ZT|hTWQx#w@+31YGfpj2$1NiFsV*p&}iCz(1$bu%NX`QRETm}?ZO{(3`B*}7w&^ky5%rgPopn~LHON+o938g1W zsI;Ia#cXG($UJ~;@GZJM!Cx&hpDF;%o6wtn|9Sx?4o`UfIQ$&VI6BVVTuqR~Fw~W2 zI%&18Z{Ati`1B^?k41Txr0w2Zbjg^kE!C-Ug(Gzmr&Xr0SaDc+yAdkR%YDrkg@5iQ zuW6}`uM+yqr#3T9ydmjEu%C0VuRQ(KZZduQd?lUOP;LHXVcb0j1Oz;99O^p&TvvX~ z#pVO?HYyl(z_fIQE2)DwITfT%D&uThGT!wk7BkLvrR-f%A|IHf&6lZck8IL)Oc238LdHp9USJA?@ ziO1RC3_ZKn;~Y{hb=u%@y>L?EH(){$5P+!IFLfmc9G=^EM@v>PYTt?A?T~d^lClY4 z8#!J{x$euyutt0AEF`)A&A}MTk?E@4|4w)#h?HEa>JDkibOxY zf?8hhpZI#NT}lvS^-F+(OpU2y!(P=w9}u%+<&XmC(1l|L5C>{(Ue&Q)na2%OWg-xUG|o{~s5t`T9+D=GEGrouX@Y#YulHcoql%y#GWnxrZUOIs+@%~ zPphGYdFYZ8F;P_!)7|G*KKtilBZ`0%Y7Ccn>4osd`&d=ZP;&6a5w!TNjc>b>k!F*$ zqwfFS7OF;CLO2#R>Fdz&#;bv{{n_`}R6yh!22$P+%6M)fD)67M=9daM2>b~gzxPBd zAEOzIP?O~~-|TKp=sC%s9gv3Lv5|+&zbba}M(7+;Q&U_B?V0?&!6k`LPVV zTOac|6KF~*a6aNvZ&be8&-D}u>1jHR0yq?@>eteTC8uE<%PLvzs z0{FbzQeiTW{|O9@Y;JhYsc@NwIC)Or>17JM5$F&-dZ;2|JwIMiyX1~J^KTp{+;>Ie zz0Zq7lzH_Tx`(zuQwN9i9j~9<5chYvev$x;`N}>caHs;0F|p)lqFEOs4!GIBuEWIQ zNVlkH@t#!m!gXFBQvBulW4|BF{UKQ|*6Y~PKj@OZMS|pK$A;=PIS@otcLZg=@z#7N z)8&BMr#BrDNe;3?y|@fYA{zv7stnJVOMy{Odm#Vol}`DKYP8}F0ekfY`U$MtOQ9`V!s57b|IUifxnkZh zqxHJOPxQaAW#jg8jf7%+ly*-jPyH(ip?^e=sFu=~J5BgyKlGxu#<^$5wZ)FzDa}xH z9uP4qh+8z|M@k(y9mW59Iz(=OhBXpvKYO(lC{x^Lr_@ck4U8o1eDp8LxU*!9w3rfF zZDQRd;FSJeED-J}C2;0lFxo%aNfj+P#8>S^(0g!8@&0wbsaLG0zVr+c@T^Sxf#`?8 zIejE(@aTm>>bPy#pzV-Ym`@E7JUa@XHPv*~j-4FaiLO@>n*jCxrp2$$MA(#lc_ytI zZ@R^J1cBH$Ss2Bac)Y`UO;mUdqVy9rIrZ`Fzvl7&opfz%5(>#FpkP0^_S78v47!u^_eZ;AA@UA6s`tD3Ld6HIRT; ziQ{*B#v+~_D**94f;7-(iF_4Lfvg=$LR#u;L78I&1`ZRD+I1AMYVdrN9zG*9Kd#y* zo`b-GAdA8>}(0kg`We$k`6C%Pzi81IHck%FVprG@nbfqYYmc*g47@Fd; zI0mB^{3mV1XDCuf)3Pe*pJ*`|>VIw;_8&h0EaR;rNJ27HvC?i0S_4qgA=n;Xo#)$TT=`t~Y357#Z z#*<)|rpoCt!}nd`j@C=F88y z0(^EO=M}YTiN)TFwJn0DHUZ2^8~#USG}(1V{aE=UWr^eWzG%e?y#2hm0h=!dx2f8| zKlv%KDZP4v=a;Tn$@qZj~1rpvZ3mkD3Fm;pvW9or7 z-J~e*)j4m3VEVyz`l8F>7e0LsWy7eW=Jx~6d7LKFjKnhs*Pb_)wh&C^L4?h0$e?Pv5`mJh!_ZvrO z+UC|$ie`j=R8;$uW8VXhuS&@%{sBQrKJL^0Dls2aw1^{WW#UnYpo)uQ1N1*B$qn)Z zXmW#<+uZ$0)yDy6D;sLr7=n;#5lCxNXD}n`e-A5*qjs5wZJ2Fu@M0g7QJd98Z6FHU zEAd$^BMNcjzQkA3t?_>|!9SU6GX@4!!}P%x5zg3)-|lX`kSqVnyX9E{JQWQ@sSxj} z-u&yS{si(KwskP+I|PX0coo`|e{=u8Kq;UJy^*?sKZ zY5V}z?M*(-1jUOA(Yu`7h=S`TiAfw@dimWv*Jj9?1>ZX0CkuCHJ#7}4WmlS9xL`E+ zBFgNw6Ieo4k>76mqiGI5;uPbsnEGQto3|c5%~qNHCBHHnb6UJ~6rs#3K}JU5bCc{n z0=Q?gLc~==pDN7B#`h8Q5Nar=rKG42DmrjE%BBzu_N#)1NMQkes30?+OEvS$oN*S% zg|NPrT(+bE$2AuNDTqYX&X65s55Z`MH$Tm={8}ni9+0ZF$kfsOIr6te7^mYOe!@rh zjmDfWl^)gmO7Yy%HDV&vM0IKx{}RfRJlwXayk=4FX*&iq96wVai+9p9e%AO%9s0q2O@QQ3J12Sr_4vU){Ml@nS+HpMSp9D^L?(A`St^VfwtfY&JrUCSF? zT-)TW$dUAldCLpml;u^KwNZ*Y(JJkyK#si`T1E$w+eF?ZAP};Ula_pj?@2BCqstef zj+(^BEX4zr*rOqJaPRizDS<3M+z$VQAtC5Uoa34ctCCBOf!V|rlwR-_dHnje2k9-c z$SQJ{HXA#=o}4$$bZ$N&NrRfZ;%`*~u101v=$oZKaGlb=CJ6rxN1buYAP2dQL$vr3 zQLYo&TbXe;uUPA-Btq>JLe$$t>7pSTqQyETDC*ie_t)nxV~@+zj}tu{BAqv*#`-}q z_>#BuY1d&jmRHkh{o&^LC6fD0fhDwSm@$2g2lcw4h|L5q?jm{vtJoMSc?~@+N-Rq6 zx3CH&xbTSkWH(_Mx%JnCroHt0P40I1XwLdDPZ3=gTE0k6H{b+x#OOYW4}IZv+*y7H z^pvwr@|sxv4cW21y+^4t8&=|hl*VnOHTRBZ_@RmQ>TPUcw@w;^Sg>_$PcK0u&<+|r z*9Cf=ovsGx9;mLvy}i)&9(|H2+b46Rn4Ak06bz{)N#8+miLhK5xB&N_^HqpgK$w*_-I=>p0I(0Sd?d|!_+RI>O zeUkH>&IR7Gy}LuN^Roy;-!s2e)Y&wpA6kw$4!7a&caEVN-;2n4h)S?uKS%VH`k{?6 zTf5sXLrPrP2ifwai6o2N!5kJ+ugejUVQftvd)b&h{5}lLWVLOoc8bgBw=p7@4mcXQ zl>5!8NP1U?J3%*dzWIJd8U~$s?$-OIDl zkoSqmjWgRppOmvnWzQhdG#6Uznan3S<_5;yj!ZDl<(qjezgF4cUw+nlxlzT<%_D9x z2fpskgSH7zoyYeH7|g2(-8x#$_=S%Xm!Qyh&@y*~0lu<)!4jIBMv~MXZBkyerqyHe zp^P8(UPCnW0ufaT8_}ZQabcfUJR$61q9r&tl0WB0g^#bh?Mnibud2<+0|KJ;mL5a0 zEBCVmtyQ~3gfcF@)_76=XtMKFrl4_RHW!B}{ZU``@$;ra^-3AHJOVcoH}x){rF9*Y zFBTBPOx*S}tv1q+x2-9nA>FIkTxfgW&1Q$@yEDU>XDp)OG!P%PGE|9F+WEde@?Lfmy|~f^HmP<&fk;Q` zMl+|8X`kT$v8GjyQC!vh*R!`c)|v62f$E>n0IqND3-+ha$;u7}qk5ggo~Pwys`rz@ z4ZnsrtJLFju*^q(_N;hEZO>W-T*l#FmvIwhywG++s4BT2B=(DpuXxdi4}wyDEol)7 z@E2P9oNacYUI%pJWpkxK)a-6zzWPMatvkGoIiZNm`3T%KEsRt&B%zCJjyM_?h%|~9 z`)pV@6bH~kS% zCS3mJ%VQaK$-#c}nYas%<>NULctFD0;Fg2S+4o=%>nR)>A3#j;8Ga~pi#=mbmzLL% z)UFntm`&9Ps^>0zBktg!Ul!i6{WxG|&{w^~!xDtj!lhZ-u#TuzSI|y(`zVx1hzuG(=4$j zFT$z89?AM$)5U;UgWEs*!FKQ!Qi;9l+iNOQe!$JP*MGYD#wa8ALn_)2W}?w~8!sTa zTC&6g*n8UD5f5uWW@Rx~X7`|2#`G{|;LCX3m?JK9#Ia)DVvrXVL1_X20zU|@tgU`( zyo&?J*-**k@X49l55+4;8}Ji$B4G2F_~^Nk3lZ$r7?8Ob0DPUNWuK>HXw>bUex!+E zz;;Qay4{5kXsl&sp?Y6KJxIF@Tn>lEGQbc>=g<7!qav*M$$q;_5ul5;m1ph)g~Ope zPHqRyw%dgU9=fD9P&rm@}ypq?1O03;@V%8u9+<30(r8FVemhb??D%CfMV%m$JSLk97Fg9WSd zN9;yo&kQS7&9?ClKmUX57t(A-DrS)SF!i3(O*=<;fj9Zpv(M*9#@%RwN$#6ev9(-T z%oE}3T6ZdGiH!!deN$kFo5rApEMze$?FdvYha13t(fGq-K!pp@Hp6a&ay-=_J_eHL z6@_MFqp?68@DObJd{PP4eftl6fchep09`9J^;K5tO%{f-c?t6@5{+W|4_9MVNG6v$1aroBqj(un!)Ol~B8{}LVGb9}QzDX1lZ9Sm_>hIOe z@K7LKdt9h#)APIt$R|325fl^9mukrn_;GB=<3*JnWl|J*;R;{XiY?hpYTr~bK|~1e z9Pz@#8FXCP!L4E~HQ4r)m17!pc8K@14@vgK<7|h$`VUJ((;S{5eOnWpm~7xTuJTfy zJf_^D-8UP+C7=C<$(x;O3Hqr~Ua;h!ej+*(`t;+^dC`BlT!KM;EAbC9mSSuq-y*S5{qg_oFjbpSXV?Wp&JKPRKjRPg@ zda$EF*I}iwZyE4HZC#u(FvsQG7iQ@+5{>EsgB7vvR{&NwR8G|#e|yhogDa{X4r?PV zlRszGMtY9!dAYc>=N<=x#Cp>M*ktTtf0o6ZNSTtI5J|wnMD7%&*mC{YNc-dEIZ0B6x1!5A9!I!2iFOUhpchv%=p>bVx3`}T>B8e}`TFg)ekI_B z)y}rXES0S}43|fTTw8Lea{@AwriHgc;9$@8amfPp0e4aVx9BLVfKIcLg(TA$%~D&N zO-~BCa2t9PO*OK84z&-{c{@IR6SGJcoKgDD;)-3Y?34T^-K|IPcrU&UwKQsNGav6G zHv|V!l=Vo*WghkAV-cYQkKAsv#eFAKx7A9x*;uzx`D)#)({Dbb$6h%%`RB8Kfz`hT z8|ir6Ry(`K5WnMK3FDunKwK+vUvzb&PXZ+Rt9{2<9H8n|F8l3m_rA01EG zUfiP=?VKJCgJ$5K55E8Bo`V{HX6wp3FE#D{*xzM+?L|Yzue$WxCW7fwa6YpuGALPwGy=WLmv6!ReXD?`rv7e26=0ZEej^7WtBGR-3*7Pm# z+u0-}ONd>HGf8`V0?Oag0mc2ZF8SJNL6G#s2GG*)(S)b=?!cXk`mDuo(Sg&2H`PRM zx-~EQp+02a8BZ>nm#kD2oW!EX_XE%3o~=3b$0KCZqd&uP>G# z4^(cI-4hxcW}ZxXOch%DlpL&sHYX)a;q_9J@Y znR|3~007L!t2N_QRa6Q!e#$y(n4a}zr{Ke*aX=Qeu9ZxkTQVscNa~M#ey>@>7v7vZ zmht8%xxx2b06euj@3&}Y?KOWJdvpWixO%UzBcegm?}=h!b9c8ecCF$t zYbg}Dw29Q`dK!4E>@m4m+176br51^!1!Q^-sWJ0KqC#8TQ)ov=;Nr=B27O8fkvk$0 zYK6waMt-sbw$YdHZDu|t^o3_MG8tTMuVg8UqUuLp4)}#ytU$!~;!Ytm;O_*l(U^X9 ze57JGZJjrO+Dj=iF6u=U=)(3Db;;)Wr=DCu3Elt;{f5&nw0{w7Q4-tkesPp^O}n?l zyhPzRUHix|vhoC&`HrtPuI7cB?xjBR=xgg=F6NKnX78?mW}J$`JW>(`+7I%=29$_f+gDp|^>JuqNQV?bdC zNQ>Wmoc!Wv-YCeB6uyP*-|QqT+tYeU2Z|KcX-UwHlP7jorxw!yQ}YVnM2j*-Dx~eg z!llJBd3~T4v^T(#oQs>-*`d`r-)D52_*Fd$$JhXugx4icL@!^U{(hsxv3R&gCI3+i zcdKQ^_%@@{13Kw&X}XYT({F4yzx2H9)~^npS9)Nv!uicC^Zi(#b45ntrdx_Y%gxT5 zK!tDhj*n}9SGJuo1-@|7kuwiKoc8`MX~Y{+D|4hhUorPnkcA`Iy1t-f1v}|rI~i0t z8X6-i*gt-BI9MB?l<7lZeyzyRju@t2`@UQ*fIZW_m;~h;#=(^#d@vWbkq_p?94@ zjL}+MOjk>qxt!#w9jJ0NG?pxI>c|HhU__zAtId4@}C*`l7bYlpz_iEP`XRjK&~6 zd&3trIq-FZHNtQ8@)szwCq6?KYM&sL+Mu%iJqn%zc1_w=^nu(@4d6w-Dcj%E(K#UM zdD(y!YCxe~XCrE{u--+>q_Ah$48M!z?&=l@j;2E<#hTb%=ZWuA{sIytq0qw8nedmx zsyzqz#VOn+Lvy$i{b-91Cvr{pFYQA$m|%!F5<;5;R%9}6q)AT8#AahQS+Gx|t7y=W z({Uk_*BH!k;f7kRln_4*)BP$8H*!JE{ql{UV07lI7Vcu}dm?k6`;T5w87yIuQu595 zSyOgEMZsjmrcY2!)cSmH!mi87;aC)p@}m3T<(I}2ZI?jHUYRS#fAe64TK4)x8$-99 zXT@FA`uJ-PF^7XTKk=`}cR`9Es~^FU#i*{#vjQ?|Ecc8`OmgFcO+Pbqtu^JhS2UH| znPxv`Cg~Ko3c_T4daz&uN%<_%M%|oUT;FYix0kl1#y|SD6@(~>j@>a^NGKIM$IK82 zBK4a-6xiyOwHar~aDYn)QL@AU7qz-Neh-Li0AYmSCF^F`+n()pk{=G766rLA&VqXA^eW!mVi!Sd$me~vvHG}`Umd*=A=7&;%d{Nm)|qVba>-Fc$&gLY-vI1w07Y!N3l zoPWr$o2VIsH2yyELC6`0>RNLm4LvAJm7`nhNllFH-3;L&iUu)v^}c%>>78pI(3_oa zs<~H5vbo{7ok%d%5ylc|Sa-<3gnKTjMOVM>Av;C0>7yObbK z3nM5UdJSvXA8`HN?{0x2Xn9W_rW?`M<0LWSv^$bTm@OOX1%a)Oz91DY8IP-ftiZ~@ zx9JfuG_oshFvfs0*$r{Xa#>+Kq*JQs`pFfuyeM}$=AzM!voTlj)1E>bxF~hzR}~?& zMCo>eH9TUwva3xjHnAzb;U(iNNAu+DGir);cEVT&2d9D^^mvTjs0EAsJaef?*)qsG zx->R0*A@-?jaFf9Ya^w_eo(PNYkjeMH0~mqJ$3~=F)X96nliD%6@2R2(Uy_t!2B%XlH;vtlxCdi&36!X9#pLD+eN=@* zChVc>3D4R?td8eHmhFlIkkHaEnlB*OFV?cN(Ro{O&)EUG4GaSm> z6T<3nTNl6;GGciIghE6u7DN=vE|-fRL)IuDAD`0hQEDr1QeJyOmruC+gl})Rb#mwP~}U*L?7Ka(XcdJ?A)K8OAOy8i={Exh|^pwZE=)n@&LH~!^Om42W1Qd zXi&&oTA6;@?4~a>5G1sJ)6*Gs?T5po;#k&f*$bt8-5rj{R+a5#tQdQ4gV9jv&H~+q zDEp?uo&2W(3eGl>x-L8&&$I;(@=nk(HogB(ZD$@2b^G=45~&o@qU@!zBwCbh3=$*V zOqNoXnM%q|gux&cL)}dFlBJ?-F{LEiOj3p{ld_d%?8^+s%otlUJl9CwJ>9?Oxu55c z+h6nYvYglTJ=gcT&N-j=IcJB8OJ5h5Zu3b(K>bZh+tVdzK?aR{FQF^}vuK6d3xX_TLK^&XE)UY{~5lf~2~ z;>c%X9P+LF4v1sL$?f)?v2HKJVJBLNeljOLxbWt+tLjxzABy-1#rwXsrE|okRUoo?QY1lalFUbi>ezGUz=?rmU zz;7x|Nd~_%o$YFn#PMbAvhY$I%z+1ID});3}IyR zlOyXGZ%wovTml%iPsG_2JDa$W@~(=Ag`6s}4I780W0G0hbpGYm3Pf1eYn)H_CLUfVXk@ zH8Hwas3Dv@61mOCC=XTMb6vnz?nQ3dLw!uCpeRX;28qKUM85$UnuK33T#^JRxqkL#?q zXqY1nU)G+@40fo(LYqNmc=FWUWU5&a5TL!z`zpp`7~=dg5SbDlXn|vKvm2>_6D1SH znk8039YhK5Kd#u7?j<*8-Z*;VNj3SiFRqlL*k)58l>u4}-KW~pp1x=_o*T0+bYGMt z_22A;%@#+9&I>Cz>j|_pdgMg$PaXBcm-^A%DYNEPh95fS!F{RK$5G)#9XF=p#<{X) z+3mNQ%iQFSsLBqr~w>OtY%pwcZT7~ucj7xav<8b&g z+C_Vh($B#@wP$zx1b=nPDw#D$*O_PZ7aGRWiI<}q3aXhPF?F%j9(P<6G=ObFjR(gr zb}d#DhKFmt!-jzTjs}{~1W#PL;dN8_;23CsTc9Fk=V~-R!8u}mP!!uSQA!SO(HhbN z<=^Au4=|LG$|8|R2OcNc`VS@?UjQ}f8Qz7Nc`}T@g5>%x61FcXEFiQ+{XHc`*?$E~ zr#VA!-gd*-6X*;%uh~{|IK}hr+KG$3ATi?p`I2>2hKYC&OxST{=yEOS<8_bI!+XW1 z&C*VvJ*}$HdN?yvGuOP|t|~S4>ZjwcnheFiaKj6+Nip16vXk?eqxP4K=zP`93Ce3m z0!wH8m%|lPFP#S2KnM)#n;XPaK}C$S0e@&c0;8cU!?H-dLKXT-z>Nof#9B8;w4EYW zTS>)j%+_SG643;aI>vj7X?geyGa(jb@Ebg2KCYt~&`cfWwcHr7n?pbj=mpE@82y20 zYx$&qpU<{Znj%;>9Rlj=(*R2?UCjm=QEI?7py!JND@Z%**TQLzeV%c+K5ZhHy3sa- zXzJJ4vduA9)HmNIiuW+3(`V0pK-L$isHo&C{mPxq%D)_}TL-1X?~Ji&%}*x!&c-v|vG$H7aorr3A zzIL82?gRXG+djW%JDZ5%O*xZ}vszsj??U_w1Dlbe>%Ps<$U_$-4o%6F?I~@#(nwlN zw;?iS=^DcVBJ1X!md`1*M9f%q1z9pRIqHWXjQ92}rwErYl8`qO+jW`*H6M)gYe~af zlBqFgw5{`^$Jv>i1pFCbDf-FIEL#XDKZV5b)9>I=Yx40n`+C+b=wchB14bUY3-o1b zjmxE>E;!!~NICN5+6>sn2WB#pD(LM^VuGeoDD5YChUH@Yr6(W2ra5*q&EbzkOQ{7~ zLz>5D;0q&ko3k#lQM23>bUs|}G=uKUsGtzQIg?{pKA}YU5MnR+TAFVXcclbn5^Vgz z%YfziZU_1KdE#OxewLIp-ICC;+e&h(P?PknUwUyQ?G>G`#o#74dE=ayKLl)NXUnes z5{g+Q?8I&vtfNJ?Wv*$`ubToFS~YxJ4V8itEBEY`l%gRzSkD6Gnor9j_#L~#EbI|} zU#GG?K>M?&0QW*TyQPKX5fcrhMh-(N_UwJtO_eLbomIhscg*w+Y4)4BrWP3wis^lP zT#B`(?@K8+vg?b6lwv#4)mN?DK=-RBjbp|plzhZzh9+ss;iD{j{)FjQL$6P3L%gA# z1AZ^g6!=xV2>CMHQ6TOnyg@_l3n=hom3DPMaid)E_sPsVlMZ_2l!@cm&97sc6B9f- zeX4c}P2H=2#`zcp4P-#gqh>Q#oC#mSTOZ&??lMfXxz90BRaL#a@Ij;HAlA$4oSm?d z$jMb!l14?B7}zbZE{-|+IQxNAMOio-)NDG#O0=ityY5UzxsmUxoKhy&SiyY7Ol|;m zsJzKJQdhtid$=hMJd$Zcc>l;zJonEkV!aN6KU)*4n``6hf4bbmAdGvJD8MA(3*Uiq zodYP{xhGx`tAF+WEmKD4j&xzYP$jQ{xWK36=NTXXq=sY4!KEgJhJelur9Gv~Q7P&q zIAyOr=$oh=qNOSxMi-7M3~9Ul=Hu zANONfqVuOt9t+%>qeYLB#`XHtLDoVI-sVC5$6xCU-9KWV=q94AS$%QHAALF9&O-fT zNDzf=<>knt)}6}prd#T4p>ysxvs?dY$LmMp7pZz^@cbq}<(g*_SUVkO}agr-R^ zF>CWwTkt$s$*C#L^g%@6xI<|fPLO()h!hoV-hK%{BVFxnwKPn*L^4zX&Kax<7j*fm zMxgryf+2dZOt205f|%U+eYF`>wKllhCQe)WLfn==IN@f5g3ap>B*pKk6E@m3dtx9o z@O*2YFXcEaOQ&XZFKXar->NU;AHz3m4cyVUUhwT;mT}1Oo=o7hRGj5!y_Ge0K$8&p__z~AL^b4WNM;u=(Uf8>(L)GTG?zpg{ zbW{|Z;^NV28oJlk9A&v}e;!VOhoXTmIqp~1avyCGH*v`^#Xo8WU;aG9$FHI}AX;le z{WH?*QEXFipIg*FAD03dRQaSWGneZa zq4Oj59hWCP1226VuM56g<<}EaWh~^FMAzlF+`e)%pEmEwwHk`o#U}ZIgekC3PiarC zFKWPuJ?4CpcOVkJ;ee>+sQh|fo*f@|P-1-R+{O9LlgDna#Qp?`bin|tMrO760rMz1 zAtCs64c=V%62!3;vM*L9E$-#;yGJf|DgZPbhQm_&*LPjLsz7zP#<%nEKTT zV)=w8)WA#@0r`01a{yg46z(vGYOLQO!}HF@p??FO4=;^YC$~l|FZD-$deWb3r%p<0 zzs~Q8gd1ZW)?}__v%-?b*|%{o$YiwB{EZa+b(ra1=$)?WRgy*qyyoktgpCXaGPhwN z(=WTOkdR|)N!SmyQfh?zla6UZ=|>-!1I>cfEhTFHULG-oX;tolEowHJS$NTc-LHn{alp``Tj>0?Yc?O#ZFMoJ6tBe!L=@pAD|OEoK9;lh~ade zc|K4N1**^(?5_9KbB{W4I^V{;J5ctTubAg)DA&RrX|vb}g7Z6MNqS+#*5AZ;mM1O^RXzPRDC?cp9O5PnPff2Nr2$#u&KirMAcuhTw#k|@ zDNrd&W_`s69{j_r0unSdwo?dXGj`l&e+;T?7<+7mAo)me1uiNuO|UR6k?3R4+^f)J zb*J3%5*wAb9txqy;eYI9$SgzwBZ>k@;IB0(6xci>AI*$qtA_le_CD&UR+$RnoN;E|MR8J(f@)_?+c+Y3}qFaUR z;y5zBw2qKK1!8wQPURRIH2QNQFIH~%{T3z4Z?R`x?1oU;=(!w@`xqYprpsK{y*cfz z-!s&)a1j))g|q;x>ivS$FfI>C&ZxR9oDBiB?}W?sTb=K|G3lQu0yo=&UTt}grd~5d z+S7bD-sW>!l!#TX@3xD+a^qv?DzC|2z(@tJ*f3j~-7x9b7j850+&)}tbFf~X)g)bb?6c2?y&0mcUr4d!BZRt0Rf7{m;|pbi`Q3I_wdBrU;_0 z3r^n_Fe}riqL-V-!gXC-d|QtLj-XewlNa(MlcMYpOYpF6(=A=#Y}$nfu|eGb}x)3p~y>CLw(@zHJpky)oG5&4aO!$=qQl zv!Kt{aCM4;URjNV0c$O0bN_WEo2_BjVOyKO?BPw`1GGH|DSi_!j_SRXLA$Fy>XgM< z`E6`y$bWI>jXr#m3sL&Hvyj2TCqN1Ya&y#wvi9zL4w}>HL#sN%`SRrnk$7+EN(utN zofsa@DMZNehRQOZ@|n@Lj`{JDIBizFz;tu`J>RYf&PIjPKfZ4E@M+mufH)TA$STq{Cm> zL3t`x0{PRr@AUL{jPJXJ|A8v|p{9SZ3+!~jV)ec04uKw=~XwU32FqR$W6bG2me=K=3R@C?a9w}d)eDd>X+-MDoj z!;b?dg#J$Sedu>{AV}yA?uJ;Bg>%_JE=LqAr2he0cSM)zLza`zmvIfoxe( z=@;mB8H9N&3kZO6&4V@&h3 zRf}7o#Ekxba%wMN&=z3O%YWG*FaOPK#k0~)Uo82VkrpPb+%d&eJi!33n@`7CdnMC)_G1i7IQIy=h_LJG$W)8JH z3xGqh$f3s&{)N5hXc+OIoO%!#qzDXhdj9VkG{}&jJyi&W=mP2QG8Op!-OM)nl_c^+ z%Wn}f-HqytGd~ZwxxZdPOCLdx1qi*jW$o@?8M^Q86~7EEOMG9Sx6Hv!JjAMOZeFuY)t@(- zJLyoliRQ8^If)@Li<{JtlKe-f-Yb=o%Qfizzid!lMvqnP{NxHyQv{7WxCqhzaCTTi z)DyUYD$qzT@1P&6aP8Ml7r(jJ$=DT34PLJFEUk|Km=m~W=^*2-kvs?~xrhBg)g8ve z57)u{!$?(SP-7C=>kZNTN2j&|QAsZ_==T59pli%`xEGC@9wXwY;7NARTqU#r1>fKO zntO(94i%2(2f%&sXaBy8w^yypQ3s^RxSq50wZ=>@|08V8v(obnYhC0!(WT%2v3Ai* zEFicDh!LxZ(jl%*$Qu^5Ky@Y!S}V;?0M&J5NTtZ%{A>k}o-hgw+8hT|Y)GfJ=_2T_ z0^z(BP(g1$Rx8i@AAVke2Mqh0H+S=Ei&z9B<7wP(AJ8?u+e08QRCKv{ldROSC2#!e zTE*@0u*MToGehqIL)+&kfi&lJm46@c&+W{5&|5;=9tdl{(VkTaLSa3T)w0Ou>s!SF z52B(jD<}y6dXRgvcS-&761Mh3-_`WV1@o{RtG8I$9@u9a$h* z`<)DMu(}|c)F}d!D}t|#K29ol)KEqo4bo_}^=_acfU0+qf#b?Het%`%kz85S)N*=e zw^3JQ+kFst&fNjCxTD*fvKEDw=dx&;BR+c9_2{})!- z6CyuMKL`4A`+{=Df(uC0YE2LpzY#oIN)Kzm(dVB}E&|E)f}QF>=c5r{j@>GLL0dl1 z2bW*y#C)<4q-P@xMulk4OU~=*jL0n?M}OS`G3@FakV!w#5k)i)%rWl;TBPdPGh3Rj z?3{Z<_iFyqH46k-f!_dFn%~CFYyyqFAzjhCpT+?2;BUKVMQH1$j}{VOI_h($Z5mM$ z#h{7b_Td!o#+4@dIbRIRgZE!}7m*4GDL=>NYh(>;C(?-7^DxjXthd@E|IeA98}+Xn zgri0%&FH-|uuG}`U3Gm{IJ>1a2*qG}Kc)pj5JKTwD z*Y+;p?>PA5;@bI+n`zCaq{7aB}I( zWYO2`_Am78riO1O#qDyGKE`o@-?Qs%`f}L-hpwbr(#T)VjzM7=KU++i-VZ(bw?(UC zXSi5UB_(+2^xWGzQjg3bRpL%P5uQ z?f-t8+XwU-D6$W^yTY-Zp;sXtA$1PC3@Ld=1m{qj^WNo(Ep|oxnI$ZnHjvOek~fQ) z4PBk|CwOyEAh>uDd^~QXt=O&ASPe!fhY`HVP(gz?4(VnOY>cTg+qdQ+ zTZB%+){@CqffoYqZFu_G_mgfrNBOIU3=F%XOir!#5)dM*n7s*5sYtZb{X@MeNRn~K zW|)mr=b?(QpUo;VgXl*!p5nf?b)m*oZA-OXwEE<^?t}DKbQyXyx-Qu!RkezL(0Iai z2+7bbzE3;`^F58auIO4%GaWJRZGscuc4`Qt^hs@@SgRUojBT4-7+T|PPW|A^EX2e9;Ju|2x$w6 zJe@v{+NZ&f8pF3GzmiiJQEemWkuy7Jb%d^pVt2Y2b0cAxY9DP}A|oZz=InBurA}5C zI2VQN4||X76eFvns@E{Z?g*;naI4t%y`el>m|_~_gq?`vzyWpqi4*&tj4brNXxz1 z3!H2O>+6vLL$yp!giq=pE0aD{b>T!^nBm9QyoP!B&hc--YHNR>qb`3`&C7bbC)4#^ zmW*mWEr;wEQfEI>e7suP&t(g!d#hA&?%9;10G!Xmuq zWkN@S3Qvn}BvnHP$YIdH9{5nLK~GM+Gk}Q$$o)3rcF`HMqkwup!e8+Uc+}X4ZO(^Ugqf6PB($y=fA( zD68#V)u|@Z_*(i&qpCpQl4AMzI)%mvV31}qD2Lv;MDaZT*TrF_@@yNXGZ^EvXkW4T z#E&%gtHad9b%6QAB%sPR`G6WzwGCtYHagC)snGx3zbrQIcxF7CTyxidyV|d_>&)R4rg)Fmnugq3o^_M(iJf4XG+?L5)V3ad?#*tLvq!eNwJvC&+S6SDg-A>Oiny(pMv9(>1mL5s;T zQYiVfso5CtP0IIWjRj<&)W?|<@X`@s+;jZ%%GP?`R%sKs!LKUI+18v#DvixKD@889 zO@q@$?%u`V zNog#+H@=p3Y&zEW^!rv;RmbKjdQZuoV&RjP(t_FN_3@UmhjPtw&3P%Ac*}f2TDYq8 zT_P{pdp;8%HA2-U9wQ7HPt6P&+a{~^fVd`%YKupf`73+6K^Ts6AoOUk-`kqy z!PW>L`bI}$`6nZ#d8ZL$a$6I@nD}=1@3Ub1^92e8Ks2->erb9*^!GZ;_Pvy%Sk;nE zY1BSGlv<&a*jc(*6CwLN)M^*mH^w+Mw(1eFq=hg67b|;&G=qp#o5ZPlAv+_cYm#9u zVyH2HWjn9o)`nyZ9^~`USKqH*=1jsVyIouI0xRla z!Yht->$9ax2dX^vj3tU|ebyLCt`XXc90k!Z8(3B~A!F;E_|LW%9TEw%Jd;)b>zG`g z9Ck)C{i^M}b4g}Gu<!QEb%fsew;y?gtsB@1%}&k))$w5 ze)7|@ElKlS9xFbzZmVVMGyn_az=eG8N$e;}!y8*RtQis8!tJ~?4`T{lTtq}lNmf)R z7~htHD6JNS5V?N)BgWg7G=0$)?7_ji$g{M*@ms+eNq5Mm?VY`}P#-O0cts}kP=ar~ zhHAylBs`YmdU8sC$awOc=iU1x6^}vq_W5XuF;+ebpKvLOWA-Q^5ww;6TRj3yV!^ZW zpSO}c+)C>oqdL3xdROY@E^r{5b2nwv{cj|3&G}qxP+7E8Us(C;vRW%4r|u7|VPyB@ z$x3vt6c`WS3fJ0s46>M`Z}w&h2;bK2a90ZN6EsAJA>n=&TLi&LL;GY z68erppku2_5%{#cDR{03*)v8h!TH+GL*P1l;O*wV@{}B;G|ICzO7#~L1cC7*!lcdx z2N7ZVVaN*T=%E8Cu>_MKu>fTLTi>$yT&O`xtQV2DCqOwo#`4Xu@sc_S2jels2}^1?5`>ZiQCodspjWFUta~d&!%+fy zu%42iG_*C&N1HbEzuh@=~#a}@i^I%6gyt?^h$nsUvK1q8~LfW1xf(1e1p7Gl4Jlz~Mas&&1G3esi z9=%<>!%^rXo3VLPJ$lr=PR=!lF1)EhtJw5+r8yuiY0-cu^I>`uUfD)>IVh zysd6y@6sW}QG&$6YC8jC(%>>2o| zc@+)l-Z=5<~cs*Qj}|GA=kIW zpo;qsujthi5V6K$M#loPPZVyRF+|jTp?K6IJ#@lHS+;?*7<(lf)^(*N_m-89{5B`C z(X&AVt})~!ms`)c%l3-?b>RN4;Z$@Z)>8ujQmECbM+KU4U9ebv( zBu#ZI;mSx;27#Qu4S4N`PQv&dm@#xN&@hp|nlSzSvi-hnOd;Yxp*s14Ih>PlZirEb zP2|V#;5n zx1H#M_8!7`_s%96lAeoua+%9`&EjoEU!#paHA=*5NTr6bm2$V@&QQrs&oZV6(hBb>!rPyX zcE7=qmO6}_1p^ak$9WDa0c40;U~YAS}wx{Z;$K)fc#A) zr{ZqB`CFK8bHX{51kIKRmL`Zll;U}`3fYZLEa@@Qevb?|m%&g_PnhN0c^kAGR13CS zo9c@S)1(p>U$2%tVVRc?3X!*mIpi0S_V>Q>tckqgoy?Lp1lfk8^12`fD(`y6PD`9bwEnoa$LnPYR9rMb+3v_)Z4(?AjKo0t?jnkM z3Z7CMk_ER1zc^K}N9XoK6beWQh4V6C3y!r+IK6$qG;BeJ3Z?Jb-Ua(j;W-#K)djB7 zw?zmW@N{`7N>RA`l(-;xJsv@vfETHHx&S!V|7VXvTSg;+-X;asc!Lf2IMqAHz=8TX ziw?Eht8mD{a40U+Tv!Pz9)%pHcENmaBRdIdP#gec5taY0T=NGjCB;O^nQerq zf``jw5b^UiJpa8iI$4VR&z;YYeNglLIIz_jn`>xMJ=o-I>iBs>L8o2-Q(@!R>U>0J zX=SG?Z-sGZn{cR4;OR~py1-V;rhii*Fx+Oo^&%^Re|K4SzlhFZo#=i>NBu_WigOCm zBlvF4R<6D&^)_On&m z2*o;Qdx9w$e&FniR?78*aYjD#Oo{Y@HylsKq zgcNeY@`1W_7GwIo;VimZzdV95mV%GN7tHpRtPy0U3N&}QY1t+hzgSH4XCHmuI)7{F z_jiJo<@mC%ZPuv#MwyF?P(^^%>FMa@U!knR&XE3V#0i!@tsynptMx1L3&Ux8y1Fz? zCdb-Ll($TFUWPRmG$?kEgOBr%_wqW>ka}N8q;SpUG?c9Oi*AoJPv!f<$H)lyO{)z> zh#>8I ziJBH!G&MI7S^Ai5L#U(FzYA)2t=EQ~w38bkq!i&-YZe85F=1$%JG?+KS*RB`qL(ar z{we`1*v@koU7{vtg#C)NaIECPmuvIDtv||!pQ6wyu_q`Ul+1Y+OiGx9V-fWi);}Vw zlV!qBrS}uk9NUg_l`HIqTO+FoBP@*sA6YTx+RJg4ihSilU?g&lP6!%Xc^ScCDO3Wr z2-;@wbUK&P{*8~hS(jM8EWjFaRvp0?NR!cl?`AM0zNPhEeq6>kpq=>S6j|c|KkVAjyWC6lyidzEzth+cm z%ik>Y^!FsX&R_c1rBY3Tdd}V{#qN2}{|~@&uUty~ekCF+O8$h& zQ;cfSr@vXF1e<-16NYp_Os3&6|K-Ggu(Ej@E5qk9nXU6OK0~bS#ZVV7Flwr|J|Or)rgF zEfNRLRB|f?LeNta#vX(yMj=JOKoE~4Nl2rr`@2Lg$be3R5GJqtwEhrYD~{ol_T5Wf zFFx2788ii2d>cwnt%n6tGDeZTN6sSc`!*ZXd!$A5wU?dqd6S3X5WO)q-@Sl~ajIZE zQG(j%OaM)VtR2=8gCuC!!E_p5c;rx!LS)l=`k9Dt71v*ydrbPI%)|TIZ38e=dZ4w% zemKc=zn0h{=i$zyf6E7c_lF5GqFpwX3e|gF*9ce16utHG(7BSnR9UpHxt_0EP(v|(*SiKO6Nm6kW1y) z_opB~wr>w|B$prdD54$O{e<5^Kfj~U&Eswr)GoF6~(P970-KEUs*4yew>E9Bc zeQN{x>)i_bsMP?%fc>*!tJzzk9}q5a#m27y&biHmM~wQp!f^pGtQ&QZ{DB@})ed!c z!{)-$V@AUjMElAkM&A_0S}>(1W3X@)Q9IE(#EM=UJ)+JrMW=%-pyzt)?fArZ?&#X~ z7{K6|gRuk%Eu8jPVmjYP9?g3E-Ej7xXy2HE==xkxS5!a1)ixEoQJy*6?!+2>ohvy_ zv1m5Pt6s(BQ(Qf_4*aNM<(BfV$~xvjqNob#YbY;l1X{X>bw!?BX+$*Ecj;onv9qIB za=>OK*Ez4|-(0!;QIHMG;S!Ji(Y4JUsq@5P>;c+?XI?#0E|rLtozRk2_1W)X`_s<+ zJAvX)2)t5xAUrZ|dgEU^|Kq@SxFRXl4r@dG@_0t2mG5tRAAbN@{l{VEf<`xw>mKl| zMI&f9ag9k8i%JA`ZS)6bS}-6GM8{BmHzdB~!xphtPe9L$JtCW?Z>nqK)0k5}`+Ka-3~3K*Ix?kt7C(@TpR&v=IugX0 zl--oa$dWWo%CVg4qa_D8D$i}SWZyb(1Eus`+tI}lK$C6Y#Xn#f1CX;VS@6Hex&5#T zq}Ts4DI5if8UhE<)1*;PUBNH~sFX>W{GbM1$XvVy@X?jX3!Wks%UA7gTXhH$K-~%l zXw@fB`X9jjdk+Uu-!zcH%KyWnq5)>FxuFXVwdyGSZ9E+V(dOYW+}~dCAJ#^y-vYE>XrOtZ8-ux$$#_&zC~H zJFge4^D|+Nc5&L}HoPeO0_mH9XwS}`>DljodxZyXn8i|W;mdk4^Lq0&RE)y^M`vAl zd=*A{HC(!}_y!6h4ahk4@F`}4)Q;ev2Oc_Ja}sD?*~$7tAz2TLMX~ekIDS@W%FZ56 zhyCma{OS)&v*wD-hXR47R$>7i6V9>^I({bx*X{iG*X6YVP+Jx0hWVI~Q@f@7+^)y{A)1Rf2i$O;y_I7fOqWPn z%9V8)iSl=A;}zvKVz;FxL!7H`HtYTA5h{%2g9S$x#l8pZcQyT-D6KBk4JG1xudTYG zxgI*7ObP91dkC?Dqcn`EF}2AER6$H%35=2h+Gbi0T_K0*RK2e9BMu*U2xW?D6KUiA zB_JB93R7h~?kiF8uuX0c+ty>Jt)RZ$B`-?d5lM+8W6N=$LHh%Bxw5!Ao^9Q=b^gUh znFIeZYtd(x%GQi0ni_Ww>iEhBRG0hiT#Hxd#is@D?O~}WM0I)*e@&oanS8}S91U{a z-?Y-_Fcq&Sm9PNbEnk$5=GH+{+DD$dueo|$PoVk;BdJD;BB{*X%(Wn!jKruK!bp~S zg3q2HE+*6KF-rvv#L;P>uX>)txE{Aom$v)Ggtt4N%+r}<{c!SxFZ>o~28`u!|6!Vf zorT4W5EV!ZziL97VkE-4W`}%5qFTbNc(Wr`F%oV)yTc_J;W7+LB{OJFUnzdZI%vXq z>y~1NAvpsz=7e5+81p#@9kxhf+kg0sBssIy< zGPdg~1+EMvifskbOc{C#54l>pjSL8a2`VZ2fDL8Psem+r>gBC4RRfq#IlL~|O%Jf1 zm=Q)D08UZ(doiZvxGPB!Xs%=a`BBIcTq=-P!4)&-$K=KM+F_8IXYO$i8mL`lVjQ2G z*>H6^KtBMq|EQQwNFa2Q3wA~pl{IYF$i?|k>uMk>h_crGJM)+_+HTu59R-(>BBuZ$ z60S8ymF+G+Y|KEe^FYX;_5yUOMD4K{&|ZEyZi8|1s=oxXvw>g<-U(LRZ{C3dE)A$? z>Ugp`qy`Z0mAv|7E2J5@eqKi1YW5&5L(C9@%hYi zwsq3~VCH<_$baJGdPX-*xLXeNe)^WrVDB;tjmDhETyU*7BtWg?>g+7j3RRS7dk&1-#_sjfyrleeM z!CVAgJdCJE$u-94iTtYVe=kx+oPT8L^16$giifR=X#N1PqWjb z_647Kl3OQn<9q@?W@!w+D!tyq`9uEDUI~M)w*;466U7TTeK#ko%`AV1OtZWek%Cb- zfyz00@pt9yDJ$q+GC1>Vxt!(SXc%=;EDB-Ex?dQPF2c5gs?mY(KytE9IFfb+Cdg!r zVI$yJO4#U|#9>C5I97f#hRSl;$rxiKE&hgM$G=xiM*$>dzxko?fj%C7CttGg_LPs# z$W#nGsD4cvvvIy_&+EuE1<}fD8+~Bd>F1e0$|hin`Nw~0-v@Uja5{PE0HMlt=KFhr zb^{Xi+`QMYrSx4a*DTx}=CY($`*q`UQ7pfp(J@$Hzsw3CV#`?&_<}u`*9j5R3vaie zjPTE@c2*{}p8JWlvU6xK*2YTF#<^bHkr6QvW`R@-1Al&~vzqQ>goQy|b8S(o)J(I^bKEpn+H% zE`Ih(MC-Qup&T{Jl zvz@J&_nfv~8Yz6i>1?hpy(QlE90|$TTp0-7n(U>NFT24PG=PLW{_a_a5?;0Jck5To z@^9H`RDbCY^}!IK4oCdRqIl3;l~X#@zcZO$Q1ABpdxrXatx%`Z!ud5XdDj_rO36)i z34#fBUD5o$0>@MR?&dl2&LW+);z=Tfbecq;ODH1RUwCTi(A&!I=Kic8cp@Y5E?L~q za{UG!N=Er)-_O7-R5-;}15?8{^<^sPteymmKwY?}f1XE-^IxjOLH*=afPd%s)NKRtJBwq)ZM^i7 zU&{}p)Fq$-m`hutvLxd^f zFmuP+KNngpQ<}XV%9T8o9l%zdJu~Yykvu5JFkb)3S*9rlw9t+bdCm9z2YIUyi%AsA z8W5(4%e?_$WNQx?y}!@kT#50(%m^}@p*a~^rJOt<>SLZq{! z=nG#T)Ql!tr>(2j59P$}3|Bf}@X+fM+A}?JZqk3!8oqpNKssk2{`3KFQyHypZ$?nE^E0u=nLUdlKeS^IX+l81Pp z{xdRFxHQYj@ejFry`(AkyHyU)Upz=JK1Y?ifrwM2qViS@U${ac@9f>}QmK(f!Z-k$|REJE#(?YXRy6TO|IB3tyPXb!>i znnow06us_==2}Xj7x;qfWNg)2#0)o% z4y<9V<^3a>k?2r4+Gyb8!h=j>6D53`HP2B(h{q^iEK!~>d!gC4MB-hln(P&~dEY`h z-XH4chRxv>&C|(~+d8L4R?iJW5P66SpR>e7)C;5d*fxwhLevUEj?lU@j*o>kCtnYgi?Txn)5z3Zv$H1RpgIm$N@EP-zHr^Ju%bd+H!Pr5>_7|EPffmVRWp zi8!0u7<<)4NM!xkDyj@`B^E_T>+U)4EP1Vg|CEW9u6CJ1j*NUj%Ap?RpS;NPOqpv9 z(mwLc$9tQ1Prx~uE{U_;J;?c$#`r`-Y{?av`&52gR7JCvT_YnNUwFC8C^z$@os}Xi zWu(ohffN5Cy_Y9@;Ptep);krx2fJOL70OB`TIy=62apeW>alGs;;-$fn9x6lm0q#X zm2eUj#zp~KVliF-1yEQFSOnmy2EP@^JL3jCLCK@n_W*Na4`9YlmanZ9YJ@uKkAKxW z!aeKdB-<9+rOLsdv~vR9gKY!lALAl!Z8xAm5jt)cHqUc$B11N#v`uukGDQW}udQF_ zWr-5H&UJ)j7+-sMc4_d?EX^qvgKtB1m=`v$a53}G3n#7~O(ke>qC&7)0ttaUkpr?n z1@y7bH2^!IEltVaGqyjAF~N(!$s0Qs_a7RAya|8t_(;VQABA1bmJuOJC95%nQZGpW z;-z#MTt>8tbHnGKcc^G>>KSUjY%i!xRHb?6X7?r-iMJFvJlA0`+bs%Q3)HC(8Olbf z3T#!;F9)C653UhBdli@Fkh=MY$3hW^ z5;;kriyj%<9cJ!$9aP}OL-6@P8I=OcC>j0vQ`YW=TteX^rt5l1y?5#lTVa-#WSxkW z_phY6azb;aaR3$azBw&nYAQ?O;JbR9^=!o7>-M&&xvB=niz!b{_;uHXOC!1<&<}`#kVsCp`djkUSLh13g6m!p z^vSkz5Ld$zyWxf24a#&fAf+I(?-JT|v_HN~6#_ zX1Ej=>zdAV-0wGEC&D)8W8bhI8g_>GDNC$$#YM2#yVl=DWaPcPlCvmksdl!9_CPFI zANTqk(v8;JeSzuUvY2{Db=Y?8`L`@v<*h$*E;h&Xr04F}>MNui5iL1CnX#dQvM8Or zlh@>D2$!Uq^DZN~f^@>|uMU$|%D*4Qmp3Vqg9cbL-#=|w?-sa)LZ}A0WviCQx{?WW ziFG^jciS5fy-5^yG1;tKQe;${J!K~D|K~|J7#eSJsueeMeOjFn%A+0F)f!0d=7`DW zN&ZjUdz-J6v|~D~6J1ASHtSIv`aaD21EuS4)7RcAtagzbzXdhlr<;mpMidSzGu++2uKvs&Bt?5&AhrCI|PvecC?wo~V>?s$1To0}w^a8y@*r zGGp3Zr=NkU`sx&1N0~3tgio3a z$g0i2r}M9RPCpsWP4u**#qkS@vOI(2*ESeB)|ic9NM89|sN!Fgk~W{O&jhrK(Y>8% zcU^l6JWeUDH)Z-yEv8=$&QZX#{ z1X63h!c|KKCaI8(D#)jS{u$q*PIIH*L$XC%r4-W4aSb=m_~b6O4a)tQXcv32x*C=1 zhX6(@Q2T0&2f`w`=fD|A!Votqk)C_Lp0@Y_r1Xj|?lZv3Id}DL%}xX=yD}NGs^&R$ z#{X3V&aZ;qFQ*&*Fu_9Rf&YcAtl;&mBb?I$Ry|RxtJ*jBtgfamdQAPu_4%ff^=7z; z08~fH(Tikpx9GPQVUwRfc09ZIL1A-9aq|PVm+qtKxNlg?Tk-~d{(Np;jvcLRla*I7 zb}=X#%gVMU4Vk>GK}-V70GqCyWk(?$ zhd`9q2H7y|PUc48Ll-T{{2AwWDVOFep9egC(E`Z(htq{IfNGfM5pj_^^FliBV<#Gq z#mmJ8ZwzPi=&V*vu*>?V-B|N|Jk^)C#$z`>+u>`t2F=pf|El|R(>kC=lzyv!;-=sA zosES9AJPxJs`8HeKlQAbp(pK_884>`VddV;o^Nvf4qKd+Ss(P3*X8pus2doJn{F6> zP3_k}_PZU3Vjk_)DuK+45e!WRj8#+7X`(|a{K)j@cUhhL6^p&7b?M}}vF+&@j!7@x zW=_YIR~28piBoy=SNXl~Jej26xrYKb(lT*t{Bp|Ly!C#cY?bCm1*MJMPK=Tv7jMg~ zNO|ngtJvL6(tE4<(jckGhj;{r-kdyddN!yvblVr**0_V2rzp)hWB1x|ch!}gyqL;( z4EYf3)&rJiC9^_vE1rT0K*%U>9P+#@Zgf3{k*^`VW6r$m35)2pNBEXw7wX>i3{c8edd#1ILKkQ2aPFDsBV8eLW95F zmi+$k*H9!Os_4QZE#tTjv`A#7^W z@M7QK2Ir1vfpl-$NQaSPH~B$+#hG|bJMwl4Q{Q2smXKwU7Qg?lxTyI13K`)X#z`Uc z%(f@P$T74fe%oe2eksHhyRY#+2>zT$vqEbjvxot54;nCp{cW&_hJ%vuwvQu24S%?I zoO{;b3%en?KoDpy4cl&xZKubG@jtS+`d#&el8o7t$49=HU>*(mebBcmcFG)B`oTrt z+FZ$+om0UyD1s?3S?LFl@GZB4i7r-Ge*`R!O%h@;E|W&-n@d^deOL0H{>(BQuhNQMd;^vCkmnRH%D^F_0irQTvx(%DyT78NOOie@{X0>s zxF4PmWp&o#bu9Xq3yX{?FDf!cT7DK9km5>fcj|0LH1rhj;vjkRZmj%x9Msq9-`5_G z&EhwL9415?ouY>WPt5+#71*}^e+>0^3gRG^+>{XDnnen}6=3DFkzKK#-Hnu3eDlh4 ztWFI8>XBp*TIL#=hG{Ez%EL<;FygDjFRXWveSir;0aQhKB^i zMA(bPx^u4l=Ns|PS+7RxhW*aI-#>ZxyL2m8;G6b10|^U;<`b=rxf*BrK|8_htnrZ8 zt2yDj2s5F`Shb;ud#E+My2OcHKhszHhJ=gY%FWm*0=cLDLd_(+!#il~qMe1})g3)% z3OJ1!HSz1pMLgo(w@4LEFN>Je;aHt=?fMo}?YhvH2rxB;ERghSJ0<^quLL_2#L&p% z7I&^(vUnWRD7fL*B$xG zv?cR?OlOy*XYbwmgruDOIy^T2R#vs(9Pe~Pjfq9O{*GmQ&4Et0q$SU(Uj`5>h;+_x zg67)N+#@{tOr`whIaEONdXbHmOY#eQP?L#Z2;79ox-W^GC?0u}R^ViU`(esmU$^ou?Bh?!h;b$iEY3*BvYX7y zFI+`w&3MEb2|c)RCO@;|BZM>l{PU*H=CBSz*^pcH5TSjSKzz)nrwT*1l8bv=v`(}r zo<}5{hb|vht#8BG=jv4x^=mKS431I^{!fF>{%mvP9VWs&)lpM;gUcl$3`TzEq>o^vv5p(9TD}L%Fx+b>)xJ6h3+YwR@GFp@ik8^E+i-;hT2G~tTu(p{B1q=@lf68(AET4J+lDn}{eCj02it%>?rrot}p8J$l7LVKpq`a>x2llU)bIiublL%~07PR?3ne@!}~> z(G}qZYf3ma);dSW%1`UIB6}Nh3PRy1OUpyEno;=fBgQOV2$+|cD}9&dX*o_+P?&m_DneGE2WHel1+FM8 zsb{*X8GtquWsjt_c?b>+pY4eEPcpg3kNJ{TpB4gYn!kYIYnd-}>3eN8UDRl$s! z9)d4*3tf1eS3I<@+^D*fyFEi%#{%b44UAhOBNHJoi}v`88ZUX1wb0S0-Z?IRD=MG& zwo>i*MZPk&&hX%n^1`D5eu7MAxAS_UtV3fmk#LHU!5C9!RsFd4Lk#{5D(!ygFZ8Be zA~p>_e>m(Q^e%kGxh~iUD{FH5;N49|qiFDIJaTiSKDcNy-N}s3`xB~}N2NR&)C2}H zT}ieL=EHt$=bxk4#l0sMuF>!y!vm8lLoxnl@TD=}4kPEHQ&HY*sftlBL7`w;tYC?DK`c^$8pmx*cX+EXra$afB6sG)S>f$ z5=lbrr^Mvj^ry9aqN`$*Q)Ty@+nCLq&IkDXpzyJuFaj zS)Mxg@ggk))1Ew}(f)d}8eM+ZQcpj>;0&1(J@~_}T=?nv=Dwk&qa7hyKsC7iodpuI zdzk@zXOlIp+Lc#=e4^)45Dva7Wz9;uURD>IoBUdOoa@s#+En9Y=zRRWpoGM?Ho^T? zB87J^kOe~0(}FkGoG$kRL`-vTQ#Ri(*=fmRIkn$cQ^2}HdS6&u)Qd|iTH*pI=MT!V zf8DB`6gL&SbS-P(=S1066f!NB5r>Royd|^vHFZdeJ&PLi6`tz9hD*|>G=vpeY=K9s zdO%Kj!2<#+7*U6Ph8_h*$p;>3UV!$6tFmqWp2RlNdS_`i?NR(9Rs^+N1!jRTbp1O! zt)w9aIg4W#m@i&n>d&Ikoyk4XEdM`Mc8MV~LYa!%X4cn(4RxlZqIFI$3}>(ZX3JUc zCBbG0-Z>r^Y z#KOg*+A1S!NlhnSLV2CC^T*TzQghaHMICg*`NU1_eY_i#0W{9IwSJg%V=>T>S8wr1r{fpvuNAd5#09^C7c zm9hK0MZrrIA#bnx>R0alvmE;Dw@BQG>e6gMs0n7$?8~f!=d;MKQp|y!nwGbaSD+~R_?`^Jnc3g(vYc_0UXWnf#cX z4n=G1WDa(~Z(Db*F8#=mYRJk`W{idLK61OM zdC~i}Z_Yhffsr9jRiqA-tV3j_03%Oo)>AvSln>VKN&7Szn;aM5e%m~_X%}o%`OCQW z&ytsRRW>hWb2NXC@V>AN|1X;iL7s^Z)pI6 zvx=IC?EcxC@q`PiLVBIqEB8qtcIc2E1{m;i|F(_6O6d;-$kZq z&p2q#3_trv*i3)%e+!$7eK)wj2uQQ-N-kM8(VKgK;! zs0hus16EN|qhNTt`)nk?hTqL=-i%LzS?wFiM~Pm#Ev(IuSAI8do}XT+x*2W#(QhbP z1ugr@lDWHCTdJ(1?dhf~ofyFQRMQU&&|$YV)=}=A!E&iuFh3soxO4oiw|uW_|IG%? z?k78CN?O097B=D%wdGht`k6bsX_Ry5C~k`7|Wwz%}^G z6_6dgQz-`>NCLhc++A!?Qor|XY{RzW{Zz{SF5jC{dA>s*PYc;y1Jea5_i9^8O*FcG zbZ0)hAV=eLg^3RbPI75DDS{u9VDEz%Rt}l*!gHk?bKtA3tm@EQ5rtPvgVh0cKuRe4 z1K$+>l{p&T_`qlA>%dy-z%TP}_cwlb*FTKHathDn@9Z4UI2T~m+itLSOrAMUEojKzKCB^|w{gQ-Yc`<$zL#Zj0O}48JvMg-n4gIB$Z4~uYacg*Pz*%E zf2IYsXl82Z`Izz0vy^7SjZXE6+_FAI9s-6U6mVYv-7I0aS{rmWWT9N|Dy3qRl^P#O zso(sgTl2rME4zCti)NXwQibBY8K*fZJG1E0h5hdqLHUp?wX!G$l>rR$2i zi?8|Ao%)>azGw(HPc7>0_cDDR9&v4og_V`p*L}b%{beHQNi}$b58vl!yVgq8UA0!&_2OV%aeW8T z<%5==)%_OtG6BXNUx*fU!u4$C&642CQXNKU=z!%cal4k~YfDl9GjVX!!&?@FC4mBn za6?L8L1shV=cv6qK0Lg}Ke(|s@|2X(m(y2X2v*gZG58dT=dJk0PfjIW+tv8MCPAw8 z&vit`o6fUtGD$8M&Kphq6)!se>gfp#5=F8?mwm8AwMPvZSCr$cO3I>Cs}zks8}$mf zKDfYT;u`(%l8K^JQ|Ms0bgyG*$HEWSclDS(c(W?f5Ep3=pzg0+jn33zD9J6O^ zeO8pyMLU-LJufb=CDF7&Ljo}s-G+(ZBBeh0)FQ39Cgryk=*A0KCC&x|%3rlx3hd_4 zMzTwtdBjpbHd^a`0P%Rd!-~=w?_THFR%j4oH_R68#O{#{=qKG{)DX^uE+=Wj8lm9O z7k(%N)ufr|>svnWAEo%NRFS)dWn68~{Ja*cdE1+{_0Fygrf3r2#&|a~{e`teY}~gK zoKgQ%jof(A`_0+jlvTeucOsTf+U{zVPU?qeaTngTdVK40$1P+r}_wQ}v5Rn0r@FI+mQ&bWXj z;FmA-0743u9Zm2{RL*=5Dy-Mkmn*Av_L|^UrUcy9BZ)8~#6?=vGl+`_70ga{ec%ya zGa{JJs8)lezCl&0YAPTdDuMZTu*PTQM|wXc=ht6^>Z)OJc~!SBEeqTgUN}Rl>Qm0Q zkQ6wJ{q~nM^|N8R+_P6OzlJwd7={e#RY{ zeOYM!D^EF=e;mmLq0q(+axu9Sta`D?{wW}W^^c)r}pv%?=79w0oY z2P2;cU|ts0yDIs#BFM67l`gKLRZVdWJ^SC9HqLSLR(F~*(VRNy9=q93pTZv^fq4ee z>2ewxX@+*8$XbZQ$-I)T2O#VgRd>MgX6}o+#b;yz*+O&7xJ|N)=9F~0Swd^L(+%F? z&|fx_6L*F3%D6B4+em3JKcCLQl)`+7Sb?iT>r1?$oYKX@xF0)*+y7GftRtz#hk3nx z5z!q7eKwY0h~rI%&#$_r9T?q2cs5ed;_S^(Zs{4X=oj@^;~Apf7lB!roM2G30@X~O z$^BkMzG1mKPvknS)0oc^l*dr_39?_GAgnw|oztOl((j`$zAUgI~-#IPU-|MhU=N`8i z_uG1QbN{#N#X%@3=u>KV12nNAMiLwiQMqQ3$NhIOyC1bkL#pL${z}VK!W&rbabL?DGTk8+`n4(s$O=IMxP(BX)yT$uk^;4zr|2OwYFL<#H`MB@ z^eN*gSTTgoY(Nw6I{h(e(@}CT3nmLMq-H-9N=rO6yBz$>)-hdH;lUzfFI^aYy(Rx( zz9}Xsx|o5}>8#lud&*_n-v$uI#OD&Rm$CO}nl%HC0Hc;uH;@1;rw8f{+%8~T!BCnw zhgyTXQ^(Na*q>J@_t|^CH%!xcd~1@@!kkF~@qs7K(nH)-9%MVouBU@Wq`1GXnia>K z$JdQYRzlbAj;>{0=-ae_l#sYLODd=UJ8{x!9MVA=D3;d*&;&qvE_6RO(Ha{WkOV+ja3>LU>^55#(%G8iKYPXES)&~W8xxKhqUSIXV% z<>r%S=rzC}cYH|{o_x;4tL`*Cfk{FvvjcI?(|BUSJqCIdxncnJ;4)I$(=(5I%DF>7 zg^ziq-5hwnJlBQxNz`nfmRHj1&SC&7rl{zQ=#xrTwl$ggh&UbiQjBV4Y=S65=p*oAw)M{ys`}*uQ^A&0Pzq4;L zyUi}t@a2vv`lv|dT(C)lmz&i%0KvoerPe&X%nnS_hhZK^VL=vZA$AD(en-?TUg9!8 zVthZ6{QPWhd>g zk{xKmJ>`~gD23p3tRk}Zwt3YxuH13a*I1ZDkmiS$E=9_?L9^`S7ecm`Rn|RnQ4AqF zU#L{B2jd#1t`^>hc|Y0tN)Lafd+ZS}?)Zw;OlsoV4wAA)l(+89PhM(05tWk{3eKFu zx=ouaz`D|FHo-x@Sw~~cNP;Drh zPI|pmJe!jyr{Nn5ghk8RoSNnDW#+vBvQ+fAex^wf<%J7}=ze`_ri%`cT``Lk&}1{X z_J%0T&2JcI_l^y$-?K4V0UVS=BJc8$}noIkBVD1CL4;tFNL8kpw9m484`XGJo+ zW#S|F9Y{zkWd0KZRq-$7UTE34Q!`|+M_nuwv;FL017EJUI`4vWAy5RsWCW)lX?zpq z*;dx#fsHDse58AHBVtdw$_>B|*7F6K1kk1$jMJG+I9=74i*hJsnp0a$@`qdoJdkp( zU)$e+Mk#mYEeP_@6+f5Ho6()YxtX~NU39`sS4MM9Qp=bAbm#t}8ru`#vV4Djd|G?4 zyO3&8$ikNDJ`-+GE+c<80e9fJzYd1XfreBH#o*G*5q7kfCJ!fg#u((cKgaJf@bsn* zX2d*ihZs#k-O(#s5|{T=z>pO#0spkys;ql}Cm=KP-*)A2#rq9P00*GL;kwS^9LNUYV^7RXfoBs?B5)Ix-zriW83r1W0_GYiR zqg7VDI=(Kv(0mcJDz=;^oPQyOKFz=|tW3^m-h1J~2#X))4VCG`ev@zXOC007n#%=4 zYRU}n3nPjsC5PVroEIGpU~B;g3gKS%^hXQnjIVy)a5oN}LxA#~Bt>wWgNbLt?073p zFwMaVK*8gdhq=W?D;|Ug0kf}@MAV9DkPZLkkj}(Vneu|UrSNp>d-8yKJQn9OelP|y z@9D*LX&G89Go(JKk;v+e*pREsnTS1cX^~iH`NIS&p$C$vUC<5(jgFIk+MX{^enb;U8=h-+Huvb z<`2CLaN0B{8Et+@NaaG6?0(#mPEQk{?SVhaTO}~RbX>F{bBwz}@1LY+fA`N@-Yh+` zCae;7M(*}?t=lCztN&7Xd~(@-&g)QDWK6H^6>p(%0aM{UQ~KEAeY3j!HA5#aFm4*c zA~&_ySsU!jg!`yA-xAhr(d4qjMHE?V9h9&y&d3@2>^ve-8a0z;o6%nyY+D#EbWmLn zrDJ0O@&lA)m+PeF%B?0KUQFLw7k&CN#&vWWfTQ(eCuEKopz{0Ier0fzufy{y`qwC- z4h^910i0k-$Iyye`rv!6%dx-S7WmQ%RZTF>sS8QJN{Vz!j}A1jjhEBAC<(sD^Omw! zN~-!vf ziM3Z1!@PSX^&|dleTx{O@B_c@YcU|HHP{Pl;|0mu{^{^S(gY~z_QqVZ**asi_g$ES zr#&Y^B<;mG1;g1u5e+hfCx(f6OvrUInB}?7^9@S+)G+7%I|pwnuR$E|r)_-`&K%!d zH2E2uWJvw3-LgB;CN;4+$A^NN(e#k=jRub>ggc+CVVM*iBp?ax4%HQIqT`LV zSiD{}Aia)Kl)@4|@Nl?L3+-34x3*^z!lf9aF#%4cCd^rgSl3J%K zJC7)N55G*3l#lScVgJyH2}JU;s(H!%CBQxxDw;_zcrhaT5$&}F=mLk2VnO*fq2Y*- zQ#ifwtpAMMcDA!+QcU{Pc8qu&Q@VLX=p_>f~UNWcGj{SUy6h^Jx)SC{UdK3g1^!Z5a_r1+T$Btbu zidtvYJDKE0FX~);LUmuiE_Pcph#M-$w2A5yY`O|b)8(_=MWI1vcX%r* z+x|LXlH1J4wM`)X-F)P(^Z8|ku}2Ha6R^#s@nrdk<7jHd^w=CjA&Of?x6Z>pL38)iXe&p%1I zb}7t#^Cg~ER1Ku8xC+@lflj!ma4gu?z(4h~BU>7x=dQ0m(khBzxDZo( zOFep7Xa7#6dslSg-8;PQ=%B3>*kVo&e~7?BrNQ;9Z?_=Yfe&A7{L=H6*4vB^g>2nrwXi-qUoha-t@1+STR7)dapO&yYWKflj+M_R zsVqg`$);5KNc=}Nu8yQeUW2r;ll|AouwWYg=SCNRdI*m4f8ebET7`u|wgz<|gSlf=#?Zu-U zd$wZ0+gGb~0+jOtTPeVY@y9(DtT_G?wGXbS!>FvpRwim)2wLaUGg{yw;=|;$4UsY8 z9TefZaiB6u7jz3vfQPiaf6HGz_)a=HCg(BCgBK&S`?^B#31}TSKAhX#HR{Gz>Ms`b z-IsBcHC2zz^Mg<2+(O9DgTD|=S2cf}r?-K$es(!uPNZ70{tzPd_MWI_4SbvwtC-Op z_ehQ$+_O4Uw1sMZ7Y&(f4kK^t5TYPF-P1)Mm9l!qZw??)oWuu?nmOvjS3$|nmqDG} zRy?FAE!h<@@bP+dp%lyL-E+P1Pna9}tMvLcvu$bSzdBCg-J*Ei@Ly97fKB@7Zm0e| zKHMr(5y)aaLck(re4^O^fc1P21em|i%U@wRj^*!hua!tvEmy8U*1a9mP6PIm z0lenNXCETpWQv|UH5U9MUjMNHbRqy=Xq>B*;3Rl=DBb0GwFw__YSFASG1;p%qJLzA z>Kf%!#RWO!y46Qxrs~@#eE}30z=oC)!+Ctq^KsxcPdD*ar%j>M^HfP@=imjxt%29C ziK{I^5?Cf3_-LoR+3$yTpZO>pu(Vl9cloWo&n7KM0@` zJiSDCR?*a*dupcm{rq~O=ga|W*}G=5dp|$#UMSCMAIZwoJj3LZL3!@X*+OB_%_Fdf z4q(Ywl)`r0l-et$BW1fQu1qccuN>>IJ}(sR{-|M!J$D6U zk(?dG;lmwyeI`(fqTG$xDsU-42fb$K?yi;RRtQDdra4?93~(P-2B7PcO)9?95IhP> zxP@N^&)-11j{JU{HnJw|IHh?6ObV`C3(dRlzYFq(=g?>YOY%b{F_kw^x+{xm95%Q< z^LN==z%sA%FCsV;fHzjAlgkDn<62-<0RAFGx1I;Z>18ge z`#`MszK&nhV+r_zcKG0HRkNn4XIlK zEQ+*REI7APN$G5m1>AJz)AEK&V;ku)*gp{Aq0AWL>~g9&2h6k@Iv2R!WkNqryOstg zdSLBuo}+jhi$D|Df4Y20XaiD0}R5 ziKD8BUJers{EMVK)P~x4acW)}3#oH}Mpe|18&TMGvm0flKJB`ebW@B%3lSZv ztG<4I&3d%~&<1)OAtjn83CQCU>l`)-oJb<{LLBFAa?(>F=&OiQ`bFx;(=utcHs1`t zo9tc+CwuN_Jz%osS2oJXcMfc?V_{O!<%3tr-PCzu7zXXm+6eJy;lBzW=_Gfg30Uwq z?3F3$8({hn3(T(hg+%df`#cMl|`S~>rMItxW6UU3z-tLe%Tqe(uX zP2GV@(BwszC=7z}oIrL_Ay2+MHKwWPk56=yeCFq;P*mxh_S_Ngnc zdk7)t16!%X<&?+u`kh?$(R6G#o+u|z-jD)$D$CB<%7JWNeovqh2e`$Pw*^FdQF$bs zU@;NcoX>v_g+jshi^aAXTsC~Oi9pq}V|J#LL4SfS#`B=}}lyM66S#z z@cFn5_yzZtV?lK)_x=Nq2ly!e2_+H71ZMsgqW4yPFnVw7Th#s96phnRED$jV3`sv| z0apV5DLt#Nw@h$2D3pHHf2XG3`zi09aYF|EZ+&y~x|B_0eN{H8{rvL&tt8kZwdsrS z8+P_66I!APE*R>n=_JnA7EFqg9f2g>vDLX*=#ZlFY4paj!CiTJH+2hwe=wr_{djKT)!=sIHuaiV}Z} z@;ltpTN@SQ2$YonCrKchjC7fhCvJw#j8U8aTQ=bWo3$l*QSjpCBeCsYO#O5`kj^!i zjuxum0eh*hr3#{42v!!*1_PWC*?aCr35aCke$}lQ=o$(Le4twci|JWJdM*a>yCzvk+ zcp~AaXe@Pk&%H5G=ART}+!L$dKhM^f5Re15p9T~rm^0UHakx2uD{xC+St}}s?9h;1 z_^kojNxLuSn5xC=JbCAwT}iA(qb^sVJMQJrU$=lse`Yr-Ngqf1Rds^>o5Y+_U&4UR ztC3E9_uV&TJPede>vYMEETm^f?!6keC{uKQG7ShxyI;nQAQEl#-hM6I;Q%i_g}N_w zm@fdNpXIYFB#MeJ7_y3jUTY4*bQd%Zb?3wkw@N&(~VoN7qF;npdf)Q z`17aJL`CKP^XDg`WWcmhDlbU@i4@XeEyj-7EGnGjk`Q&tZQFJV9t_?XvPN zyN4yapxG9pJVfWQpQVg^*Z6mMz76Q|kK{tB?1+-w!JyB48<6pf4blorfX=?bk0=67f5K=QXYv z(9u7_m~@ZDT70dDCWje^#Al>gQqZhQA3WHip-}VF6~=O0HA<*7R}0B@aCveid5|Td zwfD~2w$S~LOY+L>^eC1n!B%X4)Mw=7BfeNC~)K7@_#D|5?{aMhKxPyj+E zURPp~p=zvG8gPNxSOYnC)=Bl4Euyw72Uy|(F_ zR)hcGfYUpEvEcd_b}D8(M>jz-BbM5LjrxUeN!K~1-Ml$;6phm}i(*aCZm;mxLhV4P zhkE6Dzet%@c!ISWn#8x?6>XlqO5dcJHoLXm)E*x(?3&S~misM+7!ag&7Dw|KjzvP8 z{Paep>NDVvPQ)2ibvaV9#9CpS(sO$XFPuISF-J0(T9rI1QMm^R-U8_umWdg_5W`m~ zJ|@369jE`4nqDtl06G;!odRSg3R4rpm(>AiTH=>$7Qx?D$_$pEx+31T>~+c=!O`HY zuk@L23I|IiUJ*a}t3!PwfvuuTlwvp~R4qjIbhqmj$$j@8npVCJG`{Myw0x&TsXL|SZ?TLjFei5uWRi411-Q?K4RdDX8}zcrb& z8>MLCfgpp;>3^UqG3Tk1&yjHAh7%4XK4x4<$u@oV%~rq7^-@q7=G7OW zyZ}(Qf1H1s|L6KB#V_NC-guMpfZ5q7;f)E|f(_!j%(CqP3m6hD_1XJATollipestz zQkJE62Jb0%Yb?dNs<$&k<)Wf6*S&`2hAYH6u+In1LWR+wjo^wDAxDGrO8}E6#c7Mj zujSi0q66RU1k0$tP>^@ggGHKN2)FSSkL{sQks@BrK%Lw`In8#ih8HS&2Lzv~+Do-O z>9pf>MvPH4N37$%99&G=2P~>k3iu=dtlQ(K%DR4Lq7P#u-_US=Iok! zaPJ<`rw!3|9rJfO+x=Gk?1jBlqp-^WA!_7qcMX4NKdOFAg9+yr4Dj4mt|@k#ZjnQ; zg@GX{n41o~PHIQ9vTQ9?QundC=r?b_U-ycQllmCZ^HA9-O>WMot-b6VwlOrui8^o| z3?S}>IIq0B+vD4I^~JaD!$2BBk+V6#1LE{O)q z!5R-ngvP!(eR4mo{{=cu5aq@qIYqdjPCgftlOn(R3GrAgHsA8>EE%7k)r`9~GTpjW zn5^qPk2bsw6Uex+~TsMl=|C*UW2)`(?fUuv5o+Tk!wvScm-oa;#g`aMF99+SI51mo{}nOIhXH z|KUo{mH@oyzym;~AqxNW&mfWz5r50|AI^wBwU_O3oAjydR7j~?e>G?T=vf1xvqFYR zyD1ZIhK8d&5XJveLKZxbk`$RSQqOD~}An zPK$GIc+RDf4Gp3Ji$bQCiQM60DHHy^w}uCBpcyIo^@zc1r4BppbcRFIW1_9T_8gb(Ezi) z&j27cycuM|wQf%^d%8rBHoE86;3u2_KGWevMib3K8W|?;{j78Ptxl}@fhSin-l`(P06YH5qo}vb1_v{qUEK!A z4EOJox&ylJ**S&HRe{r|32NGV`DjvJ%&FN{ zapNbye%K|5$<;PeErV;p1&oU*W*1SbWTG$wQS$V4_}D%g5T8jm*BuUh9?aXOY?xcxajxE@xiKT!;enX zwE2f_ubw+pnd9$fu0{iks^0Kvk0Fm{YT<9)X1{8bb|(V+!45H>Fu|k6R@xp@;lf$a zX`anF$S`N&S9QMaR-&Wvu;E6>#<5Fh97!9zcIrR0yr6)oozg43d5Uh&B_fo>xhSyf zhNG`vD9w1){xHM?c=u-*ZeRQ6MRG{<2aXO>1Hc^M$Re6WE6gTbG0}FE5gFn6LlA

    `2Fs}PE9W_}M`x6S*A`zh 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 T1}DA)9-n^}`j6VZ$N%}CojS_) literal 0 HcmV?d00001 From 6644104ebcdaf12c0148804561a7784ce631f312 Mon Sep 17 00:00:00 2001 From: Trayan Azarov Date: Wed, 16 Aug 2023 14:51:10 +0300 Subject: [PATCH 05/13] feat: CIP-2 Auth Providers - Basic Auth implemented for both server and client side using 3 ways of getting the auth config - params passed to client/server, env vars and file based ('user:pass' style). - Docs will be updated later today with an example jupyter notebook - Tests are passing including the new ones for testing negative (auth failures) and variations of positive test cases. Note: Needs a bit of a cleanup for mypy errors warnings. --- chromadb/config.py | 141 ++++++++++++++++++---------- chromadb/server/fastapi/__init__.py | 1 - chromadb/test/conftest.py | 139 +++++++++++++++++++++++++-- chromadb/test/test_api.py | 12 +++ 4 files changed, 239 insertions(+), 54 deletions(-) diff --git a/chromadb/config.py b/chromadb/config.py index 6653348976d..6384e601837 100644 --- a/chromadb/config.py +++ b/chromadb/config.py @@ -1,7 +1,6 @@ import base64 import importlib import inspect -import json import logging import os from abc import ABC, abstractmethod @@ -82,7 +81,7 @@ def __init__(self, settings: "Settings") -> None: self._settings = settings @abstractmethod - def authenticate(self, request: Request) -> Response | None: + def authenticate(self, request: Request) -> Union[Response, None]: pass @@ -121,7 +120,7 @@ class Settings(BaseSettings): # type: ignore chroma_server_auth_provider: Optional[str] = None chroma_server_auth_provider_config: Optional[Union[str, Dict[str, Any]]] = None chroma_client_auth_provider: Optional[str] = None - chroma_client_auth_provider_config: Optional[Dict[str, Any]] = None + chroma_client_auth_provider_config: Optional[Union[str, Dict[str, Any]]] = None anonymized_telemetry: bool = True allow_reset: bool = False @@ -203,11 +202,14 @@ def __init__(self, settings: Settings): see https://docs.trychroma.com/usage-guide?lang=py#using-the-python-http-only-client for more information." ) if settings.chroma_client_auth_provider is not None: - print("provider: ", settings.chroma_client_auth_provider) + logger.debug( + f"Client Auth Provider: {settings.chroma_client_auth_provider}" + ) self.auth_provider = get_class( settings.chroma_client_auth_provider, ClientAuthProvider )(settings) - + else: + self.auth_provider = None # Validate settings don't contain any legacy config values for key in _legacy_config_keys: if settings[key] is not None: @@ -263,29 +265,51 @@ def stop(self) -> None: def reset_state(self) -> None: """Reset the state of this system and all constituents in reverse dependency order""" if not self.settings.allow_reset: - raise ValueError("Resetting is not allowed by this configuration (to enable it, set `allow_reset` to `True` in your Settings() or include `ALLOW_RESET=TRUE` in your environment variables)") + raise ValueError( + "Resetting is not allowed by this configuration (to enable it, set `allow_reset` to `True` in your Settings() or include `ALLOW_RESET=TRUE` in your environment variables)" + ) for component in reversed(list(self.components())): component.reset_state() class BasicAuthClientProvider(ClientAuthProvider): + _basic_auth_token: SecretStr + def __init__(self, settings: "Settings") -> None: super().__init__(settings) self._settings = settings - self._settings.require("chroma_client_auth_provider_config") - if self._settings.chroma_client_auth_provider_config: - self._basic_auth_token = SecretStr( - base64.b64encode( - f"{self._settings.chroma_client_auth_provider_config['username']}:" - f"{self._settings.chroma_client_auth_provider_config['password']}".encode( - "utf-8" - ) - ).decode("utf-8") + if os.environ.get("CHROMA_CLIENT_AUTH_BASIC_USERNAME") and os.environ.get( + "CHROMA_CLIENT_AUTH_BASIC_PASSWORD" + ): + self._basic_auth_token = _create_token( + os.environ.get("CHROMA_CLIENT_AUTH_BASIC_USERNAME", ""), + os.environ.get("CHROMA_CLIENT_AUTH_BASIC_PASSWORD", ""), ) + elif isinstance( + self._settings.chroma_client_auth_provider_config, str + ) and os.path.exists(self._settings.chroma_client_auth_provider_config): + with open(self._settings.chroma_client_auth_provider_config) as f: + # read first line of file which should be user:password + _auth_data = f.readline().strip().split(":") + # validate auth data + if len(_auth_data) != 2: + raise ValueError("Invalid auth data") + self._basic_auth_token = _create_token(_auth_data[0], _auth_data[1]) + elif self._settings.chroma_client_auth_provider_config and isinstance( + self._settings.chroma_client_auth_provider_config, dict + ): + self._basic_auth_token = _create_token( + self._settings.chroma_client_auth_provider_config["username"], + self._settings.chroma_client_auth_provider_config["password"], + ) + else: + raise ValueError("Basic auth credentials not found") @overrides def authenticate(self, session: requests.Session) -> None: - session.headers.update({"Authorization": f"Basic {self._basic_auth_token}"}) + session.headers.update( + {"Authorization": f"Basic {self._basic_auth_token.get_secret_value()}"} + ) class ChromaAuthMiddleware(BaseHTTPMiddleware): # type: ignore @@ -295,6 +319,7 @@ def __init__(self, app: ASGIApp, settings: "Settings") -> None: self._settings.require("chroma_server_auth_provider") if settings.chroma_server_auth_provider: _cls = get_class(settings.chroma_server_auth_provider, ServerAuthProvider) + logger.debug(f"Server Auth Provider: {_cls}") self._auth_provider = _cls(settings) async def dispatch( @@ -306,49 +331,71 @@ async def dispatch( return await call_next(request) +def _create_token(username: str, password: str) -> SecretStr: + return SecretStr( + base64.b64encode(f"{username}:{password}".encode("utf-8")).decode("utf-8") + ) + + class BasicAuthServerProvider(ServerAuthProvider): - @staticmethod - def _create_token(username: str, password: str) -> SecretStr: - return SecretStr( - base64.b64encode(f"{username}:{password}".encode("utf-8")).decode("utf-8") - ) + _basic_auth_token: SecretStr + _ignore_auth_paths: List[str] = ["/api/v1", "/api/v1/heartbeat"] def __init__(self, settings: "Settings") -> None: super().__init__(settings) self._settings = settings - # self._settings.require("chroma_server_auth_provider_config") - if self._settings.chroma_server_auth_provider_config and isinstance( + self._basic_auth_token = SecretStr("") + if os.environ.get("CHROMA_SERVER_AUTH_BASIC_USERNAME") and os.environ.get( + "CHROMA_SERVER_AUTH_BASIC_PASSWORD" + ): + self._basic_auth_token = _create_token( + os.environ.get("CHROMA_SERVER_AUTH_BASIC_USERNAME", ""), + os.environ.get("CHROMA_SERVER_AUTH_BASIC_PASSWORD", ""), + ) + self._ignore_auth_paths = os.environ.get( + "CHROMA_SERVER_AUTH_IGNORE_PATHS", ",".join(self._ignore_auth_paths) + ).split(",") + elif isinstance( self._settings.chroma_server_auth_provider_config, str + ) and os.path.exists(self._settings.chroma_server_auth_provider_config): + with open(self._settings.chroma_server_auth_provider_config) as f: + # read first line of file which should be user:password + _auth_data = f.readline().strip().split(":") + # validate auth data + if len(_auth_data) != 2: + raise ValueError("Invalid auth data") + self._basic_auth_token = _create_token(_auth_data[0], _auth_data[1]) + self._ignore_auth_paths = os.environ.get( + "CHROMA_SERVER_AUTH_IGNORE_PATHS", ",".join(self._ignore_auth_paths) + ).split(",") + elif self._settings.chroma_server_auth_provider_config and isinstance( + self._settings.chroma_server_auth_provider_config, dict ): - if os.path.exists(self._settings.chroma_server_auth_provider_config): - with open(self._settings.chroma_server_auth_provider_config) as f: - _auth_data = json.loads(f.read()) - self._basic_auth_token = self._create_token( - _auth_data["username"], _auth_data["password"] - ) - elif self._settings.chroma_server_auth_provider_config and isinstance( - self._settings.chroma_server_auth_provider_config, dict - ): - # encode the username and password base64 - self._basic_auth_token = self._create_token( - self._settings.chroma_server_auth_provider_config["username"], - self._settings.chroma_server_auth_provider_config["password"], - ) - elif os.environ.get("CHROMA_BASIC_AUTH_USERNAME") and os.environ.get( - "CHROMA_BASIC_AUTH_PASSWORD" - ): - self._basic_auth_token = self._create_token( - os.environ.get("CHROMA_BASIC_AUTH_USERNAME", ""), - os.environ.get("CHROMA_BASIC_AUTH_PASSWORD", ""), + # encode the username and password base64 + self._basic_auth_token = _create_token( + self._settings.chroma_server_auth_provider_config["username"], + self._settings.chroma_server_auth_provider_config["password"], + ) + if "ignore_auth_paths" in self._settings.chroma_server_auth_provider_config: + self._ignore_auth_paths = ( + self._settings.chroma_server_auth_provider_config[ + "ignore_auth_paths" + ] ) - else: - raise ValueError("Basic auth credentials not found") + else: + raise ValueError("Basic auth credentials not found") @overrides - def authenticate(self, request: Request) -> Response | None: + def authenticate(self, request: Request) -> Union[Response, None]: auth_header = request.headers.get("Authorization", "").split() # Check if the header exists and the token is correct - if len(auth_header) != 2 or auth_header[1] != self._basic_auth_token: + if request.url.path in self._ignore_auth_paths: + logger.debug(f"Skipping auth for path {request.url.path}") + return None + if ( + len(auth_header) != 2 + or auth_header[1] != self._basic_auth_token.get_secret_value() + ): return JSONResponse({"error": "Unauthorized"}, status_code=401) return None diff --git a/chromadb/server/fastapi/__init__.py b/chromadb/server/fastapi/__init__.py index 709570ab340..d4912a8ffea 100644 --- a/chromadb/server/fastapi/__init__.py +++ b/chromadb/server/fastapi/__init__.py @@ -109,7 +109,6 @@ def __init__(self, settings: Settings): allow_origins=settings.chroma_server_cors_allow_origins, allow_methods=["*"], ) - if settings.chroma_server_auth_provider is not None: self._app.add_middleware( chromadb.config.ChromaAuthMiddleware, settings=settings diff --git a/chromadb/test/conftest.py b/chromadb/test/conftest.py index acd2f843263..d5f4c0b640b 100644 --- a/chromadb/test/conftest.py +++ b/chromadb/test/conftest.py @@ -17,6 +17,9 @@ Sequence, Tuple, Callable, + Union, + Dict, + Any, ) from typing_extensions import Protocol import shutil @@ -29,7 +32,6 @@ root_logger = logging.getLogger() root_logger.setLevel(logging.DEBUG) # This will only run when testing - logger = logging.getLogger(__name__) hypothesis.settings.register_profile( @@ -52,7 +54,11 @@ def find_free_port() -> int: def _run_server( - port: int, is_persistent: bool = False, persist_directory: Optional[str] = None + port: int, + is_persistent: bool = False, + persist_directory: Optional[str] = None, + chroma_server_auth_provider: Optional[str] = None, + chroma_server_auth_provider_config: Optional[Union[str, Dict[str, Any]]] = None, ) -> None: """Run a Chroma server locally""" if is_persistent and persist_directory: @@ -65,6 +71,8 @@ def _run_server( is_persistent=is_persistent, persist_directory=persist_directory, allow_reset=True, + chroma_server_auth_provider=chroma_server_auth_provider, + chroma_server_auth_provider_config=chroma_server_auth_provider_config, ) else: settings = Settings( @@ -75,6 +83,8 @@ def _run_server( chroma_segment_manager_impl="chromadb.segment.impl.manager.local.LocalSegmentManager", is_persistent=False, allow_reset=True, + chroma_server_auth_provider=chroma_server_auth_provider, + chroma_server_auth_provider_config=chroma_server_auth_provider_config, ) server = chromadb.server.fastapi.FastAPI(settings) uvicorn.run(server.app(), host="0.0.0.0", port=port, log_level="error") @@ -93,18 +103,36 @@ def _await_server(api: API, attempts: int = 0) -> None: _await_server(api, attempts + 1) -def _fastapi_fixture(is_persistent: bool = False) -> Generator[System, None, None]: +def _fastapi_fixture( + is_persistent: bool = False, + chroma_server_auth_provider: Optional[str] = None, + chroma_server_auth_provider_config: Optional[Union[str, Dict[str, Any]]] = None, + chroma_client_auth_provider: Optional[str] = None, + chroma_client_auth_provider_config: Optional[Union[str, Dict[str, Any]]] = None, +) -> Generator[System, None, None]: """Fixture generator that launches a server in a separate process, and yields a fastapi client connect to it""" port = find_free_port() logger.info(f"Running test FastAPI server on port {port}") ctx = multiprocessing.get_context("spawn") - args: Tuple[int, bool, Optional[str]] = (port, False, None) + args: Tuple[int, bool, Optional[str], str, Union[str, Dict[str, Any], None]] = ( + port, + False, + None, + chroma_server_auth_provider, + chroma_server_auth_provider_config, + ) persist_directory = None if is_persistent: persist_directory = tempfile.mkdtemp() - args = (port, is_persistent, persist_directory) + args = ( + port, + is_persistent, + persist_directory, + chroma_server_auth_provider, + chroma_server_auth_provider_config, + ) proc = ctx.Process(target=_run_server, args=args, daemon=True) proc.start() settings = Settings( @@ -112,6 +140,8 @@ def _fastapi_fixture(is_persistent: bool = False) -> Generator[System, None, Non chroma_server_host="localhost", chroma_server_http_port=str(port), allow_reset=True, + chroma_client_auth_provider=chroma_client_auth_provider, + chroma_client_auth_provider_config=chroma_client_auth_provider_config, ) system = System(settings) api = system.instance(API) @@ -133,6 +163,67 @@ def fastapi_persistent() -> Generator[System, None, None]: return _fastapi_fixture(is_persistent=True) +def fastapi_server_auth() -> Generator[System, None, None]: + return _fastapi_fixture( + is_persistent=False, + chroma_server_auth_provider="chromadb.config.BasicAuthServerProvider", + chroma_server_auth_provider_config={"username": "admin", "password": "admin"}, + chroma_client_auth_provider="chromadb.config.BasicAuthClientProvider", + chroma_client_auth_provider_config={"username": "admin", "password": "admin"}, + ) + + +def fastapi_server_auth_param() -> Generator[System, None, None]: + yield _fastapi_fixture( + is_persistent=False, + chroma_server_auth_provider="chromadb.config.BasicAuthServerProvider", + chroma_server_auth_provider_config={"username": "admin", "password": "admin"}, + chroma_client_auth_provider="chromadb.config.BasicAuthClientProvider", + chroma_client_auth_provider_config={"username": "admin", "password": "admin"}, + ) + + +def fastapi_server_auth_file() -> Generator[System, None, None]: + server_auth_file = os.path.abspath(os.path.join(".", "server-auth")) + client_auth_file = os.path.abspath(os.path.join(".", "client-auth")) + with open(server_auth_file, "w") as f: + f.write("admin:admin") + with open(client_auth_file, "w") as f: + f.write("admin:admin") + yield _fastapi_fixture( + is_persistent=False, + chroma_server_auth_provider="chromadb.config.BasicAuthServerProvider", + chroma_server_auth_provider_config=server_auth_file, + chroma_client_auth_provider="chromadb.config.BasicAuthClientProvider", + chroma_client_auth_provider_config=client_auth_file, + ) + os.remove(server_auth_file) + os.remove(client_auth_file) + + +def fastapi_server_auth_env() -> Generator[System, None, None]: + os.environ["CHROMA_SERVER_AUTH_BASIC_USERNAME"] = "admin" + os.environ["CHROMA_SERVER_AUTH_BASIC_PASSWORD"] = "admin" + os.environ["CHROMA_CLIENT_AUTH_BASIC_USERNAME"] = "admin" + os.environ["CHROMA_CLIENT_AUTH_BASIC_PASSWORD"] = "admin" + yield _fastapi_fixture( + is_persistent=False, + chroma_server_auth_provider="chromadb.config.BasicAuthServerProvider", + chroma_client_auth_provider="chromadb.config.BasicAuthClientProvider", + ) + + +@pytest.fixture(scope="function") +def fastapi_server_auth_invalid_cred() -> Generator[System, None, None]: + return _fastapi_fixture( + is_persistent=False, + chroma_server_auth_provider="chromadb.config.BasicAuthServerProvider", + chroma_server_auth_provider_config={"username": "admin", "password": "admin"}, + chroma_client_auth_provider="chromadb.config.BasicAuthClientProvider", + chroma_client_auth_provider_config={"username": "admin", "password": "wrong"}, + ) + + def integration() -> Generator[System, None, None]: """Fixture generator for returning a client configured via environmenet variables, intended for externally configured integration tests @@ -183,7 +274,13 @@ def sqlite_persistent() -> Generator[System, None, None]: def system_fixtures() -> List[Callable[[], Generator[System, None, None]]]: - fixtures = [fastapi, fastapi_persistent, sqlite, sqlite_persistent] + fixtures = [ + fastapi, + fastapi_persistent, + sqlite, + sqlite_persistent, + fastapi_server_auth, + ] if "CHROMA_INTEGRATION_TEST" in os.environ: fixtures.append(integration) if "CHROMA_INTEGRATION_TEST_ONLY" in os.environ: @@ -191,11 +288,25 @@ def system_fixtures() -> List[Callable[[], Generator[System, None, None]]]: return fixtures +def system_fixtures_auth() -> List[Callable[[], Generator[System, None, None]]]: + fixtures = [ + fastapi_server_auth_param, + fastapi_server_auth_file, + fastapi_server_auth_env, + ] + return fixtures + + @pytest.fixture(scope="module", params=system_fixtures()) def system(request: pytest.FixtureRequest) -> Generator[API, None, None]: yield next(request.param()) +@pytest.fixture(scope="module", params=system_fixtures_auth()) +def system_auth(request: pytest.FixtureRequest) -> Generator[API, None, None]: + yield next(request.param()) + + @pytest.fixture(scope="function") def api(system: System) -> Generator[API, None, None]: system.reset_state() @@ -203,6 +314,22 @@ def api(system: System) -> Generator[API, None, None]: yield api +@pytest.fixture(scope="function") +def api_wrong_cred(fastapi_server_auth_invalid_cred) -> Generator[API, None, None]: + api = next(fastapi_server_auth_invalid_cred).instance(API) + yield api + + +@pytest.fixture(scope="function") +def api_with_server_auth( + system_auth: Generator[System, None, None] +) -> Generator[API, None, None]: + _sys = next(system_auth) + _sys.reset_state() + api = _sys.instance(API) + yield api + + # Producer / Consumer fixtures # diff --git a/chromadb/test/test_api.py b/chromadb/test/test_api.py index da051ff01be..fc0212d7a5e 100644 --- a/chromadb/test/test_api.py +++ b/chromadb/test/test_api.py @@ -1,4 +1,5 @@ # type: ignore + import chromadb from chromadb.api.types import QueryResult from chromadb.config import Settings @@ -1361,3 +1362,14 @@ def test_invalid_embeddings(api): with pytest.raises(ValueError) as e: collection.upsert(**invalid_records) assert "embedding" in str(e.value) + + +def test_invalid_auth_cred(api_wrong_cred): + with pytest.raises(Exception) as e: + api_wrong_cred.list_collections() + assert "Unauthorized" in str(e.value) + + +def test_server_auth(api_with_server_auth): + cols = api_with_server_auth.list_collections() + assert len(cols) == 0 From ea0f1480f1ba4741cac90f8e7fb2ab6cc014f43d Mon Sep 17 00:00:00 2001 From: Trayan Azarov Date: Thu, 17 Aug 2023 19:54:57 +0300 Subject: [PATCH 06/13] feat: CIP-2 Auth Providers - Fixed an issue where if empty strings are passed to params an exception is thrown - Updated `client_auth.ipynb` notebook to with relevant documentation and examples - Added exports of both client and server Basic Auth providers from `chromadb.auth` - Updated docker-compose to include server-side configuration (it works fine if env vars are not defined) --- chromadb/auth/__init__.py | 4 + chromadb/config.py | 7 +- chromadb/server/fastapi/__init__.py | 5 +- chromadb/test/conftest.py | 29 ++- docker-compose.yml | 2 + .../assets/auh-sequence.png | Bin 0 -> 139351 bytes .../assets/auth-architecture.png | Bin 0 -> 32974 bytes .../basic_functionality/client_auth.ipynb | 246 +++++++++++++++--- 8 files changed, 236 insertions(+), 57 deletions(-) create mode 100644 chromadb/auth/__init__.py create mode 100644 examples/basic_functionality/assets/auh-sequence.png create mode 100644 examples/basic_functionality/assets/auth-architecture.png diff --git a/chromadb/auth/__init__.py b/chromadb/auth/__init__.py new file mode 100644 index 00000000000..8195adc69bf --- /dev/null +++ b/chromadb/auth/__init__.py @@ -0,0 +1,4 @@ +from chromadb.config import BasicAuthClientProvider, BasicAuthServerProvider + +# Re-export types from chromadb +__all__ = ["BasicAuthClientProvider", "BasicAuthServerProvider"] diff --git a/chromadb/config.py b/chromadb/config.py index 6384e601837..5f9691dab11 100644 --- a/chromadb/config.py +++ b/chromadb/config.py @@ -201,7 +201,10 @@ def __init__(self, settings: Settings): "Chroma is running in http-only client mode, and can only be run with 'chromadb.api.fastapi.FastAPI' as the chroma_api_impl. \ see https://docs.trychroma.com/usage-guide?lang=py#using-the-python-http-only-client for more information." ) - if settings.chroma_client_auth_provider is not None: + if ( + settings.chroma_client_auth_provider is not None + and settings.chroma_client_auth_provider.strip() != "" + ): logger.debug( f"Client Auth Provider: {settings.chroma_client_auth_provider}" ) @@ -339,7 +342,7 @@ def _create_token(username: str, password: str) -> SecretStr: class BasicAuthServerProvider(ServerAuthProvider): _basic_auth_token: SecretStr - _ignore_auth_paths: List[str] = ["/api/v1", "/api/v1/heartbeat"] + _ignore_auth_paths: List[str] = ["/api/v1", "/api/v1/heartbeat", "/api/v1/version"] def __init__(self, settings: "Settings") -> None: super().__init__(settings) diff --git a/chromadb/server/fastapi/__init__.py b/chromadb/server/fastapi/__init__.py index d4912a8ffea..c734fa97574 100644 --- a/chromadb/server/fastapi/__init__.py +++ b/chromadb/server/fastapi/__init__.py @@ -109,7 +109,10 @@ def __init__(self, settings: Settings): allow_origins=settings.chroma_server_cors_allow_origins, allow_methods=["*"], ) - if settings.chroma_server_auth_provider is not None: + if ( + settings.chroma_server_auth_provider is not None + and settings.chroma_server_auth_provider.strip() != "" + ): self._app.add_middleware( chromadb.config.ChromaAuthMiddleware, settings=settings ) diff --git a/chromadb/test/conftest.py b/chromadb/test/conftest.py index d5f4c0b640b..128633490a4 100644 --- a/chromadb/test/conftest.py +++ b/chromadb/test/conftest.py @@ -116,7 +116,9 @@ def _fastapi_fixture( port = find_free_port() logger.info(f"Running test FastAPI server on port {port}") ctx = multiprocessing.get_context("spawn") - args: Tuple[int, bool, Optional[str], str, Union[str, Dict[str, Any], None]] = ( + args: Tuple[ + int, bool, Optional[str], Optional[str], Optional[Union[str, Dict[str, Any]]] + ] = ( port, False, None, @@ -174,13 +176,14 @@ def fastapi_server_auth() -> Generator[System, None, None]: def fastapi_server_auth_param() -> Generator[System, None, None]: - yield _fastapi_fixture( + for item in _fastapi_fixture( is_persistent=False, chroma_server_auth_provider="chromadb.config.BasicAuthServerProvider", chroma_server_auth_provider_config={"username": "admin", "password": "admin"}, chroma_client_auth_provider="chromadb.config.BasicAuthClientProvider", chroma_client_auth_provider_config={"username": "admin", "password": "admin"}, - ) + ): + yield item def fastapi_server_auth_file() -> Generator[System, None, None]: @@ -190,13 +193,14 @@ def fastapi_server_auth_file() -> Generator[System, None, None]: f.write("admin:admin") with open(client_auth_file, "w") as f: f.write("admin:admin") - yield _fastapi_fixture( + for item in _fastapi_fixture( is_persistent=False, chroma_server_auth_provider="chromadb.config.BasicAuthServerProvider", chroma_server_auth_provider_config=server_auth_file, chroma_client_auth_provider="chromadb.config.BasicAuthClientProvider", chroma_client_auth_provider_config=client_auth_file, - ) + ): + yield item os.remove(server_auth_file) os.remove(client_auth_file) @@ -206,11 +210,12 @@ def fastapi_server_auth_env() -> Generator[System, None, None]: os.environ["CHROMA_SERVER_AUTH_BASIC_PASSWORD"] = "admin" os.environ["CHROMA_CLIENT_AUTH_BASIC_USERNAME"] = "admin" os.environ["CHROMA_CLIENT_AUTH_BASIC_PASSWORD"] = "admin" - yield _fastapi_fixture( + for item in _fastapi_fixture( is_persistent=False, chroma_server_auth_provider="chromadb.config.BasicAuthServerProvider", chroma_client_auth_provider="chromadb.config.BasicAuthClientProvider", - ) + ): + yield item @pytest.fixture(scope="function") @@ -315,16 +320,16 @@ def api(system: System) -> Generator[API, None, None]: @pytest.fixture(scope="function") -def api_wrong_cred(fastapi_server_auth_invalid_cred) -> Generator[API, None, None]: +def api_wrong_cred( + fastapi_server_auth_invalid_cred: Generator[System, None, None] +) -> Generator[API, None, None]: api = next(fastapi_server_auth_invalid_cred).instance(API) yield api @pytest.fixture(scope="function") -def api_with_server_auth( - system_auth: Generator[System, None, None] -) -> Generator[API, None, None]: - _sys = next(system_auth) +def api_with_server_auth(system_auth: System) -> Generator[API, None, None]: + _sys = system_auth _sys.reset_state() api = _sys.instance(API) yield api diff --git a/docker-compose.yml b/docker-compose.yml index 5f298f1e741..db5f4d55862 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,6 +16,8 @@ services: command: uvicorn chromadb.app:app --reload --workers 1 --host 0.0.0.0 --port 8000 --log-config log_config.yml environment: - IS_PERSISTENT=TRUE + - CHROMA_SERVER_AUTH_PROVIDER=${CHROMA_SERVER_AUTH_PROVIDER} + - CHROMA_SERVER_AUTH_PROVIDER_CONFIG=${CHROMA_SERVER_AUTH_PROVIDER_CONFIG} ports: - 8000:8000 networks: diff --git a/examples/basic_functionality/assets/auh-sequence.png b/examples/basic_functionality/assets/auh-sequence.png new file mode 100644 index 0000000000000000000000000000000000000000..d674328f688206b8b99c4c7c03695d4349986eb0 GIT binary patch literal 139351 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 literal 0 HcmV?d00001 diff --git a/examples/basic_functionality/assets/auth-architecture.png b/examples/basic_functionality/assets/auth-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..33d049acdd36d4a19132fff5673853311f4f47f1 GIT binary patch literal 32974 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 literal 0 HcmV?d00001 diff --git a/examples/basic_functionality/client_auth.ipynb b/examples/basic_functionality/client_auth.ipynb index 5fa612893ac..35205820a6d 100644 --- a/examples/basic_functionality/client_auth.ipynb +++ b/examples/basic_functionality/client_auth.ipynb @@ -1,75 +1,237 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 2, - "id": "initial_id", + "cell_type": "markdown", + "source": [ + "# Chroma Authentication\n", + "\n", + "This tutorial aims to explain how authentication can be setup in Chroma.\n", + "\n", + "> **Important**: The concept of authentication is only applicable to Client/Server deployments. If you are using Chroma in a standalone mode, authentication is not applicable.\n", + "\n", + "## Concepts\n", + "\n", + "### Architecture Overview\n", + "\n", + "![Authentication Architecture](assets/auth-architecture.png \"Authentication Architecture\")\n", + "\n", + "### Authentication Flow (Sequence)\n", + "\n", + "The authentication sequence is applied for every request. It is important to understand that credential computation or retrieval (e.g. from external auth providers) is only done once for the first authenticated request. Subsequent requests will use the same credentials.\n", + "\n", + "The authentication flow is as follows:\n", + "\n", + "![Authentication Flow](assets/auh-sequence.png \"Authentication Flow\")\n", + "\n", + "### Preemptive Authentication\n", + "\n", + "In its current release the authentication in Chroma works in a preemptive mode. This means that the client is responsible for sending the authentication information on every request. The server will not challenge the client for authentication.\n", + "\n", + "> **Warning**: There are security risks involved with preemptive authentication in that the client might unintentionally send credentials to malicious or unintended server. When deploying authentication users are encouraged to use HTTPS (always verify server certs), to use secure providers (e.g. JWT) \n", + "> and apply good security practices.\n", + "\n", + "### Authentication Provider\n", + "\n", + "Authentication in Chroma is handled by Authentication Providers. Providers are pluggable modules that allow Chroma to abstract the authentication mechanism from the rest of the system.\n", + "\n", + "Chroma ships with the following build-in providers:\n", + "- Basic Authentication\n", + "- JWT Authentication (work in progress)\n", + "\n", + "### Client-side Authentication\n", + "\n", + "Client-side authentication refers to the process of preparing and communicating credentials information on the client-side and sending that information the Chroma server.\n", + "\n", + "### Server-side Authentication\n", + "\n", + "Server-side authentication refers to the process of validating the credentials information received from the client and authenticating the client.\n" + ], "metadata": { - "collapsed": true, - "ExecuteTime": { - "end_time": "2023-08-11T15:58:07.061237Z", - "start_time": "2023-08-11T15:58:07.058628Z" - } + "collapsed": false }, - "outputs": [], - "source": [] + "id": "eae631e46b4c1115" + }, + { + "cell_type": "markdown", + "source": [ + "## Configuration\n", + "\n", + "### Server Configuration\n", + "\n", + "The following configuration parameters are available for the server (defined as environment variables):\n", + "\n", + "- `CHROMA_SERVER_AUTH_PROVIDER` - It indicates the authentication provider class to use. In this case we are using the `chromadb.auth.BasicAuthServerProvider` class.\n", + "- `CHROMA_SERVER_AUTH_PROVIDER_CONFIG` - It is a dictionary that contains the configuration parameters for the authentication provider.\n", + "\n", + "#### Basic Authentication Provider Configuration\n", + "\n", + "The following configuration parameters are available for the Basic Authentication Provider (defined as environment variables):\n", + "\n", + "- `CHROMA_SERVER_AUTH_BASIC_USERNAME` - The username to use for authentication.\n", + "- `CHROMA_SERVER_AUTH_BASIC_PASSWORD` - The password to use for authentication.\n", + "- `CHROMA_SERVER_AUTH_IGNORE_PATHS` - A comma separated list of paths to ignore for authentication. This is useful for public endpoints that do not require authentication. This defaults to `/api/v1, /api/v1/heartbeat, /api/v1/version`.\n", + "\n", + "When using `CHROMA_SERVER_AUTH_PROVIDER_CONFIG` to define the basic auth configuration, the following formats are available:\n", + "\n", + "- JSON format: `{\"username\":\"admin\",\"password\":\"admin\"}`\n", + "- File path: `/path/to/htpasswd/file` where the file is in htpasswd format (user:password) - single line with plaintext password.\n", + "\n", + "### Client Configuration\n", + "\n", + "The following configuration parameters are available for the client (defined as environment variables or passed as configuration when setting up the client):\n", + "\n", + "- `CHROMA_CLIENT_AUTH_PROVIDER` - It indicates the authentication provider class to use. In this case we are using the `chromadb.auth.BasicAuthClientProvider` class.\n", + "- `CHROMA_CLIENT_AUTH_PROVIDER_CONFIG` - It is a dictionary that contains the configuration parameters for the authentication provider. This can also be a file path with htpasswd format (user:password) - single line with plaintext password.\n", + "\n", + "#### Basic Authentication Provider Configuration\n", + "\n", + "The following configuration parameters are available for the Basic Authentication Provider (defined as environment variables or passed as configuration when setting up the client):\n", + "\n", + "- `CHROMA_CLIENT_AUTH_BASIC_USERNAME` - The username to use for authentication.\n", + "- `CHROMA_CLIENT_AUTH_BASIC_PASSWORD` - The password to use for authentication.\n", + "\n", + "When using `CHROMA_CLIENT_AUTH_PROVIDER_CONFIG` to define the basic auth configuration, the following formats are available:\n", + "\n", + "- JSON format: `{\"username\":\"admin\",\"password\":\"admin\"}`\n", + "- File path: `/path/to/htpasswd/file` where the file is in htpasswd format (user:password) - single line with plaintext password." + ], + "metadata": { + "collapsed": false + }, + "id": "87d45f79aed65e21" + }, + { + "cell_type": "markdown", + "source": [ + "## Setting Up The client\n", + "\n", + "### Before You Begin\n", + "\n", + "Make sure you have either `chromadb` or `chromadb-client` installed. You can do that by running the following command:\n", + "\n", + "```bash\n", + "pip install chromadb\n", + "```\n", + "or\n", + "\n", + "```bash\n", + "pip install chromadb-client\n", + "```\n", + "\n", + "Make sure Chroma Server is running. Use one of the following methods to start the server:\n", + "\n", + "From the command line:\n", + "\n", + "> Note: You need to clone the git repository first and run the command from the repository root.\n", + "\n", + "```bash\n", + "CHROMA_SERVER_AUTH_PROVIDER=\"chromadb.auth.BasicAuthServerProvider\" \\\n", + "CHROMA_SERVER_AUTH_PROVIDER_CONFIG='{\"username\":\"admin\",\"password\":\"admin\"}' \\\n", + "uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 --proxy-headers --log-config log_config.yml\n", + "```\n", + "\n", + "From Docker:\n", + "\n", + "> Note: You need to clone the git repository first and run the command from the repository root.\n", + "\n", + "```bash\n", + "cat << EOF > .env\n", + "CHROMA_SERVER_AUTH_PROVIDER=chromadb.auth.BasicAuthServerProvider\n", + "CHROMA_SERVER_AUTH_PROVIDER_CONFIG={\"username\":\"admin\",\"password\":\"admin\"}\n", + "EOF\n", + "docker-compose up -d --build\n", + "```\n", + "\n", + "\n", + "In the snippet below we will configure the client to use Basic Authentication.\n", + "\n", + "Configuration parameters:\n", + "\n", + "- `chroma_client_auth_provider` - It indicates the authentication provider class to use. In this case we are using the `chromadb.auth.BasicAuthClientProvider` class.\n", + "- `chroma_client_auth_provider_config` - It is a dictionary that contains the configuration parameters for the authentication provider. In this case we are using the `username` and `password` parameters in a JSON format." + ], + "metadata": { + "collapsed": false + }, + "id": "af49d8c78f2f7347" + }, + { + "cell_type": "markdown", + "source": [ + "### Basic Authentication" + ], + "metadata": { + "collapsed": false + }, + "id": "fc77d909233f2645" }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 20, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "provider: chromadb.config.BasicAuthClientProvider\n" - ] - }, - { - "ename": "Exception", - "evalue": "{\"error\":\"Unauthorized\"}", - "output_type": "error", - "traceback": [ - "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[0;31mHTTPError\u001B[0m Traceback (most recent call last)", - "File \u001B[0;32m~/PycharmProjects/chroma-core/chromadb/api/fastapi.py:385\u001B[0m, in \u001B[0;36mraise_chroma_error\u001B[0;34m(resp)\u001B[0m\n\u001B[1;32m 384\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m--> 385\u001B[0m \u001B[43mresp\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mraise_for_status\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 386\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m requests\u001B[38;5;241m.\u001B[39mHTTPError:\n", - "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/requests/models.py:1021\u001B[0m, in \u001B[0;36mResponse.raise_for_status\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 1020\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m http_error_msg:\n\u001B[0;32m-> 1021\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m HTTPError(http_error_msg, response\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m)\n", - "\u001B[0;31mHTTPError\u001B[0m: 401 Client Error: Unauthorized for url: http://localhost:8000/api/v1", - "\nDuring handling of the above exception, another exception occurred:\n", - "\u001B[0;31mException\u001B[0m Traceback (most recent call last)", - "Cell \u001B[0;32mIn[2], line 5\u001B[0m\n\u001B[1;32m 2\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mchromadb\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m Settings\n\u001B[1;32m 4\u001B[0m client \u001B[38;5;241m=\u001B[39m chromadb\u001B[38;5;241m.\u001B[39mHttpClient(settings\u001B[38;5;241m=\u001B[39mSettings(chroma_client_auth_provider\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mchromadb.config.BasicAuthClientProvider\u001B[39m\u001B[38;5;124m\"\u001B[39m, chroma_client_auth_provider_config\u001B[38;5;241m=\u001B[39m{\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124musername\u001B[39m\u001B[38;5;124m\"\u001B[39m: \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124madmi1n\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mpassword\u001B[39m\u001B[38;5;124m\"\u001B[39m: \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124madmin\u001B[39m\u001B[38;5;124m\"\u001B[39m}))\n\u001B[0;32m----> 5\u001B[0m \u001B[43mclient\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mheartbeat\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n", - "File \u001B[0;32m~/PycharmProjects/chroma-core/chromadb/api/fastapi.py:60\u001B[0m, in \u001B[0;36mFastAPI.heartbeat\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 58\u001B[0m \u001B[38;5;250m\u001B[39m\u001B[38;5;124;03m\"\"\"Returns the current server time in nanoseconds to check if the server is alive\"\"\"\u001B[39;00m\n\u001B[1;32m 59\u001B[0m resp \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_session\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_api_url)\n\u001B[0;32m---> 60\u001B[0m \u001B[43mraise_chroma_error\u001B[49m\u001B[43m(\u001B[49m\u001B[43mresp\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 61\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mint\u001B[39m(resp\u001B[38;5;241m.\u001B[39mjson()[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mnanosecond heartbeat\u001B[39m\u001B[38;5;124m\"\u001B[39m])\n", - "File \u001B[0;32m~/PycharmProjects/chroma-core/chromadb/api/fastapi.py:387\u001B[0m, in \u001B[0;36mraise_chroma_error\u001B[0;34m(resp)\u001B[0m\n\u001B[1;32m 385\u001B[0m resp\u001B[38;5;241m.\u001B[39mraise_for_status()\n\u001B[1;32m 386\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m requests\u001B[38;5;241m.\u001B[39mHTTPError:\n\u001B[0;32m--> 387\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m (\u001B[38;5;167;01mException\u001B[39;00m(resp\u001B[38;5;241m.\u001B[39mtext))\n", - "\u001B[0;31mException\u001B[0m: {\"error\":\"Unauthorized\"}" - ] + "data": { + "text/plain": "[]" + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ "import chromadb\n", "from chromadb import Settings\n", "\n", - "client = chromadb.HttpClient(settings=Settings(chroma_client_auth_provider=\"chromadb.config.BasicAuthClientProvider\", chroma_client_auth_provider_config={\"username\": \"admin\", \"password\": \"admin\"}))\n", - "client.heartbeat()\n" + "client = chromadb.HttpClient(settings=Settings(chroma_client_auth_provider=\"chromadb.auth.BasicAuthClientProvider\",\n", + " chroma_client_auth_provider_config={\"username\": \"admin\",\n", + " \"password\": \"admin\"}))\n", + "client.heartbeat() # this should work with or without authentication - it is a public endpoint\n", + "\n", + "client.get_version() # this should work with or without authentication - it is a public endpoint\n", + "\n", + "client.list_collections() # this is a protected endpoint and requires authentication\n", + "\n" ], "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2023-08-11T16:25:06.501154Z", - "start_time": "2023-08-11T16:25:06.299634Z" + "end_time": "2023-08-17T15:19:48.881673Z", + "start_time": "2023-08-17T15:19:48.822021Z" } }, "id": "8f9307acce25f672" }, + { + "cell_type": "markdown", + "source": [ + "#### Verifying Authentication (Negative Test)" + ], + "metadata": { + "collapsed": false + }, + "id": "6b75f04e59cb1d42" + }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 23, "outputs": [], - "source": [], + "source": [ + "# Try to access a protected endpoint without authentication\n", + "import sys\n", + "client = chromadb.HttpClient()\n", + "try:\n", + " client.list_collections()\n", + "except Exception as e:\n", + " if \"Unauthorized\" in str(e):\n", + " print(\"As expected, you are not authorized to access protected endpoints.\",file=sys.stderr)\n", + " else:\n", + " raise e" + ], "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2023-08-11T16:00:53.461947Z", - "start_time": "2023-08-11T16:00:53.458763Z" + "end_time": "2023-08-17T15:25:19.857009Z", + "start_time": "2023-08-17T15:25:19.737527Z" } }, "id": "c0c3240ed4d70a79" From eced90d939c6a425cd46149607ad988e37554bcb Mon Sep 17 00:00:00 2001 From: Trayan Azarov Date: Fri, 18 Aug 2023 18:01:02 +0300 Subject: [PATCH 07/13] feat: CIP-2 Auth Providers - WIP - Redoing the whole architecture with additional abstractions and moving auth stuff in `/auth` Note: Not ready for review --- chromadb/api/fastapi.py | 14 +- chromadb/auth/__init__.py | 90 ++++++++++++- chromadb/auth/basic/__init__.py | 118 +++++++++++++++++ chromadb/auth/fastapi.py | 98 ++++++++++++++ chromadb/auth/token/__init__.py | 0 chromadb/config.py | 176 ++------------------------ chromadb/server/fastapi/__init__.py | 13 +- chromadb/test/auth/test_basic_auth.py | 12 ++ chromadb/test/conftest.py | 5 + chromadb/test/test_api.py | 11 -- chromadb/utils/__init__.py | 12 ++ docs/CIP_2_Auth_Providers_Proposal.md | 128 ++++++++++++++++--- 12 files changed, 479 insertions(+), 198 deletions(-) create mode 100644 chromadb/auth/basic/__init__.py create mode 100644 chromadb/auth/fastapi.py create mode 100644 chromadb/auth/token/__init__.py create mode 100644 chromadb/test/auth/test_basic_auth.py diff --git a/chromadb/api/fastapi.py b/chromadb/api/fastapi.py index d6fd54d2268..7c0387ff2d4 100644 --- a/chromadb/api/fastapi.py +++ b/chromadb/api/fastapi.py @@ -1,6 +1,7 @@ from typing import Optional, cast from chromadb.api import API -from chromadb.config import Settings, System +from chromadb.auth import ClientAuthProvider +from chromadb.config import Settings, System, get_class from chromadb.api.types import ( Documents, Embeddings, @@ -46,12 +47,19 @@ def __init__(self, system: System): f"{url_prefix}://{system.settings.chroma_server_host}{port_suffix}/api/v1" ) + if system.settings.chroma_client_auth_provider: + self._auth_provider = self.require( + get_class( + system.settings.chroma_client_auth_provider, ClientAuthProvider + ) + ) + self._header = system.settings.chroma_server_headers self._session = requests.Session() if self._header is not None: self._session.headers.update(self._header) - if system.auth_provider is not None: - system.auth_provider.authenticate(self._session) + # if system.auth_provider is not None: + # system.auth_provider.authenticate(self._session) @override def heartbeat(self) -> int: diff --git a/chromadb/auth/__init__.py b/chromadb/auth/__init__.py index 8195adc69bf..7c7655f439b 100644 --- a/chromadb/auth/__init__.py +++ b/chromadb/auth/__init__.py @@ -1,4 +1,90 @@ -from chromadb.config import BasicAuthClientProvider, BasicAuthServerProvider +""" +Contains only Auth abstractions, no implementations. +""" +from abc import ABC, abstractmethod +from enum import Enum +from typing import Optional + +import requests +from overrides import EnforceOverrides + +from chromadb.config import Component, System # TODO remove this circular dependency +from chromadb.utils import get_class + # Re-export types from chromadb -__all__ = ["BasicAuthClientProvider", "BasicAuthServerProvider"] +# __all__ = ["BasicAuthClientProvider", "BasicAuthServerProvider"] + + +class ClientAuthProvider(Component): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def authenticate(self, session: requests.Session) -> None: + pass + + +_provider_registry = { + # TODO we need a better way to store, update and validate this registry with new providers being added + [ + "basic", + "chromadb.auth.basic.BasicAuthClientProvider", + ]: "chromadb.auth.basic.BasicAuthClientProvider", +} + + +def resolve_client_auth_provider(classOrName) -> "ClientAuthProvider": + _cls = [ + cls + for short_hand_list, cls in _provider_registry.items() + if classOrName in short_hand_list + ] + if len(_cls) == 0: + raise ValueError(f"Unknown client auth provider: {classOrName}") + return get_class(_cls[0], ClientAuthProvider) + + +### SERVER-SIDE Abstractions + + +class AuthInfoType(Enum): + COOKIE = "cookie" + HEADER = "header" + URL = "url" + METADATA = "metadata" # gRPC + + +class ServerAuthenticationRequest(EnforceOverrides, ABC): + @abstractmethod + def get_auth_info( + self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None + ) -> str: + pass + + +class ServerAuthenticationResponse(EnforceOverrides, ABC): + def success(self) -> bool: + raise NotImplementedError() + + +class ServerAuthProvider(Component): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def authenticate( + self, request: ServerAuthenticationRequest + ) -> ServerAuthenticationResponse: + pass + + +class ChromaAuthMiddleware(Component): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def authenticate( + self, request: ServerAuthenticationRequest + ) -> Optional[ServerAuthenticationResponse]: + pass diff --git a/chromadb/auth/basic/__init__.py b/chromadb/auth/basic/__init__.py new file mode 100644 index 00000000000..b88d907ef64 --- /dev/null +++ b/chromadb/auth/basic/__init__.py @@ -0,0 +1,118 @@ +import base64 +import os + +import requests +from overrides import overrides +from pydantic import SecretStr + +from chromadb.auth import ServerAuthProvider + + +def _encode_credentials(username: str, password: str) -> SecretStr: + return SecretStr( + base64.b64encode(f"{username}:{password}".encode("utf-8")).decode("utf-8") + ) + + +class BasicAuthClientProvider(ClientAuthProvider): + _basic_auth_token: SecretStr + + def __init__(self, settings: "Settings") -> None: + super().__init__(settings) + self._settings = settings + if os.environ.get("CHROMA_CLIENT_AUTH_BASIC_USERNAME") and os.environ.get( + "CHROMA_CLIENT_AUTH_BASIC_PASSWORD" + ): + self._basic_auth_token = _encode_credentials( + os.environ.get("CHROMA_CLIENT_AUTH_BASIC_USERNAME", ""), + os.environ.get("CHROMA_CLIENT_AUTH_BASIC_PASSWORD", ""), + ) + elif isinstance( + self._settings.chroma_client_auth_provider_config, str + ) and os.path.exists(self._settings.chroma_client_auth_provider_config): + with open(self._settings.chroma_client_auth_provider_config) as f: + # read first line of file which should be user:password + _auth_data = f.readline().strip().split(":") + # validate auth data + if len(_auth_data) != 2: + raise ValueError("Invalid auth data") + self._basic_auth_token = _encode_credentials( + _auth_data[0], _auth_data[1] + ) + elif self._settings.chroma_client_auth_provider_config and isinstance( + self._settings.chroma_client_auth_provider_config, dict + ): + self._basic_auth_token = _encode_credentials( + self._settings.chroma_client_auth_provider_config["username"], + self._settings.chroma_client_auth_provider_config["password"], + ) + else: + raise ValueError("Basic auth credentials not found") + + @overrides + def authenticate(self, session: requests.Session) -> None: + session.headers.update( + {"Authorization": f"Basic {self._basic_auth_token.get_secret_value()}"} + ) + + +class BasicAuthServerProvider(ServerAuthProvider): + _basic_auth_token: SecretStr + + def __init__(self, settings: "Settings") -> None: + super().__init__(settings) + self._settings = settings + self._basic_auth_token = SecretStr("") + if os.environ.get("CHROMA_SERVER_AUTH_BASIC_USERNAME") and os.environ.get( + "CHROMA_SERVER_AUTH_BASIC_PASSWORD" + ): + self._basic_auth_token = _encode_credentials( + os.environ.get("CHROMA_SERVER_AUTH_BASIC_USERNAME", ""), + os.environ.get("CHROMA_SERVER_AUTH_BASIC_PASSWORD", ""), + ) + self._ignore_auth_paths = os.environ.get( + "CHROMA_SERVER_AUTH_IGNORE_PATHS", ",".join(self._ignore_auth_paths) + ).split(",") + elif isinstance( + self._settings.chroma_server_auth_provider_config, str + ) and os.path.exists(self._settings.chroma_server_auth_provider_config): + with open(self._settings.chroma_server_auth_provider_config) as f: + # read first line of file which should be user:password + _auth_data = f.readline().strip().split(":") + # validate auth data + if len(_auth_data) != 2: + raise ValueError("Invalid auth data") + self._basic_auth_token = _create_token(_auth_data[0], _auth_data[1]) + self._ignore_auth_paths = os.environ.get( + "CHROMA_SERVER_AUTH_IGNORE_PATHS", ",".join(self._ignore_auth_paths) + ).split(",") + elif self._settings.chroma_server_auth_provider_config and isinstance( + self._settings.chroma_server_auth_provider_config, dict + ): + # encode the username and password base64 + self._basic_auth_token = _create_token( + self._settings.chroma_server_auth_provider_config["username"], + self._settings.chroma_server_auth_provider_config["password"], + ) + if "ignore_auth_paths" in self._settings.chroma_server_auth_provider_config: + self._ignore_auth_paths = ( + self._settings.chroma_server_auth_provider_config[ + "ignore_auth_paths" + ] + ) + else: + raise ValueError("Basic auth credentials not found") + + @overrides + def authenticate(self, request: Request) -> Union[Response, None]: + auth_header = request.headers.get("Authorization", "").split() + # Check if the header exists and the token is correct + if request.url.path in self._ignore_auth_paths: + logger.debug(f"Skipping auth for path {request.url.path}") + return None + if ( + len(auth_header) != 2 + or auth_header[1] != self._basic_auth_token.get_secret_value() + ): + return JSONResponse({"error": "Unauthorized"}, status_code=401) + return None diff --git a/chromadb/auth/fastapi.py b/chromadb/auth/fastapi.py new file mode 100644 index 00000000000..50f801e93ff --- /dev/null +++ b/chromadb/auth/fastapi.py @@ -0,0 +1,98 @@ +## FAST API code +import logging +from typing import Optional, Dict, List + +from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint +from starlette.requests import Request +from starlette.responses import Response, JSONResponse +from starlette.types import ASGIApp + +from chromadb import System +from chromadb.auth import ( + ServerAuthenticationRequest, + AuthInfoType, + ServerAuthenticationResponse, + ServerAuthProvider, + ChromaAuthMiddleware, +) +from chromadb.utils import get_class + +logger = logging.getLogger(__name__) + + +class FastAPIServerAuthenticationRequest(ServerAuthenticationRequest): + def __init__(self, request: Request) -> None: + self._request = request + + def get_auth_info( + self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None + ) -> str: + if auth_info_type == AuthInfoType.HEADER: + return self._request.headers[auth_info_id] + elif auth_info_type == AuthInfoType.COOKIE: + return self._request.cookies[auth_info_id] + elif auth_info_type == AuthInfoType.URL: + return self._request.query_params[auth_info_id] + elif auth_info_type == AuthInfoType.METADATA: + raise ValueError("Metadata not supported for FastAPI") + else: + raise ValueError(f"Unknown auth info type: {auth_info_type}") + + +class FastAPIServerAuthenticationResponse(ServerAuthenticationResponse): + def __init__(self, response: Response) -> None: + self._response = response + + def success(self) -> bool: + return self._response.status_code == 200 + + +class FastAPIChromaAuthMiddleware(ChromaAuthMiddleware): # type: ignore + _auth_provider: ServerAuthProvider + + def __init__(self, app: ASGIApp, system: System) -> None: + super().__init__(system) + self._system = system + self._settings = system.settings + self._settings.require("chroma_server_auth_provider") + self._ignore_auth_paths: Dict[ + str, List[str] + ] = self._settings.chroma_server_auth_ignore_paths + if self._settings.chroma_server_auth_provider: + _cls = get_class( + self._settings.chroma_server_auth_provider, ServerAuthProvider + ) + self.require(_cls) + logger.debug(f"Server Auth Provider: {_cls}") + + def authenticate(self, request: Request) -> Optional[Response]: + if ( + request.url.path in self._ignore_auth_paths.keys() + and request.method.upper() in self._ignore_auth_paths[request.url.path] + ): + logger.debug( + f"Skipping auth for path {request.url.path} and method {request.method}" + ) + return None + response = self._auth_provider.authenticate( + FastAPIServerAuthenticationRequest(request) + ) + if response is None or not response.success(): + return JSONResponse({"error": "Unauthorized"}, status_code=401) + return None + + +class FastAPIChromaAuthMiddlewareWrapper(BaseHTTPMiddleware): + def __init__( + self, app: ASGIApp, auth_middleware: FastAPIChromaAuthMiddleware + ) -> None: + super().__init__(app) + self._middleware = auth_middleware + + async def dispatch( + self, request: Request, call_next: RequestResponseEndpoint + ) -> Response: + resp = self._middleware.authenticate(request) + if resp is not None: + return resp + return await call_next(request) diff --git a/chromadb/auth/token/__init__.py b/chromadb/auth/token/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chromadb/config.py b/chromadb/config.py index 5f9691dab11..48cb8100653 100644 --- a/chromadb/config.py +++ b/chromadb/config.py @@ -11,7 +11,7 @@ import requests from overrides import override from overrides import overrides, EnforceOverrides -from pydantic import BaseSettings, SecretStr +from pydantic import BaseSettings, SecretStr, validator from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint from starlette.requests import Request from starlette.responses import Response, JSONResponse @@ -67,24 +67,6 @@ } -class ClientAuthProvider(ABC, EnforceOverrides): - def __init__(self, settings: "Settings") -> None: - self._settings = settings - - @abstractmethod - def authenticate(self, session: requests.Session) -> None: - pass - - -class ServerAuthProvider(ABC, EnforceOverrides): - def __init__(self, settings: "Settings") -> None: - self._settings = settings - - @abstractmethod - def authenticate(self, request: Request) -> Union[Response, None]: - pass - - class Settings(BaseSettings): # type: ignore environment: str = "" @@ -114,13 +96,24 @@ class Settings(BaseSettings): # type: ignore chroma_server_ssl_enabled: Optional[bool] = False chroma_server_grpc_port: Optional[str] = None chroma_server_cors_allow_origins: List[str] = [] # eg ["http://localhost:3000"] - # eg ["chromadb.api.fastapi.middlewares.auth.AuthMiddleware"] - chroma_server_middlewares: List[str] = [] chroma_server_auth_provider: Optional[str] = None + + @validator("chroma_server_auth_provider", pre=True, always=True) + def chroma_server_auth_provider_non_empty(self, v) -> Optional[str]: + if not v or not v.strip(): + raise ValueError("String cannot be empty or just whitespace") + return v + chroma_server_auth_provider_config: Optional[Union[str, Dict[str, Any]]] = None chroma_client_auth_provider: Optional[str] = None + chroma_server_auth_ignore_paths: Dict[str, List[str]] = { + "/api/v1": ["GET"], + "/api/v1/heartbeat": ["GET"], + "/api/v1/version": ["GET"], + } chroma_client_auth_provider_config: Optional[Union[str, Dict[str, Any]]] = None + anonymized_telemetry: bool = True allow_reset: bool = False @@ -190,7 +183,6 @@ def reset_state(self) -> None: class System(Component): settings: Settings - auth_provider: Optional["ClientAuthProvider"] _instances: Dict[Type[Component], Component] def __init__(self, settings: Settings): @@ -201,18 +193,6 @@ def __init__(self, settings: Settings): "Chroma is running in http-only client mode, and can only be run with 'chromadb.api.fastapi.FastAPI' as the chroma_api_impl. \ see https://docs.trychroma.com/usage-guide?lang=py#using-the-python-http-only-client for more information." ) - if ( - settings.chroma_client_auth_provider is not None - and settings.chroma_client_auth_provider.strip() != "" - ): - logger.debug( - f"Client Auth Provider: {settings.chroma_client_auth_provider}" - ) - self.auth_provider = get_class( - settings.chroma_client_auth_provider, ClientAuthProvider - )(settings) - else: - self.auth_provider = None # Validate settings don't contain any legacy config values for key in _legacy_config_keys: if settings[key] is not None: @@ -275,134 +255,6 @@ def reset_state(self) -> None: component.reset_state() -class BasicAuthClientProvider(ClientAuthProvider): - _basic_auth_token: SecretStr - - def __init__(self, settings: "Settings") -> None: - super().__init__(settings) - self._settings = settings - if os.environ.get("CHROMA_CLIENT_AUTH_BASIC_USERNAME") and os.environ.get( - "CHROMA_CLIENT_AUTH_BASIC_PASSWORD" - ): - self._basic_auth_token = _create_token( - os.environ.get("CHROMA_CLIENT_AUTH_BASIC_USERNAME", ""), - os.environ.get("CHROMA_CLIENT_AUTH_BASIC_PASSWORD", ""), - ) - elif isinstance( - self._settings.chroma_client_auth_provider_config, str - ) and os.path.exists(self._settings.chroma_client_auth_provider_config): - with open(self._settings.chroma_client_auth_provider_config) as f: - # read first line of file which should be user:password - _auth_data = f.readline().strip().split(":") - # validate auth data - if len(_auth_data) != 2: - raise ValueError("Invalid auth data") - self._basic_auth_token = _create_token(_auth_data[0], _auth_data[1]) - elif self._settings.chroma_client_auth_provider_config and isinstance( - self._settings.chroma_client_auth_provider_config, dict - ): - self._basic_auth_token = _create_token( - self._settings.chroma_client_auth_provider_config["username"], - self._settings.chroma_client_auth_provider_config["password"], - ) - else: - raise ValueError("Basic auth credentials not found") - - @overrides - def authenticate(self, session: requests.Session) -> None: - session.headers.update( - {"Authorization": f"Basic {self._basic_auth_token.get_secret_value()}"} - ) - - -class ChromaAuthMiddleware(BaseHTTPMiddleware): # type: ignore - def __init__(self, app: ASGIApp, settings: "Settings") -> None: - super().__init__(app) - self._settings = settings - self._settings.require("chroma_server_auth_provider") - if settings.chroma_server_auth_provider: - _cls = get_class(settings.chroma_server_auth_provider, ServerAuthProvider) - logger.debug(f"Server Auth Provider: {_cls}") - self._auth_provider = _cls(settings) - - async def dispatch( - self, request: Request, call_next: RequestResponseEndpoint - ) -> Response: - response = self._auth_provider.authenticate(request) - if response is not None: - return response - return await call_next(request) - - -def _create_token(username: str, password: str) -> SecretStr: - return SecretStr( - base64.b64encode(f"{username}:{password}".encode("utf-8")).decode("utf-8") - ) - - -class BasicAuthServerProvider(ServerAuthProvider): - _basic_auth_token: SecretStr - _ignore_auth_paths: List[str] = ["/api/v1", "/api/v1/heartbeat", "/api/v1/version"] - - def __init__(self, settings: "Settings") -> None: - super().__init__(settings) - self._settings = settings - self._basic_auth_token = SecretStr("") - if os.environ.get("CHROMA_SERVER_AUTH_BASIC_USERNAME") and os.environ.get( - "CHROMA_SERVER_AUTH_BASIC_PASSWORD" - ): - self._basic_auth_token = _create_token( - os.environ.get("CHROMA_SERVER_AUTH_BASIC_USERNAME", ""), - os.environ.get("CHROMA_SERVER_AUTH_BASIC_PASSWORD", ""), - ) - self._ignore_auth_paths = os.environ.get( - "CHROMA_SERVER_AUTH_IGNORE_PATHS", ",".join(self._ignore_auth_paths) - ).split(",") - elif isinstance( - self._settings.chroma_server_auth_provider_config, str - ) and os.path.exists(self._settings.chroma_server_auth_provider_config): - with open(self._settings.chroma_server_auth_provider_config) as f: - # read first line of file which should be user:password - _auth_data = f.readline().strip().split(":") - # validate auth data - if len(_auth_data) != 2: - raise ValueError("Invalid auth data") - self._basic_auth_token = _create_token(_auth_data[0], _auth_data[1]) - self._ignore_auth_paths = os.environ.get( - "CHROMA_SERVER_AUTH_IGNORE_PATHS", ",".join(self._ignore_auth_paths) - ).split(",") - elif self._settings.chroma_server_auth_provider_config and isinstance( - self._settings.chroma_server_auth_provider_config, dict - ): - # encode the username and password base64 - self._basic_auth_token = _create_token( - self._settings.chroma_server_auth_provider_config["username"], - self._settings.chroma_server_auth_provider_config["password"], - ) - if "ignore_auth_paths" in self._settings.chroma_server_auth_provider_config: - self._ignore_auth_paths = ( - self._settings.chroma_server_auth_provider_config[ - "ignore_auth_paths" - ] - ) - else: - raise ValueError("Basic auth credentials not found") - - @overrides - def authenticate(self, request: Request) -> Union[Response, None]: - auth_header = request.headers.get("Authorization", "").split() - # Check if the header exists and the token is correct - if request.url.path in self._ignore_auth_paths: - logger.debug(f"Skipping auth for path {request.url.path}") - return None - if ( - len(auth_header) != 2 - or auth_header[1] != self._basic_auth_token.get_secret_value() - ): - return JSONResponse({"error": "Unauthorized"}, status_code=401) - return None - - C = TypeVar("C") diff --git a/chromadb/server/fastapi/__init__.py b/chromadb/server/fastapi/__init__.py index c734fa97574..d8e43c51081 100644 --- a/chromadb/server/fastapi/__init__.py +++ b/chromadb/server/fastapi/__init__.py @@ -11,6 +11,10 @@ import chromadb from chromadb.api.models.Collection import Collection from chromadb.api.types import GetResult, QueryResult +from chromadb.auth.fastapi import ( + FastAPIChromaAuthMiddleware, + FastAPIChromaAuthMiddlewareWrapper, +) from chromadb.config import Settings import chromadb.server import chromadb.api @@ -109,12 +113,11 @@ def __init__(self, settings: Settings): allow_origins=settings.chroma_server_cors_allow_origins, allow_methods=["*"], ) - if ( - settings.chroma_server_auth_provider is not None - and settings.chroma_server_auth_provider.strip() != "" - ): + if settings.chroma_server_auth_provider: + self._auth_middleware = self._api.require(FastAPIChromaAuthMiddleware) self._app.add_middleware( - chromadb.config.ChromaAuthMiddleware, settings=settings + FastAPIChromaAuthMiddlewareWrapper, + auth_middleware=self._auth_middleware, ) self.router = ChromaAPIRouter() diff --git a/chromadb/test/auth/test_basic_auth.py b/chromadb/test/auth/test_basic_auth.py new file mode 100644 index 00000000000..f064be66335 --- /dev/null +++ b/chromadb/test/auth/test_basic_auth.py @@ -0,0 +1,12 @@ +import pytest + + +def test_invalid_auth_cred(api_wrong_cred): + with pytest.raises(Exception) as e: + api_wrong_cred.list_collections() + assert "Unauthorized" in str(e.value) + + +def test_server_basic_auth(api_with_server_auth): + cols = api_with_server_auth.list_collections() + assert len(cols) == 0 diff --git a/chromadb/test/conftest.py b/chromadb/test/conftest.py index 128633490a4..762399d633f 100644 --- a/chromadb/test/conftest.py +++ b/chromadb/test/conftest.py @@ -186,6 +186,11 @@ def fastapi_server_auth_param() -> Generator[System, None, None]: yield item +def auth_provider_config() -> Generator[Dict[str, str], None, None]: + ... + + +# TODO we need a generator for auth providers def fastapi_server_auth_file() -> Generator[System, None, None]: server_auth_file = os.path.abspath(os.path.join(".", "server-auth")) client_auth_file = os.path.abspath(os.path.join(".", "client-auth")) diff --git a/chromadb/test/test_api.py b/chromadb/test/test_api.py index fc0212d7a5e..ae1b1d087f1 100644 --- a/chromadb/test/test_api.py +++ b/chromadb/test/test_api.py @@ -1362,14 +1362,3 @@ def test_invalid_embeddings(api): with pytest.raises(ValueError) as e: collection.upsert(**invalid_records) assert "embedding" in str(e.value) - - -def test_invalid_auth_cred(api_wrong_cred): - with pytest.raises(Exception) as e: - api_wrong_cred.list_collections() - assert "Unauthorized" in str(e.value) - - -def test_server_auth(api_with_server_auth): - cols = api_with_server_auth.list_collections() - assert len(cols) == 0 diff --git a/chromadb/utils/__init__.py b/chromadb/utils/__init__.py index e69de29bb2d..fe6bb81853b 100644 --- a/chromadb/utils/__init__.py +++ b/chromadb/utils/__init__.py @@ -0,0 +1,12 @@ +import importlib +from typing import Type, TypeVar, cast + +C = TypeVar("C") + + +def get_class(fqn: str, type: Type[C]) -> Type[C]: + """Given a fully qualifed class name, import the module and return the class""" + module_name, class_name = fqn.rsplit(".", 1) + module = importlib.import_module(module_name) + cls = getattr(module, class_name) + return cast(Type[C], cls) diff --git a/docs/CIP_2_Auth_Providers_Proposal.md b/docs/CIP_2_Auth_Providers_Proposal.md index 81bb098bfc1..1814a72fa74 100644 --- a/docs/CIP_2_Auth_Providers_Proposal.md +++ b/docs/CIP_2_Auth_Providers_Proposal.md @@ -18,11 +18,14 @@ in test and production environments. The community has expressed the need for au ## **Public Interfaces** -Changes to the public interface are related to the `Settings` class where we introduce new optional attributes to control server and client-side auth providers. +Changes to the public interface are related to the `Settings` class where we introduce new optional attributes to +control server and client-side auth providers. ## **Proposed Changes** -We propose two abstractions, one for the server-side and another for the [client-side.](http://client-side.In) In addition we also introduce a FastAPI/startlette middleware adapter which will allow using the server-side abstractions in the context of FastAPI. +We propose two abstractions, one for the server-side and another for the [client-side.](http://client-side.In) In +addition we also introduce a FastAPI/startlette middleware adapter which will allow using the server-side abstractions +in the context of FastAPI. Architecture Overview: @@ -32,21 +35,108 @@ Request Sequence: ![cip-2-seq.png](assets/cip-2-seq.png) +### Abstractions + +#### Server-side Auth Provider + +The server-side authentication provider is responsible for authenticating client requests reaching server endpoints. The +abstraction serves as a way for any server implementation to validate client credentials. + +Interface: + +- `authenticate(request: AuthRequest) -> bool` + +Configuration: + +- `CHROMA_SERVER_AUTH_PROVIDER` - a shortname of the provider (configured in a mapping in `__init__.py` of `auth` + package) - default: `None`. When no provider is specified client request will not be authenticated. + +Exposed to the user: Yes + +#### Client-side Auth Provider + +Exposed to the user: Yes + +#### Auth Middleware Adapter + +Configuration: + +- `CHROMA_SERVER_AUTH_IGNORE_PATHS` - a list of paths that should be ignored by the auth provider - + default: `['/api/v1', '/api/v1/version', '/api/v1/heartbeat']`. **WARNING**: Usually the defaults are safe but users + should be careful when overriding this setting as it can lead to security issues. + +Exposed to the user: No + +#### Client-side Auth Configuration Provider + +Exposed to the user: Yes, via settings + +#### Server-side Auth Configuration Provider + +This is an abstraction layer for auth providers to acquire their configuration. The abstraction is needed as we want to +support a variety of auth providers and each of them might have different configuration requirements. + +It is important to note that configuration providers are not explicitly instantiated or configured by the user but +rather are configured by the auth provider itself (using factory pattern). + +Configuration: + +> Note about provider precedence: The provider precedence is as follows: `env` -> `file` -> `programmatic`. This means +> that if a provider is configured via env var, it will take precedence over the file-based provider. Similarly, if +> both env and file-based providers are configured, the env provider will take precedence over the file-based provider. + + +File-based configuration: + +Use this provider to load configuration from a file: + +- `CHROMA_SERVER_AUTH_PROVIDER_CONFIG_FILE_TYPE` - `htpasswd` or `plaintext` - default: `htpasswd` +- `CHROMA_SERVER_AUTH_PROVIDER_CONFIG_FILE` - a path to a file containing the auth provider configuration - default: + `None` + +Env-based configuration provider: + +Use this provider to load configuration from environment variables: + +- `CHROMA_SERVER_AUTH_PROVIDER_CONFIG_ENV` - an environment variable to use for auth provider configuration - default: + `None` +- `CHROMA_SERVER_AUTH_PROVIDER_CONFIG_ENV_TYPE` - `plaintext`, `json` or `yaml` - default: `plaintext` + +> Note: Additional settings will be added as more config providers are supplied. + + +Exposed to the user: Yes, via settings + +### Client-side Auth Credentials Provider + +Exposed to the user: Yes, via settings + +#### Server-side Auth Credentials Provider + +Exposed to the user: Yes, via settings + Reasoning: - Server-side abstraction - it is very useful as the intention is to support a variety of auth providers. -- Client-side abstraction - similar reasoning but from client's perspective. It will allow for both standard and non-standard auth provider plugins to be added without further impacting the client side -- Backend (fastAPI) adapter - this is a backend-specific way of loading server-side auth provider plugins. It will also serve as a template/blueprint when it comes to introducing the auth plugins to another backend framework (e.g. Flask) +- Client-side abstraction - similar reasoning but from client's perspective. It will allow for both standard and + non-standard auth provider plugins to be added without further impacting the client side +- Backend (fastAPI) adapter - this is a backend-specific way of loading server-side auth provider plugins. It will also + serve as a template/blueprint when it comes to introducing the auth plugins to another backend framework (e.g. Flask) -We also propose that each auth provider on either side must be configurable via three main methods depending on developer preference: +We also propose that each auth provider on either side must be configurable via three main methods depending on +developer preference: - File-base - a configuration file that provides the requisite config and credentials (recommended for production) -- Env - configuration through environment variables (this can also apply for the file-based config, which can be specified in env var) -- Programmatically - provide requisite configuration through CLI or directly in code (it is left for the developer to decide how such configuration is loaded and made available to the auth provider) - this is possibly the least secure and should be used for testing +- Env - configuration through environment variables (this can also apply for the file-based config, which can be + specified in env var) +- Programmatically - provide requisite configuration through CLI or directly in code (it is left for the developer to + decide how such configuration is loaded and made available to the auth provider) - this is possibly the least secure + and should be used for testing The intention is to start with two minimal but useful Auth providers: -- Basic Auth - base64 encoded user and password credentials. The credentials will be static in nature and defined via auth provider config +- Basic Auth - base64 encoded user and password credentials. The credentials will be static in nature and defined via + auth provider config - Token - A simple static token implementation Both of the above providers will rely on the `Authorization` header to achieve their functionality. @@ -57,17 +147,21 @@ Further work: - Introduction of JWT and mTLS auth providers - API Keys -- Chroma managed user store - this would be similar to what standard DBMS’ are doing today - maintain a table with users and salted password hashes +- Chroma managed user store - this would be similar to what standard DBMS’ are doing today - maintain a table with users + and salted password hashes - K8s RBAC integration (for cloud-native deployments) - GCP service accounts? - SPIFFE and SPIRE integrations -- Go and Java client-side auth providers (for other impl like Rust and Ruby, we need to discuss with respective maintainers) +- Go and Java client-side auth providers (for other impl like Rust and Ruby, we need to discuss with respective + maintainers) -> Note: this CIP intentionally does not tackle authZ but acknowledges that authN and authZ must work in tandem in future releases +> Note: this CIP intentionally does not tackle authZ but acknowledges that authN and authZ must work in tandem in future +> releases ## **Compatibility, Deprecation, and Migration Plan** -This change, introducing a pluggable auth framework is no impacting compatibility of existing deployments and users can upgrade and use the new framework without the need for migration. +This change, introducing a pluggable auth framework is no impacting compatibility of existing deployments and users can +upgrade and use the new framework without the need for migration. No deprecations. @@ -77,8 +171,12 @@ We will introduce a new set of tests to verify both client and server-side auth ## **Rejected Alternatives** -We have considered direct middleware Auth or existing third-party libraries for FastAPI integration with auth providers, but that will create a dependency for Chroma on FastAPI itself. +We have considered direct middleware Auth or existing third-party libraries for FastAPI integration with auth providers, +but that will create a dependency for Chroma on FastAPI itself. -We have also considered using OAuth 2.0 or OIDC however the challenge there is that both of these protocols are generally intended for User (human) auth whereas in our case we have a system-to-system auth. That said there still might be room for either of these protocols, but further more in-depth use case analysis is required. +We have also considered using OAuth 2.0 or OIDC however the challenge there is that both of these protocols are +generally intended for User (human) auth whereas in our case we have a system-to-system auth. That said there still +might be room for either of these protocols, but further more in-depth use case analysis is required. -Relying entirely on external providers, while this is possible not providing out-of-the-box integrated auth capabilities is a non-starter for many enterprise customers. +Relying entirely on external providers, while this is possible not providing out-of-the-box integrated auth capabilities +is a non-starter for many enterprise customers. From 1756a9370a8d49a31aa37a0fd0f9c3152a160bbb Mon Sep 17 00:00:00 2001 From: Trayan Azarov Date: Sat, 19 Aug 2023 00:35:41 +0300 Subject: [PATCH 08/13] feat: CIP-2 Auth Providers - WIP - Added Auth credentials and Auth Configuration server-side abstractions. --- chromadb/auth/__init__.py | 102 +++++++++++++++++++++++++++++++++++--- chromadb/config.py | 12 ++++- 2 files changed, 107 insertions(+), 7 deletions(-) diff --git a/chromadb/auth/__init__.py b/chromadb/auth/__init__.py index 7c7655f439b..3f965d7ac05 100644 --- a/chromadb/auth/__init__.py +++ b/chromadb/auth/__init__.py @@ -1,14 +1,16 @@ """ Contains only Auth abstractions, no implementations. """ +import base64 from abc import ABC, abstractmethod from enum import Enum -from typing import Optional +from typing import Optional, Any, Dict import requests -from overrides import EnforceOverrides +from overrides import EnforceOverrides, overrides -from chromadb.config import Component, System # TODO remove this circular dependency +from chromadb.config import Component, System, Settings # TODO remove this circular dependency +from chromadb.errors import ChromaError from chromadb.utils import get_class @@ -58,7 +60,7 @@ class AuthInfoType(Enum): class ServerAuthenticationRequest(EnforceOverrides, ABC): @abstractmethod def get_auth_info( - self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None + self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None ) -> str: pass @@ -74,7 +76,7 @@ def __init__(self, system: System) -> None: @abstractmethod def authenticate( - self, request: ServerAuthenticationRequest + self, request: ServerAuthenticationRequest ) -> ServerAuthenticationResponse: pass @@ -85,6 +87,94 @@ def __init__(self, system: System) -> None: @abstractmethod def authenticate( - self, request: ServerAuthenticationRequest + self, request: ServerAuthenticationRequest ) -> Optional[ServerAuthenticationResponse]: pass + + +class ServerAuthConfigurationHolder(EnforceOverrides, ABC): + pass + + +class ServerAuthConfigurationProvider(Component): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def get_auth_config(self) -> Optional[ServerAuthConfigurationHolder]: + pass + + +class NoopServerAuthConfigurationProvider(ServerAuthConfigurationProvider): + def __init__(self, system: System) -> None: + super().__init__(system) + + def get_auth_config(self) -> Optional[ServerAuthConfigurationHolder]: + return None + + +class AuthenticationError(ChromaError): + + @overrides + def code(self) -> int: + return 401 + + @classmethod + @overrides + def name(cls) -> str: + return "AuthenticationError" + + +class AbstractCredentials(EnforceOverrides, ABC): + + @abstractmethod + def get_credentials(self) -> Dict[str, str]: + """ + Returns the data encapsulated by the credentials object. + """ + pass + + +class BasicAuthCredentials(AbstractCredentials): + + def __init__(self, username, password) -> None: + self.username = username + self.password = password + + def get_credentials(self) -> Dict[str, str]: + return { + "username": self.username, + "password": self.password + } + + @staticmethod + def from_header(header: str) -> "BasicAuthCredentials": + """ + Parses a basic auth header and returns a BasicAuthCredentials object. + """ + header = header.replace("Basic ", "") + header = header.strip() + base64_decoded = base64.b64decode(header).decode("utf-8") + username, password = base64_decoded.split(":") + return BasicAuthCredentials(username, password) + + +class ServerAuthCredentialsProvider(EnforceOverrides, ABC): + @abstractmethod + def validate_credentials(self, credentials: AbstractCredentials) -> bool: + pass + + +class BasicPlaintextFileServerAuthCredentialsProvider(ServerAuthCredentialsProvider): + def __init__(self, settings: Settings) -> None: + _file = settings.chroma_server_auth_credentials_file + with open(_file) as f: + _creds = f.readline().strip().split(":") + if len(_creds) != 2: + raise ValueError("Invalid basic auth data") + self._creds = ":".join(_creds) + + @overrides + def validate_credentials(self, credentials: BasicAuthCredentials) -> bool: + _creds = credentials.get_credentials() + return self._creds == f"{_creds['username']}:{_creds['password']}" diff --git a/chromadb/config.py b/chromadb/config.py index 48cb8100653..18c1391d969 100644 --- a/chromadb/config.py +++ b/chromadb/config.py @@ -102,7 +102,17 @@ class Settings(BaseSettings): # type: ignore @validator("chroma_server_auth_provider", pre=True, always=True) def chroma_server_auth_provider_non_empty(self, v) -> Optional[str]: if not v or not v.strip(): - raise ValueError("String cannot be empty or just whitespace") + raise ValueError("chroma_server_auth_provider cannot be empty or just whitespace") + return v + + chroma_server_auth_credentials_file: Optional[str] = None + + @validator("chroma_server_auth_credentials_file", pre=True, always=True) + def chroma_server_auth_credentials_file_non_empty_file_exists(self, v) -> Optional[str]: + if not v or not v.strip(): + raise ValueError("chroma_server_auth_credentials_file cannot be empty or just whitespace") + if not os.path.isfile(v): + raise ValueError(f"chroma_server_auth_credentials_file [{v}] does not exist") return v chroma_server_auth_provider_config: Optional[Union[str, Dict[str, Any]]] = None From 8b67cb82fc6260df2b13fb86412c69efbbcc1c77 Mon Sep 17 00:00:00 2001 From: Trayan Azarov Date: Sat, 19 Aug 2023 23:43:47 +0300 Subject: [PATCH 09/13] feat: CIP-2 Auth Providers - WIP - Updated abstractions - Updated CIP document (still unfinished) --- chromadb/auth/__init__.py | 192 ++++++++++++++++++++++-- chromadb/auth/fastapi.py | 52 ++++--- chromadb/config.py | 14 +- chromadb/test/auth/test_abstractions.py | 74 +++++++++ docs/CIP_2_Auth_Providers_Proposal.md | 60 +++++++- 5 files changed, 351 insertions(+), 41 deletions(-) create mode 100644 chromadb/test/auth/test_abstractions.py diff --git a/chromadb/auth/__init__.py b/chromadb/auth/__init__.py index 3f965d7ac05..fb80c729f16 100644 --- a/chromadb/auth/__init__.py +++ b/chromadb/auth/__init__.py @@ -2,17 +2,21 @@ Contains only Auth abstractions, no implementations. """ import base64 +import os from abc import ABC, abstractmethod +from collections import defaultdict from enum import Enum -from typing import Optional, Any, Dict +from typing import Optional, Any, Dict, List, Union, Type, Callable, TypeVar import requests -from overrides import EnforceOverrides, overrides +from overrides import EnforceOverrides, overrides, override -from chromadb.config import Component, System, Settings # TODO remove this circular dependency +from chromadb.config import Component, System, Settings, get_fqn # TODO remove this circular dependency from chromadb.errors import ChromaError from chromadb.utils import get_class +T = TypeVar('T') + # Re-export types from chromadb # __all__ = ["BasicAuthClientProvider", "BasicAuthServerProvider"] @@ -29,10 +33,10 @@ def authenticate(self, session: requests.Session) -> None: _provider_registry = { # TODO we need a better way to store, update and validate this registry with new providers being added - [ + ( "basic", "chromadb.auth.basic.BasicAuthClientProvider", - ]: "chromadb.auth.basic.BasicAuthClientProvider", + ): "chromadb.auth.basic.BasicAuthClientProvider", } @@ -61,7 +65,15 @@ class ServerAuthenticationRequest(EnforceOverrides, ABC): @abstractmethod def get_auth_info( self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None - ) -> str: + ) -> T: + """ + This method should return the necessary auth info based on the type of authentication (e.g. header, cookie, url) + and a given id for the respective auth type (e.g. name of the header, cookie, url param). + + :param auth_info_type: The type of auth info to return + :param auth_info_id: The id of the auth info to return + :return: The auth info which can be specific to the implementation + """ pass @@ -89,11 +101,15 @@ def __init__(self, system: System) -> None: def authenticate( self, request: ServerAuthenticationRequest ) -> Optional[ServerAuthenticationResponse]: - pass + ... + @abstractmethod + def ignore_operation(self, verb: str, path: str) -> bool: + ... -class ServerAuthConfigurationHolder(EnforceOverrides, ABC): - pass + @abstractmethod + def instrument_server(self, app: T) -> None: + ... class ServerAuthConfigurationProvider(Component): @@ -101,17 +117,101 @@ def __init__(self, system: System) -> None: super().__init__(system) @abstractmethod - def get_auth_config(self) -> Optional[ServerAuthConfigurationHolder]: + def get_configuration(self) -> Optional[T]: pass + @classmethod + @abstractmethod + def get_type(cls) -> str: + ... + + +class ServerAuthConfigurationProviderFactory: + providers = defaultdict(dict) # Organize by _type then by precedence + default_provider = None + _counter = 0 + + @classmethod + def register_provider(cls, env_vars: List[str], provider_class: ServerAuthConfigurationProvider, + precedence: Optional[int] = None): + if precedence is None: + cls._counter += 1 + precedence = cls._counter + + cls.providers[provider_class.get_type()][tuple(env_vars)] = (provider_class, precedence) + + @classmethod + def set_default_provider(cls, provider_class): + cls.default_provider = provider_class + + @classmethod + def get_provider(cls, system: System, provider_class: Optional[Union[str, Type]] = None) \ + -> Optional[ServerAuthConfigurationProvider]: + if provider_class: + _provider_class = get_class(provider_class, ServerAuthConfigurationProvider) \ + if isinstance(provider_class, str) else provider_class + _provider_by_cls = [ + provider[0] + for type_key, type_providers in cls.providers.items() + for _, provider in type_providers.items() + if provider[0] == _provider_class + ] + if len(_provider_by_cls) == 0: + raise ValueError(f"Unknown provider class: {provider_class}") + + return system.require(_provider_by_cls[0]) + available_providers = [ + (type_key, env_vars, provider) + for type_key, type_providers in cls.providers.items() + for env_vars, provider in type_providers.items() + if all(os.environ.get(env_var) for env_var in env_vars) or + all(getattr(system.settings, env_var) for env_var in env_vars + if hasattr(system.settings, env_var)) + ] + + if not available_providers: + if cls.default_provider: + return cls.default_provider() + else: + raise ValueError("No suitable provider found!") + + # Sort first by type, then by precedence within each type + sorted_providers = sorted( + available_providers, + key=lambda x: (x[0], x[2][1]) + ) + + _, _, (provider_class, _) = sorted_providers[0] + return system.require(provider_class) + + +def register_configuration_provider(*env_vars, precedence=None) -> Any: + def decorator(cls) -> Any: + ServerAuthConfigurationProviderFactory.register_provider(env_vars, cls, precedence) + return cls + + return decorator + class NoopServerAuthConfigurationProvider(ServerAuthConfigurationProvider): + """ + A no-op auth configuration provider that returns None. This is useful for cases where the auth configuration is + not required. + """ + def __init__(self, system: System) -> None: super().__init__(system) + ServerAuthConfigurationProviderFactory.set_default_provider(NoopServerAuthConfigurationProvider) - def get_auth_config(self) -> Optional[ServerAuthConfigurationHolder]: + @override + def get_configuration(self) -> Optional[str]: return None + @classmethod + @override + def get_type(cls) -> str: + return "env" + class AuthenticationError(ChromaError): @@ -141,6 +241,7 @@ def __init__(self, username, password) -> None: self.username = username self.password = password + @override def get_credentials(self) -> Dict[str, str]: return { "username": self.username, @@ -165,6 +266,71 @@ def validate_credentials(self, credentials: AbstractCredentials) -> bool: pass +class ServerAuthCredentialsProviderFactory: + providers = defaultdict(dict) # Organize by _type then by precedence + default_provider = None + _counter = 0 + + @classmethod + def register_provider(cls, env_vars: List[str], provider_class: ServerAuthCredentialsProvider, + precedence: Optional[int] = None) -> None: + if precedence is None: + cls._counter += 1 + precedence = cls._counter + + cls.providers[provider_class.get_type()][tuple(env_vars)] = (provider_class, precedence) + + @classmethod + def set_default_provider(cls, provider_class: ServerAuthCredentialsProvider): + cls.default_provider = provider_class + + @classmethod + def get_provider(cls, system: System, provider_class: Optional[Union[str, Type]] = None) \ + -> Optional[ServerAuthCredentialsProvider]: + if provider_class: + _provider_by_cls = [ + provider[0] + for type_key, type_providers in cls.providers.items() + for _, provider in type_providers.items() + if provider[0] == provider_class + ] + if len(_provider_by_cls) == 0: + raise ValueError(f"Unknown provider class: {provider_class}") + + return system.require(_provider_by_cls[0]) + available_providers = [ + (type_key, env_vars, provider) + for type_key, type_providers in cls.providers.items() + for env_vars, provider in type_providers.items() + if all(os.environ.get(env_var) for env_var in env_vars) or + all(getattr(system.settings, env_var) for env_var in env_vars + if hasattr(system.settings, env_var)) + ] + + if not available_providers: + if cls.default_provider: + return cls.default_provider() + else: + raise ValueError("No suitable provider found!") + + # Sort first by type, then by precedence within each type + sorted_providers = sorted( + available_providers, + key=lambda x: (x[0], x[2][1]) + ) + + _, _, (provider_class, _) = sorted_providers[0] + return system.require(provider_class) + + +def register_credentials_provider(*env_vars, precedence=None) -> Callable: + def decorator(cls) -> ServerAuthCredentialsProvider: + ServerAuthConfigurationProviderFactory.register_provider(env_vars, cls, precedence) + return cls + + return decorator + + class BasicPlaintextFileServerAuthCredentialsProvider(ServerAuthCredentialsProvider): def __init__(self, settings: Settings) -> None: _file = settings.chroma_server_auth_credentials_file @@ -174,7 +340,7 @@ def __init__(self, settings: Settings) -> None: raise ValueError("Invalid basic auth data") self._creds = ":".join(_creds) - @overrides - def validate_credentials(self, credentials: BasicAuthCredentials) -> bool: + @override + def validate_credentials(self, credentials: AbstractCredentials) -> bool: _creds = credentials.get_credentials() return self._creds == f"{_creds['username']}:{_creds['password']}" diff --git a/chromadb/auth/fastapi.py b/chromadb/auth/fastapi.py index 50f801e93ff..5670e848b93 100644 --- a/chromadb/auth/fastapi.py +++ b/chromadb/auth/fastapi.py @@ -2,6 +2,7 @@ import logging from typing import Optional, Dict, List +from overrides import override from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint from starlette.requests import Request from starlette.responses import Response, JSONResponse @@ -24,8 +25,9 @@ class FastAPIServerAuthenticationRequest(ServerAuthenticationRequest): def __init__(self, request: Request) -> None: self._request = request + @override def get_auth_info( - self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None + self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None ) -> str: if auth_info_type == AuthInfoType.HEADER: return self._request.headers[auth_info_id] @@ -43,6 +45,7 @@ class FastAPIServerAuthenticationResponse(ServerAuthenticationResponse): def __init__(self, response: Response) -> None: self._response = response + @override def success(self) -> bool: return self._response.status_code == 200 @@ -55,9 +58,8 @@ def __init__(self, app: ASGIApp, system: System) -> None: self._system = system self._settings = system.settings self._settings.require("chroma_server_auth_provider") - self._ignore_auth_paths: Dict[ - str, List[str] - ] = self._settings.chroma_server_auth_ignore_paths + self._ignore_auth_paths: Dict[str, List[str]] \ + = self._settings.chroma_server_auth_ignore_paths if self._settings.chroma_server_auth_provider: _cls = get_class( self._settings.chroma_server_auth_provider, ServerAuthProvider @@ -65,34 +67,44 @@ def __init__(self, app: ASGIApp, system: System) -> None: self.require(_cls) logger.debug(f"Server Auth Provider: {_cls}") - def authenticate(self, request: Request) -> Optional[Response]: + @override + def authenticate(self, request: ServerAuthenticationRequest) -> Optional[ServerAuthenticationResponse]: + return self._auth_provider.authenticate(request) + + @override + def ignore_operation(self, verb: str, path: str) -> bool: if ( - request.url.path in self._ignore_auth_paths.keys() - and request.method.upper() in self._ignore_auth_paths[request.url.path] + path in self._ignore_auth_paths.keys() + and verb.upper() in self._ignore_auth_paths[path] ): logger.debug( - f"Skipping auth for path {request.url.path} and method {request.method}" + f"Skipping auth for path {path} and method {verb}" ) - return None - response = self._auth_provider.authenticate( - FastAPIServerAuthenticationRequest(request) - ) - if response is None or not response.success(): - return JSONResponse({"error": "Unauthorized"}, status_code=401) - return None + return True + return False + + @override + def instrument_server(self, app: ASGIApp) -> None: + # We can potentially add an `/auth` endpoint to the server to allow for more complex auth flows + return class FastAPIChromaAuthMiddlewareWrapper(BaseHTTPMiddleware): def __init__( - self, app: ASGIApp, auth_middleware: FastAPIChromaAuthMiddleware + self, app: ASGIApp, auth_middleware: FastAPIChromaAuthMiddleware ) -> None: super().__init__(app) self._middleware = auth_middleware + self._middleware.instrument_server(app) + @override async def dispatch( - self, request: Request, call_next: RequestResponseEndpoint + self, request: Request, call_next: RequestResponseEndpoint ) -> Response: - resp = self._middleware.authenticate(request) - if resp is not None: - return resp + if self._middleware.ignore_operation(request.method, request.url.path): + logger.debug(f"Skipping auth for path {request.url.path} and method {request.method}") + return await call_next(request) + response = self._middleware.authenticate(FastAPIServerAuthenticationRequest(request)) + if response is None or not response.success(): + return JSONResponse({"error": "Unauthorized"}, status_code=401) return await call_next(request) diff --git a/chromadb/config.py b/chromadb/config.py index 18c1391d969..276acbf8cb0 100644 --- a/chromadb/config.py +++ b/chromadb/config.py @@ -100,22 +100,24 @@ class Settings(BaseSettings): # type: ignore chroma_server_auth_provider: Optional[str] = None @validator("chroma_server_auth_provider", pre=True, always=True) - def chroma_server_auth_provider_non_empty(self, v) -> Optional[str]: - if not v or not v.strip(): + def chroma_server_auth_provider_non_empty(cls, v) -> Optional[str]: + if v and not v.strip(): raise ValueError("chroma_server_auth_provider cannot be empty or just whitespace") return v + chroma_server_auth_configuration_provider: Optional[str] = None + chroma_server_auth_configuration_file: Optional[str] = None + chroma_server_auth_credentials_provider: Optional[str] = None chroma_server_auth_credentials_file: Optional[str] = None @validator("chroma_server_auth_credentials_file", pre=True, always=True) - def chroma_server_auth_credentials_file_non_empty_file_exists(self, v) -> Optional[str]: - if not v or not v.strip(): + def chroma_server_auth_credentials_file_non_empty_file_exists(cls, v) -> Optional[str]: + if v and not v.strip(): raise ValueError("chroma_server_auth_credentials_file cannot be empty or just whitespace") - if not os.path.isfile(v): + if v and not os.path.isfile(os.path.join(v)): raise ValueError(f"chroma_server_auth_credentials_file [{v}] does not exist") return v - chroma_server_auth_provider_config: Optional[Union[str, Dict[str, Any]]] = None chroma_client_auth_provider: Optional[str] = None chroma_server_auth_ignore_paths: Dict[str, List[str]] = { "/api/v1": ["GET"], diff --git a/chromadb/test/auth/test_abstractions.py b/chromadb/test/auth/test_abstractions.py new file mode 100644 index 00000000000..4a8694469af --- /dev/null +++ b/chromadb/test/auth/test_abstractions.py @@ -0,0 +1,74 @@ +from typing import Optional + +import pytest +from overrides import override + +from chromadb.config import System, Settings, get_fqn +from chromadb.auth import register_configuration_provider, ServerAuthConfigurationProvider, \ + ServerAuthConfigurationProviderFactory + + +@register_configuration_provider('CONF_10', 'CONF_x', precedence=10) +class ConfigurationProvider3(ServerAuthConfigurationProvider): + @override + def get_configuration(self) -> Optional[str]: + return "this is config ConfigurationProvider3" + + @classmethod + @override + def get_type(cls) -> str: + return 'file' + + +def test_register_configuration() -> None: + @register_configuration_provider('CONF_1', 'CONF_3') + class ConfigurationProvider1(ServerAuthConfigurationProvider): + @override + def get_configuration(self) -> Optional[str]: + return "this is config ConfigurationProvider1" + + @classmethod + @override + def get_type(cls) -> str: + return 'env' + + @register_configuration_provider('CONF_2', 'CONF_4', precedence=2) + class ConfigurationProvider2(ServerAuthConfigurationProvider): + @override + def get_configuration(self) -> Optional[str]: + return "this is config ConfigurationProvider2" + + @classmethod + @override + def get_type(cls) -> str: + return 'file' + + class UnregisteredConfigurationProvider1(ServerAuthConfigurationProvider): + @override + def get_configuration(self) -> Optional[str]: + return "this is config UnregisteredConfigurationProvider1" + + @classmethod + @override + def get_type(cls) -> str: + return 'file' + + class TestSettings(Settings): + CONF_1: Optional[int] = None + CONF_3: Optional[int] = None + + print(ServerAuthConfigurationProviderFactory.providers) + assert 'CONF_1' in next(iter(ServerAuthConfigurationProviderFactory.providers['env'].keys())) + assert next(iter(ServerAuthConfigurationProviderFactory.providers['env'].values()))[1] == 1 + # assert 'CONF_2' in next(iter(ServerAuthConfigurationProviderFactory.providers['file'].keys())) + # assert next(iter(ServerAuthConfigurationProviderFactory.providers['file'].values()))[1] == 2 + _s = System(TestSettings(CONF_1=1, CONF_3=2)) + assert ServerAuthConfigurationProviderFactory.get_provider(_s) is not None + assert isinstance(ServerAuthConfigurationProviderFactory.get_provider(_s), ConfigurationProvider1) + assert isinstance(ServerAuthConfigurationProviderFactory.get_provider(_s, provider_class=ConfigurationProvider2), + ConfigurationProvider2) + assert isinstance( + ServerAuthConfigurationProviderFactory.get_provider(_s, provider_class=get_fqn(ConfigurationProvider3)), + ConfigurationProvider3) + with pytest.raises(ValueError): + ServerAuthConfigurationProviderFactory.get_provider(_s, provider_class=UnregisteredConfigurationProvider1) diff --git a/docs/CIP_2_Auth_Providers_Proposal.md b/docs/CIP_2_Auth_Providers_Proposal.md index 1814a72fa74..a8a9c644c2f 100644 --- a/docs/CIP_2_Auth_Providers_Proposal.md +++ b/docs/CIP_2_Auth_Providers_Proposal.md @@ -23,9 +23,11 @@ control server and client-side auth providers. ## **Proposed Changes** -We propose two abstractions, one for the server-side and another for the [client-side.](http://client-side.In) In +We propose two abstraction groups, one for the server-side and another for the client-side. In addition we also introduce a FastAPI/startlette middleware adapter which will allow using the server-side abstractions -in the context of FastAPI. +in the context of FastAPI. For client-side we rely on `requests` + +### Architecture Overview Architecture Overview: @@ -35,6 +37,60 @@ Request Sequence: ![cip-2-seq.png](assets/cip-2-seq.png) +### Constraints + +This section provides teh architectural constraints for the authentication framework. The constraints are set of +restrictions we impose to make the design simpler and more robust. + +- There must be at most one active client-side auth provider +- There must be at most one active client-side credentials provider +- There must be at most one active server-side auth provider +- There must be at most one active server-side auth configuration provider +- There must be at most one active server-side auth credentials provider + +### Core Concepts + +- Auth Provider - an abstraction that provides authentication functionality for either client or server-side. The + provider is responsible for validating client credentials using (if available) configuration and credentials + providers. The auth provider is also responsible for carrying the Croma-leg of any authentication flow. +- Auth Configuration Provider - an abstraction that provides configuration for auth providers. The configuration can be + loaded from a file, env vars or programmatically. The configuration is used for validating and/or accessing user + credentials. Examples: secret key for JWT token based auth, DB URL for DB based auth, etc. Depending on sensitivity of + the information stored in the configuration, the provider should implement the necessary interfaces to access such + information in a secure way. +- Auth Credentials Provider - an abstraction that provides credentials for auth providers. The credentials can be + loaded from a file, env vars or programmatically. The credentials are used for validating client-side credentials (for + sever-side auth) and retrieving or generating client-side credentials (for client-side auth). + +#### Abstractions + +##### Server-Side + +We suggest multiple abstractions on the server-side to allow for easy integration with different auth providers. +We suggest the following abstractions: + +> Note: All abstractions are defined under `chromadb.auth` package + +- `ServerAuthProvider` - this is the base server auth provider abstraction that allows any server implementation of + Chroma to support variety of auth providers. The main responsibility of the auth provider is to orchestrate the auth + flow by gluing together the auth configuration and credentials providers. +- `ChromaAuthMiddleware` - The auth middleware is responsible for providing server specific + implementation of the auth middleware. This includes three general types of operations - forwarding authentication to + the auth provider, instrumenting the server if needed to support a specific auth flow, ignore certain + actions/operations (e.g. in REST this would be verb+path) that should not be authenticated. +- `ServerAuthenticationRequest` - An abstraction for querying for authentication data from server specific + implementation. +- `ServerAuthenticationResponse` - An abstraction for returning authentication data to server specific implementation. +- `ServerAuthConfigurationProvider` - this is the base abstraction for auth configuration providers. The provider is + responsible for loading auth configuration from a file, env vars or programmatically. +- `ServerAuthConfigurationProviderFactory` !!!! +- `AbstractCredentials` +- `ServerAuthCredentialsProvider` - this is the base abstraction for auth credentials providers. The provider is + responsible for verifying client credentials. +- `ServerAuthCredentialsProviderFactory` !!!! + +##### Client-Side + ### Abstractions #### Server-side Auth Provider From e66edaa8c3ee85b2d9f4d409cfc4b9e0c51babb2 Mon Sep 17 00:00:00 2001 From: Trayan Azarov Date: Mon, 21 Aug 2023 16:25:48 +0300 Subject: [PATCH 10/13] feat: CIP-2 Auth Providers - WIP Updated client and server abstractions in docs. Refs: #986 --- chromadb/auth/__init__.py | 116 ++++++++++++++++---------- docs/CIP_2_Auth_Providers_Proposal.md | 51 ++++++++++- docs/assets/cip-2-client-side-wf.png | Bin 0 -> 91473 bytes docs/assets/cip-2-server-side-wf.png | Bin 0 -> 116941 bytes 4 files changed, 120 insertions(+), 47 deletions(-) create mode 100644 docs/assets/cip-2-client-side-wf.png create mode 100644 docs/assets/cip-2-server-side-wf.png diff --git a/chromadb/auth/__init__.py b/chromadb/auth/__init__.py index fb80c729f16..6c6859b01b4 100644 --- a/chromadb/auth/__init__.py +++ b/chromadb/auth/__init__.py @@ -10,12 +10,18 @@ import requests from overrides import EnforceOverrides, overrides, override - -from chromadb.config import Component, System, Settings, get_fqn # TODO remove this circular dependency +from pydantic import SecretStr + +from chromadb.config import ( + Component, + System, + Settings, + get_fqn, +) # TODO remove this circular dependency from chromadb.errors import ChromaError from chromadb.utils import get_class -T = TypeVar('T') +T = TypeVar("T") # Re-export types from chromadb @@ -64,7 +70,7 @@ class AuthInfoType(Enum): class ServerAuthenticationRequest(EnforceOverrides, ABC): @abstractmethod def get_auth_info( - self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None + self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None ) -> T: """ This method should return the necessary auth info based on the type of authentication (e.g. header, cookie, url) @@ -88,7 +94,7 @@ def __init__(self, system: System) -> None: @abstractmethod def authenticate( - self, request: ServerAuthenticationRequest + self, request: ServerAuthenticationRequest ) -> ServerAuthenticationResponse: pass @@ -99,7 +105,7 @@ def __init__(self, system: System) -> None: @abstractmethod def authenticate( - self, request: ServerAuthenticationRequest + self, request: ServerAuthenticationRequest ) -> Optional[ServerAuthenticationResponse]: ... @@ -132,24 +138,35 @@ class ServerAuthConfigurationProviderFactory: _counter = 0 @classmethod - def register_provider(cls, env_vars: List[str], provider_class: ServerAuthConfigurationProvider, - precedence: Optional[int] = None): + def register_provider( + cls, + env_vars: List[str], + provider_class: ServerAuthConfigurationProvider, + precedence: Optional[int] = None, + ): if precedence is None: cls._counter += 1 precedence = cls._counter - cls.providers[provider_class.get_type()][tuple(env_vars)] = (provider_class, precedence) + cls.providers[provider_class.get_type()][tuple(env_vars)] = ( + provider_class, + precedence, + ) @classmethod def set_default_provider(cls, provider_class): cls.default_provider = provider_class @classmethod - def get_provider(cls, system: System, provider_class: Optional[Union[str, Type]] = None) \ - -> Optional[ServerAuthConfigurationProvider]: + def get_provider( + cls, system: System, provider_class: Optional[Union[str, Type]] = None + ) -> Optional[ServerAuthConfigurationProvider]: if provider_class: - _provider_class = get_class(provider_class, ServerAuthConfigurationProvider) \ - if isinstance(provider_class, str) else provider_class + _provider_class = ( + get_class(provider_class, ServerAuthConfigurationProvider) + if isinstance(provider_class, str) + else provider_class + ) _provider_by_cls = [ provider[0] for type_key, type_providers in cls.providers.items() @@ -164,9 +181,12 @@ def get_provider(cls, system: System, provider_class: Optional[Union[str, Type]] (type_key, env_vars, provider) for type_key, type_providers in cls.providers.items() for env_vars, provider in type_providers.items() - if all(os.environ.get(env_var) for env_var in env_vars) or - all(getattr(system.settings, env_var) for env_var in env_vars - if hasattr(system.settings, env_var)) + if all(os.environ.get(env_var) for env_var in env_vars) + or all( + getattr(system.settings, env_var) + for env_var in env_vars + if hasattr(system.settings, env_var) + ) ] if not available_providers: @@ -176,10 +196,7 @@ def get_provider(cls, system: System, provider_class: Optional[Union[str, Type]] raise ValueError("No suitable provider found!") # Sort first by type, then by precedence within each type - sorted_providers = sorted( - available_providers, - key=lambda x: (x[0], x[2][1]) - ) + sorted_providers = sorted(available_providers, key=lambda x: (x[0], x[2][1])) _, _, (provider_class, _) = sorted_providers[0] return system.require(provider_class) @@ -187,7 +204,9 @@ def get_provider(cls, system: System, provider_class: Optional[Union[str, Type]] def register_configuration_provider(*env_vars, precedence=None) -> Any: def decorator(cls) -> Any: - ServerAuthConfigurationProviderFactory.register_provider(env_vars, cls, precedence) + ServerAuthConfigurationProviderFactory.register_provider( + env_vars, cls, precedence + ) return cls return decorator @@ -201,7 +220,9 @@ class NoopServerAuthConfigurationProvider(ServerAuthConfigurationProvider): def __init__(self, system: System) -> None: super().__init__(system) - ServerAuthConfigurationProviderFactory.set_default_provider(NoopServerAuthConfigurationProvider) + ServerAuthConfigurationProviderFactory.set_default_provider( + NoopServerAuthConfigurationProvider + ) @override def get_configuration(self) -> Optional[str]: @@ -214,7 +235,6 @@ def get_type(cls) -> str: class AuthenticationError(ChromaError): - @overrides def code(self) -> int: return 401 @@ -226,9 +246,13 @@ def name(cls) -> str: class AbstractCredentials(EnforceOverrides, ABC): + """ + The class is used by Auth Providers to encapsulate credentials received from the server + and pass them to a ServerAuthCredentialsProvider. + """ @abstractmethod - def get_credentials(self) -> Dict[str, str]: + def get_credentials(self) -> Dict[str, Union[str, int, float, bool, SecretStr]]: """ Returns the data encapsulated by the credentials object. """ @@ -236,17 +260,13 @@ def get_credentials(self) -> Dict[str, str]: class BasicAuthCredentials(AbstractCredentials): - def __init__(self, username, password) -> None: self.username = username self.password = password @override - def get_credentials(self) -> Dict[str, str]: - return { - "username": self.username, - "password": self.password - } + def get_credentials(self) -> Dict[str, Union[str, int, float, bool, SecretStr]]: + return {"username": self.username, "password": self.password} @staticmethod def from_header(header: str) -> "BasicAuthCredentials": @@ -272,21 +292,29 @@ class ServerAuthCredentialsProviderFactory: _counter = 0 @classmethod - def register_provider(cls, env_vars: List[str], provider_class: ServerAuthCredentialsProvider, - precedence: Optional[int] = None) -> None: + def register_provider( + cls, + env_vars: List[str], + provider_class: ServerAuthCredentialsProvider, + precedence: Optional[int] = None, + ) -> None: if precedence is None: cls._counter += 1 precedence = cls._counter - cls.providers[provider_class.get_type()][tuple(env_vars)] = (provider_class, precedence) + cls.providers[provider_class.get_type()][tuple(env_vars)] = ( + provider_class, + precedence, + ) @classmethod def set_default_provider(cls, provider_class: ServerAuthCredentialsProvider): cls.default_provider = provider_class @classmethod - def get_provider(cls, system: System, provider_class: Optional[Union[str, Type]] = None) \ - -> Optional[ServerAuthCredentialsProvider]: + def get_provider( + cls, system: System, provider_class: Optional[Union[str, Type]] = None + ) -> Optional[ServerAuthCredentialsProvider]: if provider_class: _provider_by_cls = [ provider[0] @@ -302,9 +330,12 @@ def get_provider(cls, system: System, provider_class: Optional[Union[str, Type]] (type_key, env_vars, provider) for type_key, type_providers in cls.providers.items() for env_vars, provider in type_providers.items() - if all(os.environ.get(env_var) for env_var in env_vars) or - all(getattr(system.settings, env_var) for env_var in env_vars - if hasattr(system.settings, env_var)) + if all(os.environ.get(env_var) for env_var in env_vars) + or all( + getattr(system.settings, env_var) + for env_var in env_vars + if hasattr(system.settings, env_var) + ) ] if not available_providers: @@ -314,10 +345,7 @@ def get_provider(cls, system: System, provider_class: Optional[Union[str, Type]] raise ValueError("No suitable provider found!") # Sort first by type, then by precedence within each type - sorted_providers = sorted( - available_providers, - key=lambda x: (x[0], x[2][1]) - ) + sorted_providers = sorted(available_providers, key=lambda x: (x[0], x[2][1])) _, _, (provider_class, _) = sorted_providers[0] return system.require(provider_class) @@ -325,7 +353,9 @@ def get_provider(cls, system: System, provider_class: Optional[Union[str, Type]] def register_credentials_provider(*env_vars, precedence=None) -> Callable: def decorator(cls) -> ServerAuthCredentialsProvider: - ServerAuthConfigurationProviderFactory.register_provider(env_vars, cls, precedence) + ServerAuthConfigurationProviderFactory.register_provider( + env_vars, cls, precedence + ) return cls return decorator diff --git a/docs/CIP_2_Auth_Providers_Proposal.md b/docs/CIP_2_Auth_Providers_Proposal.md index a8a9c644c2f..1311a6a30be 100644 --- a/docs/CIP_2_Auth_Providers_Proposal.md +++ b/docs/CIP_2_Auth_Providers_Proposal.md @@ -74,7 +74,7 @@ We suggest the following abstractions: - `ServerAuthProvider` - this is the base server auth provider abstraction that allows any server implementation of Chroma to support variety of auth providers. The main responsibility of the auth provider is to orchestrate the auth flow by gluing together the auth configuration and credentials providers. -- `ChromaAuthMiddleware` - The auth middleware is responsible for providing server specific +- `ChromaAuthMiddleware` - The auth middleware is effectively an adapter responsible for providing server specific implementation of the auth middleware. This includes three general types of operations - forwarding authentication to the auth provider, instrumenting the server if needed to support a specific auth flow, ignore certain actions/operations (e.g. in REST this would be verb+path) that should not be authenticated. @@ -83,14 +83,57 @@ We suggest the following abstractions: - `ServerAuthenticationResponse` - An abstraction for returning authentication data to server specific implementation. - `ServerAuthConfigurationProvider` - this is the base abstraction for auth configuration providers. The provider is responsible for loading auth configuration from a file, env vars or programmatically. -- `ServerAuthConfigurationProviderFactory` !!!! -- `AbstractCredentials` +- `ServerAuthConfigurationProviderFactory` - a factory and a register for server auth configuration providers. The basic + idea is that providers will be pluggable as such they need to register with this class in order to be eligible for + instantiation through Settings and env vars. +- `AbstractCredentials` - base abstraction for credentials encapsulation from server to Auth Credentials Provider. - `ServerAuthCredentialsProvider` - this is the base abstraction for auth credentials providers. The provider is responsible for verifying client credentials. -- `ServerAuthCredentialsProviderFactory` !!!! +- `ServerAuthCredentialsProviderFactory` - a factory and a register for server auth credentials providers. The basic + idea is that providers will be pluggable as such they need to register with this class in order to be eligible for + instantiation through Settings and env vars. ##### Client-Side +We suggest multiple abstractions on the client-side to allow for easy integration with different auth providers. + +- `ClientAuthProvider` - this is the base client auth provider abstraction that allows any client implementation of + Chroma to support variety of auth providers. The main responsibility of the auth provider is to orchestrate the auth + flow by gluing together the auth configuration and credentials providers, and any possible auth workflows (e.g. OAuth) +- `ClientAuthConfigurationProvider` - this is the base abstraction for auth configuration providers. The provider is + responsible for loading auth configuration from a file, env vars or programmatically. +- `ClientAuthConfigurationProviderFactory` - a factory and a register for client auth configuration providers. The basic + idea is that providers will be pluggable as such they need to register with this class in order to be eligible for + instantiation through Settings and env vars. +- `ClientAuthCredentialsProvider` - this is the base abstraction for auth credentials providers. The provider is + responsible for verifying client credentials. +- `ClientAuthCredentialsProviderFactory` - a factory and a register for client auth credentials providers. The basic + idea is that providers will be pluggable as such they need to register with this class in order to be eligible for + instantiation through Settings and env vars. +- `AbstractCredentials` - base abstraction for credentials encapsulation from client to Auth Credentials Provider. +- `ClientAuthProtocolAdapter` - this is an abstraction that allows for client-side auth providers to communicate with + backends using variety of protocols and libraries (e.g. `requests`, `gRPC` etc). The adapter is responsible for + translating the auth requests to generated by the credentials provider to a protocol specific message. + +#### Workflows + +##### Server-Side + +![cip-2-server-side-wf.png](assets/cip-2-server-side-wf.png) + +##### Client-Side + +![cip-2-client-side-wf.png](assets/cip-2-client-side-wf.png) + +### Configuration + +#### Server-side + +TBD + +#### Client-side + + ### Abstractions #### Server-side Auth Provider diff --git a/docs/assets/cip-2-client-side-wf.png b/docs/assets/cip-2-client-side-wf.png new file mode 100644 index 0000000000000000000000000000000000000000..82d49898f8804b8b1482f9a4bfee2d7eb0e74473 GIT binary patch literal 91473 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 Date: Tue, 22 Aug 2023 04:31:47 +0300 Subject: [PATCH 11/13] feat: CIP-2 Auth Providers - Basic Auth implemented - Simple tests for valid/invalid credentials added Refs: #986 --- chromadb/api/fastapi.py | 22 +- chromadb/auth/README.md | 46 --- chromadb/auth/__init__.py | 345 +++++++----------- chromadb/auth/basic/__init__.py | 169 ++++----- chromadb/auth/fastapi.py | 57 +-- chromadb/config.py | 28 +- chromadb/test/auth/test_abstractions.py | 74 ---- chromadb/test/conftest.py | 111 +++--- docs/CIP_2_Auth_Providers_Proposal.md | 95 +---- .../basic_functionality/client_auth.ipynb | 62 ++-- pyproject.toml | 3 +- requirements.txt | 1 + 12 files changed, 386 insertions(+), 627 deletions(-) delete mode 100644 chromadb/auth/README.md delete mode 100644 chromadb/test/auth/test_abstractions.py diff --git a/chromadb/api/fastapi.py b/chromadb/api/fastapi.py index 7c0387ff2d4..09adef3e440 100644 --- a/chromadb/api/fastapi.py +++ b/chromadb/api/fastapi.py @@ -1,6 +1,10 @@ from typing import Optional, cast from chromadb.api import API -from chromadb.auth import ClientAuthProvider +from chromadb.auth import ( + ClientAuthProvider, + ClientAuthProtocolAdapter, + RequestsClientAuthProtocolAdapter, +) from chromadb.config import Settings, System, get_class from chromadb.api.types import ( Documents, @@ -55,11 +59,21 @@ def __init__(self, system: System): ) self._header = system.settings.chroma_server_headers - self._session = requests.Session() + if ( + system.settings.chroma_client_auth_provider + and system.settings.chroma_client_auth_protocol_adapter + ): + self._adapter = system.require( + get_class( + system.settings.chroma_client_auth_protocol_adapter, + RequestsClientAuthProtocolAdapter, + ) + ) + self._session = self._adapter.session + else: + self._session = requests.Session() if self._header is not None: self._session.headers.update(self._header) - # if system.auth_provider is not None: - # system.auth_provider.authenticate(self._session) @override def heartbeat(self) -> int: diff --git a/chromadb/auth/README.md b/chromadb/auth/README.md deleted file mode 100644 index 309b29d1410..00000000000 --- a/chromadb/auth/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# Chroma Server Middlewares - -## Basic Auth - -This is very rudimentary security middleware that checks Authorization headers for basic auth credentials. - -The basic auth user and pass are configured on the server side using `CHROMA_SERVER_AUTH_PROVIDER_CONFIG`. Make sure to -also define the auth provider `CHROMA_SERVER_AUTH_PROVIDER="chromadb.auth.BasicAuthServerProvider"`. - -### Usage - -Start the server: - -```bash -CHROMA_SERVER_AUTH_PROVIDER="chromadb.BasicAuthServerProvider" \ -CHROMA_SERVER_AUTH_PROVIDER_CONFIG='{"username":"admin","password":"admin"}' \ -ALLOW_RESET=1 \ -IS_PERSISTENT=1 \ -uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 --proxy-headers --log-config log_config.yml --reload -``` - -Test request with `curl`: - -```bash -curl http://localhost:8000/api/v1 -v -H "Authorization: Basic YWRtaW46YWRtaW4=" -``` - -Test with client side auth provider: - -```python -import chromadb -from chromadb import Settings - -client = chromadb.HttpClient(settings=Settings(chroma_client_auth_provider="chromadb.auth.BasicAuthClientProvider", - chroma_client_auth_provider_config={"username": "admin", "password": "admin"})) -client.heartbeat() -``` - -Test with Http Client and basic auth header: - -```python -import chromadb - -client = chromadb.HttpClient(host="localhost", port="8000", headers={"Authorization": "Basic YWRtaW46YWRtaW4="}) -client.heartbeat() -``` diff --git a/chromadb/auth/__init__.py b/chromadb/auth/__init__.py index 6c6859b01b4..d1ed9784674 100644 --- a/chromadb/auth/__init__.py +++ b/chromadb/auth/__init__.py @@ -6,8 +6,21 @@ from abc import ABC, abstractmethod from collections import defaultdict from enum import Enum -from typing import Optional, Any, Dict, List, Union, Type, Callable, TypeVar - +from typing import ( + Optional, + Any, + Dict, + List, + Union, + Type, + Callable, + TypeVar, + Tuple, + Generic, + Mapping, +) + +import bcrypt import requests from overrides import EnforceOverrides, overrides, override from pydantic import SecretStr @@ -22,21 +35,121 @@ from chromadb.utils import get_class T = TypeVar("T") +S = TypeVar("S") # Re-export types from chromadb # __all__ = ["BasicAuthClientProvider", "BasicAuthServerProvider"] +class AuthInfoType(Enum): + COOKIE = "cookie" + HEADER = "header" + URL = "url" + METADATA = "metadata" # gRPC + + +class ClientAuthResponse(EnforceOverrides, ABC): + @abstractmethod + def get_auth_info_type(self) -> AuthInfoType: + ... + + @abstractmethod + def get_auth_info(self) -> Tuple[str, SecretStr]: + ... + + class ClientAuthProvider(Component): def __init__(self, system: System) -> None: super().__init__(system) @abstractmethod - def authenticate(self, session: requests.Session) -> None: + def authenticate(self) -> ClientAuthResponse: + pass + + +class ClientAuthConfigurationProvider(Component): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def get_configuration(self) -> Optional[T]: + pass + + +class ClientAuthCredentialsProvider(Component, Generic[T]): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def get_credentials(self) -> T: + pass + + +class ClientAuthProtocolAdapter(Component): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def inject_credentials(self, injection_context: T) -> None: pass +class RequestsClientAuthProtocolAdapter(ClientAuthProtocolAdapter): + class _Session(requests.Session): + _protocol_adapter: ClientAuthProtocolAdapter + + def __init__(self, protocol_adapter: ClientAuthProtocolAdapter) -> None: + super().__init__() + self._protocol_adapter = protocol_adapter + + @override + def send( + self, request: requests.PreparedRequest, **kwargs: Any + ) -> requests.Response: + self._protocol_adapter.inject_credentials(request) + return super().send(request, **kwargs) + + _session: _Session + _auth_provider: ClientAuthProvider + + def __init__(self, system: System) -> None: + super().__init__(system) + system.settings.require("chroma_client_auth_provider") + self._auth_provider = system.require( + get_class(system.settings.chroma_client_auth_provider, ClientAuthProvider) + ) + self._session = self._Session(self) + self._auth_header = self._auth_provider.authenticate() + + @property + def session(self) -> requests.Session: + return self._session + + @override + def inject_credentials(self, injection_context: requests.PreparedRequest) -> None: + if self._auth_header.get_auth_info_type() == AuthInfoType.HEADER: + _header_info = self._auth_header.get_auth_info() + injection_context.headers[_header_info[0]] = _header_info[1] + else: + raise ValueError( + f"Unsupported auth type: {self._auth_header.get_auth_info_type()}" + ) + + +class ConfigurationClientAuthCredentialsProvider(ClientAuthCredentialsProvider): + _creds: SecretStr + + def __init__(self, system: System) -> None: + super().__init__(system) + system.settings.require("chroma_client_auth_credentials") + self._creds = SecretStr(system.settings.chroma_client_auth_credentials) + + @override + def get_credentials(self) -> SecretStr: + return self._creds + + _provider_registry = { # TODO we need a better way to store, update and validate this registry with new providers being added ( @@ -60,14 +173,7 @@ def resolve_client_auth_provider(classOrName) -> "ClientAuthProvider": ### SERVER-SIDE Abstractions -class AuthInfoType(Enum): - COOKIE = "cookie" - HEADER = "header" - URL = "url" - METADATA = "metadata" # gRPC - - -class ServerAuthenticationRequest(EnforceOverrides, ABC): +class ServerAuthenticationRequest(EnforceOverrides, ABC, Generic[T]): @abstractmethod def get_auth_info( self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None @@ -93,9 +199,7 @@ def __init__(self, system: System) -> None: super().__init__(system) @abstractmethod - def authenticate( - self, request: ServerAuthenticationRequest - ) -> ServerAuthenticationResponse: + def authenticate(self, request: ServerAuthenticationRequest) -> bool: pass @@ -126,113 +230,6 @@ def __init__(self, system: System) -> None: def get_configuration(self) -> Optional[T]: pass - @classmethod - @abstractmethod - def get_type(cls) -> str: - ... - - -class ServerAuthConfigurationProviderFactory: - providers = defaultdict(dict) # Organize by _type then by precedence - default_provider = None - _counter = 0 - - @classmethod - def register_provider( - cls, - env_vars: List[str], - provider_class: ServerAuthConfigurationProvider, - precedence: Optional[int] = None, - ): - if precedence is None: - cls._counter += 1 - precedence = cls._counter - - cls.providers[provider_class.get_type()][tuple(env_vars)] = ( - provider_class, - precedence, - ) - - @classmethod - def set_default_provider(cls, provider_class): - cls.default_provider = provider_class - - @classmethod - def get_provider( - cls, system: System, provider_class: Optional[Union[str, Type]] = None - ) -> Optional[ServerAuthConfigurationProvider]: - if provider_class: - _provider_class = ( - get_class(provider_class, ServerAuthConfigurationProvider) - if isinstance(provider_class, str) - else provider_class - ) - _provider_by_cls = [ - provider[0] - for type_key, type_providers in cls.providers.items() - for _, provider in type_providers.items() - if provider[0] == _provider_class - ] - if len(_provider_by_cls) == 0: - raise ValueError(f"Unknown provider class: {provider_class}") - - return system.require(_provider_by_cls[0]) - available_providers = [ - (type_key, env_vars, provider) - for type_key, type_providers in cls.providers.items() - for env_vars, provider in type_providers.items() - if all(os.environ.get(env_var) for env_var in env_vars) - or all( - getattr(system.settings, env_var) - for env_var in env_vars - if hasattr(system.settings, env_var) - ) - ] - - if not available_providers: - if cls.default_provider: - return cls.default_provider() - else: - raise ValueError("No suitable provider found!") - - # Sort first by type, then by precedence within each type - sorted_providers = sorted(available_providers, key=lambda x: (x[0], x[2][1])) - - _, _, (provider_class, _) = sorted_providers[0] - return system.require(provider_class) - - -def register_configuration_provider(*env_vars, precedence=None) -> Any: - def decorator(cls) -> Any: - ServerAuthConfigurationProviderFactory.register_provider( - env_vars, cls, precedence - ) - return cls - - return decorator - - -class NoopServerAuthConfigurationProvider(ServerAuthConfigurationProvider): - """ - A no-op auth configuration provider that returns None. This is useful for cases where the auth configuration is - not required. - """ - - def __init__(self, system: System) -> None: - super().__init__(system) - ServerAuthConfigurationProviderFactory.set_default_provider( - NoopServerAuthConfigurationProvider - ) - - @override - def get_configuration(self) -> Optional[str]: - return None - - @classmethod - @override - def get_type(cls) -> str: - return "env" - class AuthenticationError(ChromaError): @overrides @@ -277,100 +274,38 @@ def from_header(header: str) -> "BasicAuthCredentials": header = header.strip() base64_decoded = base64.b64decode(header).decode("utf-8") username, password = base64_decoded.split(":") - return BasicAuthCredentials(username, password) + return BasicAuthCredentials(SecretStr(username), SecretStr(password)) -class ServerAuthCredentialsProvider(EnforceOverrides, ABC): +class ServerAuthCredentialsProvider(Component): + def __init__(self, system: System) -> None: + super().__init__(system) + @abstractmethod def validate_credentials(self, credentials: AbstractCredentials) -> bool: pass -class ServerAuthCredentialsProviderFactory: - providers = defaultdict(dict) # Organize by _type then by precedence - default_provider = None - _counter = 0 - - @classmethod - def register_provider( - cls, - env_vars: List[str], - provider_class: ServerAuthCredentialsProvider, - precedence: Optional[int] = None, - ) -> None: - if precedence is None: - cls._counter += 1 - precedence = cls._counter - - cls.providers[provider_class.get_type()][tuple(env_vars)] = ( - provider_class, - precedence, - ) - - @classmethod - def set_default_provider(cls, provider_class: ServerAuthCredentialsProvider): - cls.default_provider = provider_class - - @classmethod - def get_provider( - cls, system: System, provider_class: Optional[Union[str, Type]] = None - ) -> Optional[ServerAuthCredentialsProvider]: - if provider_class: - _provider_by_cls = [ - provider[0] - for type_key, type_providers in cls.providers.items() - for _, provider in type_providers.items() - if provider[0] == provider_class - ] - if len(_provider_by_cls) == 0: - raise ValueError(f"Unknown provider class: {provider_class}") - - return system.require(_provider_by_cls[0]) - available_providers = [ - (type_key, env_vars, provider) - for type_key, type_providers in cls.providers.items() - for env_vars, provider in type_providers.items() - if all(os.environ.get(env_var) for env_var in env_vars) - or all( - getattr(system.settings, env_var) - for env_var in env_vars - if hasattr(system.settings, env_var) - ) - ] - - if not available_providers: - if cls.default_provider: - return cls.default_provider() - else: - raise ValueError("No suitable provider found!") - - # Sort first by type, then by precedence within each type - sorted_providers = sorted(available_providers, key=lambda x: (x[0], x[2][1])) - - _, _, (provider_class, _) = sorted_providers[0] - return system.require(provider_class) - +class HtpasswdServerAuthCredentialsProvider(ServerAuthCredentialsProvider): + _creds: List[SecretStr] -def register_credentials_provider(*env_vars, precedence=None) -> Callable: - def decorator(cls) -> ServerAuthCredentialsProvider: - ServerAuthConfigurationProviderFactory.register_provider( - env_vars, cls, precedence - ) - return cls - - return decorator - - -class BasicPlaintextFileServerAuthCredentialsProvider(ServerAuthCredentialsProvider): - def __init__(self, settings: Settings) -> None: - _file = settings.chroma_server_auth_credentials_file + def __init__(self, system: System) -> None: + super().__init__(system) + system.settings.require("chroma_server_auth_credentials_file") + _file = system.settings.chroma_server_auth_credentials_file with open(_file) as f: - _creds = f.readline().strip().split(":") - if len(_creds) != 2: - raise ValueError("Invalid basic auth data") - self._creds = ":".join(_creds) + self._creds = [SecretStr(v) for v in f.readline().strip().split(":")] + if len(self._creds) != 2: + raise ValueError( + f"Invalid Htpasswd credentials file [{_file}]. Must be :." + ) @override def validate_credentials(self, credentials: AbstractCredentials) -> bool: _creds = credentials.get_credentials() - return self._creds == f"{_creds['username']}:{_creds['password']}" + return _creds["username"].get_secret_value() == self._creds[ + 0 + ].get_secret_value() and bcrypt.checkpw( + _creds["password"].get_secret_value().encode("utf-8"), + self._creds[1].get_secret_value().encode("utf-8"), + ) diff --git a/chromadb/auth/basic/__init__.py b/chromadb/auth/basic/__init__.py index b88d907ef64..1e909775d90 100644 --- a/chromadb/auth/basic/__init__.py +++ b/chromadb/auth/basic/__init__.py @@ -1,11 +1,28 @@ import base64 +import logging import os +from typing import Tuple import requests -from overrides import overrides +from overrides import override from pydantic import SecretStr -from chromadb.auth import ServerAuthProvider +from chromadb.config import System, Settings +from chromadb.auth import ( + ServerAuthProvider, + ClientAuthProvider, + ServerAuthenticationRequest, + ServerAuthCredentialsProvider, + AuthInfoType, + BasicAuthCredentials, + AuthenticationError, + ClientAuthCredentialsProvider, + ClientAuthProtocolAdapter, + ClientAuthResponse, +) +from chromadb.utils import get_class + +logger = logging.getLogger(__name__) def _encode_credentials(username: str, password: str) -> SecretStr: @@ -14,105 +31,69 @@ def _encode_credentials(username: str, password: str) -> SecretStr: ) +class BasicAuthClientAuthResponse(ClientAuthResponse): + def __init__(self, credentials: SecretStr) -> None: + self._credentials = credentials + + @override + def get_auth_info_type(self) -> AuthInfoType: + return AuthInfoType.HEADER + + @override + def get_auth_info(self) -> Tuple[str, SecretStr]: + return "Authorization", f"Basic {self._credentials.get_secret_value()}" + + class BasicAuthClientProvider(ClientAuthProvider): - _basic_auth_token: SecretStr - - def __init__(self, settings: "Settings") -> None: - super().__init__(settings) - self._settings = settings - if os.environ.get("CHROMA_CLIENT_AUTH_BASIC_USERNAME") and os.environ.get( - "CHROMA_CLIENT_AUTH_BASIC_PASSWORD" - ): - self._basic_auth_token = _encode_credentials( - os.environ.get("CHROMA_CLIENT_AUTH_BASIC_USERNAME", ""), - os.environ.get("CHROMA_CLIENT_AUTH_BASIC_PASSWORD", ""), + _credentials_provider: ClientAuthCredentialsProvider + _protocol_adapter: ClientAuthProtocolAdapter + + def __init__(self, system: System) -> None: + super().__init__(system) + self._settings = system.settings + system.settings.require("chroma_client_auth_credentials_provider") + self._credentials_provider = system.require( + get_class( + system.settings.chroma_client_auth_credentials_provider, + ClientAuthCredentialsProvider, ) - elif isinstance( - self._settings.chroma_client_auth_provider_config, str - ) and os.path.exists(self._settings.chroma_client_auth_provider_config): - with open(self._settings.chroma_client_auth_provider_config) as f: - # read first line of file which should be user:password - _auth_data = f.readline().strip().split(":") - # validate auth data - if len(_auth_data) != 2: - raise ValueError("Invalid auth data") - self._basic_auth_token = _encode_credentials( - _auth_data[0], _auth_data[1] + ) + + @override + def authenticate(self) -> ClientAuthResponse: + _creds = self._credentials_provider.get_credentials() + return BasicAuthClientAuthResponse( + SecretStr( + base64.b64encode(f"{_creds.get_secret_value()}".encode("utf-8")).decode( + "utf-8" ) - elif self._settings.chroma_client_auth_provider_config and isinstance( - self._settings.chroma_client_auth_provider_config, dict - ): - self._basic_auth_token = _encode_credentials( - self._settings.chroma_client_auth_provider_config["username"], - self._settings.chroma_client_auth_provider_config["password"], ) - else: - raise ValueError("Basic auth credentials not found") - - @overrides - def authenticate(self, session: requests.Session) -> None: - session.headers.update( - {"Authorization": f"Basic {self._basic_auth_token.get_secret_value()}"} ) class BasicAuthServerProvider(ServerAuthProvider): - _basic_auth_token: SecretStr - - def __init__(self, settings: "Settings") -> None: - super().__init__(settings) - self._settings = settings - self._basic_auth_token = SecretStr("") - if os.environ.get("CHROMA_SERVER_AUTH_BASIC_USERNAME") and os.environ.get( - "CHROMA_SERVER_AUTH_BASIC_PASSWORD" - ): - self._basic_auth_token = _encode_credentials( - os.environ.get("CHROMA_SERVER_AUTH_BASIC_USERNAME", ""), - os.environ.get("CHROMA_SERVER_AUTH_BASIC_PASSWORD", ""), + _credentials_provider: ServerAuthCredentialsProvider + + def __init__(self, system: System) -> None: + super().__init__(system) + self._settings = system.settings + system.settings.require("chroma_server_auth_credentials_provider") + self._credentials_provider = system.require( + get_class( + system.settings.chroma_server_auth_credentials_provider, + ServerAuthCredentialsProvider, ) - self._ignore_auth_paths = os.environ.get( - "CHROMA_SERVER_AUTH_IGNORE_PATHS", ",".join(self._ignore_auth_paths) - ).split(",") - elif isinstance( - self._settings.chroma_server_auth_provider_config, str - ) and os.path.exists(self._settings.chroma_server_auth_provider_config): - with open(self._settings.chroma_server_auth_provider_config) as f: - # read first line of file which should be user:password - _auth_data = f.readline().strip().split(":") - # validate auth data - if len(_auth_data) != 2: - raise ValueError("Invalid auth data") - self._basic_auth_token = _create_token(_auth_data[0], _auth_data[1]) - self._ignore_auth_paths = os.environ.get( - "CHROMA_SERVER_AUTH_IGNORE_PATHS", ",".join(self._ignore_auth_paths) - ).split(",") - elif self._settings.chroma_server_auth_provider_config and isinstance( - self._settings.chroma_server_auth_provider_config, dict - ): - # encode the username and password base64 - self._basic_auth_token = _create_token( - self._settings.chroma_server_auth_provider_config["username"], - self._settings.chroma_server_auth_provider_config["password"], + ) + + @override + def authenticate(self, request: ServerAuthenticationRequest) -> bool: + try: + # print(f"BasicAuthServerProvider.authenticate: {}") + _auth_header = request.get_auth_info(AuthInfoType.HEADER, "Authorization") + return self._credentials_provider.validate_credentials( + BasicAuthCredentials.from_header(_auth_header) ) - if "ignore_auth_paths" in self._settings.chroma_server_auth_provider_config: - self._ignore_auth_paths = ( - self._settings.chroma_server_auth_provider_config[ - "ignore_auth_paths" - ] - ) - else: - raise ValueError("Basic auth credentials not found") - - @overrides - def authenticate(self, request: Request) -> Union[Response, None]: - auth_header = request.headers.get("Authorization", "").split() - # Check if the header exists and the token is correct - if request.url.path in self._ignore_auth_paths: - logger.debug(f"Skipping auth for path {request.url.path}") - return None - if ( - len(auth_header) != 2 - or auth_header[1] != self._basic_auth_token.get_secret_value() - ): - return JSONResponse({"error": "Unauthorized"}, status_code=401) - return None + except Exception as e: + logger.error(f"BasicAuthServerProvider.authenticate failed: {repr(e)}") + return False + # raise AuthenticationError() diff --git a/chromadb/auth/fastapi.py b/chromadb/auth/fastapi.py index 5670e848b93..88f03e5aabd 100644 --- a/chromadb/auth/fastapi.py +++ b/chromadb/auth/fastapi.py @@ -21,13 +21,13 @@ logger = logging.getLogger(__name__) -class FastAPIServerAuthenticationRequest(ServerAuthenticationRequest): +class FastAPIServerAuthenticationRequest(ServerAuthenticationRequest[str]): def __init__(self, request: Request) -> None: self._request = request @override def get_auth_info( - self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None + self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None ) -> str: if auth_info_type == AuthInfoType.HEADER: return self._request.headers[auth_info_id] @@ -42,44 +42,51 @@ def get_auth_info( class FastAPIServerAuthenticationResponse(ServerAuthenticationResponse): - def __init__(self, response: Response) -> None: - self._response = response + _auth_success: bool + + def __init__(self, auth_success) -> None: + self._auth_success = auth_success @override def success(self) -> bool: - return self._response.status_code == 200 + return self._auth_success -class FastAPIChromaAuthMiddleware(ChromaAuthMiddleware): # type: ignore +class FastAPIChromaAuthMiddleware(ChromaAuthMiddleware): _auth_provider: ServerAuthProvider - def __init__(self, app: ASGIApp, system: System) -> None: + def __init__(self, system: System) -> None: super().__init__(system) self._system = system self._settings = system.settings self._settings.require("chroma_server_auth_provider") - self._ignore_auth_paths: Dict[str, List[str]] \ - = self._settings.chroma_server_auth_ignore_paths + self._ignore_auth_paths: Dict[ + str, List[str] + ] = self._settings.chroma_server_auth_ignore_paths if self._settings.chroma_server_auth_provider: + logger.debug( + f"Server Auth Provider: {self._settings.chroma_server_auth_provider}" + ) _cls = get_class( self._settings.chroma_server_auth_provider, ServerAuthProvider ) - self.require(_cls) - logger.debug(f"Server Auth Provider: {_cls}") + self._auth_provider = self.require(_cls) @override - def authenticate(self, request: ServerAuthenticationRequest) -> Optional[ServerAuthenticationResponse]: - return self._auth_provider.authenticate(request) + def authenticate( + self, request: ServerAuthenticationRequest + ) -> Optional[ServerAuthenticationResponse]: + return FastAPIServerAuthenticationResponse( + self._auth_provider.authenticate(request) + ) @override def ignore_operation(self, verb: str, path: str) -> bool: if ( - path in self._ignore_auth_paths.keys() - and verb.upper() in self._ignore_auth_paths[path] + path in self._ignore_auth_paths.keys() + and verb.upper() in self._ignore_auth_paths[path] ): - logger.debug( - f"Skipping auth for path {path} and method {verb}" - ) + logger.debug(f"Skipping auth for path {path} and method {verb}") return True return False @@ -91,7 +98,7 @@ def instrument_server(self, app: ASGIApp) -> None: class FastAPIChromaAuthMiddlewareWrapper(BaseHTTPMiddleware): def __init__( - self, app: ASGIApp, auth_middleware: FastAPIChromaAuthMiddleware + self, app: ASGIApp, auth_middleware: FastAPIChromaAuthMiddleware ) -> None: super().__init__(app) self._middleware = auth_middleware @@ -99,12 +106,16 @@ def __init__( @override async def dispatch( - self, request: Request, call_next: RequestResponseEndpoint + self, request: Request, call_next: RequestResponseEndpoint ) -> Response: if self._middleware.ignore_operation(request.method, request.url.path): - logger.debug(f"Skipping auth for path {request.url.path} and method {request.method}") + logger.debug( + f"Skipping auth for path {request.url.path} and method {request.method}" + ) return await call_next(request) - response = self._middleware.authenticate(FastAPIServerAuthenticationRequest(request)) - if response is None or not response.success(): + response = self._middleware.authenticate( + FastAPIServerAuthenticationRequest(request) + ) + if not response or not response.success(): return JSONResponse({"error": "Unauthorized"}, status_code=401) return await call_next(request) diff --git a/chromadb/config.py b/chromadb/config.py index 276acbf8cb0..20e47302c48 100644 --- a/chromadb/config.py +++ b/chromadb/config.py @@ -100,9 +100,11 @@ class Settings(BaseSettings): # type: ignore chroma_server_auth_provider: Optional[str] = None @validator("chroma_server_auth_provider", pre=True, always=True) - def chroma_server_auth_provider_non_empty(cls, v) -> Optional[str]: + def chroma_server_auth_provider_non_empty(cls: Type, v: str) -> Optional[str]: if v and not v.strip(): - raise ValueError("chroma_server_auth_provider cannot be empty or just whitespace") + raise ValueError( + "chroma_server_auth_provider cannot be empty or just whitespace" + ) return v chroma_server_auth_configuration_provider: Optional[str] = None @@ -111,11 +113,17 @@ def chroma_server_auth_provider_non_empty(cls, v) -> Optional[str]: chroma_server_auth_credentials_file: Optional[str] = None @validator("chroma_server_auth_credentials_file", pre=True, always=True) - def chroma_server_auth_credentials_file_non_empty_file_exists(cls, v) -> Optional[str]: + def chroma_server_auth_credentials_file_non_empty_file_exists( + cls: Type, v: str + ) -> Optional[str]: if v and not v.strip(): - raise ValueError("chroma_server_auth_credentials_file cannot be empty or just whitespace") + raise ValueError( + "chroma_server_auth_credentials_file cannot be empty or just whitespace" + ) if v and not os.path.isfile(os.path.join(v)): - raise ValueError(f"chroma_server_auth_credentials_file [{v}] does not exist") + raise ValueError( + f"chroma_server_auth_credentials_file [{v}] does not exist" + ) return v chroma_client_auth_provider: Optional[str] = None @@ -124,7 +132,15 @@ def chroma_server_auth_credentials_file_non_empty_file_exists(cls, v) -> Optiona "/api/v1/heartbeat": ["GET"], "/api/v1/version": ["GET"], } - chroma_client_auth_provider_config: Optional[Union[str, Dict[str, Any]]] = None + + chroma_client_auth_credentials_provider: Optional[ + str + ] = "chromadb.auth.ConfigurationClientAuthCredentialsProvider" + chroma_client_auth_protocol_adapter: Optional[ + str + ] = "chromadb.auth.RequestsClientAuthProtocolAdapter" + chroma_client_auth_credentials_file: Optional[str] = None + chroma_client_auth_credentials: Optional[str] = None anonymized_telemetry: bool = True diff --git a/chromadb/test/auth/test_abstractions.py b/chromadb/test/auth/test_abstractions.py deleted file mode 100644 index 4a8694469af..00000000000 --- a/chromadb/test/auth/test_abstractions.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import Optional - -import pytest -from overrides import override - -from chromadb.config import System, Settings, get_fqn -from chromadb.auth import register_configuration_provider, ServerAuthConfigurationProvider, \ - ServerAuthConfigurationProviderFactory - - -@register_configuration_provider('CONF_10', 'CONF_x', precedence=10) -class ConfigurationProvider3(ServerAuthConfigurationProvider): - @override - def get_configuration(self) -> Optional[str]: - return "this is config ConfigurationProvider3" - - @classmethod - @override - def get_type(cls) -> str: - return 'file' - - -def test_register_configuration() -> None: - @register_configuration_provider('CONF_1', 'CONF_3') - class ConfigurationProvider1(ServerAuthConfigurationProvider): - @override - def get_configuration(self) -> Optional[str]: - return "this is config ConfigurationProvider1" - - @classmethod - @override - def get_type(cls) -> str: - return 'env' - - @register_configuration_provider('CONF_2', 'CONF_4', precedence=2) - class ConfigurationProvider2(ServerAuthConfigurationProvider): - @override - def get_configuration(self) -> Optional[str]: - return "this is config ConfigurationProvider2" - - @classmethod - @override - def get_type(cls) -> str: - return 'file' - - class UnregisteredConfigurationProvider1(ServerAuthConfigurationProvider): - @override - def get_configuration(self) -> Optional[str]: - return "this is config UnregisteredConfigurationProvider1" - - @classmethod - @override - def get_type(cls) -> str: - return 'file' - - class TestSettings(Settings): - CONF_1: Optional[int] = None - CONF_3: Optional[int] = None - - print(ServerAuthConfigurationProviderFactory.providers) - assert 'CONF_1' in next(iter(ServerAuthConfigurationProviderFactory.providers['env'].keys())) - assert next(iter(ServerAuthConfigurationProviderFactory.providers['env'].values()))[1] == 1 - # assert 'CONF_2' in next(iter(ServerAuthConfigurationProviderFactory.providers['file'].keys())) - # assert next(iter(ServerAuthConfigurationProviderFactory.providers['file'].values()))[1] == 2 - _s = System(TestSettings(CONF_1=1, CONF_3=2)) - assert ServerAuthConfigurationProviderFactory.get_provider(_s) is not None - assert isinstance(ServerAuthConfigurationProviderFactory.get_provider(_s), ConfigurationProvider1) - assert isinstance(ServerAuthConfigurationProviderFactory.get_provider(_s, provider_class=ConfigurationProvider2), - ConfigurationProvider2) - assert isinstance( - ServerAuthConfigurationProviderFactory.get_provider(_s, provider_class=get_fqn(ConfigurationProvider3)), - ConfigurationProvider3) - with pytest.raises(ValueError): - ServerAuthConfigurationProviderFactory.get_provider(_s, provider_class=UnregisteredConfigurationProvider1) diff --git a/chromadb/test/conftest.py b/chromadb/test/conftest.py index 762399d633f..0a7fef64d69 100644 --- a/chromadb/test/conftest.py +++ b/chromadb/test/conftest.py @@ -58,7 +58,8 @@ def _run_server( is_persistent: bool = False, persist_directory: Optional[str] = None, chroma_server_auth_provider: Optional[str] = None, - chroma_server_auth_provider_config: Optional[Union[str, Dict[str, Any]]] = None, + chroma_server_auth_credentials_provider: Optional[str] = None, + chroma_server_auth_credentials_file: Optional[str] = None, ) -> None: """Run a Chroma server locally""" if is_persistent and persist_directory: @@ -72,7 +73,8 @@ def _run_server( persist_directory=persist_directory, allow_reset=True, chroma_server_auth_provider=chroma_server_auth_provider, - chroma_server_auth_provider_config=chroma_server_auth_provider_config, + chroma_server_auth_credentials_provider=chroma_server_auth_credentials_provider, + chroma_server_auth_credentials_file=chroma_server_auth_credentials_file, ) else: settings = Settings( @@ -84,7 +86,8 @@ def _run_server( is_persistent=False, allow_reset=True, chroma_server_auth_provider=chroma_server_auth_provider, - chroma_server_auth_provider_config=chroma_server_auth_provider_config, + chroma_server_auth_credentials_provider=chroma_server_auth_credentials_provider, + chroma_server_auth_credentials_file=chroma_server_auth_credentials_file, ) server = chromadb.server.fastapi.FastAPI(settings) uvicorn.run(server.app(), host="0.0.0.0", port=port, log_level="error") @@ -106,9 +109,10 @@ def _await_server(api: API, attempts: int = 0) -> None: def _fastapi_fixture( is_persistent: bool = False, chroma_server_auth_provider: Optional[str] = None, - chroma_server_auth_provider_config: Optional[Union[str, Dict[str, Any]]] = None, + chroma_server_auth_credentials_provider: Optional[str] = None, chroma_client_auth_provider: Optional[str] = None, - chroma_client_auth_provider_config: Optional[Union[str, Dict[str, Any]]] = None, + chroma_server_auth_credentials_file: Optional[str] = None, + chroma_client_auth_credentials: Optional[str] = None, ) -> Generator[System, None, None]: """Fixture generator that launches a server in a separate process, and yields a fastapi client connect to it""" @@ -117,13 +121,14 @@ def _fastapi_fixture( logger.info(f"Running test FastAPI server on port {port}") ctx = multiprocessing.get_context("spawn") args: Tuple[ - int, bool, Optional[str], Optional[str], Optional[Union[str, Dict[str, Any]]] + int, bool, Optional[str], Optional[str], Optional[str], Optional[str] ] = ( port, False, None, chroma_server_auth_provider, - chroma_server_auth_provider_config, + chroma_server_auth_credentials_provider, + chroma_server_auth_credentials_file, ) persist_directory = None if is_persistent: @@ -133,7 +138,8 @@ def _fastapi_fixture( is_persistent, persist_directory, chroma_server_auth_provider, - chroma_server_auth_provider_config, + chroma_server_auth_credentials_provider, + chroma_server_auth_credentials_file, ) proc = ctx.Process(target=_run_server, args=args, daemon=True) proc.start() @@ -143,7 +149,7 @@ def _fastapi_fixture( chroma_server_http_port=str(port), allow_reset=True, chroma_client_auth_provider=chroma_client_auth_provider, - chroma_client_auth_provider_config=chroma_client_auth_provider_config, + chroma_client_auth_credentials=chroma_client_auth_credentials, ) system = System(settings) api = system.instance(API) @@ -166,72 +172,68 @@ def fastapi_persistent() -> Generator[System, None, None]: def fastapi_server_auth() -> Generator[System, None, None]: - return _fastapi_fixture( + server_auth_file = os.path.abspath(os.path.join(".", "server.htpasswd")) + with open(server_auth_file, "w") as f: + f.write("admin:$2y$05$e5sRb6NCcSH3YfbIxe1AGu2h5K7OOd982OXKmd8WyQ3DRQ4MvpnZS\n") + yield _fastapi_fixture( is_persistent=False, - chroma_server_auth_provider="chromadb.config.BasicAuthServerProvider", - chroma_server_auth_provider_config={"username": "admin", "password": "admin"}, - chroma_client_auth_provider="chromadb.config.BasicAuthClientProvider", - chroma_client_auth_provider_config={"username": "admin", "password": "admin"}, + chroma_server_auth_provider="chromadb.auth.basic.BasicAuthServerProvider", + chroma_server_auth_credentials_provider="chromadb.auth.HtpasswdServerAuthCredentialsProvider", + chroma_server_auth_credentials_file="./server.htpasswd", + chroma_client_auth_provider="chromadb.auth.basic.BasicAuthClientProvider", + chroma_client_auth_credentials="admin:admin", ) + os.remove(server_auth_file) def fastapi_server_auth_param() -> Generator[System, None, None]: + server_auth_file = os.path.abspath(os.path.join(".", "server.htpasswd")) + with open(server_auth_file, "w") as f: + f.write("admin:$2y$05$e5sRb6NCcSH3YfbIxe1AGu2h5K7OOd982OXKmd8WyQ3DRQ4MvpnZS\n") for item in _fastapi_fixture( is_persistent=False, - chroma_server_auth_provider="chromadb.config.BasicAuthServerProvider", - chroma_server_auth_provider_config={"username": "admin", "password": "admin"}, - chroma_client_auth_provider="chromadb.config.BasicAuthClientProvider", - chroma_client_auth_provider_config={"username": "admin", "password": "admin"}, + chroma_server_auth_provider="chromadb.auth.basic.BasicAuthServerProvider", + chroma_server_auth_credentials_provider="chromadb.auth.HtpasswdServerAuthCredentialsProvider", + chroma_server_auth_credentials_file="./server.htpasswd", + chroma_client_auth_provider="chromadb.auth.basic.BasicAuthClientProvider", + chroma_client_auth_credentials="admin:admin", ): yield item - - -def auth_provider_config() -> Generator[Dict[str, str], None, None]: - ... + os.remove(server_auth_file) # TODO we need a generator for auth providers def fastapi_server_auth_file() -> Generator[System, None, None]: - server_auth_file = os.path.abspath(os.path.join(".", "server-auth")) - client_auth_file = os.path.abspath(os.path.join(".", "client-auth")) + server_auth_file = os.path.abspath(os.path.join(".", "server.htpasswd")) with open(server_auth_file, "w") as f: - f.write("admin:admin") - with open(client_auth_file, "w") as f: - f.write("admin:admin") + f.write("admin:$2y$05$e5sRb6NCcSH3YfbIxe1AGu2h5K7OOd982OXKmd8WyQ3DRQ4MvpnZS\n") for item in _fastapi_fixture( is_persistent=False, - chroma_server_auth_provider="chromadb.config.BasicAuthServerProvider", - chroma_server_auth_provider_config=server_auth_file, - chroma_client_auth_provider="chromadb.config.BasicAuthClientProvider", - chroma_client_auth_provider_config=client_auth_file, + chroma_server_auth_provider="chromadb.auth.basic.BasicAuthServerProvider", + chroma_server_auth_credentials_provider="chromadb.auth.HtpasswdServerAuthCredentialsProvider", + chroma_server_auth_credentials_file="./server.htpasswd", + chroma_client_auth_provider="chromadb.auth.basic.BasicAuthClientProvider", + chroma_client_auth_credentials="admin:admin", ): yield item os.remove(server_auth_file) - os.remove(client_auth_file) - - -def fastapi_server_auth_env() -> Generator[System, None, None]: - os.environ["CHROMA_SERVER_AUTH_BASIC_USERNAME"] = "admin" - os.environ["CHROMA_SERVER_AUTH_BASIC_PASSWORD"] = "admin" - os.environ["CHROMA_CLIENT_AUTH_BASIC_USERNAME"] = "admin" - os.environ["CHROMA_CLIENT_AUTH_BASIC_PASSWORD"] = "admin" - for item in _fastapi_fixture( - is_persistent=False, - chroma_server_auth_provider="chromadb.config.BasicAuthServerProvider", - chroma_client_auth_provider="chromadb.config.BasicAuthClientProvider", - ): - yield item @pytest.fixture(scope="function") def fastapi_server_auth_invalid_cred() -> Generator[System, None, None]: - return _fastapi_fixture( + print("=========wewqeweqwqe") + server_auth_file = os.path.abspath(os.path.join(".", "server.htpasswd")) + with open(server_auth_file, "w") as f: + f.write("admin:$2y$05$e5sRb6NCcSH3YfbIxe1AGu2h5K7OOd982OXKmd8WyQ3DRQ4MvpnZS\n") + yield _fastapi_fixture( is_persistent=False, - chroma_server_auth_provider="chromadb.config.BasicAuthServerProvider", - chroma_server_auth_provider_config={"username": "admin", "password": "admin"}, - chroma_client_auth_provider="chromadb.config.BasicAuthClientProvider", - chroma_client_auth_provider_config={"username": "admin", "password": "wrong"}, + chroma_server_auth_provider="chromadb.auth.basic.BasicAuthServerProvider", + chroma_server_auth_credentials_provider="chromadb.auth.HtpasswdServerAuthCredentialsProvider", + chroma_server_auth_credentials_file="./server.htpasswd", + chroma_client_auth_provider="chromadb.auth.basic.BasicAuthClientProvider", + chroma_client_auth_credentials="admin:admin1", ) + os.remove(server_auth_file) def integration() -> Generator[System, None, None]: @@ -284,13 +286,7 @@ def sqlite_persistent() -> Generator[System, None, None]: def system_fixtures() -> List[Callable[[], Generator[System, None, None]]]: - fixtures = [ - fastapi, - fastapi_persistent, - sqlite, - sqlite_persistent, - fastapi_server_auth, - ] + fixtures = [fastapi, fastapi_persistent, sqlite, sqlite_persistent] if "CHROMA_INTEGRATION_TEST" in os.environ: fixtures.append(integration) if "CHROMA_INTEGRATION_TEST_ONLY" in os.environ: @@ -302,7 +298,6 @@ def system_fixtures_auth() -> List[Callable[[], Generator[System, None, None]]]: fixtures = [ fastapi_server_auth_param, fastapi_server_auth_file, - fastapi_server_auth_env, ] return fixtures diff --git a/docs/CIP_2_Auth_Providers_Proposal.md b/docs/CIP_2_Auth_Providers_Proposal.md index 1311a6a30be..2652f626523 100644 --- a/docs/CIP_2_Auth_Providers_Proposal.md +++ b/docs/CIP_2_Auth_Providers_Proposal.md @@ -52,7 +52,7 @@ restrictions we impose to make the design simpler and more robust. - Auth Provider - an abstraction that provides authentication functionality for either client or server-side. The provider is responsible for validating client credentials using (if available) configuration and credentials - providers. The auth provider is also responsible for carrying the Croma-leg of any authentication flow. + providers. The auth provider is also responsible for carrying the Chroma-leg of any authentication flow. - Auth Configuration Provider - an abstraction that provides configuration for auth providers. The configuration can be loaded from a file, env vars or programmatically. The configuration is used for validating and/or accessing user credentials. Examples: secret key for JWT token based auth, DB URL for DB based auth, etc. Depending on sensitivity of @@ -83,15 +83,9 @@ We suggest the following abstractions: - `ServerAuthenticationResponse` - An abstraction for returning authentication data to server specific implementation. - `ServerAuthConfigurationProvider` - this is the base abstraction for auth configuration providers. The provider is responsible for loading auth configuration from a file, env vars or programmatically. -- `ServerAuthConfigurationProviderFactory` - a factory and a register for server auth configuration providers. The basic - idea is that providers will be pluggable as such they need to register with this class in order to be eligible for - instantiation through Settings and env vars. - `AbstractCredentials` - base abstraction for credentials encapsulation from server to Auth Credentials Provider. - `ServerAuthCredentialsProvider` - this is the base abstraction for auth credentials providers. The provider is responsible for verifying client credentials. -- `ServerAuthCredentialsProviderFactory` - a factory and a register for server auth credentials providers. The basic - idea is that providers will be pluggable as such they need to register with this class in order to be eligible for - instantiation through Settings and env vars. ##### Client-Side @@ -102,14 +96,8 @@ We suggest multiple abstractions on the client-side to allow for easy integratio flow by gluing together the auth configuration and credentials providers, and any possible auth workflows (e.g. OAuth) - `ClientAuthConfigurationProvider` - this is the base abstraction for auth configuration providers. The provider is responsible for loading auth configuration from a file, env vars or programmatically. -- `ClientAuthConfigurationProviderFactory` - a factory and a register for client auth configuration providers. The basic - idea is that providers will be pluggable as such they need to register with this class in order to be eligible for - instantiation through Settings and env vars. - `ClientAuthCredentialsProvider` - this is the base abstraction for auth credentials providers. The provider is responsible for verifying client credentials. -- `ClientAuthCredentialsProviderFactory` - a factory and a register for client auth credentials providers. The basic - idea is that providers will be pluggable as such they need to register with this class in order to be eligible for - instantiation through Settings and env vars. - `AbstractCredentials` - base abstraction for credentials encapsulation from client to Auth Credentials Provider. - `ClientAuthProtocolAdapter` - this is an abstraction that allows for client-side auth providers to communicate with backends using variety of protocols and libraries (e.g. `requests`, `gRPC` etc). The adapter is responsible for @@ -134,87 +122,8 @@ TBD #### Client-side -### Abstractions -#### Server-side Auth Provider - -The server-side authentication provider is responsible for authenticating client requests reaching server endpoints. The -abstraction serves as a way for any server implementation to validate client credentials. - -Interface: - -- `authenticate(request: AuthRequest) -> bool` - -Configuration: - -- `CHROMA_SERVER_AUTH_PROVIDER` - a shortname of the provider (configured in a mapping in `__init__.py` of `auth` - package) - default: `None`. When no provider is specified client request will not be authenticated. - -Exposed to the user: Yes - -#### Client-side Auth Provider - -Exposed to the user: Yes - -#### Auth Middleware Adapter - -Configuration: - -- `CHROMA_SERVER_AUTH_IGNORE_PATHS` - a list of paths that should be ignored by the auth provider - - default: `['/api/v1', '/api/v1/version', '/api/v1/heartbeat']`. **WARNING**: Usually the defaults are safe but users - should be careful when overriding this setting as it can lead to security issues. - -Exposed to the user: No - -#### Client-side Auth Configuration Provider - -Exposed to the user: Yes, via settings - -#### Server-side Auth Configuration Provider - -This is an abstraction layer for auth providers to acquire their configuration. The abstraction is needed as we want to -support a variety of auth providers and each of them might have different configuration requirements. - -It is important to note that configuration providers are not explicitly instantiated or configured by the user but -rather are configured by the auth provider itself (using factory pattern). - -Configuration: - -> Note about provider precedence: The provider precedence is as follows: `env` -> `file` -> `programmatic`. This means -> that if a provider is configured via env var, it will take precedence over the file-based provider. Similarly, if -> both env and file-based providers are configured, the env provider will take precedence over the file-based provider. - - -File-based configuration: - -Use this provider to load configuration from a file: - -- `CHROMA_SERVER_AUTH_PROVIDER_CONFIG_FILE_TYPE` - `htpasswd` or `plaintext` - default: `htpasswd` -- `CHROMA_SERVER_AUTH_PROVIDER_CONFIG_FILE` - a path to a file containing the auth provider configuration - default: - `None` - -Env-based configuration provider: - -Use this provider to load configuration from environment variables: - -- `CHROMA_SERVER_AUTH_PROVIDER_CONFIG_ENV` - an environment variable to use for auth provider configuration - default: - `None` -- `CHROMA_SERVER_AUTH_PROVIDER_CONFIG_ENV_TYPE` - `plaintext`, `json` or `yaml` - default: `plaintext` - -> Note: Additional settings will be added as more config providers are supplied. - - -Exposed to the user: Yes, via settings - -### Client-side Auth Credentials Provider - -Exposed to the user: Yes, via settings - -#### Server-side Auth Credentials Provider - -Exposed to the user: Yes, via settings - -Reasoning: +### Reasoning - Server-side abstraction - it is very useful as the intention is to support a variety of auth providers. - Client-side abstraction - similar reasoning but from client's perspective. It will allow for both standard and diff --git a/examples/basic_functionality/client_auth.ipynb b/examples/basic_functionality/client_auth.ipynb index 35205820a6d..c9ed61c9606 100644 --- a/examples/basic_functionality/client_auth.ipynb +++ b/examples/basic_functionality/client_auth.ipynb @@ -103,7 +103,7 @@ { "cell_type": "markdown", "source": [ - "## Setting Up The client\n", + "## Setting Up\n", "\n", "### Before You Begin\n", "\n", @@ -122,24 +122,32 @@ "\n", "From the command line:\n", "\n", - "> Note: You need to clone the git repository first and run the command from the repository root.\n", + "> Note: The below options will configure the server to use Basic Authentication with the username `admin` and password `admin`.\n", "\n", "```bash\n", - "CHROMA_SERVER_AUTH_PROVIDER=\"chromadb.auth.BasicAuthServerProvider\" \\\n", - "CHROMA_SERVER_AUTH_PROVIDER_CONFIG='{\"username\":\"admin\",\"password\":\"admin\"}' \\\n", + "export CHROMA_USER=admin\n", + "export CHROMA_PASSWORD=admin\n", + "docker run --rm --entrypoint htpasswd httpd:2 -Bbn ${CHROMA_USER} ${CHROMA_PASSWORD} > server.htpasswd\n", + "CHROMA_SERVER_AUTH_CREDENTIALS_FILE=\"./server.htpasswd\" \\\n", + "CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.HtpasswdServerAuthCredentialsProvider' \\\n", + "CHROMA_SERVER_AUTH_PROVIDER='chromadb.auth.basic.BasicAuthServerProvider' \\\n", "uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 --proxy-headers --log-config log_config.yml\n", "```\n", "\n", - "From Docker:\n", + "With Docker Compose:\n", "\n", "> Note: You need to clone the git repository first and run the command from the repository root.\n", "\n", "```bash\n", + "export CHROMA_USER=admin\n", + "export CHROMA_PASSWORD=admin\n", + "docker run --rm --entrypoint htpasswd httpd:2 -Bbn ${CHROMA_USER} ${CHROMA_PASSWORD} > server.htpasswd\n", "cat << EOF > .env\n", - "CHROMA_SERVER_AUTH_PROVIDER=chromadb.auth.BasicAuthServerProvider\n", - "CHROMA_SERVER_AUTH_PROVIDER_CONFIG={\"username\":\"admin\",\"password\":\"admin\"}\n", + "CHROMA_SERVER_AUTH_CREDENTIALS_FILE=\"/chroma/server.htpasswd\"\n", + "CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.HtpasswdServerAuthCredentialsProvider'\n", + "CHROMA_SERVER_AUTH_PROVIDER='chromadb.auth.basic.BasicAuthServerProvider'\n", "EOF\n", - "docker-compose up -d --build\n", + "docker-compose up -d --build \n", "```\n", "\n", "\n", @@ -167,13 +175,13 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 2, "outputs": [ { "data": { "text/plain": "[]" }, - "execution_count": 20, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -182,21 +190,20 @@ "import chromadb\n", "from chromadb import Settings\n", "\n", - "client = chromadb.HttpClient(settings=Settings(chroma_client_auth_provider=\"chromadb.auth.BasicAuthClientProvider\",\n", - " chroma_client_auth_provider_config={\"username\": \"admin\",\n", - " \"password\": \"admin\"}))\n", - "client.heartbeat() # this should work with or without authentication - it is a public endpoint\n", + "client = chromadb.HttpClient(\n", + " settings=Settings(chroma_client_auth_provider=\"chromadb.auth.basic.BasicAuthClientProvider\",chroma_client_auth_credentials=\"admin:admin\"))\n", + "client.heartbeat() # this should work with or without authentication - it is a public endpoint\n", "\n", - "client.get_version() # this should work with or without authentication - it is a public endpoint\n", + "client.get_version() # this should work with or without authentication - it is a public endpoint\n", "\n", - "client.list_collections() # this is a protected endpoint and requires authentication\n", + "client.list_collections() # this is a protected endpoint and requires authentication\n", "\n" ], "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2023-08-17T15:19:48.881673Z", - "start_time": "2023-08-17T15:19:48.822021Z" + "end_time": "2023-08-22T00:33:16.354523Z", + "start_time": "2023-08-22T00:33:15.715736Z" } }, "id": "8f9307acce25f672" @@ -213,25 +220,34 @@ }, { "cell_type": "code", - "execution_count": 23, - "outputs": [], + "execution_count": 3, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "As expected, you are not authorized to access protected endpoints.\n" + ] + } + ], "source": [ "# Try to access a protected endpoint without authentication\n", "import sys\n", + "\n", "client = chromadb.HttpClient()\n", "try:\n", " client.list_collections()\n", "except Exception as e:\n", " if \"Unauthorized\" in str(e):\n", - " print(\"As expected, you are not authorized to access protected endpoints.\",file=sys.stderr)\n", + " print(\"As expected, you are not authorized to access protected endpoints.\", file=sys.stderr)\n", " else:\n", " raise e" ], "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2023-08-17T15:25:19.857009Z", - "start_time": "2023-08-17T15:25:19.737527Z" + "end_time": "2023-08-22T00:33:19.119718Z", + "start_time": "2023-08-22T00:33:19.097558Z" } }, "id": "c0c3240ed4d70a79" diff --git a/pyproject.toml b/pyproject.toml index 4f8d34c760d..b7ae444bf96 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,8 @@ dependencies = [ 'tqdm >= 4.65.0', 'overrides >= 7.3.1', 'importlib-resources', - 'graphlib_backport >= 1.0.3; python_version < "3.9"' + 'graphlib_backport >= 1.0.3; python_version < "3.9"', + 'bcrypt >= 4.0.1' ] [tool.black] diff --git a/requirements.txt b/requirements.txt index 04387f95cd0..c23a24cafdb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +bcrypt==4.0.1 chroma-hnswlib==0.7.2 fastapi>=0.95.2, <0.100.0 graphlib_backport==1.0.3; python_version < '3.9' From b446120dd5bc88244fa6b4312fef421af9064f7b Mon Sep 17 00:00:00 2001 From: Trayan Azarov Date: Tue, 22 Aug 2023 16:15:50 +0300 Subject: [PATCH 12/13] feat: CIP-2 Auth Providers - Added new provider configuration Htpasswd provider to read from config value (env or passed via settings) - Added shorthands for providers (e.g. `basic` for both Client and Server auths) - Added registry for auth providers to simplify shorthand lookups - Fixed mypy errors Refs: #986 --- chromadb/api/fastapi.py | 53 +++--- chromadb/auth/__init__.py | 158 +++------------- chromadb/auth/basic/__init__.py | 37 ++-- chromadb/auth/fastapi.py | 28 +-- chromadb/auth/providers.py | 171 ++++++++++++++++++ chromadb/auth/registry.py | 107 +++++++++++ chromadb/config.py | 25 ++- chromadb/test/conftest.py | 71 +++++--- .../basic_functionality/client_auth.ipynb | 51 +----- 9 files changed, 434 insertions(+), 267 deletions(-) create mode 100644 chromadb/auth/providers.py create mode 100644 chromadb/auth/registry.py diff --git a/chromadb/api/fastapi.py b/chromadb/api/fastapi.py index 09adef3e440..5551b051370 100644 --- a/chromadb/api/fastapi.py +++ b/chromadb/api/fastapi.py @@ -1,11 +1,15 @@ +import json from typing import Optional, cast +from typing import Sequence +from uuid import UUID + +import requests +from overrides import override + +import chromadb.errors as errors +import chromadb.utils.embedding_functions as ef from chromadb.api import API -from chromadb.auth import ( - ClientAuthProvider, - ClientAuthProtocolAdapter, - RequestsClientAuthProtocolAdapter, -) -from chromadb.config import Settings, System, get_class +from chromadb.api.models.Collection import Collection from chromadb.api.types import ( Documents, Embeddings, @@ -19,15 +23,13 @@ QueryResult, CollectionMetadata, ) -import chromadb.utils.embedding_functions as ef -import requests -import json -from typing import Sequence -from chromadb.api.models.Collection import Collection -import chromadb.errors as errors -from uuid import UUID +from chromadb.auth import ( + ClientAuthProvider, +) +from chromadb.auth.providers import RequestsClientAuthProtocolAdapter +from chromadb.auth.registry import resolve_provider +from chromadb.config import Settings, System from chromadb.telemetry import Telemetry -from overrides import override class FastAPI(API): @@ -51,24 +53,25 @@ def __init__(self, system: System): f"{url_prefix}://{system.settings.chroma_server_host}{port_suffix}/api/v1" ) - if system.settings.chroma_client_auth_provider: - self._auth_provider = self.require( - get_class( - system.settings.chroma_client_auth_provider, ClientAuthProvider - ) - ) - self._header = system.settings.chroma_server_headers if ( system.settings.chroma_client_auth_provider and system.settings.chroma_client_auth_protocol_adapter ): - self._adapter = system.require( - get_class( - system.settings.chroma_client_auth_protocol_adapter, - RequestsClientAuthProtocolAdapter, + self._auth_provider = self.require( + resolve_provider( + system.settings.chroma_client_auth_provider, ClientAuthProvider ) ) + self._adapter = cast( + RequestsClientAuthProtocolAdapter, + system.require( + resolve_provider( + system.settings.chroma_client_auth_protocol_adapter, + RequestsClientAuthProtocolAdapter, + ) + ), + ) self._session = self._adapter.session else: self._session = requests.Session() diff --git a/chromadb/auth/__init__.py b/chromadb/auth/__init__.py index d1ed9784674..67f296bb35c 100644 --- a/chromadb/auth/__init__.py +++ b/chromadb/auth/__init__.py @@ -2,46 +2,32 @@ Contains only Auth abstractions, no implementations. """ import base64 -import os +import logging from abc import ABC, abstractmethod -from collections import defaultdict from enum import Enum from typing import ( Optional, - Any, Dict, - List, - Union, - Type, - Callable, TypeVar, Tuple, Generic, - Mapping, ) -import bcrypt -import requests -from overrides import EnforceOverrides, overrides, override +from overrides import EnforceOverrides, override from pydantic import SecretStr from chromadb.config import ( Component, System, - Settings, - get_fqn, -) # TODO remove this circular dependency +) from chromadb.errors import ChromaError -from chromadb.utils import get_class + +logger = logging.getLogger(__name__) T = TypeVar("T") S = TypeVar("S") -# Re-export types from chromadb -# __all__ = ["BasicAuthClientProvider", "BasicAuthServerProvider"] - - class AuthInfoType(Enum): COOKIE = "cookie" HEADER = "header" @@ -86,7 +72,7 @@ def get_credentials(self) -> T: pass -class ClientAuthProtocolAdapter(Component): +class ClientAuthProtocolAdapter(Component, Generic[T]): def __init__(self, system: System) -> None: super().__init__(system) @@ -95,82 +81,7 @@ def inject_credentials(self, injection_context: T) -> None: pass -class RequestsClientAuthProtocolAdapter(ClientAuthProtocolAdapter): - class _Session(requests.Session): - _protocol_adapter: ClientAuthProtocolAdapter - - def __init__(self, protocol_adapter: ClientAuthProtocolAdapter) -> None: - super().__init__() - self._protocol_adapter = protocol_adapter - - @override - def send( - self, request: requests.PreparedRequest, **kwargs: Any - ) -> requests.Response: - self._protocol_adapter.inject_credentials(request) - return super().send(request, **kwargs) - - _session: _Session - _auth_provider: ClientAuthProvider - - def __init__(self, system: System) -> None: - super().__init__(system) - system.settings.require("chroma_client_auth_provider") - self._auth_provider = system.require( - get_class(system.settings.chroma_client_auth_provider, ClientAuthProvider) - ) - self._session = self._Session(self) - self._auth_header = self._auth_provider.authenticate() - - @property - def session(self) -> requests.Session: - return self._session - - @override - def inject_credentials(self, injection_context: requests.PreparedRequest) -> None: - if self._auth_header.get_auth_info_type() == AuthInfoType.HEADER: - _header_info = self._auth_header.get_auth_info() - injection_context.headers[_header_info[0]] = _header_info[1] - else: - raise ValueError( - f"Unsupported auth type: {self._auth_header.get_auth_info_type()}" - ) - - -class ConfigurationClientAuthCredentialsProvider(ClientAuthCredentialsProvider): - _creds: SecretStr - - def __init__(self, system: System) -> None: - super().__init__(system) - system.settings.require("chroma_client_auth_credentials") - self._creds = SecretStr(system.settings.chroma_client_auth_credentials) - - @override - def get_credentials(self) -> SecretStr: - return self._creds - - -_provider_registry = { - # TODO we need a better way to store, update and validate this registry with new providers being added - ( - "basic", - "chromadb.auth.basic.BasicAuthClientProvider", - ): "chromadb.auth.basic.BasicAuthClientProvider", -} - - -def resolve_client_auth_provider(classOrName) -> "ClientAuthProvider": - _cls = [ - cls - for short_hand_list, cls in _provider_registry.items() - if classOrName in short_hand_list - ] - if len(_cls) == 0: - raise ValueError(f"Unknown client auth provider: {classOrName}") - return get_class(_cls[0], ClientAuthProvider) - - -### SERVER-SIDE Abstractions +# SERVER-SIDE Abstractions class ServerAuthenticationRequest(EnforceOverrides, ABC, Generic[T]): @@ -199,7 +110,7 @@ def __init__(self, system: System) -> None: super().__init__(system) @abstractmethod - def authenticate(self, request: ServerAuthenticationRequest) -> bool: + def authenticate(self, request: ServerAuthenticationRequest[T]) -> bool: pass @@ -209,7 +120,7 @@ def __init__(self, system: System) -> None: @abstractmethod def authenticate( - self, request: ServerAuthenticationRequest + self, request: ServerAuthenticationRequest[T] ) -> Optional[ServerAuthenticationResponse]: ... @@ -232,37 +143,47 @@ def get_configuration(self) -> Optional[T]: class AuthenticationError(ChromaError): - @overrides + @override def code(self) -> int: return 401 @classmethod - @overrides + @override def name(cls) -> str: return "AuthenticationError" -class AbstractCredentials(EnforceOverrides, ABC): +class AbstractCredentials(EnforceOverrides, ABC, Generic[T]): """ The class is used by Auth Providers to encapsulate credentials received from the server and pass them to a ServerAuthCredentialsProvider. """ @abstractmethod - def get_credentials(self) -> Dict[str, Union[str, int, float, bool, SecretStr]]: + def get_credentials(self) -> Dict[str, T]: """ Returns the data encapsulated by the credentials object. """ pass -class BasicAuthCredentials(AbstractCredentials): - def __init__(self, username, password) -> None: +class SecretStrAbstractCredentials(AbstractCredentials[SecretStr]): + @abstractmethod + @override + def get_credentials(self) -> Dict[str, SecretStr]: + """ + Returns the data encapsulated by the credentials object. + """ + pass + + +class BasicAuthCredentials(SecretStrAbstractCredentials): + def __init__(self, username: SecretStr, password: SecretStr) -> None: self.username = username self.password = password @override - def get_credentials(self) -> Dict[str, Union[str, int, float, bool, SecretStr]]: + def get_credentials(self) -> Dict[str, SecretStr]: return {"username": self.username, "password": self.password} @staticmethod @@ -282,30 +203,5 @@ def __init__(self, system: System) -> None: super().__init__(system) @abstractmethod - def validate_credentials(self, credentials: AbstractCredentials) -> bool: + def validate_credentials(self, credentials: AbstractCredentials[T]) -> bool: pass - - -class HtpasswdServerAuthCredentialsProvider(ServerAuthCredentialsProvider): - _creds: List[SecretStr] - - def __init__(self, system: System) -> None: - super().__init__(system) - system.settings.require("chroma_server_auth_credentials_file") - _file = system.settings.chroma_server_auth_credentials_file - with open(_file) as f: - self._creds = [SecretStr(v) for v in f.readline().strip().split(":")] - if len(self._creds) != 2: - raise ValueError( - f"Invalid Htpasswd credentials file [{_file}]. Must be :." - ) - - @override - def validate_credentials(self, credentials: AbstractCredentials) -> bool: - _creds = credentials.get_credentials() - return _creds["username"].get_secret_value() == self._creds[ - 0 - ].get_secret_value() and bcrypt.checkpw( - _creds["password"].get_secret_value().encode("utf-8"), - self._creds[1].get_secret_value().encode("utf-8"), - ) diff --git a/chromadb/auth/basic/__init__.py b/chromadb/auth/basic/__init__.py index 1e909775d90..bbd8e75e452 100644 --- a/chromadb/auth/basic/__init__.py +++ b/chromadb/auth/basic/__init__.py @@ -1,13 +1,10 @@ import base64 import logging -import os -from typing import Tuple +from typing import Tuple, Any, cast -import requests from overrides import override from pydantic import SecretStr -from chromadb.config import System, Settings from chromadb.auth import ( ServerAuthProvider, ClientAuthProvider, @@ -15,15 +12,18 @@ ServerAuthCredentialsProvider, AuthInfoType, BasicAuthCredentials, - AuthenticationError, ClientAuthCredentialsProvider, ClientAuthProtocolAdapter, ClientAuthResponse, ) +from chromadb.auth.registry import register_provider, resolve_provider +from chromadb.config import System from chromadb.utils import get_class logger = logging.getLogger(__name__) +__all__ = ["BasicAuthServerProvider", "BasicAuthClientProvider"] + def _encode_credentials(username: str, password: str) -> SecretStr: return SecretStr( @@ -41,12 +41,15 @@ def get_auth_info_type(self) -> AuthInfoType: @override def get_auth_info(self) -> Tuple[str, SecretStr]: - return "Authorization", f"Basic {self._credentials.get_secret_value()}" + return "Authorization", SecretStr( + f"Basic {self._credentials.get_secret_value()}" + ) +@register_provider("basic") class BasicAuthClientProvider(ClientAuthProvider): - _credentials_provider: ClientAuthCredentialsProvider - _protocol_adapter: ClientAuthProtocolAdapter + _credentials_provider: ClientAuthCredentialsProvider[Any] + _protocol_adapter: ClientAuthProtocolAdapter[Any] def __init__(self, system: System) -> None: super().__init__(system) @@ -54,7 +57,7 @@ def __init__(self, system: System) -> None: system.settings.require("chroma_client_auth_credentials_provider") self._credentials_provider = system.require( get_class( - system.settings.chroma_client_auth_credentials_provider, + str(system.settings.chroma_client_auth_credentials_provider), ClientAuthCredentialsProvider, ) ) @@ -71,6 +74,7 @@ def authenticate(self) -> ClientAuthResponse: ) +@register_provider("basic") class BasicAuthServerProvider(ServerAuthProvider): _credentials_provider: ServerAuthCredentialsProvider @@ -78,15 +82,18 @@ def __init__(self, system: System) -> None: super().__init__(system) self._settings = system.settings system.settings.require("chroma_server_auth_credentials_provider") - self._credentials_provider = system.require( - get_class( - system.settings.chroma_server_auth_credentials_provider, - ServerAuthCredentialsProvider, - ) + self._credentials_provider = cast( + ServerAuthCredentialsProvider, + system.require( + resolve_provider( + str(system.settings.chroma_server_auth_credentials_provider), + ServerAuthCredentialsProvider, + ) + ), ) @override - def authenticate(self, request: ServerAuthenticationRequest) -> bool: + def authenticate(self, request: ServerAuthenticationRequest[Any]) -> bool: try: # print(f"BasicAuthServerProvider.authenticate: {}") _auth_header = request.get_auth_info(AuthInfoType.HEADER, "Authorization") diff --git a/chromadb/auth/fastapi.py b/chromadb/auth/fastapi.py index 88f03e5aabd..a488ef5f2b3 100644 --- a/chromadb/auth/fastapi.py +++ b/chromadb/auth/fastapi.py @@ -1,6 +1,6 @@ -## FAST API code +# FAST API code import logging -from typing import Optional, Dict, List +from typing import Optional, Dict, List, cast, Any from overrides import override from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint @@ -8,7 +8,7 @@ from starlette.responses import Response, JSONResponse from starlette.types import ASGIApp -from chromadb import System +from chromadb.config import System from chromadb.auth import ( ServerAuthenticationRequest, AuthInfoType, @@ -16,25 +16,25 @@ ServerAuthProvider, ChromaAuthMiddleware, ) -from chromadb.utils import get_class +from chromadb.auth.registry import resolve_provider logger = logging.getLogger(__name__) -class FastAPIServerAuthenticationRequest(ServerAuthenticationRequest[str]): +class FastAPIServerAuthenticationRequest(ServerAuthenticationRequest[Optional[str]]): def __init__(self, request: Request) -> None: self._request = request @override def get_auth_info( self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None - ) -> str: + ) -> Optional[str]: if auth_info_type == AuthInfoType.HEADER: - return self._request.headers[auth_info_id] + return str(self._request.headers[auth_info_id]) elif auth_info_type == AuthInfoType.COOKIE: - return self._request.cookies[auth_info_id] + return str(self._request.cookies[auth_info_id]) elif auth_info_type == AuthInfoType.URL: - return self._request.query_params[auth_info_id] + return str(self._request.query_params[auth_info_id]) elif auth_info_type == AuthInfoType.METADATA: raise ValueError("Metadata not supported for FastAPI") else: @@ -44,7 +44,7 @@ def get_auth_info( class FastAPIServerAuthenticationResponse(ServerAuthenticationResponse): _auth_success: bool - def __init__(self, auth_success) -> None: + def __init__(self, auth_success: bool) -> None: self._auth_success = auth_success @override @@ -67,14 +67,14 @@ def __init__(self, system: System) -> None: logger.debug( f"Server Auth Provider: {self._settings.chroma_server_auth_provider}" ) - _cls = get_class( + _cls = resolve_provider( self._settings.chroma_server_auth_provider, ServerAuthProvider ) - self._auth_provider = self.require(_cls) + self._auth_provider = cast(ServerAuthProvider, self.require(_cls)) @override def authenticate( - self, request: ServerAuthenticationRequest + self, request: ServerAuthenticationRequest[Any] ) -> Optional[ServerAuthenticationResponse]: return FastAPIServerAuthenticationResponse( self._auth_provider.authenticate(request) @@ -96,7 +96,7 @@ def instrument_server(self, app: ASGIApp) -> None: return -class FastAPIChromaAuthMiddlewareWrapper(BaseHTTPMiddleware): +class FastAPIChromaAuthMiddlewareWrapper(BaseHTTPMiddleware): # type: ignore def __init__( self, app: ASGIApp, auth_middleware: FastAPIChromaAuthMiddleware ) -> None: diff --git a/chromadb/auth/providers.py b/chromadb/auth/providers.py new file mode 100644 index 00000000000..de782dd4695 --- /dev/null +++ b/chromadb/auth/providers.py @@ -0,0 +1,171 @@ +import importlib +import logging +from typing import cast, Dict, TypeVar, Any + +import requests +from overrides import override +from pydantic import SecretStr + +from chromadb.auth import ( + ServerAuthCredentialsProvider, + AbstractCredentials, + ClientAuthCredentialsProvider, + AuthInfoType, + ClientAuthProvider, + ClientAuthProtocolAdapter, +) +from chromadb.auth.registry import register_provider, resolve_provider +from chromadb.config import System + +T = TypeVar("T") + +logger = logging.getLogger(__name__) + + +class HtpasswdServerAuthCredentialsProvider(ServerAuthCredentialsProvider): + _creds: Dict[str, SecretStr] + + def __init__(self, system: System) -> None: + super().__init__(system) + try: + # Equivalent to import onnxruntime + self.bc = importlib.import_module("bcrypt") + except ImportError: + raise ValueError( + "The onnxruntime python package is not installed. Please install it with `pip install bcrypt`" + ) + + @override + def validate_credentials(self, credentials: AbstractCredentials[T]) -> bool: + _creds = cast(Dict[str, SecretStr], credentials.get_credentials()) + if len(_creds) != 2: + logger.error( + "Returned credentials did match expected format: dict[username:SecretStr, password: SecretStr]" + ) + return False + if "username" not in _creds or "password" not in _creds: + logger.error("Returned credentials do not contain username or password") + return False + _usr_check = bool( + _creds["username"].get_secret_value() + == self._creds["username"].get_secret_value() + ) + return _usr_check and self.bc.checkpw( + _creds["password"].get_secret_value().encode("utf-8"), + self._creds["password"].get_secret_value().encode("utf-8"), + ) + + +@register_provider("htpasswd_file") +class HtpasswdFileServerAuthCredentialsProvider(HtpasswdServerAuthCredentialsProvider): + def __init__(self, system: System) -> None: + super().__init__(system) + system.settings.require("chroma_server_auth_credentials_file") + _file = str(system.settings.chroma_server_auth_credentials_file) + with open(_file) as f: + _raw_creds = [v for v in f.readline().strip().split(":")] + self._creds = { + "username": SecretStr(_raw_creds[0]), + "password": SecretStr(_raw_creds[1]), + } + if ( + len(self._creds) != 2 + or "username" not in self._creds + or "password" not in self._creds + ): + raise ValueError( + "Invalid Htpasswd credentials found in [chroma_server_auth_credentials]. " + "Must be :." + ) + + +class HtpasswdConfigurationServerAuthCredentialsProvider( + HtpasswdServerAuthCredentialsProvider +): + def __init__(self, system: System) -> None: + super().__init__(system) + system.settings.require("chroma_server_auth_credentials") + _raw_creds = ( + str(system.settings.chroma_server_auth_credentials).strip().split(":") + ) + self._creds = { + "username": SecretStr(_raw_creds[0]), + "password": SecretStr(_raw_creds[1]), + } + if ( + len(self._creds) != 2 + or "username" not in self._creds + or "password" not in self._creds + ): + raise ValueError( + "Invalid Htpasswd credentials found in [chroma_server_auth_credentials]. " + "Must be :." + ) + + +class RequestsClientAuthProtocolAdapter( + ClientAuthProtocolAdapter[requests.PreparedRequest] +): + class _Session(requests.Session): + _protocol_adapter: ClientAuthProtocolAdapter[requests.PreparedRequest] + + def __init__( + self, protocol_adapter: ClientAuthProtocolAdapter[requests.PreparedRequest] + ) -> None: + super().__init__() + self._protocol_adapter = protocol_adapter + + @override + def send( + self, request: requests.PreparedRequest, **kwargs: Any + ) -> requests.Response: + self._protocol_adapter.inject_credentials(request) + return super().send(request, **kwargs) + + _session: _Session + _auth_provider: ClientAuthProvider + + def __init__(self, system: System) -> None: + super().__init__(system) + system.settings.require("chroma_client_auth_provider") + self._auth_provider = cast( + ClientAuthProvider, + system.require( + resolve_provider( + str(system.settings.chroma_client_auth_provider), ClientAuthProvider + ), + ), + ) + self._session = self._Session(self) + self._auth_header = self._auth_provider.authenticate() + + @property + def session(self) -> requests.Session: + return self._session + + @override + def inject_credentials(self, injection_context: requests.PreparedRequest) -> None: + if self._auth_header.get_auth_info_type() == AuthInfoType.HEADER: + _header_info = self._auth_header.get_auth_info() + injection_context.headers[_header_info[0]] = _header_info[ + 1 + ].get_secret_value() + else: + raise ValueError( + f"Unsupported auth type: {self._auth_header.get_auth_info_type()}" + ) + + +class ConfigurationClientAuthCredentialsProvider( + ClientAuthCredentialsProvider[SecretStr] +): + _creds: SecretStr + + def __init__(self, system: System) -> None: + super().__init__(system) + system.settings.require("chroma_client_auth_credentials") + self._creds = SecretStr(str(system.settings.chroma_client_auth_credentials)) + + @override + def get_credentials(self) -> SecretStr: + return self._creds diff --git a/chromadb/auth/registry.py b/chromadb/auth/registry.py new file mode 100644 index 00000000000..cebf6667175 --- /dev/null +++ b/chromadb/auth/registry.py @@ -0,0 +1,107 @@ +import importlib +import logging +import pkgutil +from typing import Union, Dict, Type, Callable + +from chromadb.auth import ( + ClientAuthConfigurationProvider, + ClientAuthCredentialsProvider, + ClientAuthProtocolAdapter, + ServerAuthProvider, + ServerAuthConfigurationProvider, + ServerAuthCredentialsProvider, + ClientAuthProvider, +) +from chromadb.utils import get_class + +logger = logging.getLogger(__name__) +ProviderTypes = Union[ + "ClientAuthProvider", + "ClientAuthConfigurationProvider", + "ClientAuthCredentialsProvider", + "ServerAuthProvider", + "ServerAuthConfigurationProvider", + "ServerAuthCredentialsProvider", + "ClientAuthProtocolAdapter", +] + +_provider_registry = { + "client_auth_providers": {}, + "client_auth_config_providers": {}, + "client_auth_credentials_providers": {}, + "client_auth_protocol_adapters": {}, + "server_auth_providers": {}, + "server_auth_config_providers": {}, + "server_auth_credentials_providers": {}, +} # type: Dict[str, Dict[str, Type[ProviderTypes]]] + + +def register_classes_from_package(package_name: str) -> None: + package = importlib.import_module(package_name) + for _, module_name, _ in pkgutil.iter_modules(package.__path__): + full_module_name = f"{package_name}.{module_name}" + _ = importlib.import_module(full_module_name) + + +def register_provider( + short_hand: str, +) -> Callable[[Type[ProviderTypes]], Type[ProviderTypes]]: + def decorator(cls: Type[ProviderTypes]) -> Type[ProviderTypes]: + logger.error("Registering provider: %s", short_hand) + global _provider_registry + if issubclass(cls, ClientAuthProvider): + _provider_registry["client_auth_providers"][short_hand] = cls + elif issubclass(cls, ClientAuthConfigurationProvider): + _provider_registry["client_auth_config_providers"][short_hand] = cls + elif issubclass(cls, ClientAuthCredentialsProvider): + _provider_registry["client_auth_credentials_providers"][short_hand] = cls + elif issubclass(cls, ClientAuthProtocolAdapter): + _provider_registry["client_auth_protocol_adapters"][short_hand] = cls + elif issubclass(cls, ServerAuthProvider): + _provider_registry["server_auth_providers"][short_hand] = cls + elif issubclass(cls, ServerAuthConfigurationProvider): + _provider_registry["server_auth_config_providers"][short_hand] = cls + elif issubclass(cls, ServerAuthCredentialsProvider): + _provider_registry["server_auth_credentials_providers"][short_hand] = cls + else: + raise ValueError( + "Only ClientAuthProvider, ClientAuthConfigurationProvider, " + "ClientAuthCredentialsProvider, ServerAuthProvider, " + "ServerAuthConfigurationProvider, and ServerAuthCredentialsProvider, ClientAuthProtocolAdapter " + "can be registered." + ) + return cls + + return decorator + + +def resolve_provider( + class_or_name: str, cls: Type[ProviderTypes] +) -> Type[ProviderTypes]: + register_classes_from_package("chromadb.auth") + global _provider_registry + if issubclass(cls, ClientAuthProvider): + _key = "client_auth_providers" + elif issubclass(cls, ClientAuthConfigurationProvider): + _key = "client_auth_config_providers" + elif issubclass(cls, ClientAuthCredentialsProvider): + _key = "client_auth_credentials_providers" + elif issubclass(cls, ClientAuthProtocolAdapter): + _key = "client_auth_protocol_adapters" + elif issubclass(cls, ServerAuthProvider): + _key = "server_auth_providers" + elif issubclass(cls, ServerAuthConfigurationProvider): + _key = "server_auth_config_providers" + elif issubclass(cls, ServerAuthCredentialsProvider): + _key = "server_auth_credentials_providers" + else: + raise ValueError( + "Only ClientAuthProvider, ClientAuthConfigurationProvider, " + "ClientAuthCredentialsProvider, ServerAuthProvider, " + "ServerAuthConfigurationProvider, and ServerAuthCredentialsProvider,ClientAuthProtocolAdapter " + "can be registered." + ) + if class_or_name in _provider_registry[_key]: + return _provider_registry[_key][class_or_name] + else: + return get_class(class_or_name, cls) # type: ignore diff --git a/chromadb/config.py b/chromadb/config.py index 20e47302c48..67dbfe8ef40 100644 --- a/chromadb/config.py +++ b/chromadb/config.py @@ -1,21 +1,15 @@ -import base64 import importlib import inspect import logging import os -from abc import ABC, abstractmethod +from abc import ABC from graphlib import TopologicalSorter -from typing import Optional, List, Any, Dict, Set, Iterable, Union +from typing import Optional, List, Any, Dict, Set, Iterable from typing import Type, TypeVar, cast -import requests +from overrides import EnforceOverrides from overrides import override -from overrides import overrides, EnforceOverrides -from pydantic import BaseSettings, SecretStr, validator -from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint -from starlette.requests import Request -from starlette.responses import Response, JSONResponse -from starlette.types import ASGIApp +from pydantic import BaseSettings, validator from typing_extensions import Literal # The thin client will have a flag to control which implementations to use @@ -100,7 +94,9 @@ class Settings(BaseSettings): # type: ignore chroma_server_auth_provider: Optional[str] = None @validator("chroma_server_auth_provider", pre=True, always=True) - def chroma_server_auth_provider_non_empty(cls: Type, v: str) -> Optional[str]: + def chroma_server_auth_provider_non_empty( + cls: Type["Settings"], v: str + ) -> Optional[str]: if v and not v.strip(): raise ValueError( "chroma_server_auth_provider cannot be empty or just whitespace" @@ -111,10 +107,11 @@ def chroma_server_auth_provider_non_empty(cls: Type, v: str) -> Optional[str]: chroma_server_auth_configuration_file: Optional[str] = None chroma_server_auth_credentials_provider: Optional[str] = None chroma_server_auth_credentials_file: Optional[str] = None + chroma_server_auth_credentials: Optional[str] = None @validator("chroma_server_auth_credentials_file", pre=True, always=True) def chroma_server_auth_credentials_file_non_empty_file_exists( - cls: Type, v: str + cls: Type["Settings"], v: str ) -> Optional[str]: if v and not v.strip(): raise ValueError( @@ -135,10 +132,10 @@ def chroma_server_auth_credentials_file_non_empty_file_exists( chroma_client_auth_credentials_provider: Optional[ str - ] = "chromadb.auth.ConfigurationClientAuthCredentialsProvider" + ] = "chromadb.auth.providers.ConfigurationClientAuthCredentialsProvider" chroma_client_auth_protocol_adapter: Optional[ str - ] = "chromadb.auth.RequestsClientAuthProtocolAdapter" + ] = "chromadb.auth.providers.RequestsClientAuthProtocolAdapter" chroma_client_auth_credentials_file: Optional[str] = None chroma_client_auth_credentials: Optional[str] = None diff --git a/chromadb/test/conftest.py b/chromadb/test/conftest.py index 0a7fef64d69..50d5d7f4772 100644 --- a/chromadb/test/conftest.py +++ b/chromadb/test/conftest.py @@ -1,14 +1,10 @@ -from chromadb.config import Settings, System -from chromadb.api import API -from chromadb.ingest import Producer -import chromadb.server.fastapi -from requests.exceptions import ConnectionError -import hypothesis -import tempfile +import logging +import multiprocessing import os -import uvicorn +import shutil +import socket +import tempfile import time -import pytest from typing import ( Generator, Iterator, @@ -17,16 +13,18 @@ Sequence, Tuple, Callable, - Union, - Dict, - Any, ) + +import hypothesis +import pytest +import uvicorn +from requests.exceptions import ConnectionError from typing_extensions import Protocol -import shutil -import logging -import socket -import multiprocessing +import chromadb.server.fastapi +from chromadb.api import API +from chromadb.config import Settings, System +from chromadb.ingest import Producer from chromadb.types import SeqId, SubmitEmbeddingRecord root_logger = logging.getLogger() @@ -175,14 +173,15 @@ def fastapi_server_auth() -> Generator[System, None, None]: server_auth_file = os.path.abspath(os.path.join(".", "server.htpasswd")) with open(server_auth_file, "w") as f: f.write("admin:$2y$05$e5sRb6NCcSH3YfbIxe1AGu2h5K7OOd982OXKmd8WyQ3DRQ4MvpnZS\n") - yield _fastapi_fixture( + for item in _fastapi_fixture( is_persistent=False, chroma_server_auth_provider="chromadb.auth.basic.BasicAuthServerProvider", - chroma_server_auth_credentials_provider="chromadb.auth.HtpasswdServerAuthCredentialsProvider", + chroma_server_auth_credentials_provider="chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider", chroma_server_auth_credentials_file="./server.htpasswd", chroma_client_auth_provider="chromadb.auth.basic.BasicAuthClientProvider", chroma_client_auth_credentials="admin:admin", - ) + ): + yield item os.remove(server_auth_file) @@ -193,7 +192,7 @@ def fastapi_server_auth_param() -> Generator[System, None, None]: for item in _fastapi_fixture( is_persistent=False, chroma_server_auth_provider="chromadb.auth.basic.BasicAuthServerProvider", - chroma_server_auth_credentials_provider="chromadb.auth.HtpasswdServerAuthCredentialsProvider", + chroma_server_auth_credentials_provider="chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider", chroma_server_auth_credentials_file="./server.htpasswd", chroma_client_auth_provider="chromadb.auth.basic.BasicAuthClientProvider", chroma_client_auth_credentials="admin:admin", @@ -210,7 +209,7 @@ def fastapi_server_auth_file() -> Generator[System, None, None]: for item in _fastapi_fixture( is_persistent=False, chroma_server_auth_provider="chromadb.auth.basic.BasicAuthServerProvider", - chroma_server_auth_credentials_provider="chromadb.auth.HtpasswdServerAuthCredentialsProvider", + chroma_server_auth_credentials_provider="chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider", chroma_server_auth_credentials_file="./server.htpasswd", chroma_client_auth_provider="chromadb.auth.basic.BasicAuthClientProvider", chroma_client_auth_credentials="admin:admin", @@ -219,20 +218,36 @@ def fastapi_server_auth_file() -> Generator[System, None, None]: os.remove(server_auth_file) +def fastapi_server_auth_shorthand() -> Generator[System, None, None]: + server_auth_file = os.path.abspath(os.path.join(".", "server.htpasswd")) + with open(server_auth_file, "w") as f: + f.write("admin:$2y$05$e5sRb6NCcSH3YfbIxe1AGu2h5K7OOd982OXKmd8WyQ3DRQ4MvpnZS\n") + for item in _fastapi_fixture( + is_persistent=False, + chroma_server_auth_provider="basic", + chroma_server_auth_credentials_provider="htpasswd_file", + chroma_server_auth_credentials_file="./server.htpasswd", + chroma_client_auth_provider="basic", + chroma_client_auth_credentials="admin:admin", + ): + yield item + os.remove(server_auth_file) + + @pytest.fixture(scope="function") def fastapi_server_auth_invalid_cred() -> Generator[System, None, None]: - print("=========wewqeweqwqe") server_auth_file = os.path.abspath(os.path.join(".", "server.htpasswd")) with open(server_auth_file, "w") as f: f.write("admin:$2y$05$e5sRb6NCcSH3YfbIxe1AGu2h5K7OOd982OXKmd8WyQ3DRQ4MvpnZS\n") - yield _fastapi_fixture( + for item in _fastapi_fixture( is_persistent=False, chroma_server_auth_provider="chromadb.auth.basic.BasicAuthServerProvider", - chroma_server_auth_credentials_provider="chromadb.auth.HtpasswdServerAuthCredentialsProvider", + chroma_server_auth_credentials_provider="chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider", chroma_server_auth_credentials_file="./server.htpasswd", chroma_client_auth_provider="chromadb.auth.basic.BasicAuthClientProvider", chroma_client_auth_credentials="admin:admin1", - ) + ): + yield item os.remove(server_auth_file) @@ -298,6 +313,7 @@ def system_fixtures_auth() -> List[Callable[[], Generator[System, None, None]]]: fixtures = [ fastapi_server_auth_param, fastapi_server_auth_file, + fastapi_server_auth_shorthand, ] return fixtures @@ -321,9 +337,10 @@ def api(system: System) -> Generator[API, None, None]: @pytest.fixture(scope="function") def api_wrong_cred( - fastapi_server_auth_invalid_cred: Generator[System, None, None] + fastapi_server_auth_invalid_cred: System, ) -> Generator[API, None, None]: - api = next(fastapi_server_auth_invalid_cred).instance(API) + fastapi_server_auth_invalid_cred.reset_state() + api = fastapi_server_auth_invalid_cred.instance(API) yield api diff --git a/examples/basic_functionality/client_auth.ipynb b/examples/basic_functionality/client_auth.ipynb index c9ed61c9606..0fdb82e7af8 100644 --- a/examples/basic_functionality/client_auth.ipynb +++ b/examples/basic_functionality/client_auth.ipynb @@ -58,42 +58,19 @@ "\n", "### Server Configuration\n", "\n", - "The following configuration parameters are available for the server (defined as environment variables):\n", + "In order for the server to provide auth it needs several pieces of information and depending on the authentication provider you may or may not need to provide all of them.\n", "\n", - "- `CHROMA_SERVER_AUTH_PROVIDER` - It indicates the authentication provider class to use. In this case we are using the `chromadb.auth.BasicAuthServerProvider` class.\n", - "- `CHROMA_SERVER_AUTH_PROVIDER_CONFIG` - It is a dictionary that contains the configuration parameters for the authentication provider.\n", + "- `CHROMA_SERVER_AUTH_PROVIDER` - It indicates the authentication provider class to use. In this case we are using the `chromadb.auth.basic.BasicAuthServerProvider` class (it is also possible to use `basic` as a shorthand).\n", + "- `CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER` - The credentials provider is a way for the server to validate the provided auth information from the client. You can use `chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider` to validate against a file in htpasswd format (user:password) - single line with bcrypt hash for password. Alternatively you can use a shorthand to load providers (e.g. `htpasswd_file` for `chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider`).\n", + "- `CHROMA_SERVER_AUTH_CREDENTIALS_FILE` - The path to the credentials file in case the credentials provider requires it. In this case we are using the `chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider` provider which requires a file path.\n", "\n", - "#### Basic Authentication Provider Configuration\n", - "\n", - "The following configuration parameters are available for the Basic Authentication Provider (defined as environment variables):\n", - "\n", - "- `CHROMA_SERVER_AUTH_BASIC_USERNAME` - The username to use for authentication.\n", - "- `CHROMA_SERVER_AUTH_BASIC_PASSWORD` - The password to use for authentication.\n", - "- `CHROMA_SERVER_AUTH_IGNORE_PATHS` - A comma separated list of paths to ignore for authentication. This is useful for public endpoints that do not require authentication. This defaults to `/api/v1, /api/v1/heartbeat, /api/v1/version`.\n", - "\n", - "When using `CHROMA_SERVER_AUTH_PROVIDER_CONFIG` to define the basic auth configuration, the following formats are available:\n", - "\n", - "- JSON format: `{\"username\":\"admin\",\"password\":\"admin\"}`\n", - "- File path: `/path/to/htpasswd/file` where the file is in htpasswd format (user:password) - single line with plaintext password.\n", "\n", "### Client Configuration\n", "\n", - "The following configuration parameters are available for the client (defined as environment variables or passed as configuration when setting up the client):\n", - "\n", - "- `CHROMA_CLIENT_AUTH_PROVIDER` - It indicates the authentication provider class to use. In this case we are using the `chromadb.auth.BasicAuthClientProvider` class.\n", - "- `CHROMA_CLIENT_AUTH_PROVIDER_CONFIG` - It is a dictionary that contains the configuration parameters for the authentication provider. This can also be a file path with htpasswd format (user:password) - single line with plaintext password.\n", - "\n", - "#### Basic Authentication Provider Configuration\n", - "\n", - "The following configuration parameters are available for the Basic Authentication Provider (defined as environment variables or passed as configuration when setting up the client):\n", + "Similarly on the client side we need to provide the following configuration parameters:\n", "\n", - "- `CHROMA_CLIENT_AUTH_BASIC_USERNAME` - The username to use for authentication.\n", - "- `CHROMA_CLIENT_AUTH_BASIC_PASSWORD` - The password to use for authentication.\n", - "\n", - "When using `CHROMA_CLIENT_AUTH_PROVIDER_CONFIG` to define the basic auth configuration, the following formats are available:\n", - "\n", - "- JSON format: `{\"username\":\"admin\",\"password\":\"admin\"}`\n", - "- File path: `/path/to/htpasswd/file` where the file is in htpasswd format (user:password) - single line with plaintext password." + "- `CHROMA_CLIENT_AUTH_PROVIDER` - It indicates the authentication provider class to use. In this case we are using the `chromadb.auth.basic.BasicAuthClientProvider` class or `basic` shorthand.\n", + "- `CHROMA_CLIENT_AUTH_CREDENTIALS` - The auth credentials to be passed to the provider. In this case we are using the `admin:admin` credentials as we'll be using Basic Auth.\n" ], "metadata": { "collapsed": false @@ -129,7 +106,7 @@ "export CHROMA_PASSWORD=admin\n", "docker run --rm --entrypoint htpasswd httpd:2 -Bbn ${CHROMA_USER} ${CHROMA_PASSWORD} > server.htpasswd\n", "CHROMA_SERVER_AUTH_CREDENTIALS_FILE=\"./server.htpasswd\" \\\n", - "CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.HtpasswdServerAuthCredentialsProvider' \\\n", + "CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider' \\\n", "CHROMA_SERVER_AUTH_PROVIDER='chromadb.auth.basic.BasicAuthServerProvider' \\\n", "uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 --proxy-headers --log-config log_config.yml\n", "```\n", @@ -144,19 +121,11 @@ "docker run --rm --entrypoint htpasswd httpd:2 -Bbn ${CHROMA_USER} ${CHROMA_PASSWORD} > server.htpasswd\n", "cat << EOF > .env\n", "CHROMA_SERVER_AUTH_CREDENTIALS_FILE=\"/chroma/server.htpasswd\"\n", - "CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.HtpasswdServerAuthCredentialsProvider'\n", + "CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider'\n", "CHROMA_SERVER_AUTH_PROVIDER='chromadb.auth.basic.BasicAuthServerProvider'\n", "EOF\n", "docker-compose up -d --build \n", - "```\n", - "\n", - "\n", - "In the snippet below we will configure the client to use Basic Authentication.\n", - "\n", - "Configuration parameters:\n", - "\n", - "- `chroma_client_auth_provider` - It indicates the authentication provider class to use. In this case we are using the `chromadb.auth.BasicAuthClientProvider` class.\n", - "- `chroma_client_auth_provider_config` - It is a dictionary that contains the configuration parameters for the authentication provider. In this case we are using the `username` and `password` parameters in a JSON format." + "```\n" ], "metadata": { "collapsed": false From 4b6485f115831247c1d489ff0966c149c38aa90d Mon Sep 17 00:00:00 2001 From: Trayan Azarov Date: Wed, 23 Aug 2023 04:09:23 +0300 Subject: [PATCH 13/13] fix: CIP-2 Auth Providers - Removed unused code. Refs: #986 --- chromadb/auth/basic/__init__.py | 10 ---------- chromadb/auth/providers.py | 18 +++++++++--------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/chromadb/auth/basic/__init__.py b/chromadb/auth/basic/__init__.py index bbd8e75e452..a03d195e8ae 100644 --- a/chromadb/auth/basic/__init__.py +++ b/chromadb/auth/basic/__init__.py @@ -13,7 +13,6 @@ AuthInfoType, BasicAuthCredentials, ClientAuthCredentialsProvider, - ClientAuthProtocolAdapter, ClientAuthResponse, ) from chromadb.auth.registry import register_provider, resolve_provider @@ -25,12 +24,6 @@ __all__ = ["BasicAuthServerProvider", "BasicAuthClientProvider"] -def _encode_credentials(username: str, password: str) -> SecretStr: - return SecretStr( - base64.b64encode(f"{username}:{password}".encode("utf-8")).decode("utf-8") - ) - - class BasicAuthClientAuthResponse(ClientAuthResponse): def __init__(self, credentials: SecretStr) -> None: self._credentials = credentials @@ -49,7 +42,6 @@ def get_auth_info(self) -> Tuple[str, SecretStr]: @register_provider("basic") class BasicAuthClientProvider(ClientAuthProvider): _credentials_provider: ClientAuthCredentialsProvider[Any] - _protocol_adapter: ClientAuthProtocolAdapter[Any] def __init__(self, system: System) -> None: super().__init__(system) @@ -95,7 +87,6 @@ def __init__(self, system: System) -> None: @override def authenticate(self, request: ServerAuthenticationRequest[Any]) -> bool: try: - # print(f"BasicAuthServerProvider.authenticate: {}") _auth_header = request.get_auth_info(AuthInfoType.HEADER, "Authorization") return self._credentials_provider.validate_credentials( BasicAuthCredentials.from_header(_auth_header) @@ -103,4 +94,3 @@ def authenticate(self, request: ServerAuthenticationRequest[Any]) -> bool: except Exception as e: logger.error(f"BasicAuthServerProvider.authenticate failed: {repr(e)}") return False - # raise AuthenticationError() diff --git a/chromadb/auth/providers.py b/chromadb/auth/providers.py index de782dd4695..a3bb23616e2 100644 --- a/chromadb/auth/providers.py +++ b/chromadb/auth/providers.py @@ -32,7 +32,7 @@ def __init__(self, system: System) -> None: self.bc = importlib.import_module("bcrypt") except ImportError: raise ValueError( - "The onnxruntime python package is not installed. Please install it with `pip install bcrypt`" + "The bcrypt python package is not installed. Please install it with `pip install bcrypt`" ) @override @@ -69,9 +69,9 @@ def __init__(self, system: System) -> None: "password": SecretStr(_raw_creds[1]), } if ( - len(self._creds) != 2 - or "username" not in self._creds - or "password" not in self._creds + len(self._creds) != 2 + or "username" not in self._creds + or "password" not in self._creds ): raise ValueError( "Invalid Htpasswd credentials found in [chroma_server_auth_credentials]. " @@ -93,9 +93,9 @@ def __init__(self, system: System) -> None: "password": SecretStr(_raw_creds[1]), } if ( - len(self._creds) != 2 - or "username" not in self._creds - or "password" not in self._creds + len(self._creds) != 2 + or "username" not in self._creds + or "password" not in self._creds ): raise ValueError( "Invalid Htpasswd credentials found in [chroma_server_auth_credentials]. " @@ -110,14 +110,14 @@ class _Session(requests.Session): _protocol_adapter: ClientAuthProtocolAdapter[requests.PreparedRequest] def __init__( - self, protocol_adapter: ClientAuthProtocolAdapter[requests.PreparedRequest] + self, protocol_adapter: ClientAuthProtocolAdapter[requests.PreparedRequest] ) -> None: super().__init__() self._protocol_adapter = protocol_adapter @override def send( - self, request: requests.PreparedRequest, **kwargs: Any + self, request: requests.PreparedRequest, **kwargs: Any ) -> requests.Response: self._protocol_adapter.inject_credentials(request) return super().send(request, **kwargs)