-
-
Save drlinux/a1bb8e2e545ae24596e514ba24b9aeed to your computer and use it in GitHub Desktop.
Python SAML parser and validator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from base64 import b64decode | |
from defusedxml.lxml import fromstring | |
from signxml import xmldsig | |
class SAMLParser(object): | |
def __init__(self, rawresp): | |
self.b64 = rawresp | |
self.xml = b64decode(rawresp) | |
self.root = fromstring(self.xml) | |
# Namespace mappings | |
self.samlp_ns = self.root.nsmap['samlp'] | |
self.saml_ns = self.root.nsmap['saml'] | |
self.ds_ns = 'http://www.w3.org/2000/09/xmldsig#' | |
def validate(self, cert=None): | |
"""Validate saml signature with xmldsig""" | |
assertion = self.root.find("{%s}Assertion" % self.saml_ns) | |
# etree can't seem to find the ds:Tag namespace from root so we need the assertion first. | |
signature = assertion.find("{%s}Signature" % self.ds_ns) | |
if not cert: | |
cert = signature.find('.{%s}KeyInfo//{%s}X509Certificate' % (self.ds_ns, | |
self.ds_ns)).text | |
try: | |
assertion_data = xmldsig(assertion).verify(x509_cert=cert) | |
except: | |
raise SAMLInvalidError | |
def groups(self): | |
groups = self.root.findall(".//{%s}Attribute[@Name='groups']/" | |
"{%s}AttributeValue" % (self.saml_ns, | |
self.saml_ns)) | |
return [group.text for group in groups] | |
def username(self): | |
return self.root.find(".//{%s}Attribute[@Name='userLoginID']/" | |
"{%s}AttributeValue" % (self.saml_ns, self.saml_ns)).text | |
def conditions(self): | |
return self.root.find(".//{%s}Conditions" % self.saml_ns).attrib | |
class SAMLInvalidError(Exception): | |
pass | |
class SAMLParseError(Exception): | |
pass |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment