Esempio n. 1
0
def main(config_file):
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s.%(msecs)03d example: %(levelname)s: %(message)s',
        datefmt='%Y-%m-%dT%H:%M:%S',
    )

    config = ConfigParser.RawConfigParser()
    config_path = os.path.expanduser(config_file)
    config_path = os.path.abspath(config_path)
    with open(config_path) as f:
        config.readfp(f)

    host = config.get('app', 'host')
    port = config.get('app', 'port')
    port = int(port)

    settings = dict()
    settings['assertion_consumer_service_url'] = config.get(
        'saml',
        'assertion_consumer_service_url'
    )
    settings['issuer'] = config.get(
        'saml',
        'issuer'
    )
    settings['name_identifier_format'] = config.get(
        'saml',
        'name_identifier_format'
    )
    settings['idp_sso_target_url'] = config.get(
        'saml',
        'idp_sso_target_url'
    )
    settings['idp_cert_file'] = config.get(
        'saml',
        'idp_cert_file'
    )
    settings['idp_cert_fingerprint'] = config.get(
        'saml',
        'idp_cert_fingerprint'
    )

    cert_file = settings.pop('idp_cert_file', None)

    # idp_cert_file has priority over idp_cert_fingerprint
    if cert_file:
        cert_path = os.path.expanduser(cert_file)
        cert_path = os.path.abspath(cert_path)

        with open(cert_path) as f:
            cert = f.read()
            fingerprint = calculate_x509_fingerprint(cert)
            if fingerprint:
                settings['idp_cert_fingerprint'] = fingerprint
    else:
        formated = format_finger_print(settings['idp_cert_fingerprint'])
        settings['idp_cert_fingerprint'] = formated

    parts = urlparse.urlparse(settings['assertion_consumer_service_url'])
    SampleAppHTTPRequestHandler.protocol_version = 'HTTP/1.0'
    SampleAppHTTPRequestHandler.settings = settings
    SampleAppHTTPRequestHandler.saml_post_path = parts.path
    httpd = HTTPServer(
        (host, port),
        SampleAppHTTPRequestHandler,
    )

    socket_name = httpd.socket.getsockname()

    log.info(
        'Serving HTTP on {host} port {port} ...'.format(
            host=socket_name[0],
            port=socket_name[1],
        )
    )

    httpd.serve_forever()
Esempio n. 2
0
def verify(document, signature, _etree=None, _tempfile=None, _subprocess=None,
           _os=None):
    """
    Verify that signature contained in the samlp:Response is valid when checked
    against the provided signature. Return True if valid, otherwise False
    Arguments:
    document -- lxml.etree.XML object containing the samlp:Response
    signature -- The fingerprint to check the samlp:Response against
    """
    if _etree is None:
        _etree = etree
    if _tempfile is None:
        _tempfile = tempfile
    if _subprocess is None:
        _subprocess = subprocess
    if _os is None:
        _os = os

    signatureNodes = document.xpath("//ds:Signature", namespaces={'ds': 'http://www.w3.org/2000/09/xmldsig#'})

    parent_id_container = 'urn:oasis:names:tc:SAML:2.0:assertion:Assertion'
    if signatureNodes and signatureNodes[0].getparent().tag == '{urn:oasis:names:tc:SAML:2.0:protocol}Response':
        parent_id_container = 'urn:oasis:names:tc:SAML:2.0:protocol:Response'

    certificateNodes = document.xpath("//ds:X509Certificate", namespaces={'ds': 'http://www.w3.org/2000/09/xmldsig#'})

    if not certificateNodes or calculate_x509_fingerprint(certificateNodes[0].text) != signature:
        return False
    else:
        # use the x509 cert instead of fingerprint required by xmlsec
        signature = format_cert(certificateNodes[0].text)

    xmlsec_bin = _get_xmlsec_bin()

    verified = False
    cert_filename = None
    xml_filename = None
    # Windows hack: Without the delete=False parameter in NamedTemporaryFile
    # xmlsec.exe will get an IO Permission Denied error.
    try:
        with _tempfile.NamedTemporaryFile(delete=False) as xml_fp:
            doc_str = _etree.tostring(document)
            xml_fp.write(doc_str)
            xml_fp.seek(0)
            with _tempfile.NamedTemporaryFile(delete=False) as cert_fp:
                cert_fp.write(signature)
                cert_fp.seek(0)

                cert_filename = cert_fp.name
                xml_filename = xml_fp.name

                # We cannot use xmlsec python bindings to verify here because
                # that would require a call to libxml2.xmlAddID. The libxml2
                # python bindings do not yet provide this function.
                # http://www.aleksey.com/xmlsec/faq.html Section 3.2
                cmds = [
                    xmlsec_bin,
                    '--verify',
                    '--pubkey-cert-pem',
                    cert_filename,
                    '--id-attr:ID',
                    parent_id_container,
                    xml_filename,
                ]

                proc = _subprocess.Popen(
                    cmds,
                    stderr=_subprocess.PIPE,
                    stdout=_subprocess.PIPE,
                )
                proc.wait()
                verified = _parse_stderr(proc)
    finally:
        if cert_filename is not None:
            _os.remove(cert_filename)
        if xml_filename is not None:
            _os.remove(xml_filename)

    return verified
Esempio n. 3
0
def verify(document, signature, _etree=None, _tempfile=None, _subprocess=None, _os=None):
    """
    Verify that signature contained in the samlp:Response is valid when checked
    against the provided signature. Return True if valid, otherwise False
    Arguments:
    document -- lxml.etree.XML object containing the samlp:Response
    signature -- The fingerprint to check the samlp:Response against
    """
    if _etree is None:
        _etree = etree
    if _tempfile is None:
        _tempfile = tempfile
    if _subprocess is None:
        _subprocess = subprocess
    if _os is None:
        _os = os

    signatureNodes = document.xpath("//ds:Signature", namespaces={"ds": "http://www.w3.org/2000/09/xmldsig#"})

    parent_id_container = "urn:oasis:names:tc:SAML:2.0:assertion:Assertion"
    if signatureNodes and signatureNodes[0].getparent().tag == "{urn:oasis:names:tc:SAML:2.0:protocol}Response":
        parent_id_container = "urn:oasis:names:tc:SAML:2.0:protocol:Response"

    certificateNodes = document.xpath("//ds:X509Certificate", namespaces={"ds": "http://www.w3.org/2000/09/xmldsig#"})

    if not certificateNodes or calculate_x509_fingerprint(certificateNodes[0].text) != signature:
        return False
    else:
        # use the x509 cert instead of fingerprint required by xmlsec
        signature = format_cert(certificateNodes[0].text)

    xmlsec_bin = _get_xmlsec_bin()

    verified = False
    cert_filename = None
    xml_filename = None
    # Windows hack: Without the delete=False parameter in NamedTemporaryFile
    # xmlsec.exe will get an IO Permission Denied error.
    try:
        with _tempfile.NamedTemporaryFile(delete=False) as xml_fp:
            doc_str = _etree.tostring(document)
            xml_fp.write(doc_str)
            xml_fp.seek(0)
            with _tempfile.NamedTemporaryFile(delete=False) as cert_fp:
                cert_fp.write(signature)
                cert_fp.seek(0)

                cert_filename = cert_fp.name
                xml_filename = xml_fp.name

                # We cannot use xmlsec python bindings to verify here because
                # that would require a call to libxml2.xmlAddID. The libxml2
                # python bindings do not yet provide this function.
                # http://www.aleksey.com/xmlsec/faq.html Section 3.2
                cmds = [
                    xmlsec_bin,
                    "--verify",
                    "--pubkey-cert-pem",
                    cert_filename,
                    "--id-attr:ID",
                    parent_id_container,
                    xml_filename,
                ]

                proc = _subprocess.Popen(cmds, stderr=_subprocess.PIPE, stdout=_subprocess.PIPE)
                proc.wait()
                verified = _parse_stderr(proc)
    finally:
        if cert_filename is not None:
            _os.remove(cert_filename)
        if xml_filename is not None:
            _os.remove(xml_filename)

    return verified
Esempio n. 4
0
def main(config_file):
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s.%(msecs)03d example: %(levelname)s: %(message)s',
        datefmt='%Y-%m-%dT%H:%M:%S',
    )

    config = ConfigParser.RawConfigParser()
    config_path = os.path.expanduser(config_file)
    config_path = os.path.abspath(config_path)
    with open(config_path) as f:
        config.readfp(f)

    host = config.get('app', 'host')
    port = config.get('app', 'port')
    port = int(port)

    settings = dict()
    settings['assertion_consumer_service_url'] = config.get(
        'saml', 'assertion_consumer_service_url')
    settings['issuer'] = config.get('saml', 'issuer')
    settings['name_identifier_format'] = config.get('saml',
                                                    'name_identifier_format')
    settings['idp_sso_target_url'] = config.get('saml', 'idp_sso_target_url')
    settings['idp_cert_file'] = config.get('saml', 'idp_cert_file')
    settings['idp_cert_fingerprint'] = config.get('saml',
                                                  'idp_cert_fingerprint')

    cert_file = settings.pop('idp_cert_file', None)

    # idp_cert_file has priority over idp_cert_fingerprint
    if cert_file:
        cert_path = os.path.expanduser(cert_file)
        cert_path = os.path.abspath(cert_path)

        with open(cert_path) as f:
            cert = f.read()
            fingerprint = calculate_x509_fingerprint(cert)
            if fingerprint:
                settings['idp_cert_fingerprint'] = fingerprint
    else:
        formated = format_finger_print(settings['idp_cert_fingerprint'])
        settings['idp_cert_fingerprint'] = formated

    parts = urlparse.urlparse(settings['assertion_consumer_service_url'])
    SampleAppHTTPRequestHandler.protocol_version = 'HTTP/1.0'
    SampleAppHTTPRequestHandler.settings = settings
    SampleAppHTTPRequestHandler.saml_post_path = parts.path
    httpd = HTTPServer(
        (host, port),
        SampleAppHTTPRequestHandler,
    )

    socket_name = httpd.socket.getsockname()

    log.info('Serving HTTP on {host} port {port} ...'.format(
        host=socket_name[0],
        port=socket_name[1],
    ))

    httpd.serve_forever()