From a1e703b1555bc52ce0c157935144cc805f7c7401 Mon Sep 17 00:00:00 2001 From: Greg Wong Date: Thu, 9 Nov 2023 18:25:49 +0800 Subject: [PATCH 1/8] feat: allow passing `encryption_keypairs` setting to saml2, and set it automatically if both key_file and cert_file are provided --- django_saml2_auth/saml.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/django_saml2_auth/saml.py b/django_saml2_auth/saml.py index 0248863..a40c0d0 100644 --- a/django_saml2_auth/saml.py +++ b/django_saml2_auth/saml.py @@ -231,6 +231,17 @@ def get_saml_client(domain: str, if cert_file: saml_settings['cert_file'] = cert_file + encryption_keypairs = saml2_auth_settings.get("ENCRYPTION_KEYPAIRS") + if encryption_keypairs: + saml_settings["encryption_keypairs"] = encryption_keypairs + elif key_file and cert_file: + saml_settings["encryption_keypairs"] = [ + { + "key_file": key_file, + "cert_file": cert_file, + } + ] + try: sp_config = Saml2Config() sp_config.load(saml_settings) From 61df369f29e10656ed85c18eafd82c81ee3e2b29 Mon Sep 17 00:00:00 2001 From: Greg Wong Date: Thu, 9 Nov 2023 18:39:46 +0800 Subject: [PATCH 2/8] docs: update README.md and AUTHORS.md --- AUTHORS.md | 1 + README.md | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/AUTHORS.md b/AUTHORS.md index 8d3477d..68c0598 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -57,3 +57,4 @@ an issue. - [Paolo Romolini](https://github.com/paoloromolini) - [Uraiz Ali](https://github.com/UraizAli) - [Santiago Gandolfo](https://github.com/santigandolfo) +- [Greg Wong](https://github.com/gregorywong) diff --git a/README.md b/README.md index 8f4c9b6..5fb93b4 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,14 @@ python setup.py install 'METADATA_LOCAL_FILE_PATH': '[The metadata configuration file path]', 'KEY_FILE': '[The key file path]', 'CERT_FILE': '[The certificate file path]', + + # If both `KEY_FILE` and `CERT_FILE` are provided, `ENCRYPTION_KEYPAIRS` will be added automatically. There is no need to provide it unless you wish to override the default value. + 'ENCRYPTION_KEYPAIRS': [ + { + "key_file": '[The key file path]', + "cert_file": '[The certificate file path]', + } + ], 'DEBUG': False, # Send debug information to a log file # Optional logging configuration. From 7dd806019a588a586b8d98ddbfb372d93078b068 Mon Sep 17 00:00:00 2001 From: Greg Wong Date: Thu, 9 Nov 2023 21:32:16 +0800 Subject: [PATCH 3/8] test: add tests --- django_saml2_auth/tests/dummy_cert.pem | 32 ++++++++++++++++ django_saml2_auth/tests/dummy_key.pem | 52 +++++++++++++++++++++++++ django_saml2_auth/tests/test_saml.py | 53 +++++++++++++++++++++++++- 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 django_saml2_auth/tests/dummy_cert.pem create mode 100644 django_saml2_auth/tests/dummy_key.pem diff --git a/django_saml2_auth/tests/dummy_cert.pem b/django_saml2_auth/tests/dummy_cert.pem new file mode 100644 index 0000000..097e6db --- /dev/null +++ b/django_saml2_auth/tests/dummy_cert.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFbTCCA1WgAwIBAgIUbcK0caWcYgQq/PgM/HpXsfGc7xYwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMzExMDkxMzI4MTNaGA8zMDIz +MDMxMjEzMjgxM1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx +ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAO0hfWkIoYvRBSvSQJazwp2NadhPCJEPliY0ZgKu +dQibzV1oav6DdxZWxs3ys3HKpUnfRTsMXMXzYFJv3M17X8kAsEAfjLKIC3POV/Og +73fW7T/2uJubIE0bI6whe44/4vV6JVKuZUf7N/eD2k0x9t7O+ljITdnFyNbwLJ24 +ZoVSB9VhhAN+gVlR+D9yr5NwcWSVSnn9wxKh5cHpNu85g/dpQ7sA8QNSQGgJ763V +WiITxGQ1S13+RKRDdtzaahjkEezh0nCeVBypQ2u4zMj3jEVgnSqcxIaGoSyRlsr4 +kyoeFVHFJq3vVOMHa21luPaDsskssBMu13udVUmsaiEQc4Z7ItlHeXgQc0cy6N94 +uZw+qw+CMRWvZGsyKWuvNfQu/ZAME8MrhveLot9pcf2PFXLG+kitE741m0A1JP3v +xRaGRHU4L0fkBalTVUncLo6hBAvgH+uN+Dl2p7KnIanHgMXQXv/UdRyzuJ5E7q+B +yHnwXwNRcCOWrOFe07yQetc5f+Z8+p2X6lkjgMD+d6IrKIsYCMU1ZMHi+oWkSbei +oDx/kk7xPnNLM1hbmQPNrbt19M49rGg6CN8Z6vjVavdJ5Rpj0Tq13JWA52eJu/NT +wpxYaWeh7WkzhHAS9bgyOX/ot9iJSPicLdrl5qMkwmPqi8UyXrVLA2LCG0SH2Oz5 +YT8TAgMBAAGjUzBRMB0GA1UdDgQWBBQzOZToKlK9pjiv6JG78CLq/+GJuTAfBgNV +HSMEGDAWgBQzOZToKlK9pjiv6JG78CLq/+GJuTAPBgNVHRMBAf8EBTADAQH/MA0G +CSqGSIb3DQEBCwUAA4ICAQAygpKdXrSPYdTSuLfDXHAo+CPSynNFBUUbbQta23r+ +ucJVc79fgIT+lZbXm35ddQ2uhCuZuQy+K2JSBv7Zcr7xii89YyMkHGKINvJVhjgG +aZQARrdWcd1c8DnSfC144TITDFC2uqX0L2f6m/V//J8y7Dwetqh13nzKXE8xmWc5 +fmwiULXQrJ1cqn1cEB/1y1rQOT+bAbsJ6gzpSyxf8gRklKYQmkPvATvOOg+GK1d3 +GeQLhw6KcDql1d2VnHb7vQRow7Uidtxi7lKcj6k4R+7hg8BBNtrsHH0GsGCfun8O ++VxtS+YT6xM7LYwuyTEtcHz1pyqyIpFBYsyNm8WH/F9i1Is1Jj5om5Zx6inL31YV +RRKujvvRjRe3g3uZY15p5/HHNK5riPkVZRPT9qVPDxnScjgaI5EhLw173sEt6ktG +7zrlC7yZFpNMkGSs5SkT8lUQTmGr2gD5b02N4UNdhCF+WZOmMLjQAvinMGfdjqek +3e6llupoyNOzG+4LvI/HzVHqg6WjVO5QSP/4gt21SSgUo7mHa0GQMymVmkCrWEMY ++PhpuNE5fv9CGyi22f+LZ988jGhpHApzrdGBY/M3h7k4mD7Ap/a8J3inJPLKOgIG +z1VT29ZzR8R7NpkoJV1zX9/wFUf5lZMi3UJPuj/LPOf0jcoZbV8B/E7ydf6akm69 +Xg== +-----END CERTIFICATE----- diff --git a/django_saml2_auth/tests/dummy_key.pem b/django_saml2_auth/tests/dummy_key.pem new file mode 100644 index 0000000..a94956a --- /dev/null +++ b/django_saml2_auth/tests/dummy_key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +K1a3lfdFi6tz5qORy3yofYqvqi6wEko= +-----END PRIVATE KEY----- diff --git a/django_saml2_auth/tests/test_saml.py b/django_saml2_auth/tests/test_saml.py index fcb1f97..def9cbf 100644 --- a/django_saml2_auth/tests/test_saml.py +++ b/django_saml2_auth/tests/test_saml.py @@ -2,7 +2,7 @@ Tests for saml.py """ -from typing import Optional, List, Mapping +from typing import Dict, Optional, List, Mapping, Union import pytest import responses @@ -349,6 +349,57 @@ def test_get_saml_client_failure_with_invalid_file(settings: SettingsWrapper): assert isinstance(exc_info.value.extra["exc"], FileNotFoundError) +@pytest.mark.parametrize( + "supplied_config_values,expected_encryption_keypairs", + [ + ( + { + "KEY_FILE": "django_saml2_auth/tests/dummy_key.pem", + }, + None, + ), + ( + { + "CERT_FILE": "django_saml2_auth/tests/dummy_cert.pem", + }, + None, + ), + ( + { + "KEY_FILE": "django_saml2_auth/tests/dummy_key.pem", + "CERT_FILE": "django_saml2_auth/tests/dummy_cert.pem", + }, + [ + { + "key_file": "django_saml2_auth/tests/dummy_key.pem", + "cert_file": "django_saml2_auth/tests/dummy_cert.pem", + } + ], + ), + ], +) +def test_get_saml_client_success_with_key_and_cert_files(settings: SettingsWrapper, supplied_config_values: Dict[str, str], expected_encryption_keypairs: Union[List, None]): + """Test get_saml_client function to verify if it is correctly instantiated with encryption keypairs + if both key and cert files are provided (and encryption keypair isn't provided). + + Args: + settings (SettingsWrapper): Fixture for django settings + """ + + settings.SAML2_AUTH["METADATA_LOCAL_FILE_PATH"] = "django_saml2_auth/tests/metadata.xml" + + for key, value in supplied_config_values.items(): + settings.SAML2_AUTH[key] = value + + result = get_saml_client("example.com", acs) + assert isinstance(result, Saml2Client) + assert result.config.encryption_keypairs == expected_encryption_keypairs + + for key, value in supplied_config_values.items(): + # ensure that the added settings do not get carried over to other tests + del settings.SAML2_AUTH[key] + + @responses.activate def test_decode_saml_response_success( settings: SettingsWrapper, monkeypatch: "MonkeyPatch"): # type: ignore From 760b2f670b08e29cff61c509d4737ed19a3c4c6e Mon Sep 17 00:00:00 2001 From: Greg Wong Date: Thu, 9 Nov 2023 21:37:40 +0800 Subject: [PATCH 4/8] docs: update docstring --- django_saml2_auth/tests/test_saml.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/django_saml2_auth/tests/test_saml.py b/django_saml2_auth/tests/test_saml.py index def9cbf..74e008b 100644 --- a/django_saml2_auth/tests/test_saml.py +++ b/django_saml2_auth/tests/test_saml.py @@ -379,8 +379,8 @@ def test_get_saml_client_failure_with_invalid_file(settings: SettingsWrapper): ], ) def test_get_saml_client_success_with_key_and_cert_files(settings: SettingsWrapper, supplied_config_values: Dict[str, str], expected_encryption_keypairs: Union[List, None]): - """Test get_saml_client function to verify if it is correctly instantiated with encryption keypairs - if both key and cert files are provided (and encryption keypair isn't provided). + """Test get_saml_client function to verify that it is correctly instantiated with encryption_keypairs + if both key_file and cert_file are provided (even if encryption_keypairs isn't). Args: settings (SettingsWrapper): Fixture for django settings From 6acce98ccfe5c60c54bb85af2a2d52b8754c3b33 Mon Sep 17 00:00:00 2001 From: Greg Wong Date: Thu, 9 Nov 2023 21:38:44 +0800 Subject: [PATCH 5/8] lint: fix formatting --- django_saml2_auth/tests/test_saml.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/django_saml2_auth/tests/test_saml.py b/django_saml2_auth/tests/test_saml.py index 74e008b..3411346 100644 --- a/django_saml2_auth/tests/test_saml.py +++ b/django_saml2_auth/tests/test_saml.py @@ -378,7 +378,11 @@ def test_get_saml_client_failure_with_invalid_file(settings: SettingsWrapper): ), ], ) -def test_get_saml_client_success_with_key_and_cert_files(settings: SettingsWrapper, supplied_config_values: Dict[str, str], expected_encryption_keypairs: Union[List, None]): +def test_get_saml_client_success_with_key_and_cert_files( + settings: SettingsWrapper, + supplied_config_values: Dict[str, str], + expected_encryption_keypairs: Union[List, None], +): """Test get_saml_client function to verify that it is correctly instantiated with encryption_keypairs if both key_file and cert_file are provided (even if encryption_keypairs isn't). From 3f80211622a78d43614eab0d325b1b951c087064 Mon Sep 17 00:00:00 2001 From: Greg Wong Date: Thu, 9 Nov 2023 23:16:47 +0800 Subject: [PATCH 6/8] docs: update Module Settings section --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5fb93b4..719a435 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,7 @@ Some of the following settings are related to how this module operates. The rest | **METADATA\_LOCAL\_FILE\_PATH** | SAML2 metadata configuration file path | `str` | `None` | `/path/to/the/metadata.xml` | | **KEY_FILE** | SAML2 private key file path | `str` | `None` | `/path/to/the/key.pem` | | **CERT_FILE** | SAML2 public certificate file path | `str` | `None` | `/path/to/the/cert.pem` | +| **ENCRYPTION_KEYPAIRS** | Required for handling encrypted assertions. Will be automatically set if both `KEY_FILE` and `CERT_FILE` are set. | `list` | Not set. | [ { "key_file": '[The key file path]', "cert_file": '[The certificate file path]' } ] | | **DEBUG** | Send debug information to a log file | `bool` | `False` | | | **LOGGING** | Logging configuration dictionary | `dict` | Not set. | | | **DEFAULT\_NEXT\_URL** | Custom target redirect URL after the user get logged in. Default to /admin if not set. This setting will be overwritten if you have parameter `?next=` specificed in the login URL. | `str` | `admin:index` | `https://app.example.com/account/login` | From 1a6b4521b7f0fada8667063a0aee4d8b4ec1cc11 Mon Sep 17 00:00:00 2001 From: Greg Wong Date: Thu, 9 Nov 2023 23:17:48 +0800 Subject: [PATCH 7/8] docs: fix formatting --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 719a435..45537c3 100644 --- a/README.md +++ b/README.md @@ -229,7 +229,7 @@ Some of the following settings are related to how this module operates. The rest | **METADATA\_LOCAL\_FILE\_PATH** | SAML2 metadata configuration file path | `str` | `None` | `/path/to/the/metadata.xml` | | **KEY_FILE** | SAML2 private key file path | `str` | `None` | `/path/to/the/key.pem` | | **CERT_FILE** | SAML2 public certificate file path | `str` | `None` | `/path/to/the/cert.pem` | -| **ENCRYPTION_KEYPAIRS** | Required for handling encrypted assertions. Will be automatically set if both `KEY_FILE` and `CERT_FILE` are set. | `list` | Not set. | [ { "key_file": '[The key file path]', "cert_file": '[The certificate file path]' } ] | +| **ENCRYPTION_KEYPAIRS** | Required for handling encrypted assertions. Will be automatically set if both `KEY_FILE` and `CERT_FILE` are set. | `list` | Not set. | `[ { "key_file": '[The key file path]', "cert_file": '[The certificate file path]' } ]` | | **DEBUG** | Send debug information to a log file | `bool` | `False` | | | **LOGGING** | Logging configuration dictionary | `dict` | Not set. | | | **DEFAULT\_NEXT\_URL** | Custom target redirect URL after the user get logged in. Default to /admin if not set. This setting will be overwritten if you have parameter `?next=` specificed in the login URL. | `str` | `admin:index` | `https://app.example.com/account/login` | From 8cf2f6e9b001a6310d90fecc057385674fb1645f Mon Sep 17 00:00:00 2001 From: Greg Wong Date: Thu, 9 Nov 2023 23:20:43 +0800 Subject: [PATCH 8/8] docs: use single quotes for consistency across other parts of the doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 45537c3..df16324 100644 --- a/README.md +++ b/README.md @@ -229,7 +229,7 @@ Some of the following settings are related to how this module operates. The rest | **METADATA\_LOCAL\_FILE\_PATH** | SAML2 metadata configuration file path | `str` | `None` | `/path/to/the/metadata.xml` | | **KEY_FILE** | SAML2 private key file path | `str` | `None` | `/path/to/the/key.pem` | | **CERT_FILE** | SAML2 public certificate file path | `str` | `None` | `/path/to/the/cert.pem` | -| **ENCRYPTION_KEYPAIRS** | Required for handling encrypted assertions. Will be automatically set if both `KEY_FILE` and `CERT_FILE` are set. | `list` | Not set. | `[ { "key_file": '[The key file path]', "cert_file": '[The certificate file path]' } ]` | +| **ENCRYPTION_KEYPAIRS** | Required for handling encrypted assertions. Will be automatically set if both `KEY_FILE` and `CERT_FILE` are set. | `list` | Not set. | `[ { 'key_file': '[The key file path]', 'cert_file': '[The certificate file path]' } ]` | | **DEBUG** | Send debug information to a log file | `bool` | `False` | | | **LOGGING** | Logging configuration dictionary | `dict` | Not set. | | | **DEFAULT\_NEXT\_URL** | Custom target redirect URL after the user get logged in. Default to /admin if not set. This setting will be overwritten if you have parameter `?next=` specificed in the login URL. | `str` | `admin:index` | `https://app.example.com/account/login` |