Made things work after the last merge.
This commit is contained in:
@@ -97,8 +97,11 @@ def filter_on_attributes(ava, required=None, optional=None):
|
|||||||
found = False
|
found = False
|
||||||
nform = ""
|
nform = ""
|
||||||
for nform in ["friendly_name", "name"]:
|
for nform in ["friendly_name", "name"]:
|
||||||
if nform in attr:
|
try:
|
||||||
_fn = _match(attr[nform], ava)
|
_fn = _match(attr[nform], ava)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
if _fn:
|
if _fn:
|
||||||
try:
|
try:
|
||||||
values = [av["text"] for av in attr["attribute_value"]]
|
values = [av["text"] for av in attr["attribute_value"]]
|
||||||
@@ -239,6 +242,8 @@ def filter_attribute_value_assertions(ava, attribute_restrictions=None):
|
|||||||
else:
|
else:
|
||||||
if _rests is None:
|
if _rests is None:
|
||||||
continue
|
continue
|
||||||
|
if isinstance(vals, basestring):
|
||||||
|
vals = [vals]
|
||||||
rvals = []
|
rvals = []
|
||||||
for restr in _rests:
|
for restr in _rests:
|
||||||
for val in vals:
|
for val in vals:
|
||||||
@@ -289,6 +294,8 @@ class Policy(object):
|
|||||||
self._restrictions = restrictions.copy()
|
self._restrictions = restrictions.copy()
|
||||||
|
|
||||||
for who, spec in self._restrictions.items():
|
for who, spec in self._restrictions.items():
|
||||||
|
if spec is None:
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
items = spec["entity_categories"]
|
items = spec["entity_categories"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -311,14 +318,14 @@ class Policy(object):
|
|||||||
if restr is None:
|
if restr is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
_are = {}
|
||||||
for key, values in restr.items():
|
for key, values in restr.items():
|
||||||
if not values:
|
if not values:
|
||||||
spec["attribute_restrictions"][key.lower()] = None
|
_are[key.lower()] = None
|
||||||
continue
|
continue
|
||||||
|
|
||||||
spec["attribute_restrictions"][key.lower()] = \
|
_are[key.lower()] = [re.compile(value) for value in values]
|
||||||
[re.compile(value) for value in values]
|
spec["attribute_restrictions"] = _are
|
||||||
|
|
||||||
logger.debug("policy restrictions: %s" % self._restrictions)
|
logger.debug("policy restrictions: %s" % self._restrictions)
|
||||||
|
|
||||||
return self._restrictions
|
return self._restrictions
|
||||||
@@ -430,20 +437,21 @@ class Policy(object):
|
|||||||
for attr in attrs:
|
for attr in attrs:
|
||||||
restrictions[attr] = None
|
restrictions[attr] = None
|
||||||
|
|
||||||
try:
|
if mds:
|
||||||
ecs = mds.entity_categories(sp_entity_id)
|
try:
|
||||||
except KeyError:
|
ecs = mds.entity_categories(sp_entity_id)
|
||||||
pass
|
except KeyError:
|
||||||
else:
|
pass
|
||||||
for ec in ecs:
|
else:
|
||||||
for ec_map in ec_maps:
|
for ec in ecs:
|
||||||
try:
|
for ec_map in ec_maps:
|
||||||
attrs = ec_map[ec]
|
try:
|
||||||
except KeyError:
|
attrs = ec_map[ec]
|
||||||
pass
|
except KeyError:
|
||||||
else:
|
pass
|
||||||
for attr in attrs:
|
else:
|
||||||
restrictions[attr] = None
|
for attr in attrs:
|
||||||
|
restrictions[attr] = None
|
||||||
|
|
||||||
return restrictions
|
return restrictions
|
||||||
|
|
||||||
|
@@ -72,7 +72,7 @@ def signed(item):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _get_xmlsec_binary(paths=None):
|
def get_xmlsec_binary(paths=None):
|
||||||
"""
|
"""
|
||||||
Tries to find the xmlsec1 binary.
|
Tries to find the xmlsec1 binary.
|
||||||
|
|
||||||
@@ -107,6 +107,7 @@ def _get_xmlsec_binary(paths=None):
|
|||||||
|
|
||||||
raise Exception("Can't find %s" % bin_name)
|
raise Exception("Can't find %s" % bin_name)
|
||||||
|
|
||||||
|
|
||||||
def _get_xmlsec_cryptobackend(path=None, search_paths=None, debug=False):
|
def _get_xmlsec_cryptobackend(path=None, search_paths=None, debug=False):
|
||||||
"""
|
"""
|
||||||
Initialize a CryptoBackendXmlSec1 crypto backend.
|
Initialize a CryptoBackendXmlSec1 crypto backend.
|
||||||
@@ -114,7 +115,7 @@ def _get_xmlsec_cryptobackend(path=None, search_paths=None, debug=False):
|
|||||||
This function is now internal to this module.
|
This function is now internal to this module.
|
||||||
"""
|
"""
|
||||||
if path is None:
|
if path is None:
|
||||||
path=_get_xmlsec_binary(paths=search_paths)
|
path = get_xmlsec_binary(paths=search_paths)
|
||||||
return CryptoBackendXmlSec1(path, debug=debug)
|
return CryptoBackendXmlSec1(path, debug=debug)
|
||||||
|
|
||||||
|
|
||||||
@@ -144,7 +145,6 @@ class DecryptError(Exception):
|
|||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _make_vals(val, klass, seccont, klass_inst=None, prop=None, part=False,
|
def _make_vals(val, klass, seccont, klass_inst=None, prop=None, part=False,
|
||||||
base64encode=False, elements_to_sign=None):
|
base64encode=False, elements_to_sign=None):
|
||||||
"""
|
"""
|
||||||
@@ -173,7 +173,8 @@ def _make_vals(val, klass, seccont, klass_inst=None, prop=None, part=False,
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
if not part:
|
if not part:
|
||||||
cis = [_make_vals(sval, klass, seccont, klass_inst, prop,
|
cis = [_make_vals(sval, klass, seccont, klass_inst, prop,
|
||||||
True, base64encode, elements_to_sign) for sval in val]
|
True, base64encode, elements_to_sign) for sval
|
||||||
|
in val]
|
||||||
setattr(klass_inst, prop, cis)
|
setattr(klass_inst, prop, cis)
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
@@ -485,6 +486,7 @@ def sha1_digest(msg):
|
|||||||
|
|
||||||
class Signer(object):
|
class Signer(object):
|
||||||
"""Abstract base class for signing algorithms."""
|
"""Abstract base class for signing algorithms."""
|
||||||
|
|
||||||
def sign(self, msg, key):
|
def sign(self, msg, key):
|
||||||
"""Sign ``msg`` with ``key`` and return the signature."""
|
"""Sign ``msg`` with ``key`` and return the signature."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@@ -544,6 +546,7 @@ def verify_redirect_signature(info, cert):
|
|||||||
else:
|
else:
|
||||||
raise Unsupported("Signature algorithm: %s" % info["SigAlg"])
|
raise Unsupported("Signature algorithm: %s" % info["SigAlg"])
|
||||||
|
|
||||||
|
|
||||||
LOG_LINE = 60 * "=" + "\n%s\n" + 60 * "-" + "\n%s" + 60 * "="
|
LOG_LINE = 60 * "=" + "\n%s\n" + 60 * "-" + "\n%s" + 60 * "="
|
||||||
LOG_LINE_2 = 60 * "=" + "\n%s\n%s\n" + 60 * "-" + "\n%s" + 60 * "="
|
LOG_LINE_2 = 60 * "=" + "\n%s\n%s\n" + 60 * "-" + "\n%s" + 60 * "="
|
||||||
|
|
||||||
@@ -588,7 +591,6 @@ def read_cert_from_file(cert_file, cert_type):
|
|||||||
|
|
||||||
|
|
||||||
class CryptoBackend():
|
class CryptoBackend():
|
||||||
|
|
||||||
def __init__(self, debug=False):
|
def __init__(self, debug=False):
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
|
|
||||||
@@ -620,7 +622,7 @@ class CryptoBackendXmlSec1(CryptoBackend):
|
|||||||
|
|
||||||
def __init__(self, xmlsec_binary, **kwargs):
|
def __init__(self, xmlsec_binary, **kwargs):
|
||||||
CryptoBackend.__init__(self, **kwargs)
|
CryptoBackend.__init__(self, **kwargs)
|
||||||
assert(isinstance(xmlsec_binary, basestring))
|
assert (isinstance(xmlsec_binary, basestring))
|
||||||
self.xmlsec = xmlsec_binary
|
self.xmlsec = xmlsec_binary
|
||||||
|
|
||||||
def version(self):
|
def version(self):
|
||||||
@@ -637,7 +639,7 @@ class CryptoBackendXmlSec1(CryptoBackend):
|
|||||||
|
|
||||||
com_list = [self.xmlsec, "--encrypt", "--pubkey-cert-pem", recv_key,
|
com_list = [self.xmlsec, "--encrypt", "--pubkey-cert-pem", recv_key,
|
||||||
"--session-key", key_type, "--xml-data", fil,
|
"--session-key", key_type, "--xml-data", fil,
|
||||||
]
|
]
|
||||||
|
|
||||||
(_stdout, _stderr, output) = self._run_xmlsec(com_list, [template],
|
(_stdout, _stderr, output) = self._run_xmlsec(com_list, [template],
|
||||||
exception=DecryptError,
|
exception=DecryptError,
|
||||||
@@ -650,7 +652,7 @@ class CryptoBackendXmlSec1(CryptoBackend):
|
|||||||
|
|
||||||
com_list = [self.xmlsec, "--decrypt", "--privkey-pem",
|
com_list = [self.xmlsec, "--decrypt", "--privkey-pem",
|
||||||
key_file, "--id-attr:%s" % ID_ATTR, ENC_KEY_CLASS,
|
key_file, "--id-attr:%s" % ID_ATTR, ENC_KEY_CLASS,
|
||||||
]
|
]
|
||||||
|
|
||||||
(_stdout, _stderr, output) = self._run_xmlsec(com_list, [fil],
|
(_stdout, _stderr, output) = self._run_xmlsec(com_list, [fil],
|
||||||
exception=DecryptError,
|
exception=DecryptError,
|
||||||
@@ -677,7 +679,7 @@ class CryptoBackendXmlSec1(CryptoBackend):
|
|||||||
"--privkey-pem", key_file,
|
"--privkey-pem", key_file,
|
||||||
"--id-attr:%s" % id_attr, class_name,
|
"--id-attr:%s" % id_attr, class_name,
|
||||||
#"--store-signatures"
|
#"--store-signatures"
|
||||||
]
|
]
|
||||||
if node_id:
|
if node_id:
|
||||||
com_list.extend(["--node-id", node_id])
|
com_list.extend(["--node-id", node_id])
|
||||||
|
|
||||||
@@ -767,6 +769,7 @@ class CryptoBackendXmlSec1(CryptoBackend):
|
|||||||
ntf.seek(0)
|
ntf.seek(0)
|
||||||
return p_out, p_err, ntf.read()
|
return p_out, p_err, ntf.read()
|
||||||
|
|
||||||
|
|
||||||
class CryptoBackendXMLSecurity(CryptoBackend):
|
class CryptoBackendXMLSecurity(CryptoBackend):
|
||||||
"""
|
"""
|
||||||
CryptoBackend implementation using pyXMLSecurity to sign and verify
|
CryptoBackend implementation using pyXMLSecurity to sign and verify
|
||||||
@@ -804,6 +807,7 @@ class CryptoBackendXMLSecurity(CryptoBackend):
|
|||||||
"""
|
"""
|
||||||
import xmlsec
|
import xmlsec
|
||||||
import lxml.etree
|
import lxml.etree
|
||||||
|
|
||||||
xml = xmlsec.parse_xml(statement)
|
xml = xmlsec.parse_xml(statement)
|
||||||
signed = xmlsec.sign(xml, key_file)
|
signed = xmlsec.sign(xml, key_file)
|
||||||
return lxml.etree.tostring(signed, xml_declaration=True)
|
return lxml.etree.tostring(signed, xml_declaration=True)
|
||||||
@@ -825,12 +829,14 @@ class CryptoBackendXMLSecurity(CryptoBackend):
|
|||||||
if cert_type != "pem":
|
if cert_type != "pem":
|
||||||
raise Unsupported("Only PEM certs supported here")
|
raise Unsupported("Only PEM certs supported here")
|
||||||
import xmlsec
|
import xmlsec
|
||||||
|
|
||||||
xml = xmlsec.parse_xml(signedtext)
|
xml = xmlsec.parse_xml(signedtext)
|
||||||
try:
|
try:
|
||||||
return xmlsec.verify(xml, cert_file)
|
return xmlsec.verify(xml, cert_file)
|
||||||
except xmlsec.XMLSigException:
|
except xmlsec.XMLSigException:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def security_context(conf, debug=None):
|
def security_context(conf, debug=None):
|
||||||
""" Creates a security context based on the configuration
|
""" Creates a security context based on the configuration
|
||||||
|
|
||||||
@@ -852,8 +858,8 @@ def security_context(conf, debug=None):
|
|||||||
if conf.crypto_backend == 'xmlsec1':
|
if conf.crypto_backend == 'xmlsec1':
|
||||||
xmlsec_binary = conf.xmlsec_binary
|
xmlsec_binary = conf.xmlsec_binary
|
||||||
if not xmlsec_binary:
|
if not xmlsec_binary:
|
||||||
xmlsec_binary = _get_xmlsec_binary()
|
xmlsec_binary = get_xmlsec_binary()
|
||||||
# verify that xmlsec is where it's supposed to be
|
# verify that xmlsec is where it's supposed to be
|
||||||
if not os.path.exists(xmlsec_binary):
|
if not os.path.exists(xmlsec_binary):
|
||||||
#if not os.access(, os.F_OK):
|
#if not os.access(, os.F_OK):
|
||||||
raise Exception(
|
raise Exception(
|
||||||
@@ -864,7 +870,7 @@ def security_context(conf, debug=None):
|
|||||||
crypto = CryptoBackendXMLSecurity(debug=debug)
|
crypto = CryptoBackendXMLSecurity(debug=debug)
|
||||||
else:
|
else:
|
||||||
raise Exception('Unknown crypto_backend %s' % (
|
raise Exception('Unknown crypto_backend %s' % (
|
||||||
repr(conf.crypto_backend)))
|
repr(conf.crypto_backend)))
|
||||||
|
|
||||||
return SecurityContext(crypto, conf.key_file,
|
return SecurityContext(crypto, conf.key_file,
|
||||||
cert_file=conf.cert_file, metadata=metadata,
|
cert_file=conf.cert_file, metadata=metadata,
|
||||||
@@ -957,7 +963,7 @@ class SecurityContext(object):
|
|||||||
cert_type=cert_type,
|
cert_type=cert_type,
|
||||||
node_name=node_name,
|
node_name=node_name,
|
||||||
node_id=node_id, id_attr=id_attr,
|
node_id=node_id, id_attr=id_attr,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _check_signature(self, decoded_xml, item, node_name=NODE_NAME,
|
def _check_signature(self, decoded_xml, item, node_name=NODE_NAME,
|
||||||
origdoc=None, id_attr="", must=False):
|
origdoc=None, id_attr="", must=False):
|
||||||
|
@@ -1,8 +1,12 @@
|
|||||||
from saml2 import BINDING_SOAP, BINDING_HTTP_REDIRECT, BINDING_HTTP_POST
|
from saml2.sigver import get_xmlsec_binary
|
||||||
from saml2.saml import NAMEID_FORMAT_PERSISTENT
|
from saml2 import BINDING_SOAP
|
||||||
|
from saml2 import BINDING_HTTP_REDIRECT
|
||||||
|
from saml2 import BINDING_HTTP_POST
|
||||||
from saml2.saml import NAME_FORMAT_URI
|
from saml2.saml import NAME_FORMAT_URI
|
||||||
|
|
||||||
from pathutils import full_path, xmlsec_path
|
from pathutils import full_path
|
||||||
|
|
||||||
|
xmlsec_path = get_xmlsec_binary(["/opt/local/bin"])
|
||||||
|
|
||||||
BASE = "http://localhost:8088"
|
BASE = "http://localhost:8088"
|
||||||
|
|
||||||
|
@@ -172,15 +172,15 @@ def test_ava_filter_2():
|
|||||||
"surName": "Jeter",
|
"surName": "Jeter",
|
||||||
"mail": "derek@example.com"}
|
"mail": "derek@example.com"}
|
||||||
|
|
||||||
raises(Exception, policy.filter, ava, 'urn:mace:umu.se:saml:roland:sp',
|
raises(MissingValue, policy.filter, ava, 'urn:mace:umu.se:saml:roland:sp',
|
||||||
[mail], [gn, sn])
|
None, [mail], [gn, sn])
|
||||||
|
|
||||||
ava = {"givenName": "Derek",
|
ava = {"givenName": "Derek",
|
||||||
"surName": "Jeter"}
|
"surName": "Jeter"}
|
||||||
|
|
||||||
# it wasn't there to begin with
|
# it wasn't there to begin with
|
||||||
raises(Exception, policy.filter, ava, 'urn:mace:umu.se:saml:roland:sp',
|
raises(Exception, policy.filter, ava, 'urn:mace:umu.se:saml:roland:sp',
|
||||||
[gn, sn, mail])
|
None, [gn, sn, mail])
|
||||||
|
|
||||||
|
|
||||||
def test_filter_attribute_value_assertions_0(AVA):
|
def test_filter_attribute_value_assertions_0(AVA):
|
||||||
@@ -643,7 +643,7 @@ def test_req_opt():
|
|||||||
'uid': 'rohe0002', 'edupersonaffiliation': 'staff'}
|
'uid': 'rohe0002', 'edupersonaffiliation': 'staff'}
|
||||||
|
|
||||||
sp_entity_id = "urn:mace:example.com:saml:curt:sp"
|
sp_entity_id = "urn:mace:example.com:saml:curt:sp"
|
||||||
fava = policy.filter(ava, sp_entity_id, req, opt)
|
fava = policy.filter(ava, sp_entity_id, None, req, opt)
|
||||||
assert fava
|
assert fava
|
||||||
|
|
||||||
|
|
||||||
@@ -736,19 +736,20 @@ def test_filter_ava_5():
|
|||||||
"default": {
|
"default": {
|
||||||
"lifetime": {"minutes": 15},
|
"lifetime": {"minutes": 15},
|
||||||
#"attribute_restrictions": None # means all I have
|
#"attribute_restrictions": None # means all I have
|
||||||
"entity_categories": ["swami", "edugain"]
|
"entity_categories": ["swamid", "edugain"]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ava = {"givenName": ["Derek"], "surName": ["Jeter"],
|
ava = {"givenName": ["Derek"], "surName": ["Jeter"],
|
||||||
"mail": ["derek@nyy.mlb.com", "dj@example.com"]}
|
"mail": ["derek@nyy.mlb.com", "dj@example.com"]}
|
||||||
|
|
||||||
# No restrictions apply
|
ava = policy.filter(ava, "urn:mace:example.com:saml:curt:sp", None, [], [])
|
||||||
ava = policy.filter(ava, "urn:mace:example.com:saml:curt:sp", [], [])
|
|
||||||
|
|
||||||
assert _eq(ava.keys(), ['mail', 'givenName', 'surName'])
|
# using entity_categories means there *always* are restrictions
|
||||||
assert _eq(ava["mail"], ["derek@nyy.mlb.com", "dj@example.com"])
|
# in this case the only allowed attribute is eduPersonTargetedID
|
||||||
|
# which isn't available in the ava hence zip is returned.
|
||||||
|
assert ava == {}
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
test_assertion_with_noop_attribute_conv()
|
test_filter_ava_5()
|
@@ -14,29 +14,31 @@ from saml2 import root_logger
|
|||||||
from pathutils import dotname, full_path
|
from pathutils import dotname, full_path
|
||||||
|
|
||||||
sp1 = {
|
sp1 = {
|
||||||
"entityid" : "urn:mace:umu.se:saml:roland:sp",
|
"entityid": "urn:mace:umu.se:saml:roland:sp",
|
||||||
"service": {
|
"service": {
|
||||||
"sp": {
|
"sp": {
|
||||||
"endpoints" : {
|
"endpoints": {
|
||||||
"assertion_consumer_service" : ["http://lingon.catalogix.se:8087/"],
|
"assertion_consumer_service": [
|
||||||
|
"http://lingon.catalogix.se:8087/"],
|
||||||
},
|
},
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"idp" : {
|
"idp": {
|
||||||
"urn:mace:example.com:saml:roland:idp": {'single_sign_on_service':
|
"urn:mace:example.com:saml:roland:idp": {
|
||||||
{'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect':
|
'single_sign_on_service':
|
||||||
'http://localhost:8088/sso/'}},
|
{'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect':
|
||||||
|
'http://localhost:8088/sso/'}},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"key_file" : full_path("test.key"),
|
"key_file": full_path("test.key"),
|
||||||
"cert_file" : full_path("test.pem"),
|
"cert_file": full_path("test.pem"),
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"local": [full_path("metadata.xml"),
|
"local": [full_path("metadata.xml"),
|
||||||
full_path("urn-mace-swami.se-swamid-test-1.0-metadata.xml")],
|
full_path("urn-mace-swami.se-swamid-test-1.0-metadata.xml")],
|
||||||
},
|
},
|
||||||
"virtual_organization" : {
|
"virtual_organization": {
|
||||||
"coip":{
|
"coip": {
|
||||||
"nameid_format" : "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
|
"nameid_format": "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
|
||||||
"common_identifier": "eduPersonPrincipalName",
|
"common_identifier": "eduPersonPrincipalName",
|
||||||
"attribute_auth": [
|
"attribute_auth": [
|
||||||
"https://coip-test.sunet.se/idp/shibboleth",
|
"https://coip-test.sunet.se/idp/shibboleth",
|
||||||
@@ -48,17 +50,18 @@ sp1 = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sp2 = {
|
sp2 = {
|
||||||
"entityid" : "urn:mace:umu.se:saml:roland:sp",
|
"entityid": "urn:mace:umu.se:saml:roland:sp",
|
||||||
"name" : "Rolands SP",
|
"name": "Rolands SP",
|
||||||
"service": {
|
"service": {
|
||||||
"sp": {
|
"sp": {
|
||||||
"endpoints" : {
|
"endpoints": {
|
||||||
"assertion_consumer_service" : ["http://lingon.catalogix.se:8087/"],
|
"assertion_consumer_service": [
|
||||||
|
"http://lingon.catalogix.se:8087/"],
|
||||||
},
|
},
|
||||||
"required_attributes": ["surName", "givenName", "mail"],
|
"required_attributes": ["surName", "givenName", "mail"],
|
||||||
"optional_attributes": ["title"],
|
"optional_attributes": ["title"],
|
||||||
"idp": {
|
"idp": {
|
||||||
"" : "https://example.com/saml2/idp/SSOService.php",
|
"": "https://example.com/saml2/idp/SSOService.php",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -66,12 +69,12 @@ sp2 = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IDP1 = {
|
IDP1 = {
|
||||||
"entityid" : "urn:mace:umu.se:saml:roland:idp",
|
"entityid": "urn:mace:umu.se:saml:roland:idp",
|
||||||
"name" : "Rolands IdP",
|
"name": "Rolands IdP",
|
||||||
"service": {
|
"service": {
|
||||||
"idp": {
|
"idp": {
|
||||||
"endpoints": {
|
"endpoints": {
|
||||||
"single_sign_on_service" : ["http://localhost:8088/"],
|
"single_sign_on_service": ["http://localhost:8088/"],
|
||||||
},
|
},
|
||||||
"policy": {
|
"policy": {
|
||||||
"default": {
|
"default": {
|
||||||
@@ -90,15 +93,16 @@ IDP1 = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IDP2 = {
|
IDP2 = {
|
||||||
"entityid" : "urn:mace:umu.se:saml:roland:idp",
|
"entityid": "urn:mace:umu.se:saml:roland:idp",
|
||||||
"name" : "Rolands IdP",
|
"name": "Rolands IdP",
|
||||||
"service": {
|
"service": {
|
||||||
"idp": {
|
"idp": {
|
||||||
"endpoints": {
|
"endpoints": {
|
||||||
"single_sign_on_service" : ["http://localhost:8088/"],
|
"single_sign_on_service": ["http://localhost:8088/"],
|
||||||
"single_logout_service" : [("http://localhost:8088/", BINDING_HTTP_REDIRECT)],
|
"single_logout_service": [
|
||||||
|
("http://localhost:8088/", BINDING_HTTP_REDIRECT)],
|
||||||
},
|
},
|
||||||
"policy":{
|
"policy": {
|
||||||
"default": {
|
"default": {
|
||||||
"attribute_restrictions": {
|
"attribute_restrictions": {
|
||||||
"givenName": None,
|
"givenName": None,
|
||||||
@@ -115,41 +119,42 @@ IDP2 = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PDP = {
|
PDP = {
|
||||||
"entityid" : "http://example.org/pysaml2/pdp",
|
"entityid": "http://example.org/pysaml2/pdp",
|
||||||
"name" : "Rolands PdP",
|
"name": "Rolands PdP",
|
||||||
"service": {
|
"service": {
|
||||||
"pdp": {
|
"pdp": {
|
||||||
"endpoints": {
|
"endpoints": {
|
||||||
"authz_service" : [("http://example.org/pysaml2/pdp/authz",
|
"authz_service": [("http://example.org/pysaml2/pdp/authz",
|
||||||
BINDING_SOAP)],
|
BINDING_SOAP)],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"key_file" : full_path("test.key"),
|
"key_file": full_path("test.key"),
|
||||||
"cert_file" : full_path("test.pem"),
|
"cert_file": full_path("test.pem"),
|
||||||
"organization": {
|
"organization": {
|
||||||
"name": "Exempel AB",
|
"name": "Exempel AB",
|
||||||
"display_name": [("Exempel AB","se"),("Example Co.","en")],
|
"display_name": [("Exempel AB", "se"), ("Example Co.", "en")],
|
||||||
"url":"http://www.example.com/roland",
|
"url": "http://www.example.com/roland",
|
||||||
},
|
},
|
||||||
"contact_person": [{
|
"contact_person": [{
|
||||||
"given_name":"John",
|
"given_name": "John",
|
||||||
"sur_name": "Smith",
|
"sur_name": "Smith",
|
||||||
"email_address": ["john.smith@example.com"],
|
"email_address": ["john.smith@example.com"],
|
||||||
"contact_type": "technical",
|
"contact_type": "technical",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
ECP_SP = {
|
ECP_SP = {
|
||||||
"entityid" : "urn:mace:umu.se:saml:roland:ecpsp",
|
"entityid": "urn:mace:umu.se:saml:roland:ecpsp",
|
||||||
"name" : "Rolands ECP_SP",
|
"name": "Rolands ECP_SP",
|
||||||
"service": {
|
"service": {
|
||||||
"sp": {
|
"sp": {
|
||||||
"endpoints" : {
|
"endpoints": {
|
||||||
"assertion_consumer_service" : ["http://lingon.catalogix.se:8087/"],
|
"assertion_consumer_service": [
|
||||||
|
"http://lingon.catalogix.se:8087/"],
|
||||||
},
|
},
|
||||||
"ecp" : {
|
"ecp": {
|
||||||
"130.239.": "http://example.com/idp",
|
"130.239.": "http://example.com/idp",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,9 +162,11 @@ ECP_SP = {
|
|||||||
#"xmlsec_binary" : "/opt/local/bin/xmlsec1",
|
#"xmlsec_binary" : "/opt/local/bin/xmlsec1",
|
||||||
}
|
}
|
||||||
|
|
||||||
def _eq(l1,l2):
|
|
||||||
|
def _eq(l1, l2):
|
||||||
return set(l1) == set(l2)
|
return set(l1) == set(l2)
|
||||||
|
|
||||||
|
|
||||||
def test_1():
|
def test_1():
|
||||||
c = SPConfig().load(sp1)
|
c = SPConfig().load(sp1)
|
||||||
c.context = "sp"
|
c.context = "sp"
|
||||||
@@ -173,11 +180,13 @@ def test_1():
|
|||||||
assert len(c._sp_idp) == 1
|
assert len(c._sp_idp) == 1
|
||||||
assert c._sp_idp.keys() == ["urn:mace:example.com:saml:roland:idp"]
|
assert c._sp_idp.keys() == ["urn:mace:example.com:saml:roland:idp"]
|
||||||
assert c._sp_idp.values() == [{'single_sign_on_service':
|
assert c._sp_idp.values() == [{'single_sign_on_service':
|
||||||
{'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect':
|
{
|
||||||
'http://localhost:8088/sso/'}}]
|
'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect':
|
||||||
|
'http://localhost:8088/sso/'}}]
|
||||||
|
|
||||||
assert c.only_use_keys_in_metadata
|
assert c.only_use_keys_in_metadata
|
||||||
|
|
||||||
|
|
||||||
def test_2():
|
def test_2():
|
||||||
c = SPConfig().load(sp2)
|
c = SPConfig().load(sp2)
|
||||||
c.context = "sp"
|
c.context = "sp"
|
||||||
@@ -192,20 +201,22 @@ def test_2():
|
|||||||
|
|
||||||
assert len(c._sp_idp) == 1
|
assert len(c._sp_idp) == 1
|
||||||
assert c._sp_idp.keys() == [""]
|
assert c._sp_idp.keys() == [""]
|
||||||
assert c._sp_idp.values() == ["https://example.com/saml2/idp/SSOService.php"]
|
assert c._sp_idp.values() == [
|
||||||
|
"https://example.com/saml2/idp/SSOService.php"]
|
||||||
assert c.only_use_keys_in_metadata is True
|
assert c.only_use_keys_in_metadata is True
|
||||||
|
|
||||||
|
|
||||||
def test_minimum():
|
def test_minimum():
|
||||||
minimum = {
|
minimum = {
|
||||||
"entityid" : "urn:mace:example.com:saml:roland:sp",
|
"entityid": "urn:mace:example.com:saml:roland:sp",
|
||||||
"service": {
|
"service": {
|
||||||
"sp": {
|
"sp": {
|
||||||
"endpoints" : {
|
"endpoints": {
|
||||||
"assertion_consumer_service" : ["http://sp.example.org/"],
|
"assertion_consumer_service": ["http://sp.example.org/"],
|
||||||
},
|
},
|
||||||
"name" : "test",
|
"name": "test",
|
||||||
"idp": {
|
"idp": {
|
||||||
"" : "https://example.com/idp/SSOService.php",
|
"": "https://example.com/idp/SSOService.php",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -216,7 +227,8 @@ def test_minimum():
|
|||||||
c.context = "sp"
|
c.context = "sp"
|
||||||
|
|
||||||
assert c is not None
|
assert c is not None
|
||||||
|
|
||||||
|
|
||||||
def test_idp_1():
|
def test_idp_1():
|
||||||
c = IdPConfig().load(IDP1)
|
c = IdPConfig().load(IDP1)
|
||||||
c.context = "idp"
|
c.context = "idp"
|
||||||
@@ -224,8 +236,10 @@ def test_idp_1():
|
|||||||
print c
|
print c
|
||||||
assert c.endpoint("single_sign_on_service")[0] == 'http://localhost:8088/'
|
assert c.endpoint("single_sign_on_service")[0] == 'http://localhost:8088/'
|
||||||
|
|
||||||
attribute_restrictions = c.getattr("policy","idp").get_attribute_restriction("")
|
attribute_restrictions = c.getattr("policy",
|
||||||
assert attribute_restrictions["eduPersonAffiliation"][0].match("staff")
|
"idp").get_attribute_restriction("")
|
||||||
|
assert attribute_restrictions["edupersonaffiliation"][0].match("staff")
|
||||||
|
|
||||||
|
|
||||||
def test_idp_2():
|
def test_idp_2():
|
||||||
c = IdPConfig().load(IDP2)
|
c = IdPConfig().load(IDP2)
|
||||||
@@ -235,11 +249,13 @@ def test_idp_2():
|
|||||||
assert c.endpoint("single_logout_service",
|
assert c.endpoint("single_logout_service",
|
||||||
BINDING_SOAP) == []
|
BINDING_SOAP) == []
|
||||||
assert c.endpoint("single_logout_service",
|
assert c.endpoint("single_logout_service",
|
||||||
BINDING_HTTP_REDIRECT) == ["http://localhost:8088/"]
|
BINDING_HTTP_REDIRECT) == ["http://localhost:8088/"]
|
||||||
|
|
||||||
|
attribute_restrictions = c.getattr("policy",
|
||||||
|
"idp").get_attribute_restriction("")
|
||||||
|
assert attribute_restrictions["edupersonaffiliation"][0].match("staff")
|
||||||
|
|
||||||
|
|
||||||
attribute_restrictions = c.getattr("policy","idp").get_attribute_restriction("")
|
|
||||||
assert attribute_restrictions["eduPersonAffiliation"][0].match("staff")
|
|
||||||
|
|
||||||
def test_wayf():
|
def test_wayf():
|
||||||
c = SPConfig().load_file("server_conf")
|
c = SPConfig().load_file("server_conf")
|
||||||
c.context = "sp"
|
c.context = "sp"
|
||||||
@@ -255,7 +271,7 @@ def test_wayf():
|
|||||||
assert root_logger.level == logging.INFO
|
assert root_logger.level == logging.INFO
|
||||||
assert len(root_logger.handlers) == 1
|
assert len(root_logger.handlers) == 1
|
||||||
assert isinstance(root_logger.handlers[0],
|
assert isinstance(root_logger.handlers[0],
|
||||||
logging.handlers.RotatingFileHandler)
|
logging.handlers.RotatingFileHandler)
|
||||||
handler = root_logger.handlers[0]
|
handler = root_logger.handlers[0]
|
||||||
assert handler.backupCount == 5
|
assert handler.backupCount == 5
|
||||||
try:
|
try:
|
||||||
@@ -266,6 +282,7 @@ def test_wayf():
|
|||||||
assert root_logger.name == "saml2"
|
assert root_logger.name == "saml2"
|
||||||
assert root_logger.level == 20
|
assert root_logger.level == 20
|
||||||
|
|
||||||
|
|
||||||
def test_conf_syslog():
|
def test_conf_syslog():
|
||||||
c = SPConfig().load_file("server_conf_syslog")
|
c = SPConfig().load_file("server_conf_syslog")
|
||||||
c.context = "sp"
|
c.context = "sp"
|
||||||
@@ -273,7 +290,7 @@ def test_conf_syslog():
|
|||||||
# otherwise the logger setting is not changed
|
# otherwise the logger setting is not changed
|
||||||
root_logger.level = logging.NOTSET
|
root_logger.level = logging.NOTSET
|
||||||
root_logger.handlers = []
|
root_logger.handlers = []
|
||||||
|
|
||||||
print c.logger
|
print c.logger
|
||||||
c.setup_logger()
|
c.setup_logger()
|
||||||
|
|
||||||
@@ -281,7 +298,7 @@ def test_conf_syslog():
|
|||||||
assert root_logger.level == logging.INFO
|
assert root_logger.level == logging.INFO
|
||||||
assert len(root_logger.handlers) == 1
|
assert len(root_logger.handlers) == 1
|
||||||
assert isinstance(root_logger.handlers[0],
|
assert isinstance(root_logger.handlers[0],
|
||||||
logging.handlers.SysLogHandler)
|
logging.handlers.SysLogHandler)
|
||||||
handler = root_logger.handlers[0]
|
handler = root_logger.handlers[0]
|
||||||
print handler.__dict__
|
print handler.__dict__
|
||||||
assert handler.facility == "local3"
|
assert handler.facility == "local3"
|
||||||
@@ -307,11 +324,13 @@ def test_3():
|
|||||||
assert cnf.metadata is not None
|
assert cnf.metadata is not None
|
||||||
assert cnf.attribute_converters is not None
|
assert cnf.attribute_converters is not None
|
||||||
|
|
||||||
|
|
||||||
def test_sp():
|
def test_sp():
|
||||||
cnf = SPConfig()
|
cnf = SPConfig()
|
||||||
cnf.load_file(dotname("sp_1_conf"))
|
cnf.load_file(dotname("sp_1_conf"))
|
||||||
assert cnf.endpoint("assertion_consumer_service") == \
|
assert cnf.endpoint("assertion_consumer_service") == \
|
||||||
["http://lingon.catalogix.se:8087/"]
|
["http://lingon.catalogix.se:8087/"]
|
||||||
|
|
||||||
|
|
||||||
def test_dual():
|
def test_dual():
|
||||||
cnf = Config().load_file(dotname("idp_sp_conf"))
|
cnf = Config().load_file(dotname("idp_sp_conf"))
|
||||||
@@ -322,16 +341,18 @@ def test_dual():
|
|||||||
assert idpe
|
assert idpe
|
||||||
assert spe != idpe
|
assert spe != idpe
|
||||||
|
|
||||||
|
|
||||||
def test_ecp():
|
def test_ecp():
|
||||||
cnf = SPConfig()
|
cnf = SPConfig()
|
||||||
cnf.load(ECP_SP)
|
cnf.load(ECP_SP)
|
||||||
assert cnf.endpoint("assertion_consumer_service") == \
|
assert cnf.endpoint("assertion_consumer_service") == \
|
||||||
["http://lingon.catalogix.se:8087/"]
|
["http://lingon.catalogix.se:8087/"]
|
||||||
eid = cnf.ecp_endpoint("130.239.16.3")
|
eid = cnf.ecp_endpoint("130.239.16.3")
|
||||||
assert eid == "http://example.com/idp"
|
assert eid == "http://example.com/idp"
|
||||||
eid = cnf.ecp_endpoint("130.238.20.20")
|
eid = cnf.ecp_endpoint("130.238.20.20")
|
||||||
assert eid is None
|
assert eid is None
|
||||||
|
|
||||||
|
|
||||||
def test_assertion_consumer_service():
|
def test_assertion_consumer_service():
|
||||||
c = IdPConfig()
|
c = IdPConfig()
|
||||||
c.load_file(dotname("idp_conf"))
|
c.load_file(dotname("idp_conf"))
|
||||||
@@ -342,4 +363,8 @@ def test_assertion_consumer_service():
|
|||||||
entity_id = "https://www.zimride.com/shibboleth"
|
entity_id = "https://www.zimride.com/shibboleth"
|
||||||
acs = c.metadata.assertion_consumer_service(entity_id)
|
acs = c.metadata.assertion_consumer_service(entity_id)
|
||||||
assert len(acs) == 1
|
assert len(acs) == 1
|
||||||
assert acs[0]["location"] == 'https://www.zimride.com/Shibboleth.sso/SAML2/POST'
|
assert acs[0][
|
||||||
|
"location"] == 'https://www.zimride.com/Shibboleth.sso/SAML2/POST'
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_idp_1()
|
@@ -50,12 +50,12 @@ def test_filter_ava():
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ava = {"givenName": ["Derek"], "surname": ["Jeter"],
|
ava = {"givenName": ["Derek"], "sn": ["Jeter"],
|
||||||
"email": ["derek@nyy.mlb.com", "dj@example.com"], "c": ["USA"]}
|
"email": ["derek@nyy.mlb.com", "dj@example.com"], "c": ["USA"]}
|
||||||
|
|
||||||
ava = policy.filter(ava, "https://connect.sunet.se/shibboleth", MDS)
|
ava = policy.filter(ava, "https://connect.sunet.se/shibboleth", MDS)
|
||||||
|
|
||||||
assert _eq(ava.keys(), ['email', 'givenName', 'surname', 'c'])
|
assert _eq(ava.keys(), ['email', 'givenName', 'sn', 'c'])
|
||||||
assert _eq(ava["email"], ["derek@nyy.mlb.com", "dj@example.com"])
|
assert _eq(ava["email"], ["derek@nyy.mlb.com", "dj@example.com"])
|
||||||
|
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ def test_filter_ava2():
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ava = {"givenName": ["Derek"], "surname": ["Jeter"],
|
ava = {"givenName": ["Derek"], "sn": ["Jeter"],
|
||||||
"email": ["derek@nyy.mlb.com"], "c": ["USA"],
|
"email": ["derek@nyy.mlb.com"], "c": ["USA"],
|
||||||
"eduPersonTargetedID": "foo!bar!xyz"}
|
"eduPersonTargetedID": "foo!bar!xyz"}
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ def test_filter_ava3():
|
|||||||
disable_ssl_certificate_validation=True)
|
disable_ssl_certificate_validation=True)
|
||||||
mds.imp({"local": [full_path("entity_cat_sfs_hei.xml")]})
|
mds.imp({"local": [full_path("entity_cat_sfs_hei.xml")]})
|
||||||
|
|
||||||
ava = {"givenName": ["Derek"], "surname": ["Jeter"],
|
ava = {"givenName": ["Derek"], "sn": ["Jeter"],
|
||||||
"email": ["derek@nyy.mlb.com"], "c": ["USA"],
|
"email": ["derek@nyy.mlb.com"], "c": ["USA"],
|
||||||
"eduPersonTargetedID": "foo!bar!xyz",
|
"eduPersonTargetedID": "foo!bar!xyz",
|
||||||
"norEduPersonNIN": "19800101134"}
|
"norEduPersonNIN": "19800101134"}
|
||||||
@@ -105,7 +105,7 @@ def test_filter_ava3():
|
|||||||
def test_idp_policy_filter():
|
def test_idp_policy_filter():
|
||||||
idp = Server("idp_conf_ec")
|
idp = Server("idp_conf_ec")
|
||||||
|
|
||||||
ava = {"givenName": ["Derek"], "surname": ["Jeter"],
|
ava = {"givenName": ["Derek"], "sn": ["Jeter"],
|
||||||
"email": ["derek@nyy.mlb.com"], "c": ["USA"],
|
"email": ["derek@nyy.mlb.com"], "c": ["USA"],
|
||||||
"eduPersonTargetedID": "foo!bar!xyz",
|
"eduPersonTargetedID": "foo!bar!xyz",
|
||||||
"norEduPersonNIN": "19800101134"}
|
"norEduPersonNIN": "19800101134"}
|
||||||
|
Reference in New Issue
Block a user