From 1675dab314a58a1ccb2bd4f62cb36cf5e3330b57 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Sun, 12 Jul 2020 17:55:09 +0200 Subject: [PATCH] providers/saml: fix encoding for POST bindings --- e2e/test_source_saml.py | 1 + passbook/providers/saml/utils/encoding.py | 4 ++-- passbook/providers/saml/views.py | 6 +++--- passbook/sources/saml/forms.py | 9 ++++----- passbook/sources/saml/processors/request.py | 5 +++-- passbook/sources/saml/processors/response.py | 1 + 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/e2e/test_source_saml.py b/e2e/test_source_saml.py index c2fca68f1..4ea9b2d6d 100644 --- a/e2e/test_source_saml.py +++ b/e2e/test_source_saml.py @@ -186,6 +186,7 @@ class TestSourceSAML(SeleniumTestCase): self.driver.find_element( By.CLASS_NAME, "pf-c-login__main-footer-links-item-link" ).click() + sleep(1) self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click() # Now we should be at the IDP, wait for the username field diff --git a/passbook/providers/saml/utils/encoding.py b/passbook/providers/saml/utils/encoding.py index 387e0a947..ee4d6d9b6 100644 --- a/passbook/providers/saml/utils/encoding.py +++ b/passbook/providers/saml/utils/encoding.py @@ -19,6 +19,6 @@ def deflate_and_base64_encode(inflated: str, encoding="utf-8"): return base64.b64encode(compressed_string).decode(encoding) -def nice64(src): +def nice64(src: str) -> str: """Returns src base64-encoded and formatted nicely for our XML. """ - return base64.b64encode(src).decode("utf-8").replace("\n", "") + return base64.b64encode(src.encode()).decode("utf-8").replace("\n", "") diff --git a/passbook/providers/saml/views.py b/passbook/providers/saml/views.py index 942c7489b..a43f37c8e 100644 --- a/passbook/providers/saml/views.py +++ b/passbook/providers/saml/views.py @@ -33,7 +33,7 @@ from passbook.providers.saml.processors.request_parser import ( AuthNRequest, AuthNRequestParser, ) -from passbook.providers.saml.utils.encoding import nice64 +from passbook.providers.saml.utils.encoding import deflate_and_base64_encode, nice64 from passbook.stages.consent.stage import PLAN_CONTEXT_CONSENT_TEMPLATE LOGGER = get_logger() @@ -190,7 +190,7 @@ class SAMLFlowFinalView(StageView): if provider.sp_binding == SAMLBindings.POST: form_attrs = { "ACSUrl": provider.acs_url, - REQUEST_KEY_SAML_RESPONSE: nice64(response.encode()), + REQUEST_KEY_SAML_RESPONSE: nice64(response), } if auth_n_request.relay_state: form_attrs[REQUEST_KEY_RELAY_STATE] = auth_n_request.relay_state @@ -205,7 +205,7 @@ class SAMLFlowFinalView(StageView): ) if provider.sp_binding == SAMLBindings.REDIRECT: url_args = { - REQUEST_KEY_SAML_RESPONSE: nice64(response.encode()), + REQUEST_KEY_SAML_RESPONSE: deflate_and_base64_encode(response), } if auth_n_request.relay_state: url_args[REQUEST_KEY_RELAY_STATE] = auth_n_request.relay_state diff --git a/passbook/sources/saml/forms.py b/passbook/sources/saml/forms.py index ae3b4fa6e..29f6516b8 100644 --- a/passbook/sources/saml/forms.py +++ b/passbook/sources/saml/forms.py @@ -1,12 +1,12 @@ """passbook SAML SP Forms""" from django import forms +from django.utils.translation import gettext as _ from passbook.admin.forms.source import SOURCE_FORM_FIELDS -from passbook.flows.models import Flow, FlowDesignation from passbook.crypto.models import CertificateKeyPair +from passbook.flows.models import Flow, FlowDesignation from passbook.sources.saml.models import SAMLSource -from django.utils.translation import gettext as _ class SAMLSourceForm(forms.ModelForm): @@ -20,10 +20,9 @@ class SAMLSourceForm(forms.ModelForm): ) signing_kp = forms.ModelChoiceField( queryset=CertificateKeyPair.objects.filter( - certificate_data__isnull=False, - key_data__isnull=False, + certificate_data__isnull=False, key_data__isnull=False, ), - help_text=_("Certificate used to sign Requests.") + help_text=_("Certificate used to sign Requests."), ) class Meta: diff --git a/passbook/sources/saml/processors/request.py b/passbook/sources/saml/processors/request.py index 50b09e8de..07812ffde 100644 --- a/passbook/sources/saml/processors/request.py +++ b/passbook/sources/saml/processors/request.py @@ -1,4 +1,5 @@ """SAML AuthnRequest Processor""" +from base64 import b64encode from typing import Dict from urllib.parse import quote_plus @@ -10,7 +11,7 @@ from lxml.etree import Element # nosec from signxml import XMLSigner from passbook.providers.saml.utils import get_random_id -from passbook.providers.saml.utils.encoding import deflate_and_base64_encode, nice64 +from passbook.providers.saml.utils.encoding import deflate_and_base64_encode from passbook.providers.saml.utils.time import get_time_string from passbook.sources.saml.models import SAMLSource from passbook.sources.saml.processors.constants import ( @@ -115,6 +116,6 @@ class RequestProcessor: sig_hash, ) response_dict["SigAlg"] = sig_alg - response_dict["Signature"] = nice64(signature) + response_dict["Signature"] = b64encode(signature).decode() return response_dict diff --git a/passbook/sources/saml/processors/response.py b/passbook/sources/saml/processors/response.py index 52aab8aa6..a707c9941 100644 --- a/passbook/sources/saml/processors/response.py +++ b/passbook/sources/saml/processors/response.py @@ -68,6 +68,7 @@ class ResponseProcessor: verifier.verify( self._root_xml, x509_cert=self._source.signing_kp.certificate_data ) + LOGGER.debug("Successfully verified signautre") def _handle_name_id_transient(self, request: HttpRequest) -> HttpResponse: """Handle a NameID with the Format of Transient. This is a bit more complex than other