Skip to content

Commit

Permalink
Merge pull request #196 from lucagobbi/custom_auth_handlers
Browse files Browse the repository at this point in the history
Custom auth handlers
  • Loading branch information
sambarza authored Oct 26, 2024
2 parents 7922f6d + e61c975 commit f5b549b
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 4 deletions.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ nav:
- Authentication: production/auth/authentication.md
- Authorization: production/auth/authorization.md
- User Management: production/auth/user-management.md
- Custom Auth: production/auth/custom-auth.md
- Use Cases:
- Integrations: production/use-cases/integrations.md
- Examples: production/use-cases/examples.md
Expand Down
29 changes: 27 additions & 2 deletions mkdocs/plugins/hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -1161,8 +1161,9 @@ Not all the hooks have been documented yet. ( [help needed! 😸](https://d

| Name | Description |
| :---------------------------- | :--------------------------------------------- |
| Factory Allowed LLMs (1) | Intervene before cat retrive llm settings |
| Factory Allowed Embedders (2) | Intervene before cat retrive embedder settings |
| Factory Allowed LLMs (1) | Intervene before cat retrieve llm settings |
| Factory Allowed Embedders (2) | Intervene before cat retrieve embedder settings |
| Factory Allowed AuthHandlers (3) | Intervene before cat retrieve auth handler settings |

</div>

Expand Down Expand Up @@ -1245,4 +1246,28 @@ Not all the hooks have been documented yet. ( [help needed! &#128568;](https://d
- [Python reference]()
- [Plugin object](https://github.com/cheshire-cat-ai/core/blob/main/core/cat/mad_hatter/core_plugin/hooks/language.py#L23)

3. **Input arguments**
`allowed`: List of AuthHandlerConfig classes
!!! info
Useful to extend support of custom auth handlers.

??? example

```python

from cat.mad_hatter.decorators import hook
from typing import List
@hook(priority=0)
def factory_allowed_auth_handlers(allowed: List[AuthHandlerConfig], cat) -> List:
# Add your custom auth handler configuration here
allowed.append(CustomAuthHandlerConfig)
return allowed
```

??? note "Other resources"

- [Custom Auth](../production/auth/custom-auth.md)

> ***NOTE:*** Any function in a plugin decorated by `@plugin` and named properly (among the list of available overrides, **Plugin** tab in the table above) is used to override plugin behaviour. These are not hooks because they are not piped, they are *specific* for every plugin.
143 changes: 142 additions & 1 deletion mkdocs/production/auth/custom-auth.md
Original file line number Diff line number Diff line change
@@ -1 +1,142 @@
# TODO:Custom AuthHandler Docs
# Custom Auth Handler

Want to bring in your own authentication system with your own users? The Cat provides a useful API to
customize the default authentication flow and add a custom auth handler which delegates authentication and authorization
to third party systems.

## Preliminary steps

Since the Cat has its own auth handler mechanism, which is always inserted in the auth handler pipe, you need to lock
your instance following the instructions in the [authentication](authentication.md) section.

## Building a Custom AuthHandler

Let's walk through the process of creating a custom `AuthHandler`. While the exact implementation is subject to the
provider or system you choose to rely on, the overall structure will remain the same.

### Create the Custom Handler

Start by extending the `BaseAuthHandler` class to define the behaviour for handling
tokens and validating users. Here's an example:

```python
from cat.factory.custom_auth_handler import BaseAuthHandler
from cat.auth.permissions import (
AuthPermission, AuthResource, AuthUserInfo, get_base_permissions
)
import httpx

class CustomAuthHandler(BaseAuthHandler):

def __init__(self, **config):
self.server_url = config.get("server_url")


async def authorize_user_from_jwt(self, token: str, auth_resource: str, auth_permission: str):
jwt_validation_url = f"{self.server_url}/validate-token"

async with httpx.AsyncClient() as client:
response = await client.get(jwt_validation_url, headers={
"Authorization": f"Bearer {token}"
})

if response.status_code == 200:
user_data = response.json()

# Return the user information mapped to AuthUserInfo
return AuthUserInfo(
id=user_data.get("username"),
name=user_data.get("name", ""),
extra=user_data.get("extra") # Optional data to be passed to the Cat
)
else:
return None # If the server responds with an error or doesn't respond at all


async def authorize_user_from_key(self, protocol: str, user_id: str, api_key: str, auth_resource, auth_permission):
# Optional: Handle API key authentication, if applicable
return None

```

### Create the Custom Handler Config

Create a new `AuthHandlerConfig` class that inherits from `BaseAuthHandlerConfig`.
This will be the configuration class that contains all the necessary settings to initialize your custom handler.

```python
from cat.factory.auth_handler import AuthHandlerConfig
from typing import Type
from pydantic import ConfigDict, Field

class CustomAuthHandlerConfig(AuthHandlerConfig):
_pyclass: Type = CustomAuthHandler

server_url: str = Field(..., description="The URL of the identity provider")

model_config = ConfigDict(
json_schema_extra={
"humanReadableName": "Custom Auth Handler",
"description": "Delegate auth to a custom identity provider."
}
)

```

### Register the Custom Handler

Register the new handler with the `factory_auth_handlers` hook.

```python
from cat.mad_hatter.decorators import hook
from typing import List

@hook(priority=0)
def factory_allowed_auth_handlers(allowed: List[AuthHandlerConfig], cat) -> List:
allowed.append(CustomAuthHandlerConfig)
return allowed

```

### Activate the Custom Handler

Activate the new handler using the proper endpoint in your Cat installation.

```bash
curl --location --request PUT 'http://{your_cat_instance}/auth_handler/settings/CustomAuthHandlerConfig' \
--header 'Content-Type: application/json' \
--data '{
"server_url": {your_idp_url},
}'
```

That's it! Now every incoming request will be authenticated using the custom auth handler.

## Key Components and Concepts

### BaseAuthHandler

`BaseAuthHandler` is the class that you will extend to implement your custom auth flow. This is an abstract class that
forces you to implement two basic methods: `authorize_user_from_jwt` and `authorize_user_from_key`. You'll write your
own auth logic in there inserting, for example, credentials validation request to external identity providers.

- `authorize_user_from_jwt`: Validates and processes incoming JWT tokens, extracting user information and
- mapping it into Cheshire Cat’s `AuthUserInfo` structure.
- `authorize_user_from_key`: Allows validation of requests based on an API key, usually used for machine to machine communication.

### AuthHandlerConfig

The `AuthHandlerConfig` class provides a base configuration that you can extend to define custom settings for your
authentication handler. It includes all the necessary settings to initialize your custom handler.
These may include: information about the external identity provider, authentication endpoint, client secrets, etc.

### Allowed Auth Handlers Hook

The `factory_allowed_auth_handlers` hook allows you to add your own auth handlers to the list of allowed auth handlers.

### AuthUserInfo

The `AuthUserInfo` class represents the decoded content of an authentication token. This class is used to standardize the
output of AuthHandlers, ensuring that token details are consistent across different authentication systems.
The AuthUserInfo object is crucial for session management within Cat's core, as it either retrieves or creates a user
session, known as a StrayCat.
2 changes: 1 addition & 1 deletion mkdocs/production/auth/user-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ If you're looking for a straightforward way to manage users, you can use the Adm

#### Restful API

The internal user management system is also accessible via a comprehensive RESTful API. There are endpoints for creation, retrieval, updating, and deletion of users. For more information, check the [endpoints](../../production/endpoints.md) page.
The internal user management system is also accessible via a comprehensive RESTful API. There are endpoints for creation, retrieval, updating, and deletion of users. For more information, check the [endpoints](../../production/network/http-endpoints.md) page.

## Want to bring in your own users?

Expand Down

0 comments on commit f5b549b

Please sign in to comment.