Skip to content

Commit

Permalink
[feat] Implement a setting to disable the exception handler. (#345)
Browse files Browse the repository at this point in the history
* [FEAT] Implement a setting to disable the exception handler.
* Some fixes and improvements
  • Loading branch information
henryh9n authored Oct 23, 2024
1 parent cba317c commit df32f5f
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 3 deletions.
1 change: 1 addition & 0 deletions AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,4 @@ an issue.
- [Greg Wong](https://github.com/gregorywong)
- [Michael V. Battista](https://github.com/mvbattista)
- [William Abbott](https://github.com/wrabit)
- [Henry Harutyunyan](https://github.com/henryh9n) (Revolut)
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ python setup.py install
'ACCEPTED_TIME_DIFF': None, # Accepted time difference between your server and the Identity Provider
'ALLOWED_REDIRECT_HOSTS': ["https://myfrontendclient.com"], # Allowed hosts to redirect to using the ?next parameter
'TOKEN_REQUIRED': True, # Whether or not to require the token parameter in the SAML assertion
'DISABLE_EXCEPTION_HANDLER': True, # Whether the custom exception handler should be used
}

```
Expand All @@ -231,7 +232,7 @@ Some of the following settings are related to how this module operates. The rest
<summary>Click to see the module settings</summary>

| **Field name** | **Description** | **Data type(s)** | **Default value(s)** | **Example** |
| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------|
| **METADATA\_AUTO\_CONF\_URL** | Auto SAML2 metadata configuration URL | `str` | `None` | `https://ORG.okta.com/app/APP-ID/sso/saml/metadata` |
| **METADATA\_LOCAL\_FILE\_PATH** | SAML2 metadata configuration file path | `str` | `None` | `/path/to/the/metadata.xml` |
| **KEY_FILE** | SAML2 private key file path. Required for AUTHN\_REQUESTS\_SIGNED | `str` | `None` | `/path/to/the/key.pem` |
Expand Down Expand Up @@ -273,6 +274,7 @@ Some of the following settings are related to how this module operates. The rest
| **WANT\_RESPONSE\_SIGNED** | Set this to `False` if you don't want your provider to sign the response. | `bool` | `True` | |
| **ACCEPTED\_TIME\_DIFF** | Sets the [accepted time diff](https://pysaml2.readthedocs.io/en/latest/howto/config.html#accepted-time-diff) in seconds | `int` or `None` | `None` | |
| **ALLOWED\_REDIRECT\_HOSTS** | Allowed hosts to redirect to using the `?next=` parameter | `list` | `[]` | `['https://app.example.com', 'https://api.exmaple.com']` |
| **DISABLE\_EXCEPTION\_HANDLER** | Set this to `True` if you want to disable the exception handler. Make sure to handle the `SAMLAuthError`s and other exceptions. | `bool` | `False` | |

### Triggers

Expand Down Expand Up @@ -349,11 +351,21 @@ def get_custom_token_query(refresh):

```

## Customize Error Messages
## Exception Handling
This library implements an exception handler that returns an error response with a default error template. See the
section below if you want to implement a custom error template.

If you want to disable error handling, set `DISABLE_EXCEPTION_HANDLER` to `True`. In this case the library will raise
`SAMLAuthError` when an error happens and you might need to implement an exception handler. This might come in handy if
you are using the library for an API.

## Customize Error Messages and Templates

The default permission `denied`, `error` and user `welcome` page can be overridden.

To override these pages put a template named 'django\_saml2\_auth/error.html', 'django\_saml2\_auth/welcome.html' or 'django\_saml2\_auth/denied.html' in your project's template folder.
> [!Note]
> If you set `DISABLE_EXCEPTION_HANDLER` to `True`, the custom error pages will not be displayed.

If a 'django\_saml2\_auth/welcome.html' template exists, that page will be shown to the user upon login instead of the user being redirected to the previous visited page. This welcome page can contain some first-visit notes and welcome words. The [Django user object](https://docs.djangoproject.com/en/1.9/ref/contrib/auth/#django.contrib.auth.models.User) is available within the template as the `user` template variable.

Expand Down
23 changes: 22 additions & 1 deletion django_saml2_auth/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import pytest
from django.http import HttpRequest, HttpResponse
from django.urls import NoReverseMatch
from pytest_django.fixtures import SettingsWrapper

from django_saml2_auth.exceptions import SAMLAuthError
from django_saml2_auth.utils import (
exception_handler,
Expand Down Expand Up @@ -39,7 +41,7 @@ def hello(_: HttpRequest) -> HttpResponse:
return HttpResponse(content="Hello, world!")


def goodbye(_: HttpRequest) -> None:
def goodbye(_: HttpRequest) -> HttpResponse:
"""Simple view function for testing exception_handler
Args:
Expand Down Expand Up @@ -139,6 +141,25 @@ def test_exception_handler_handle_exception():
assert "Reason: Internal world error!" in contents


def test_exception_handler_diabled_success(settings: SettingsWrapper):
"""Test exception_handler decorator in disabled state with a valid function."""
settings.SAML2_AUTH["DISABLE_EXCEPTION_HANDLER"] = True

decorated_hello = exception_handler(hello)
result = decorated_hello(HttpRequest())
assert result.content.decode("utf-8") == "Hello, world!"


def test_exception_handler_disabled_on_exception(settings: SettingsWrapper):
"""Test exception_handler decorator in a disabled state to make sure it raises the
exception."""
settings.SAML2_AUTH["DISABLE_EXCEPTION_HANDLER"] = True

decorated_goodbye = exception_handler(goodbye)
with pytest.raises(SAMLAuthError):
decorated_goodbye(HttpRequest())


def test_jwt_well_formed():
"""Test if passed RelayState is a well formed JWT"""
token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0MjQyIiwibmFtZSI6Ikplc3NpY2EgVGVtcG9yYWwiLCJuaWNrbmFtZSI6Ikplc3MifQ.EDkUUxaM439gWLsQ8a8mJWIvQtgZe0et3O3z4Fd_J8o" # noqa
Expand Down
3 changes: 3 additions & 0 deletions django_saml2_auth/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ def exception_handler(
Decorated view function with exception handling
"""

if dictor(settings.SAML2_AUTH, "DISABLE_EXCEPTION_HANDLER", False):
return function

def handle_exception(exc: Exception, request: HttpRequest) -> HttpResponse:
"""Render page with exception details
Expand Down

0 comments on commit df32f5f

Please sign in to comment.