providers/saml: fix encoding for POST bindings

This commit is contained in:
Jens Langhammer 2020-07-12 17:55:09 +02:00
parent 996aa367d3
commit 1675dab314
6 changed files with 14 additions and 12 deletions

View file

@ -186,6 +186,7 @@ class TestSourceSAML(SeleniumTestCase):
self.driver.find_element( self.driver.find_element(
By.CLASS_NAME, "pf-c-login__main-footer-links-item-link" By.CLASS_NAME, "pf-c-login__main-footer-links-item-link"
).click() ).click()
sleep(1)
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click() self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
# Now we should be at the IDP, wait for the username field # Now we should be at the IDP, wait for the username field

View file

@ -19,6 +19,6 @@ def deflate_and_base64_encode(inflated: str, encoding="utf-8"):
return base64.b64encode(compressed_string).decode(encoding) 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. """ """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", "")

View file

@ -33,7 +33,7 @@ from passbook.providers.saml.processors.request_parser import (
AuthNRequest, AuthNRequest,
AuthNRequestParser, 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 from passbook.stages.consent.stage import PLAN_CONTEXT_CONSENT_TEMPLATE
LOGGER = get_logger() LOGGER = get_logger()
@ -190,7 +190,7 @@ class SAMLFlowFinalView(StageView):
if provider.sp_binding == SAMLBindings.POST: if provider.sp_binding == SAMLBindings.POST:
form_attrs = { form_attrs = {
"ACSUrl": provider.acs_url, "ACSUrl": provider.acs_url,
REQUEST_KEY_SAML_RESPONSE: nice64(response.encode()), REQUEST_KEY_SAML_RESPONSE: nice64(response),
} }
if auth_n_request.relay_state: if auth_n_request.relay_state:
form_attrs[REQUEST_KEY_RELAY_STATE] = 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: if provider.sp_binding == SAMLBindings.REDIRECT:
url_args = { url_args = {
REQUEST_KEY_SAML_RESPONSE: nice64(response.encode()), REQUEST_KEY_SAML_RESPONSE: deflate_and_base64_encode(response),
} }
if auth_n_request.relay_state: if auth_n_request.relay_state:
url_args[REQUEST_KEY_RELAY_STATE] = auth_n_request.relay_state url_args[REQUEST_KEY_RELAY_STATE] = auth_n_request.relay_state

View file

@ -1,12 +1,12 @@
"""passbook SAML SP Forms""" """passbook SAML SP Forms"""
from django import forms from django import forms
from django.utils.translation import gettext as _
from passbook.admin.forms.source import SOURCE_FORM_FIELDS from passbook.admin.forms.source import SOURCE_FORM_FIELDS
from passbook.flows.models import Flow, FlowDesignation
from passbook.crypto.models import CertificateKeyPair from passbook.crypto.models import CertificateKeyPair
from passbook.flows.models import Flow, FlowDesignation
from passbook.sources.saml.models import SAMLSource from passbook.sources.saml.models import SAMLSource
from django.utils.translation import gettext as _
class SAMLSourceForm(forms.ModelForm): class SAMLSourceForm(forms.ModelForm):
@ -20,10 +20,9 @@ class SAMLSourceForm(forms.ModelForm):
) )
signing_kp = forms.ModelChoiceField( signing_kp = forms.ModelChoiceField(
queryset=CertificateKeyPair.objects.filter( queryset=CertificateKeyPair.objects.filter(
certificate_data__isnull=False, certificate_data__isnull=False, key_data__isnull=False,
key_data__isnull=False,
), ),
help_text=_("Certificate used to sign Requests.") help_text=_("Certificate used to sign Requests."),
) )
class Meta: class Meta:

View file

@ -1,4 +1,5 @@
"""SAML AuthnRequest Processor""" """SAML AuthnRequest Processor"""
from base64 import b64encode
from typing import Dict from typing import Dict
from urllib.parse import quote_plus from urllib.parse import quote_plus
@ -10,7 +11,7 @@ from lxml.etree import Element # nosec
from signxml import XMLSigner from signxml import XMLSigner
from passbook.providers.saml.utils import get_random_id 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.providers.saml.utils.time import get_time_string
from passbook.sources.saml.models import SAMLSource from passbook.sources.saml.models import SAMLSource
from passbook.sources.saml.processors.constants import ( from passbook.sources.saml.processors.constants import (
@ -115,6 +116,6 @@ class RequestProcessor:
sig_hash, sig_hash,
) )
response_dict["SigAlg"] = sig_alg response_dict["SigAlg"] = sig_alg
response_dict["Signature"] = nice64(signature) response_dict["Signature"] = b64encode(signature).decode()
return response_dict return response_dict

View file

@ -68,6 +68,7 @@ class ResponseProcessor:
verifier.verify( verifier.verify(
self._root_xml, x509_cert=self._source.signing_kp.certificate_data 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: 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 """Handle a NameID with the Format of Transient. This is a bit more complex than other