Methods creating request changed to return a tuple consisting of request id and request.

This commit is contained in:
Roland Hedberg
2014-03-20 21:15:21 +01:00
parent 53df90fb9d
commit a442e039d2
13 changed files with 121 additions and 94 deletions

View File

@@ -79,7 +79,7 @@ class Saml2Client(Base):
destination = self._sso_location(entityid, binding)
req = self.create_authn_request(destination, vorg, scoping,
reqid, req = self.create_authn_request(destination, vorg, scoping,
response_binding, nameid_format,
consent=consent, extensions=extensions,
sign=sign, **kwargs)
@@ -89,7 +89,7 @@ class Saml2Client(Base):
info = self.apply_binding(binding, _req_str, destination, relay_state)
return req.id, info
return reqid, info
def global_logout(self, name_id, reason="", expire=None, sign=None):
""" More or less a layer of indirection :-/
@@ -161,10 +161,9 @@ class Saml2Client(Base):
destination = destinations(srvs)[0]
logger.info("destination to provider: %s" % destination)
request = self.create_logout_request(destination, entity_id,
name_id=name_id,
reason=reason,
expire=expire)
req_id, request = self.create_logout_request(
destination, entity_id, name_id=name_id, reason=reason,
expire=expire)
#to_sign = []
if binding.startswith("http://"):
@@ -178,7 +177,7 @@ class Saml2Client(Base):
else:
srequest = "%s" % request
relay_state = self._relay_state(request.id)
relay_state = self._relay_state(req_id)
http_info = self.apply_binding(binding, srequest, destination,
relay_state)
@@ -196,7 +195,7 @@ class Saml2Client(Base):
logger.info("NOT OK response from %s" % destination)
else:
self.state[request.id] = {"entity_id": entity_id,
self.state[req_id] = {"entity_id": entity_id,
"operation": "SLO",
"entity_ids": entity_ids,
"name_id": name_id,
@@ -264,7 +263,7 @@ class Saml2Client(Base):
except KeyError:
response_args = None
query = _create_func(destination, **kwargs)
qid, query = _create_func(destination, **kwargs)
response = self.send_using_soap(query, destination)

View File

@@ -230,7 +230,7 @@ class Base(Entity):
of fulfilling the request, to create a new identifier to represent
the principal.
:param kwargs: Extra key word arguments
:return: <samlp:AuthnRequest> instance
:return: tuple of request ID and <samlp:AuthnRequest> instance
"""
client_crt = None
if "client_crt" in kwargs:
@@ -304,13 +304,14 @@ class Base(Entity):
except KeyError:
pass
rid = ""
if (sign and self.sec.cert_handler.generate_cert()) or client_crt is not None:
with self.lock:
self.sec.cert_handler.update_cert(True, client_crt)
if client_crt is not None:
sign_prepare = True
return self._message(AuthnRequest, destination, message_id, consent,
extensions, sign, sign_prepare,
return self._message(AuthnRequest, destination, message_id,
consent, extensions, sign, sign_prepare,
protocol_binding=binding,
scoping=scoping, **args)
return self._message(AuthnRequest, destination, message_id, consent,
@@ -343,7 +344,7 @@ class Base(Entity):
:param extensions: Possible extensions
:param sign: Whether the query should be signed or not.
:param sign_prepare: Whether the Signature element should be added.
:return: An AttributeQuery instance
:return: Tuple of request ID and an AttributeQuery instance
"""
if name_id is None:
@@ -666,7 +667,7 @@ class Base(Entity):
# SingleSignOnService
_, location = self.pick_binding("single_sign_on_service",
[_binding], entity_id=entityid)
authn_req = self.create_authn_request(
req_id, authn_req = self.create_authn_request(
location, service_url_binding=BINDING_PAOS, **kwargs)
# ----------------------------------------
@@ -677,7 +678,7 @@ class Base(Entity):
[paos_request,
relay_state])
return authn_req.id, "%s" % soap_envelope
return req_id, "%s" % soap_envelope
def parse_ecp_authn_response(self, txt, outstanding=None):
rdict = soap.class_instances_from_soap_enveloped_saml_thingies(txt,
@@ -757,7 +758,8 @@ class Base(Entity):
params = urlencode(args)
return "%s?%s" % (url, params)
def parse_discovery_service_response(self, url="", query="",
@staticmethod
def parse_discovery_service_response(url="", query="",
returnIDParam="entityID"):
"""
Deal with the response url from a Discovery Service

View File

@@ -115,9 +115,8 @@ def ecp_auth_request(cls, entityid=None, relay_state="", sign=False):
logger.info("entityid: %s, binding: %s" % (entityid, BINDING_SOAP))
location = cls._sso_location(entityid, binding=BINDING_SOAP)
authn_req = cls.create_authn_request(location,
binding=BINDING_PAOS,
service_url_binding=BINDING_PAOS)
req_id, authn_req = cls.create_authn_request(
location, binding=BINDING_PAOS, service_url_binding=BINDING_PAOS)
body = soapenv.Body()
body.extension_elements = [element_to_extension_element(authn_req)]
@@ -128,7 +127,7 @@ def ecp_auth_request(cls, entityid=None, relay_state="", sign=False):
soap_envelope = soapenv.Envelope(header=header, body=body)
return authn_req.id, "%s" % soap_envelope
return req_id, "%s" % soap_envelope
def handle_ecp_authn_response(cls, soap_message, outstanding=None):

View File

@@ -1,6 +1,5 @@
import base64
from binascii import hexlify
import copy
import logging
from hashlib import sha1
from saml2.metadata import ENDPOINTS
@@ -20,10 +19,10 @@ from saml2 import soap
from saml2 import element_to_extension_element
from saml2 import extension_elements_to_elements
from saml2.saml import NameID, EncryptedAssertion
from saml2.saml import NameID
from saml2.saml import Issuer
from saml2.saml import NAMEID_FORMAT_ENTITY
from saml2.response import LogoutResponse, AuthnResponse
from saml2.response import LogoutResponse
from saml2.time_util import instant
from saml2.s_utils import sid
from saml2.s_utils import UnravelError
@@ -32,7 +31,9 @@ from saml2.s_utils import rndstr
from saml2.s_utils import success_status_factory
from saml2.s_utils import decode_base64_and_inflate
from saml2.s_utils import UnsupportedBinding
from saml2.samlp import AuthnRequest, AuthzDecisionQuery, AuthnQuery, response_from_string
from saml2.samlp import AuthnRequest
from saml2.samlp import AuthzDecisionQuery
from saml2.samlp import AuthnQuery
from saml2.samlp import AssertionIDRequest
from saml2.samlp import ManageNameIDRequest
from saml2.samlp import NameIDMappingRequest
@@ -50,8 +51,12 @@ from saml2 import VERSION
from saml2 import class_name
from saml2.config import config_factory
from saml2.httpbase import HTTPBase
from saml2.sigver import security_context, response_factory, SigverError, CryptoBackendXmlSec1, make_temp, \
pre_encryption_part
from saml2.sigver import security_context
from saml2.sigver import response_factory
from saml2.sigver import SigverError
from saml2.sigver import CryptoBackendXmlSec1
from saml2.sigver import make_temp
from saml2.sigver import pre_encryption_part
from saml2.sigver import pre_signature_part
from saml2.sigver import signed_instance_factory
from saml2.virtual_org import VirtualOrg
@@ -367,7 +372,8 @@ class Entity(HTTPBase):
:param sign: Whether the request should be signed or not.
:param sign_prepare: Whether the signature should be prepared or not.
:param kwargs: Key word arguments specific to one request type
:return: An instance of the request_cls
:return: A tuple containing the request ID and an instance of the
request_cls
"""
if not message_id:
message_id = sid(self.seed)
@@ -377,6 +383,7 @@ class Entity(HTTPBase):
kwargs[key] = val
req = request_cls(**kwargs)
reqid = req.id
if destination:
req.destination = destination
@@ -388,12 +395,13 @@ class Entity(HTTPBase):
req.extensions = extensions
if sign:
return self.sign(req, sign_prepare=sign_prepare)
return reqid, self.sign(req, sign_prepare=sign_prepare)
else:
logger.info("REQUEST: %s" % req)
return req
return reqid, req
def _filter_args(self, instance, extensions=None, **kwargs):
@staticmethod
def _filter_args(instance, extensions=None, **kwargs):
args = {}
if extensions is None:
extensions = []
@@ -933,7 +941,7 @@ class Entity(HTTPBase):
raise SAMLError("Missing endpoint location")
_sid = sid()
msg = self.create_artifact_resolve(artifact, destination, _sid)
mid, msg = self.create_artifact_resolve(artifact, destination, _sid)
return self.send_using_soap(msg, destination)
def parse_artifact_resolve(self, txt, **kwargs):

View File

@@ -124,7 +124,7 @@ class TestServer1():
assert status.status_code.value == samlp.STATUS_SUCCESS
def test_parse_faulty_request(self):
authn_request = self.client.create_authn_request(
req_id, authn_request = self.client.create_authn_request(
destination="http://www.example.com", id="id1")
# should raise an error because faulty spentityid
@@ -137,7 +137,7 @@ class TestServer1():
_dict["SAMLRequest"][0], binding)
def test_parse_faulty_request_to_err_status(self):
authn_request = self.client.create_authn_request(
req_id, authn_request = self.client.create_authn_request(
destination="http://www.example.com")
binding = BINDING_HTTP_REDIRECT
@@ -163,7 +163,7 @@ class TestServer1():
assert status_code.status_code.value == samlp.STATUS_UNKNOWN_PRINCIPAL
def test_parse_ok_request(self):
authn_request = self.client.create_authn_request(
req_id, authn_request = self.client.create_authn_request(
message_id="id1", destination="http://localhost:8088/sso")
print authn_request
@@ -378,7 +378,7 @@ class TestServer1():
}
self.client.users.add_information_about_person(sinfo)
logout_request = self.client.create_logout_request(
req_id, logout_request = self.client.create_logout_request(
destination="http://localhost:8088/slop", name_id=nid,
issuer_entity_id="urn:mace:example.com:saml:roland:idp",
reason="I'm tired of this")
@@ -404,7 +404,7 @@ class TestServer1():
sp = client.Saml2Client(config_file="server_conf")
sp.users.add_information_about_person(sinfo)
logout_request = sp.create_logout_request(
req_id, logout_request = sp.create_logout_request(
name_id=nid, destination="http://localhost:8088/slo",
issuer_entity_id="urn:mace:example.com:saml:roland:idp",
reason="I'm tired of this")
@@ -483,7 +483,7 @@ class TestServerLogout():
def test_1(self):
server = Server("idp_slo_redirect_conf")
request = _logout_request("sp_slo_redirect_conf")
req_id, request = _logout_request("sp_slo_redirect_conf")
print request
bindings = [BINDING_HTTP_REDIRECT]
response = server.create_logout_response(request, bindings)

View File

@@ -27,7 +27,7 @@ AUTHN = {
}
def for_me(condition, me ):
def for_me(condition, me):
for restriction in condition.audience_restriction:
audience = restriction.audience
if audience.text.strip() == me:
@@ -60,11 +60,25 @@ def _leq(l1, l2):
# print name_id
# assert False
REQ1 = { "1.2.14": """<?xml version='1.0' encoding='UTF-8'?>
<ns0:AttributeQuery Destination="https://idp.example.com/idp/" ID="id1" IssueInstant="%s" Version="2.0" xmlns:ns0="urn:oasis:names:tc:SAML:2.0:protocol"><ns1:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion">urn:mace:example.com:saml:roland:sp</ns1:Issuer><ns1:Subject xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion"><ns1:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">E8042FB4-4D5B-48C3-8E14-8EDD852790DD</ns1:NameID></ns1:Subject></ns0:AttributeQuery>""",
"1.2.16":"""<?xml version='1.0' encoding='UTF-8'?>
<ns0:AttributeQuery xmlns:ns0="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion" Destination="https://idp.example.com/idp/" ID="id1" IssueInstant="%s" Version="2.0"><ns1:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">urn:mace:example.com:saml:roland:sp</ns1:Issuer><ns1:Subject><ns1:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">E8042FB4-4D5B-48C3-8E14-8EDD852790DD</ns1:NameID></ns1:Subject></ns0:AttributeQuery>"""}
REQ1 = {"1.2.14": """<?xml version='1.0' encoding='UTF-8'?>
<ns0:AttributeQuery Destination="https://idp.example.com/idp/" ID="id1"
IssueInstant="%s" Version="2.0" xmlns:ns0="urn:oasis:names:tc:SAML:2
.0:protocol"><ns1:Issuer Format="urn:oasis:names:tc:SAML:2
.0:nameid-format:entity" xmlns:ns1="urn:oasis:names:tc:SAML:2
.0:assertion">urn:mace:example.com:saml:roland:sp</ns1:Issuer><ns1:Subject
xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion"><ns1:NameID
Format="urn:oasis:names:tc:SAML:2
.0:nameid-format:persistent">E8042FB4-4D5B-48C3-8E14-8EDD852790DD</ns1:NameID
></ns1:Subject></ns0:AttributeQuery>""",
"1.2.16": """<?xml version='1.0' encoding='UTF-8'?>
<ns0:AttributeQuery xmlns:ns0="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion" Destination="https://idp
.example.com/idp/" ID="id1" IssueInstant="%s" Version="2.0"><ns1:Issuer
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">urn:mace:example
.com:saml:roland:sp</ns1:Issuer><ns1:Subject><ns1:NameID
Format="urn:oasis:names:tc:SAML:2
.0:nameid-format:persistent">E8042FB4-4D5B-48C3-8E14-8EDD852790DD</ns1:NameID
></ns1:Subject></ns0:AttributeQuery>"""}
nid = NameID(name_qualifier="foo", format=NAMEID_FORMAT_TRANSIENT,
text="123456")
@@ -79,7 +93,7 @@ class TestClient:
self.client = Saml2Client(conf)
def test_create_attribute_query1(self):
req = self.client.create_attribute_query(
req_id, req = self.client.create_attribute_query(
"https://idp.example.com/idp/",
"E8042FB4-4D5B-48C3-8E14-8EDD852790DD",
format=saml.NAMEID_FORMAT_PERSISTENT,
@@ -111,7 +125,7 @@ class TestClient:
assert attrq.subject.name_id.text == name_id.text
def test_create_attribute_query2(self):
req = self.client.create_attribute_query(
req_id, req = self.client.create_attribute_query(
"https://idp.example.com/idp/",
"E8042FB4-4D5B-48C3-8E14-8EDD852790DD",
attribute={
@@ -155,14 +169,15 @@ class TestClient:
assert _leq(seen, ["givenName", "surname", "email"])
def test_create_attribute_query_3(self):
req = self.client.create_attribute_query(
req_id, req = self.client.create_attribute_query(
"https://aai-demo-idp.switch.ch/idp/shibboleth",
"_e7b68a04488f715cda642fbdd90099f5",
format=saml.NAMEID_FORMAT_TRANSIENT,
message_id="id1")
assert isinstance(req, samlp.AttributeQuery)
assert req.destination == "https://aai-demo-idp.switch.ch/idp/shibboleth"
assert req.destination == "https://aai-demo-idp.switch" \
".ch/idp/shibboleth"
assert req.id == "id1"
assert req.version == "2.0"
assert req.issue_instant
@@ -173,10 +188,12 @@ class TestClient:
def test_create_auth_request_0(self):
ar_str = "%s" % self.client.create_authn_request(
"http://www.example.com/sso", message_id="id1")
"http://www.example.com/sso", message_id="id1")[1]
ar = samlp.authn_request_from_string(ar_str)
print ar
assert ar.assertion_consumer_service_url == "http://lingon.catalogix.se:8087/"
assert ar.assertion_consumer_service_url == ("http://lingon.catalogix"
".se:8087/")
assert ar.destination == "http://www.example.com/sso"
assert ar.protocol_binding == BINDING_HTTP_POST
assert ar.version == "2.0"
@@ -194,12 +211,13 @@ class TestClient:
"http://www.example.com/sso",
"urn:mace:example.com:it:tek", # vo
nameid_format=NAMEID_FORMAT_PERSISTENT,
message_id="666")
message_id="666")[1]
ar = samlp.authn_request_from_string(ar_str)
print ar
assert ar.id == "666"
assert ar.assertion_consumer_service_url == "http://lingon.catalogix.se:8087/"
assert ar.assertion_consumer_service_url == "http://lingon.catalogix" \
".se:8087/"
assert ar.destination == "http://www.example.com/sso"
assert ar.protocol_binding == BINDING_HTTP_POST
assert ar.version == "2.0"
@@ -213,9 +231,10 @@ class TestClient:
def test_sign_auth_request_0(self):
#print self.client.config
ar_str = "%s" % self.client.create_authn_request(
req_id, areq = self.client.create_authn_request(
"http://www.example.com/sso", sign=True, message_id="id1")
ar_str = "%s" % areq
ar = samlp.authn_request_from_string(ar_str)
assert ar
@@ -237,11 +256,11 @@ class TestClient:
def test_response(self):
IDP = "urn:mace:example.com:saml:roland:idp"
ava = { "givenName": ["Derek"], "surName": ["Jeter"],
"mail": ["derek@nyy.mlb.com"], "title":["The man"]}
ava = {"givenName": ["Derek"], "surName": ["Jeter"],
"mail": ["derek@nyy.mlb.com"], "title": ["The man"]}
nameid_policy=samlp.NameIDPolicy(allow_create="false",
format=saml.NAMEID_FORMAT_PERSISTENT)
nameid_policy = samlp.NameIDPolicy(allow_create="false",
format=saml.NAMEID_FORMAT_PERSISTENT)
resp = self.server.create_authn_response(
identity=ava,
@@ -359,7 +378,7 @@ class TestClientWithDummy():
def test_do_attribute_query(self):
response = self.client.do_attribute_query(
IDP, "_e7b68a04488f715cda642fbdd90099f5",
attribute={"eduPersonAffiliation":None},
attribute={"eduPersonAffiliation": None},
nameid_format=NAMEID_FORMAT_TRANSIENT)
def test_logout_1(self):
@@ -417,7 +436,7 @@ class TestClientWithDummy():
{sid: "/"})
ac = resp.assertion.authn_statement[0].authn_context
assert ac.authenticating_authority[0].text == \
'http://www.example.com/login'
'http://www.example.com/login'
assert ac.authn_context_class_ref.text == INTERNETPROTOCOLPASSWORD
@@ -429,4 +448,4 @@ class TestClientWithDummy():
if __name__ == "__main__":
tc = TestClient()
tc.setup_class()
tc.test_init_values()
tc.test_sign_auth_request_0()

View File

@@ -83,7 +83,7 @@ def test_create_artifact_resolve():
destination = idp.artifact2destination(b64art, "spsso")
msg = idp.create_artifact_resolve(b64art, destination, sid())
msg_id, msg = idp.create_artifact_resolve(b64art, destination, sid())
print msg
@@ -108,7 +108,7 @@ def test_artifact_flow():
binding, destination = sp.pick_binding("single_sign_on_service",
entity_id=idp.config.entityid)
relay_state = "RS0"
req = sp.create_authn_request(destination, id="id1")
req_id, req = sp.create_authn_request(destination, id="id1")
artifact = sp.use_artifact(req, 1)
@@ -128,7 +128,7 @@ def test_artifact_flow():
destination = idp.artifact2destination(artifact2, "spsso")
msg = idp.create_artifact_resolve(artifact2, destination, sid())
msg_id, msg = idp.create_artifact_resolve(artifact2, destination, sid())
hinfo = idp.use_soap(msg, destination, None, False)
@@ -199,7 +199,7 @@ def test_artifact_flow():
destination = sp.artifact2destination(artifact3, "idpsso")
# Got an artifact want to replace it with the real message
msg = sp.create_artifact_resolve(artifact3, destination, sid())
msg_id, msg = sp.create_artifact_resolve(artifact3, destination, sid())
print msg

View File

@@ -53,7 +53,7 @@ def test_basic():
subject = Subject(text="abc",
name_id=NameID(format=NAMEID_FORMAT_TRANSIENT))
aq = sp.create_authn_query(subject, destination, authn_context)
_id, aq = sp.create_authn_query(subject, destination, authn_context)
print aq
@@ -102,7 +102,7 @@ def test_flow():
subject = aresp.assertion.subject
aq = sp.create_authn_query(subject, destination, authn_context)
aq_id, aq = sp.create_authn_query(subject, destination, authn_context)
print aq

View File

@@ -21,7 +21,7 @@ def test_base_request():
nameid = NameID(format=NAMEID_FORMAT_TRANSIENT, text="foobar")
nmr = sp.create_name_id_mapping_request(policy, nameid, destination)
mid, nmr = sp.create_name_id_mapping_request(policy, nameid, destination)
print nmr
@@ -41,7 +41,7 @@ def test_request_response():
nameid = NameID(format=NAMEID_FORMAT_TRANSIENT, text="foobar")
nmr = sp.create_name_id_mapping_request(policy, nameid, destination)
mid, nmr = sp.create_name_id_mapping_request(policy, nameid, destination)
print nmr

View File

@@ -17,11 +17,11 @@ def test_basic():
nameid = NameID(format=NAMEID_FORMAT_TRANSIENT, text="foobar")
newid = NewID(text="Barfoo")
mid = sp.create_manage_name_id_request(destination, name_id=nameid,
mid, mreq = sp.create_manage_name_id_request(destination, name_id=nameid,
new_id=newid)
print mid
rargs = sp.apply_binding(binding, "%s" % mid, destination, "")
print mreq
rargs = sp.apply_binding(binding, "%s" % mreq, destination, "")
# --------- @IDP --------------
@@ -29,7 +29,7 @@ def test_basic():
print _req.message
assert mid.id == _req.message.id
assert mid == _req.message.id
def test_flow():
sp = Saml2Client(config_file="servera_conf")
@@ -41,11 +41,11 @@ def test_flow():
nameid = NameID(format=NAMEID_FORMAT_TRANSIENT, text="foobar")
newid = NewID(text="Barfoo")
mid = sp.create_manage_name_id_request(destination, name_id=nameid,
mid, midq = sp.create_manage_name_id_request(destination, name_id=nameid,
new_id=newid)
print mid
rargs = sp.apply_binding(binding, "%s" % mid, destination, "")
print midq
rargs = sp.apply_binding(binding, "%s" % midq, destination, "")
# --------- @IDP --------------

View File

@@ -24,7 +24,7 @@ def test():
BINDING_HTTP_REDIRECT)
destination = srvs[0]["location"]
req = sp.create_authn_request(destination, id="id1")
req_id, req = sp.create_authn_request(destination, id="id1")
try:
key = sp.sec.key

View File

@@ -26,7 +26,7 @@ def test_flow():
idp1.ident.mdb.db.drop()
# -- dummy request ---
orig_req = sp.create_authn_request(idp1.config.entityid)
req_id, orig_req = sp.create_authn_request(idp1.config.entityid)
# == Create an AuthnRequest response

View File

@@ -26,7 +26,7 @@ spcertenc = SPCertEnc(
extensions = Extensions(
extension_elements=[element_to_extension_element(spcertenc)])
req = client.create_authn_request(
req_id, req = client.create_authn_request(
"http://www.example.com/sso",
"urn:mace:example.com:it:tek",
nameid_format=saml.NAMEID_FORMAT_PERSISTENT,