commit
9e0f8afece
|
@ -24,6 +24,8 @@ from saml2.schema import soapenv
|
||||||
|
|
||||||
from saml2.response import authn_response
|
from saml2.response import authn_response
|
||||||
|
|
||||||
|
from saml2 import saml
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,7 +55,7 @@ def ecp_auth_request(cls, entityid=None, relay_state="", sign=False):
|
||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
# <paos:Request>
|
# <paos:Request>
|
||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
my_url = cls.service_url(BINDING_PAOS)
|
my_url = cls.service_urls(BINDING_PAOS)[0]
|
||||||
|
|
||||||
# must_understand and actor according to the standard
|
# must_understand and actor according to the standard
|
||||||
#
|
#
|
||||||
|
@ -63,38 +65,6 @@ def ecp_auth_request(cls, entityid=None, relay_state="", sign=False):
|
||||||
|
|
||||||
eelist.append(element_to_extension_element(paos_request))
|
eelist.append(element_to_extension_element(paos_request))
|
||||||
|
|
||||||
# ----------------------------------------
|
|
||||||
# <ecp:Request>
|
|
||||||
# ----------------------------------------
|
|
||||||
|
|
||||||
# idp = samlp.IDPEntry(
|
|
||||||
# provider_id = "https://idp.example.org/entity",
|
|
||||||
# name = "Example identity provider",
|
|
||||||
# loc = "https://idp.example.org/saml2/sso",
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
# idp_list = samlp.IDPList(idp_entry= [idp])
|
|
||||||
#
|
|
||||||
# ecp_request = ecp.Request(
|
|
||||||
# actor = ACTOR, must_understand = "1",
|
|
||||||
# provider_name = "Example Service Provider",
|
|
||||||
# issuer=saml.Issuer(text="https://sp.example.org/entity"),
|
|
||||||
# idp_list = idp_list)
|
|
||||||
#
|
|
||||||
# eelist.append(element_to_extension_element(ecp_request))
|
|
||||||
|
|
||||||
# ----------------------------------------
|
|
||||||
# <ecp:RelayState>
|
|
||||||
# ----------------------------------------
|
|
||||||
|
|
||||||
relay_state = ecp.RelayState(actor=ACTOR, must_understand="1",
|
|
||||||
text=relay_state)
|
|
||||||
|
|
||||||
eelist.append(element_to_extension_element(relay_state))
|
|
||||||
|
|
||||||
header = soapenv.Header()
|
|
||||||
header.extension_elements = eelist
|
|
||||||
|
|
||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
# <samlp:AuthnRequest>
|
# <samlp:AuthnRequest>
|
||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
|
@ -108,6 +78,40 @@ def ecp_auth_request(cls, entityid=None, relay_state="", sign=False):
|
||||||
body = soapenv.Body()
|
body = soapenv.Body()
|
||||||
body.extension_elements = [element_to_extension_element(authn_req)]
|
body.extension_elements = [element_to_extension_element(authn_req)]
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# <ecp:Request>
|
||||||
|
# ----------------------------------------
|
||||||
|
|
||||||
|
# idp = samlp.IDPEntry(
|
||||||
|
# provider_id = "https://idp.example.org/entity",
|
||||||
|
# name = "Example identity provider",
|
||||||
|
# loc = "https://idp.example.org/saml2/sso",
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# idp_list = samlp.IDPList(idp_entry= [idp])
|
||||||
|
|
||||||
|
idp_list = None
|
||||||
|
ecp_request = ecp.Request(
|
||||||
|
actor=ACTOR,
|
||||||
|
must_understand="1",
|
||||||
|
provider_name=None,
|
||||||
|
issuer=saml.Issuer(text=authn_req.issuer.text),
|
||||||
|
idp_list=idp_list)
|
||||||
|
|
||||||
|
eelist.append(element_to_extension_element(ecp_request))
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# <ecp:RelayState>
|
||||||
|
# ----------------------------------------
|
||||||
|
|
||||||
|
relay_state = ecp.RelayState(actor=ACTOR, must_understand="1",
|
||||||
|
text=relay_state)
|
||||||
|
|
||||||
|
eelist.append(element_to_extension_element(relay_state))
|
||||||
|
|
||||||
|
header = soapenv.Header()
|
||||||
|
header.extension_elements = eelist
|
||||||
|
|
||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
# The SOAP envelope
|
# The SOAP envelope
|
||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
|
@ -126,7 +130,7 @@ def handle_ecp_authn_response(cls, soap_message, outstanding=None):
|
||||||
if item.c_tag == "RelayState" and item.c_namespace == ecp.NAMESPACE:
|
if item.c_tag == "RelayState" and item.c_namespace == ecp.NAMESPACE:
|
||||||
_relay_state = item
|
_relay_state = item
|
||||||
|
|
||||||
response = authn_response(cls.config, cls.service_url(), outstanding,
|
response = authn_response(cls.config, cls.service_urls(), outstanding,
|
||||||
allow_unsolicited=True)
|
allow_unsolicited=True)
|
||||||
|
|
||||||
response.loads("%s" % rdict["body"], False, soap_message)
|
response.loads("%s" % rdict["body"], False, soap_message)
|
||||||
|
|
|
@ -119,7 +119,7 @@ class Client(Entity):
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
raise SAMLError(
|
raise SAMLError(
|
||||||
"Request to IdP failed (%s): %s" % (response.status_code,
|
"Request to IdP failed (%s): %s" % (response.status_code,
|
||||||
response.error))
|
response.text))
|
||||||
|
|
||||||
# SAMLP response in a SOAP envelope body, ecp response in headers
|
# SAMLP response in a SOAP envelope body, ecp response in headers
|
||||||
respdict = self.parse_soap_message(response.text)
|
respdict = self.parse_soap_message(response.text)
|
||||||
|
@ -200,22 +200,19 @@ class Client(Entity):
|
||||||
|
|
||||||
ht_args = self.use_soap(idp_response, args["rc_url"],
|
ht_args = self.use_soap(idp_response, args["rc_url"],
|
||||||
[args["relay_state"]])
|
[args["relay_state"]])
|
||||||
|
ht_args["headers"][0] = ('Content-Type', MIME_PAOS)
|
||||||
logger.debug("[P3] Post to SP: %s", ht_args["data"])
|
logger.debug("[P3] Post to SP: %s", ht_args["data"])
|
||||||
|
|
||||||
ht_args["headers"].append(('Content-Type', 'application/vnd.paos+xml'))
|
|
||||||
|
|
||||||
# POST the package from the IdP to the SP
|
# POST the package from the IdP to the SP
|
||||||
response = self.send(args["rc_url"], "POST", **ht_args)
|
response = self.send(**ht_args)
|
||||||
|
|
||||||
if response.status_code == 302:
|
if response.status_code == 302:
|
||||||
# ignore where the SP is redirecting us to and go for the
|
# ignore where the SP is redirecting us to and go for the
|
||||||
# url I started off with.
|
# url I started off with.
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
print(response.error)
|
|
||||||
raise SAMLError(
|
raise SAMLError(
|
||||||
"Error POSTing package to SP: %s" % response.error)
|
"Error POSTing package to SP: %s" % response.text)
|
||||||
|
|
||||||
logger.debug("[P3] SP response: %s", response.text)
|
logger.debug("[P3] SP response: %s", response.text)
|
||||||
|
|
||||||
|
@ -255,8 +252,7 @@ class Client(Entity):
|
||||||
:param opargs: Arguments to the HTTP call
|
:param opargs: Arguments to the HTTP call
|
||||||
:return: The page
|
:return: The page
|
||||||
"""
|
"""
|
||||||
if url not in opargs:
|
sp_url = self._sp
|
||||||
url = self._sp
|
|
||||||
|
|
||||||
# ********************************************
|
# ********************************************
|
||||||
# Phase 1 - First conversation with the SP
|
# Phase 1 - First conversation with the SP
|
||||||
|
@ -264,13 +260,13 @@ class Client(Entity):
|
||||||
# headers needed to indicate to the SP that I'm ECP enabled
|
# headers needed to indicate to the SP that I'm ECP enabled
|
||||||
|
|
||||||
opargs["headers"] = self.add_paos_headers(opargs["headers"])
|
opargs["headers"] = self.add_paos_headers(opargs["headers"])
|
||||||
|
response = self.send(sp_url, op, **opargs)
|
||||||
response = self.send(url, op, **opargs)
|
logger.debug("[Op] SP response: %s" % response)
|
||||||
logger.debug("[Op] SP response: %s", response)
|
print(response.text)
|
||||||
|
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
raise SAMLError(
|
raise SAMLError(
|
||||||
"Request to SP failed: %s" % response.error)
|
"Request to SP failed: %s" % response.text)
|
||||||
|
|
||||||
# The response might be a AuthnRequest instance in a SOAP envelope
|
# The response might be a AuthnRequest instance in a SOAP envelope
|
||||||
# body. If so it's the start of the ECP conversation
|
# body. If so it's the start of the ECP conversation
|
||||||
|
@ -282,7 +278,6 @@ class Client(Entity):
|
||||||
# header blocks may also be present
|
# header blocks may also be present
|
||||||
try:
|
try:
|
||||||
respdict = self.parse_soap_message(response.text)
|
respdict = self.parse_soap_message(response.text)
|
||||||
|
|
||||||
self.ecp_conversation(respdict, idp_entity_id)
|
self.ecp_conversation(respdict, idp_entity_id)
|
||||||
|
|
||||||
# should by now be authenticated so this should go smoothly
|
# should by now be authenticated so this should go smoothly
|
||||||
|
@ -290,11 +285,9 @@ class Client(Entity):
|
||||||
except (soap.XmlParseError, AssertionError, KeyError):
|
except (soap.XmlParseError, AssertionError, KeyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
#print("RESP",response, self.http.response)
|
if response.status_code >= 400:
|
||||||
|
|
||||||
if response.status_code != 404:
|
|
||||||
raise SAMLError("Error performing operation: %s" % (
|
raise SAMLError("Error performing operation: %s" % (
|
||||||
response.error,))
|
response.text,))
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ from binascii import hexlify
|
||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
|
|
||||||
from saml2.metadata import ENDPOINTS
|
from saml2.metadata import ENDPOINTS
|
||||||
from saml2.profile import paos, ecp
|
from saml2.profile import paos, ecp, samlec
|
||||||
from saml2.soap import parse_soap_enveloped_saml_artifact_resolve
|
from saml2.soap import parse_soap_enveloped_saml_artifact_resolve
|
||||||
from saml2.soap import class_instances_from_soap_enveloped_saml_thingies
|
from saml2.soap import class_instances_from_soap_enveloped_saml_thingies
|
||||||
from saml2.soap import open_soap_envelope
|
from saml2.soap import open_soap_envelope
|
||||||
|
@ -407,7 +407,8 @@ class Entity(HTTPBase):
|
||||||
"""
|
"""
|
||||||
return class_instances_from_soap_enveloped_saml_thingies(text, [paos,
|
return class_instances_from_soap_enveloped_saml_thingies(text, [paos,
|
||||||
ecp,
|
ecp,
|
||||||
samlp])
|
samlp,
|
||||||
|
samlec])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def unpack_soap_message(text):
|
def unpack_soap_message(text):
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
from saml2 import SamlBase
|
||||||
|
|
||||||
|
|
||||||
|
NAMESPACE = 'urn:ietf:params:xml:ns:samlec'
|
||||||
|
|
||||||
|
|
||||||
|
class GeneratedKey(SamlBase):
|
||||||
|
c_tag = 'GeneratedKey'
|
||||||
|
c_namespace = NAMESPACE
|
||||||
|
|
||||||
|
|
||||||
|
ELEMENT_BY_TAG = {
|
||||||
|
'GeneratedKey': GeneratedKey,
|
||||||
|
}
|
Loading…
Reference in New Issue