예제 #1
0
    def GetSAMLRequest(strACSUrl = None, strIssuer = None):

        xSAMLPNode = ElementMaker(namespace='urn:oasis:names:tc:SAML:2.0:protocol', nsmap=dict(saml2p='urn:oasis:names:tc:SAML:2.0:protocol'))
        xSAMLNode = ElementMaker(namespace='urn:oasis:names:tc:SAML:2.0:assertion', nsmap=dict(saml2='urn:oasis:names:tc:SAML:2.0:assertion'))

        dCurrentTime = datetime.utcnow()

        xAuthnRequestNode = xSAMLPNode.AuthnRequest(ProtocolBinding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', Version='2.0', IssueInstant= dCurrentTime.replace(microsecond=0).isoformat() + ".46Z", ID=uuid.uuid4().hex, AssertionConsumerServiceURL=strACSUrl)

        xIssuerNode = xSAMLNode.Issuer()
        xIssuerNode.text = strIssuer
        xAuthnRequestNode.append(xIssuerNode)

        xNameIDNode = xSAMLPNode.NameIDPolicy('urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified',AllowCreate='true')
        xAuthnRequestNode.append(xNameIDNode)

        xAuthnContextNode = xSAMLPNode.RequestedAuthnContext(Comparison='exact')
        xAuthnRequestNode.append(xAuthnContextNode)
        xAuthnContextClassRef = xSAMLNode.AuthnContextClassRef()
        xAuthnContextClassRef.text = 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
        xAuthnContextNode.append(xAuthnContextClassRef)

        strBase64Request = base64.b64encode(etree.tostring(xAuthnRequestNode))
        strUrlParams = urllib.parse.urlencode([('SAMLRequest', strBase64Request)])
  
        return strUrlParams
예제 #2
0
    def __init__(self, _clock=None, _uuid=None, **kwargs):
        """Create a URL string which can be used to redirect a samlp:AuthnRequest to the identity provider.
        Return a URL string containing the idp_sso_target_url and a deflated, base64-encoded, url-encoded (in that order) samlp:AuthnRequest XML element as the value of the SAMLRequest parameter.

        Keyword arguments:
        assertion_consumer_service_url -- The URL at which the SAML assertion should be received.
        issuer -- The name of your application. Some identity providers might need this to establish the identity of the service provider requesting the login.
        name_identifier_format -- The format of the username required by this application. If you need the email address, use "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress". See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf section 8.3 for other options. Note that the identity provider might not support all options.
        idp_sso_target_url -- The URL to which the authentication request should be sent. This would be on the identity
        sp_assertion_binding -- The assertion-bind type, possible values HTTP_POST or HTTP-Artifact, default HTTP-Artifact.
        """
        super(AuthRequest, self).__init__()
        if _clock is None:
            _clock = datetime.utcnow
        if _uuid is None:
            _uuid = uuid.uuid4

        assertion_consumer_service_url = kwargs.pop(
            'assertion_consumer_service_url')

        issuer = kwargs.pop('issuer')
        name_identifier_format = kwargs.pop('name_identifier_format')
        self.target_url = kwargs.pop('idp_sso_target_url')
        # Introduced when ID-porten stopped using HTTP-POST.
        assertion_binding = kwargs.get('sp_assertion_binding', '')

        if assertion_binding is None or len(assertion_binding.strip()) == 0:
            assertion_binding = 'HTTP-Artifact'
        if not assertion_binding in LEGAL_BINDINGS:
            raise Exception('Illegal binding')

        now = _clock()
        # Resolution finer than milliseconds not allowed
        # http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf Section
        # 1.3.3
        now = now.replace(microsecond=0)
        now_iso = now.isoformat() + ".875Z"  #TODO: add better format here

        unique_id = _uuid()
        unique_id = unique_id.hex

        samlp_maker = ElementMaker(
            namespace='urn:oasis:names:tc:SAML:2.0:protocol',
            nsmap=dict(saml2p='urn:oasis:names:tc:SAML:2.0:protocol'),
        )
        saml_maker = ElementMaker(
            namespace='urn:oasis:names:tc:SAML:2.0:assertion',
            nsmap=dict(saml2='urn:oasis:names:tc:SAML:2.0:assertion'),
        )

        authn_request = samlp_maker.AuthnRequest(
            ProtocolBinding=('urn:oasis:names:tc:SAML:2.0:bindings:%s' %
                             assertion_binding),
            Version='2.0',
            IssueInstant=now_iso,
            ID=unique_id,
            AssertionConsumerServiceURL=assertion_consumer_service_url,
            Destination=self.target_url,
            IsPassive="False")

        saml_issuer = saml_maker.Issuer()
        saml_issuer.text = issuer
        authn_request.append(saml_issuer)

        name_id_policy = samlp_maker.NameIDPolicy(
            Format=name_identifier_format,
            AllowCreate='true',
            SPNameQualifier=issuer)
        authn_request.append(name_id_policy)

        request_authn_context = samlp_maker.RequestedAuthnContext(
            Comparison='minimum', )
        authn_request.append(request_authn_context)
        authn_context_class_ref = saml_maker.AuthnContextClassRef()
        authn_context_class_ref.text = ('urn:oasis:names:tc:SAML:2.0:ac:'
                                        'classes:PasswordProtectedTransport')

        request_authn_context.append(authn_context_class_ref)
        self.document = authn_request
예제 #3
0
def create(
    _clock=None,
    _uuid=None,
    _zlib=None,
    _base64=None,
    _urllib=None,
    **kwargs
    ):
    """Create a URL string which can be used to redirect a samlp:AuthnRequest to the identity provider.
    Return a URL string containing the idp_sso_target_url and a deflated, base64-encoded, url-encoded (in that order) samlp:AuthnRequest XML element as the value of the SAMLRequest parameter.

    Keyword arguments:
    assertion_consumer_service_url -- The URL at which the SAML assertion should be received.
    issuer -- The name of your application. Some identity providers might need this to establish the identity of the service provider requesting the login.
    name_identifier_format -- The format of the username required by this application. If you need the email address, use "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress". See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf section 8.3 for other options. Note that the identity provider might not support all options.
    idp_sso_target_url -- The URL to which the authentication request should be sent. This would be on the identity
"""
    if _clock is None:
        _clock = datetime.utcnow
    if _uuid is None:
        _uuid = uuid.uuid4
    if _zlib is None:
        _zlib = zlib
    if _base64 is None:
        _base64 = base64
    if _urllib is None:
        _urllib = urllib

    assertion_consumer_service_url = kwargs.pop(
        'assertion_consumer_service_url',
        )
    issuer = kwargs.pop('issuer')
    name_identifier_format = kwargs.pop('name_identifier_format')
    idp_sso_target_url = kwargs.pop('idp_sso_target_url')

    now = _clock()
    # Resolution finer than milliseconds not allowed
    # http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf Section
    # 1.3.3
    now = now.replace(microsecond=0)
    now_iso = now.strftime('%Y-%m-%dT%H:%M:%SZ')

    unique_id = _uuid()
    unique_id = unique_id.hex

    samlp_maker = ElementMaker(
        namespace='urn:oasis:names:tc:SAML:2.0:protocol',
        nsmap=dict(samlp='urn:oasis:names:tc:SAML:2.0:protocol'),
        )
    saml_maker = ElementMaker(
        namespace='urn:oasis:names:tc:SAML:2.0:assertion',
        nsmap=dict(saml='urn:oasis:names:tc:SAML:2.0:assertion'),
        )

    authn_request = samlp_maker.AuthnRequest(
        ProtocolBinding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
        Version='2.0',
        IssueInstant=now_iso,
        ID=unique_id,
        AssertionConsumerServiceURL=assertion_consumer_service_url,
        )

    saml_issuer = saml_maker.Issuer()
    saml_issuer.text = issuer
    authn_request.append(saml_issuer)

    name_id_policy = samlp_maker.NameIDPolicy(
        Format=name_identifier_format,
        AllowCreate='true',
        )
    authn_request.append(name_id_policy)

    request_authn_context = samlp_maker.RequestedAuthnContext(
        Comparison='exact',
        )
    authn_request.append(request_authn_context)

    authn_context_class_ref = saml_maker.AuthnContextClassRef()
    authn_context_class_ref.text = ('urn:oasis:names:tc:SAML:2.0:ac:classes:'
                                    + 'PasswordProtectedTransport'
                                    )
    request_authn_context.append(authn_context_class_ref)

    compressed_request = _zlib.compress(etree.tostring(authn_request))
    # Strip the first 2 bytes (header) and the last 4 bytes (checksum) to get the raw deflate
    deflated_request = compressed_request[2:-4]
    encoded_request = _base64.b64encode(deflated_request)
    urlencoded_request = _urllib.urlencode(
        [('SAMLRequest', encoded_request)],
        )

    return '{url}?{query}'.format(
        url=idp_sso_target_url,
        query=urlencoded_request,
        )