Added support for entity categories.
This commit is contained in:
parent
76da2bb6bb
commit
655a24f0d2
@ -22,12 +22,12 @@ else:
|
||||
#BASE = "http://lingon.catalogix.se:8088"
|
||||
BASE = "http://localhost:8088"
|
||||
|
||||
CONFIG={
|
||||
"entityid" : "%s/idp.xml" % BASE,
|
||||
CONFIG = {
|
||||
"entityid": "%s/idp.xml" % BASE,
|
||||
"description": "My IDP",
|
||||
"service": {
|
||||
"aa": {
|
||||
"endpoints" : {
|
||||
"endpoints": {
|
||||
"attribute_service": [
|
||||
("%s/attr" % BASE, BINDING_SOAP)
|
||||
]
|
||||
@ -36,16 +36,16 @@ CONFIG={
|
||||
NAMEID_FORMAT_PERSISTENT]
|
||||
},
|
||||
"aq": {
|
||||
"endpoints" : {
|
||||
"endpoints": {
|
||||
"authn_query_service": [
|
||||
("%s/aqs" % BASE, BINDING_SOAP)
|
||||
]
|
||||
},
|
||||
},
|
||||
"idp": {
|
||||
"name" : "Rolands IdP",
|
||||
"endpoints" : {
|
||||
"single_sign_on_service" : [
|
||||
"name": "Rolands IdP",
|
||||
"endpoints": {
|
||||
"single_sign_on_service": [
|
||||
("%s/sso/redirect" % BASE, BINDING_HTTP_REDIRECT),
|
||||
("%s/sso/post" % BASE, BINDING_HTTP_POST),
|
||||
("%s/sso/art" % BASE, BINDING_HTTP_ARTIFACT),
|
||||
@ -56,27 +56,28 @@ CONFIG={
|
||||
("%s/slo/post" % BASE, BINDING_HTTP_POST),
|
||||
("%s/slo/redirect" % BASE, BINDING_HTTP_REDIRECT)
|
||||
],
|
||||
"artifact_resolve_service":[
|
||||
"artifact_resolve_service": [
|
||||
("%s/ars" % BASE, BINDING_SOAP)
|
||||
],
|
||||
"assertion_id_request_service": [
|
||||
("%s/airs" % BASE, BINDING_URI)
|
||||
],
|
||||
"manage_name_id_service":[
|
||||
"manage_name_id_service": [
|
||||
("%s/mni/soap" % BASE, BINDING_SOAP),
|
||||
("%s/mni/post" % BASE, BINDING_HTTP_POST),
|
||||
("%s/mni/redirect" % BASE, BINDING_HTTP_REDIRECT),
|
||||
("%s/mni/art" % BASE, BINDING_HTTP_ARTIFACT)
|
||||
],
|
||||
"name_id_mapping_service":[
|
||||
"name_id_mapping_service": [
|
||||
("%s/nim" % BASE, BINDING_SOAP),
|
||||
],
|
||||
},
|
||||
"policy": {
|
||||
"default": {
|
||||
"lifetime": {"minutes":15},
|
||||
"lifetime": {"minutes": 15},
|
||||
"attribute_restrictions": None, # means all I have
|
||||
"name_form": NAME_FORMAT_URI
|
||||
"name_form": NAME_FORMAT_URI,
|
||||
"entity_categories": ["swami", "edugain"]
|
||||
},
|
||||
},
|
||||
"subject_data": "./idp.subject",
|
||||
@ -84,10 +85,10 @@ CONFIG={
|
||||
NAMEID_FORMAT_PERSISTENT]
|
||||
},
|
||||
},
|
||||
"debug" : 1,
|
||||
"key_file" : "pki/mykey.pem",
|
||||
"cert_file" : "pki/mycert.pem",
|
||||
"metadata" : {
|
||||
"debug": 1,
|
||||
"key_file": "pki/mykey.pem",
|
||||
"cert_file": "pki/mycert.pem",
|
||||
"metadata": {
|
||||
"local": ["../sp/sp.xml"],
|
||||
},
|
||||
"organization": {
|
||||
@ -95,27 +96,28 @@ CONFIG={
|
||||
"name": "Rolands Identiteter",
|
||||
"url": "http://www.example.com",
|
||||
},
|
||||
"contact_person": [{
|
||||
"contact_type": "technical",
|
||||
"given_name": "Roland",
|
||||
"sur_name": "Hedberg",
|
||||
"email_address": "technical@example.com"
|
||||
},{
|
||||
"contact_type": "support",
|
||||
"given_name": "Support",
|
||||
"email_address": "support@example.com"
|
||||
},
|
||||
"contact_person": [
|
||||
{
|
||||
"contact_type": "technical",
|
||||
"given_name": "Roland",
|
||||
"sur_name": "Hedberg",
|
||||
"email_address": "technical@example.com"
|
||||
}, {
|
||||
"contact_type": "support",
|
||||
"given_name": "Support",
|
||||
"email_address": "support@example.com"
|
||||
},
|
||||
],
|
||||
# This database holds the map between a subjects local identifier and
|
||||
# the identifier returned to a SP
|
||||
"xmlsec_binary": xmlsec_path,
|
||||
"attribute_map_dir" : "../attributemaps",
|
||||
"attribute_map_dir": "../attributemaps",
|
||||
"logger": {
|
||||
"rotating": {
|
||||
"filename": "idp.log",
|
||||
"maxBytes": 500000,
|
||||
"backupCount": 5,
|
||||
},
|
||||
},
|
||||
"loglevel": "debug",
|
||||
}
|
||||
}
|
||||
|
3
setup.py
3
setup.py
@ -73,7 +73,8 @@ setup(
|
||||
|
||||
packages=['saml2', 'xmldsig', 'xmlenc', 's2repoze', 's2repoze.plugins',
|
||||
"saml2/profile", "saml2/schema", "saml2/extension",
|
||||
"saml2/attributemaps", "saml2/authn_context"],
|
||||
"saml2/attributemaps", "saml2/authn_context",
|
||||
"saml2/entity_category"],
|
||||
|
||||
package_dir={'': 'src'},
|
||||
package_data={'': ['xml/*.xml']},
|
||||
|
@ -14,6 +14,7 @@
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import importlib
|
||||
import logging
|
||||
|
||||
import re
|
||||
@ -21,14 +22,15 @@ from saml2.saml import NAME_FORMAT_URI
|
||||
import xmlenc
|
||||
|
||||
from saml2 import saml
|
||||
from saml2 import entity_category
|
||||
|
||||
from saml2.time_util import instant, in_a_while
|
||||
from saml2.attribute_converter import from_local
|
||||
|
||||
from saml2.s_utils import sid, MissingValue
|
||||
from saml2.s_utils import factory
|
||||
from saml2.s_utils import assertion_factory
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -286,7 +288,19 @@ class Policy(object):
|
||||
for _, spec in self._restrictions.items():
|
||||
if spec is None:
|
||||
continue
|
||||
|
||||
|
||||
try:
|
||||
_entcat = spec["entity_categories"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
ecs = []
|
||||
for cat in _entcat:
|
||||
_mod = importlib.import_module(
|
||||
"saml2.entity_category.%s" % cat)
|
||||
ecs.append(_mod.RELEASE)
|
||||
spec["entity_categories"] = ecs
|
||||
|
||||
try:
|
||||
restr = spec["attribute_restrictions"]
|
||||
except KeyError:
|
||||
@ -383,7 +397,53 @@ class Policy(object):
|
||||
restrictions = None
|
||||
|
||||
return restrictions
|
||||
|
||||
|
||||
def get_entity_categories_restriction(self, sp_entity_id, mds):
|
||||
if not self._restrictions:
|
||||
return None
|
||||
|
||||
restrictions = {}
|
||||
ec_maps = []
|
||||
try:
|
||||
try:
|
||||
ec_maps = self._restrictions[sp_entity_id]["entity_categories"]
|
||||
except KeyError:
|
||||
try:
|
||||
ec_maps = self._restrictions["default"]["entity_categories"]
|
||||
except KeyError:
|
||||
pass
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if ec_maps:
|
||||
# always released
|
||||
for ec_map in ec_maps:
|
||||
try:
|
||||
attrs = ec_map[""]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
for attr in attrs:
|
||||
restrictions[attr] = None
|
||||
|
||||
try:
|
||||
ecs = mds.entity_categories(sp_entity_id)
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
for ec in ecs:
|
||||
for ec_map in ec_maps:
|
||||
try:
|
||||
attrs = ec_map[ec]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
for attr in attrs:
|
||||
restrictions[attr] = None
|
||||
|
||||
return restrictions
|
||||
|
||||
|
||||
def not_on_or_after(self, sp_entity_id):
|
||||
""" When the assertion stops being valid, should not be
|
||||
used after this time.
|
||||
@ -394,7 +454,7 @@ class Policy(object):
|
||||
|
||||
return in_a_while(**self.get_lifetime(sp_entity_id))
|
||||
|
||||
def filter(self, ava, sp_entity_id, required=None, optional=None):
|
||||
def filter(self, ava, sp_entity_id, mdstore, required=None, optional=None):
|
||||
""" What attribute and attribute values returns depends on what
|
||||
the SP has said it wants in the request or in the metadata file and
|
||||
what the IdP/AA wants to release. An assumption is that what the SP
|
||||
@ -408,8 +468,11 @@ class Policy(object):
|
||||
:return: A possibly modified AVA
|
||||
"""
|
||||
|
||||
ava = filter_attribute_value_assertions(
|
||||
ava, self.get_attribute_restriction(sp_entity_id))
|
||||
_rest = self.get_attribute_restriction(sp_entity_id)
|
||||
if _rest is None:
|
||||
_rest = self.get_entity_categories_restriction(sp_entity_id,
|
||||
mdstore)
|
||||
ava = filter_attribute_value_assertions(ava, _rest)
|
||||
|
||||
if required or optional:
|
||||
ava = filter_on_attributes(ava, required, optional)
|
||||
@ -427,8 +490,8 @@ class Policy(object):
|
||||
if metadata:
|
||||
spec = metadata.attribute_requirement(sp_entity_id)
|
||||
if spec:
|
||||
return self.filter(ava, sp_entity_id, spec["required"],
|
||||
spec["optional"])
|
||||
ava = self.filter(ava, sp_entity_id, metadata,
|
||||
spec["required"], spec["optional"])
|
||||
|
||||
return self.filter(ava, sp_entity_id, [], [])
|
||||
|
||||
@ -447,19 +510,6 @@ class Policy(object):
|
||||
audience=factory(saml.Audience,
|
||||
text=sp_entity_id))])
|
||||
|
||||
NAME = ["givenName", "surname", "initials", "displayName", "schacSn1",
|
||||
"schacSn2"]
|
||||
STATIC_ORG_INFO = ["organizationName", ""]
|
||||
|
||||
RESEARCH_AND_EDUCATION = "http://www.swamid.se/category/research-and-education"
|
||||
SFS_1993_1153 = "http://www.swamid.se/category/sfs-1993-1153"
|
||||
|
||||
# EC_RELEASE = {
|
||||
# "eduPersonPrincipalName", "eduPersonTargetedID", "mail", "email",
|
||||
# "eduPersonScopedAffiliation"
|
||||
# ]),
|
||||
# "http://www.swamid.se/category/sfs-1993-1153": ["norEduPersonNIN"]
|
||||
# }
|
||||
|
||||
|
||||
class EntityCategories(object):
|
||||
|
@ -60,7 +60,8 @@ COMMON_ARGS = [
|
||||
"logout_requests_signed",
|
||||
"disable_ssl_certificate_validation",
|
||||
"referred_binding",
|
||||
"session_storage"
|
||||
"session_storage",
|
||||
"entity_category"
|
||||
]
|
||||
|
||||
SP_ARGS = [
|
||||
@ -189,6 +190,7 @@ class Config(object):
|
||||
self.preferred_binding = PREFERRED_BINDING
|
||||
self.domain = ""
|
||||
self.name_qualifier = ""
|
||||
self.entity_category = ""
|
||||
|
||||
def setattr(self, context, attr, val):
|
||||
if context == "":
|
||||
|
@ -7,6 +7,7 @@ __author__ = 'rolandh'
|
||||
|
||||
IDPDISC_POLICY = "urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol:single"
|
||||
|
||||
|
||||
class DiscoveryServer(Entity):
|
||||
def __init__(self, config=None, config_file=""):
|
||||
Entity.__init__(self, "disco", config, config_file)
|
||||
@ -65,7 +66,7 @@ class DiscoveryServer(Entity):
|
||||
returnIDParam="entityID",
|
||||
entity_id=None):
|
||||
if entity_id:
|
||||
qp = urlencode({returnIDParam:entity_id})
|
||||
qp = urlencode({returnIDParam: entity_id})
|
||||
|
||||
part = urlparse(return_url)
|
||||
if part.query:
|
||||
|
14
src/saml2/entity_category/__init__.py
Normal file
14
src/saml2/entity_category/__init__.py
Normal file
@ -0,0 +1,14 @@
|
||||
__author__ = 'rolandh'
|
||||
|
||||
ENTITYATTRIBUTES = "urn:oasis:names:tc:SAML:metadata:attribute&EntityAttributes"
|
||||
|
||||
|
||||
def entity_categories(md):
|
||||
res = []
|
||||
if "extensions" in md:
|
||||
for elem in md["extensions"]["extension_elements"]:
|
||||
if elem["__class__"] == ENTITYATTRIBUTES:
|
||||
for attr in elem["attribute"]:
|
||||
res.append(attr["text"])
|
||||
|
||||
return res
|
10
src/saml2/entity_category/edugain.py
Normal file
10
src/saml2/entity_category/edugain.py
Normal file
@ -0,0 +1,10 @@
|
||||
__author__ = 'rolandh'
|
||||
|
||||
COC = "http://www.edugain.org/dataprotection/coc-eu-01-draft"
|
||||
|
||||
RELEASE = {
|
||||
"": ["eduPersonTargetedID"],
|
||||
COC: ["eduPersonPrincipalName", "eduPersonScopedAffiliation", "email",
|
||||
"givenName", "surname", "displayName", "schacHomeOrganization"]
|
||||
}
|
||||
|
20
src/saml2/entity_category/swamid.py
Normal file
20
src/saml2/entity_category/swamid.py
Normal file
@ -0,0 +1,20 @@
|
||||
__author__ = 'rolandh'
|
||||
|
||||
|
||||
NAME = ["givenName", "surname", "initials", "displayName"]
|
||||
STATIC_ORG_INFO = ["c", "o", "ou"]
|
||||
OTHER = ["eduPersonPrincipalName", "eduPersonScopedAffiliation", "email"]
|
||||
|
||||
RESEARCH_AND_EDUCATION = "http://www.swamid.se/category/research-and-education"
|
||||
SFS_1993_1153 = "http://www.swamid.se/category/sfs-1993-1153"
|
||||
|
||||
EU = "http://www.swamid.se/category/eu-adequate-protection"
|
||||
NREN = "http://www.swamid.se/category/nren-service"
|
||||
HEI = "http://www.swamid.se/category/hei-service"
|
||||
|
||||
RELEASE = {
|
||||
"": ["eduPersonTargetedID"],
|
||||
SFS_1993_1153: ["norEduPersonNIN"],
|
||||
RESEARCH_AND_EDUCATION: NAME + STATIC_ORG_INFO + OTHER,
|
||||
}
|
||||
|
@ -46,6 +46,9 @@ REQ2SRV = {
|
||||
"discovery_service_request": "discovery_response"
|
||||
}
|
||||
|
||||
|
||||
ENTITYATTRIBUTES = "urn:oasis:names:tc:SAML:metadata:attribute&EntityAttributes"
|
||||
|
||||
# ---------------------------------------------------
|
||||
|
||||
|
||||
@ -321,6 +324,16 @@ class MetaData(object):
|
||||
|
||||
return res
|
||||
|
||||
def entity_categories(self, entity_id):
|
||||
res = []
|
||||
if "extensions" in self[entity_id]:
|
||||
for elem in self[entity_id]["extensions"]["extension_elements"]:
|
||||
if elem["__class__"] == ENTITYATTRIBUTES:
|
||||
for attr in elem["attribute"]:
|
||||
res.append(attr["text"])
|
||||
|
||||
return res
|
||||
|
||||
|
||||
class MetaDataFile(MetaData):
|
||||
"""
|
||||
@ -649,6 +662,17 @@ class MetadataStore(object):
|
||||
ad = self.__getitem__(entity_id)["affiliation_descriptor"]
|
||||
return [m["text"] for m in ad["affiliate_member"]]
|
||||
|
||||
def entity_categories(self, entity_id):
|
||||
ext = self.__getitem__(entity_id)["extensions"]
|
||||
res = []
|
||||
for elem in ext["extension_elements"]:
|
||||
if elem["__class__"] == ENTITYATTRIBUTES:
|
||||
for attr in elem["attribute"]:
|
||||
if attr["name"] == "http://macedir.org/entity-category":
|
||||
res.extend([v["text"] for v in attr["attribute_value"]])
|
||||
|
||||
return res
|
||||
|
||||
def bindings(self, entity_id, typ, service):
|
||||
for md in self.metadata.values():
|
||||
if entity_id in md.items():
|
||||
|
@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
from saml2.time_util import in_a_while
|
||||
from saml2.extension import mdui, idpdisc, shibmd
|
||||
from saml2.saml import NAME_FORMAT_URI
|
||||
from saml2.extension import mdui, idpdisc, shibmd, mdattr
|
||||
from saml2.saml import NAME_FORMAT_URI, AttributeValue, Attribute
|
||||
from saml2.attribute_converter import from_local_name
|
||||
from saml2 import md
|
||||
from saml2 import md, saml
|
||||
from saml2 import BINDING_HTTP_POST
|
||||
from saml2 import BINDING_HTTP_REDIRECT
|
||||
from saml2 import BINDING_SOAP
|
||||
@ -549,6 +549,14 @@ def entity_descriptor(confd):
|
||||
if confd.contact_person is not None:
|
||||
entd.contact_person = do_contact_person_info(confd.contact_person)
|
||||
|
||||
if confd.entity_category:
|
||||
entd.extensions = md.Extensions()
|
||||
ava = [AttributeValue(text=c) for c in confd.entity_category]
|
||||
attr = Attribute(attribute_value=ava,
|
||||
name="http://macedir.org/entity-category")
|
||||
item = mdattr.EntityAttributes(attribute=attr)
|
||||
entd.extensions.add_extension_element(item)
|
||||
|
||||
serves = confd.serves
|
||||
if not serves:
|
||||
raise Exception(
|
||||
|
@ -9,6 +9,8 @@ import sys
|
||||
import hmac
|
||||
|
||||
# from python 2.5
|
||||
import imp
|
||||
|
||||
if sys.version_info >= (2, 5):
|
||||
import hashlib
|
||||
else: # before python 2.5
|
||||
@ -406,4 +408,31 @@ def fticks_log(sp, logf, idp_entity_id, user_id, secret, assertion):
|
||||
"PN": csum.hexdigest(),
|
||||
"AM": assertion.AuthnStatement.AuthnContext.AuthnContextClassRef.text
|
||||
}
|
||||
logf.info(FTICKS_FORMAT % "#".join(["%s=%s" % (a,v) for a,v in info]))
|
||||
logf.info(FTICKS_FORMAT % "#".join(["%s=%s" % (a,v) for a,v in info]))
|
||||
|
||||
|
||||
def dynamic_importer(name, class_name=None):
|
||||
"""
|
||||
Dynamically imports modules / classes
|
||||
"""
|
||||
try:
|
||||
fp, pathname, description = imp.find_module(name)
|
||||
except ImportError:
|
||||
print "unable to locate module: " + name
|
||||
return None, None
|
||||
|
||||
try:
|
||||
package = imp.load_module(name, fp, pathname, description)
|
||||
except Exception, e:
|
||||
raise
|
||||
|
||||
if class_name:
|
||||
try:
|
||||
_class = imp.load_module("%s.%s" % (name, class_name), fp,
|
||||
pathname, description)
|
||||
except Exception, e:
|
||||
raise
|
||||
|
||||
return package, _class
|
||||
else:
|
||||
return package, None
|
||||
|
@ -344,7 +344,7 @@ class Server(Entity):
|
||||
ast = Assertion(identity)
|
||||
policy = self.config.getattr("policy", "aa")
|
||||
if policy:
|
||||
ast.apply_policy(sp_entity_id, policy)
|
||||
ast.apply_policy(sp_entity_id, policy, self.metadata)
|
||||
else:
|
||||
policy = Policy()
|
||||
|
||||
|
@ -11,9 +11,9 @@ from pathutils import full_path, xmlsec_path
|
||||
|
||||
BASE = "http://lingon.catalogix.se:8087"
|
||||
|
||||
CONFIG={
|
||||
"entityid" : "urn:mace:example.com:saml:roland:sp",
|
||||
"name" : "urn:mace:example.com:saml:roland:sp",
|
||||
CONFIG = {
|
||||
"entityid": "urn:mace:example.com:saml:roland:sp",
|
||||
"name": "urn:mace:example.com:saml:roland:sp",
|
||||
"description": "My own SP",
|
||||
"service": {
|
||||
"sp": {
|
||||
@ -22,10 +22,10 @@ CONFIG={
|
||||
("%s/" % BASE, BINDING_HTTP_POST),
|
||||
("%s/paos" % BASE, BINDING_PAOS),
|
||||
("%s/redirect" % BASE, BINDING_HTTP_REDIRECT)],
|
||||
"artifact_resolution_service":[
|
||||
"artifact_resolution_service": [
|
||||
("%s/ars" % BASE, BINDING_SOAP)
|
||||
],
|
||||
"manage_name_id_service":[
|
||||
"manage_name_id_service": [
|
||||
("%s/mni/soap" % BASE, BINDING_SOAP),
|
||||
("%s/mni/post" % BASE, BINDING_HTTP_POST),
|
||||
("%s/mni/redirect" % BASE, BINDING_HTTP_REDIRECT),
|
||||
@ -34,26 +34,27 @@ CONFIG={
|
||||
"single_logout_service": [
|
||||
("%s/sls" % BASE, BINDING_SOAP)
|
||||
],
|
||||
"discovery_response":[
|
||||
"discovery_response": [
|
||||
("%s/disco" % BASE, BINDING_DISCO)
|
||||
]
|
||||
},
|
||||
"required_attributes": ["surName", "givenName", "mail"],
|
||||
"optional_attributes": ["title", "eduPersonAffiliation"],
|
||||
"idp": ["urn:mace:example.com:saml:roland:idp"],
|
||||
"name_id_format":[NAMEID_FORMAT_TRANSIENT, NAMEID_FORMAT_PERSISTENT]
|
||||
"name_id_format": [NAMEID_FORMAT_TRANSIENT,
|
||||
NAMEID_FORMAT_PERSISTENT]
|
||||
}
|
||||
},
|
||||
"debug": 1,
|
||||
"key_file": full_path("test.key"),
|
||||
"cert_file": full_path("test.pem"),
|
||||
"ca_certs": full_path("cacerts.txt"),
|
||||
"xmlsec_binary" : xmlsec_path,
|
||||
"xmlsec_binary": xmlsec_path,
|
||||
"metadata": {
|
||||
"local": [full_path("idp_all.xml"), full_path("vo_metadata.xml")],
|
||||
},
|
||||
"virtual_organization": {
|
||||
"urn:mace:example.com:it:tek":{
|
||||
"urn:mace:example.com:it:tek": {
|
||||
"nameid_format": "urn:oid:1.3.6.1.4.1.1466.115.121.1.15-NameID",
|
||||
"common_identifier": "umuselin",
|
||||
}
|
||||
@ -61,12 +62,15 @@ CONFIG={
|
||||
"subject_data": "subject_data.db",
|
||||
"accepted_time_diff": 60,
|
||||
"attribute_map_dir": full_path("attributemaps"),
|
||||
"entity_category": ["http://www.swamid.se/category/sfs-1993-1153",
|
||||
#"http://www.swamid.se/category/research-and-education",
|
||||
"http://www.swamid.se/category/hei-service"],
|
||||
#"valid_for": 6,
|
||||
"organization": {
|
||||
"name": ("AB Exempel", "se"),
|
||||
"display_name": ("AB Exempel", "se"),
|
||||
"url": "http://www.example.org",
|
||||
},
|
||||
},
|
||||
"contact_person": [
|
||||
{
|
||||
"given_name": "Roland",
|
||||
|
@ -731,5 +731,24 @@ def test_assertion_with_noop_attribute_conv():
|
||||
assert attr.attribute_value[0].text == "Roland"
|
||||
|
||||
|
||||
def test_filter_ava_5():
|
||||
policy = Policy({
|
||||
"default": {
|
||||
"lifetime": {"minutes": 15},
|
||||
#"attribute_restrictions": None # means all I have
|
||||
"entity_categories": ["swami", "edugain"]
|
||||
}
|
||||
})
|
||||
|
||||
ava = {"givenName": ["Derek"], "surName": ["Jeter"],
|
||||
"mail": ["derek@nyy.mlb.com", "dj@example.com"]}
|
||||
|
||||
# No restrictions apply
|
||||
ava = policy.filter(ava, "urn:mace:example.com:saml:curt:sp", [], [])
|
||||
|
||||
assert _eq(ava.keys(), ['mail', 'givenName', 'surName'])
|
||||
assert _eq(ava["mail"], ["derek@nyy.mlb.com", "dj@example.com"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_assertion_with_noop_attribute_conv()
|
@ -12,7 +12,6 @@ from saml2 import BINDING_HTTP_REDIRECT
|
||||
from saml2 import BINDING_HTTP_POST
|
||||
from saml2 import BINDING_HTTP_ARTIFACT
|
||||
from saml2 import saml
|
||||
from saml2 import sigver
|
||||
from saml2 import config
|
||||
from saml2.attribute_converter import ac_factory
|
||||
from saml2.attribute_converter import d_to_local_name
|
||||
|
105
tests/test_37_entity_categories.py
Normal file
105
tests/test_37_entity_categories.py
Normal file
@ -0,0 +1,105 @@
|
||||
from saml2 import saml, sigver
|
||||
from saml2 import md
|
||||
from saml2 import config
|
||||
from saml2.assertion import Policy
|
||||
from saml2.attribute_converter import ac_factory
|
||||
from saml2.extension import mdui
|
||||
from saml2.extension import idpdisc
|
||||
from saml2.extension import dri
|
||||
from saml2.extension import mdattr
|
||||
from saml2.extension import ui
|
||||
from pathutils import full_path
|
||||
from saml2.mdstore import MetadataStore
|
||||
import xmldsig
|
||||
import xmlenc
|
||||
|
||||
ONTS = {
|
||||
saml.NAMESPACE: saml,
|
||||
mdui.NAMESPACE: mdui,
|
||||
mdattr.NAMESPACE: mdattr,
|
||||
dri.NAMESPACE: dri,
|
||||
ui.NAMESPACE: ui,
|
||||
idpdisc.NAMESPACE: idpdisc,
|
||||
md.NAMESPACE: md,
|
||||
xmldsig.NAMESPACE: xmldsig,
|
||||
xmlenc.NAMESPACE: xmlenc
|
||||
}
|
||||
|
||||
ATTRCONV = ac_factory(full_path("attributemaps"))
|
||||
sec_config = config.Config()
|
||||
sec_config.xmlsec_binary = sigver.get_xmlsec_binary(["/opt/local/bin"])
|
||||
|
||||
__author__ = 'rolandh'
|
||||
|
||||
MDS = MetadataStore(ONTS.values(), ATTRCONV, sec_config,
|
||||
disable_ssl_certificate_validation=True)
|
||||
MDS.imp({"mdfile": [full_path("swamid.md")]})
|
||||
|
||||
|
||||
def _eq(l1, l2):
|
||||
return set(l1) == set(l2)
|
||||
|
||||
|
||||
def test_filter_ava():
|
||||
policy = Policy({
|
||||
"default": {
|
||||
"lifetime": {"minutes": 15},
|
||||
#"attribute_restrictions": None # means all I have
|
||||
"entity_categories": ["swamid"]
|
||||
}
|
||||
})
|
||||
|
||||
ava = {"givenName": ["Derek"], "surname": ["Jeter"],
|
||||
"email": ["derek@nyy.mlb.com", "dj@example.com"], "c": ["USA"]}
|
||||
|
||||
ava = policy.filter(ava, "https://connect.sunet.se/shibboleth", MDS)
|
||||
|
||||
assert _eq(ava.keys(), ['email', 'givenName', 'surname', 'c'])
|
||||
assert _eq(ava["email"], ["derek@nyy.mlb.com", "dj@example.com"])
|
||||
|
||||
|
||||
def test_filter_ava2():
|
||||
policy = Policy({
|
||||
"default": {
|
||||
"lifetime": {"minutes": 15},
|
||||
#"attribute_restrictions": None # means all I have
|
||||
"entity_categories": ["edugain"]
|
||||
}
|
||||
})
|
||||
|
||||
ava = {"givenName": ["Derek"], "surname": ["Jeter"],
|
||||
"email": ["derek@nyy.mlb.com"], "c": ["USA"],
|
||||
"eduPersonTargetedID": "foo!bar!xyz"}
|
||||
|
||||
ava = policy.filter(ava, "https://connect.sunet.se/shibboleth", MDS)
|
||||
|
||||
# Mismatch, policy deals with eduGAIN, metadata says SWAMID
|
||||
# So only minimum should come out
|
||||
assert _eq(ava.keys(), ['eduPersonTargetedID'])
|
||||
|
||||
|
||||
def test_filter_ava3():
|
||||
policy = Policy({
|
||||
"default": {
|
||||
"lifetime": {"minutes": 15},
|
||||
#"attribute_restrictions": None # means all I have
|
||||
"entity_categories": ["swamid"]
|
||||
}
|
||||
})
|
||||
|
||||
mds = MetadataStore(ONTS.values(), ATTRCONV, sec_config,
|
||||
disable_ssl_certificate_validation=True)
|
||||
mds.imp({"local": [full_path("entity_cat_sfs_hei.xml")]})
|
||||
|
||||
ava = {"givenName": ["Derek"], "surname": ["Jeter"],
|
||||
"email": ["derek@nyy.mlb.com"], "c": ["USA"],
|
||||
"eduPersonTargetedID": "foo!bar!xyz",
|
||||
"norEduPersonNIN": "19800101134"}
|
||||
|
||||
ava = policy.filter(ava, "urn:mace:example.com:saml:roland:sp", mds)
|
||||
|
||||
assert _eq(ava.keys(), ['eduPersonTargetedID', "norEduPersonNIN"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_filter_ava2()
|
@ -6,7 +6,7 @@ from saml2.metadata import entity_descriptor
|
||||
from saml2.metadata import entities_descriptor
|
||||
from saml2.metadata import sign_entity_descriptor
|
||||
|
||||
from saml2.sigver import SecurityContext
|
||||
from saml2.sigver import SecurityContext, CryptoBackendXmlSec1
|
||||
from saml2.sigver import get_xmlsec_cryptobackend
|
||||
from saml2.sigver import get_xmlsec_binary
|
||||
from saml2.validate import valid_instance
|
||||
@ -61,9 +61,13 @@ for filespec in args.config:
|
||||
cnf = Config().load_file(fil, metadata_construction=True)
|
||||
eds.append(entity_descriptor(cnf))
|
||||
|
||||
crypto = get_xmlsec_cryptobackend()
|
||||
secc = SecurityContext(crypto, key_file=args.keyfile,
|
||||
cert_file=args.cert, debug=1)
|
||||
if not xmlsec:
|
||||
crypto = get_xmlsec_cryptobackend()
|
||||
else:
|
||||
crypto = CryptoBackendXmlSec1(xmlsec)
|
||||
|
||||
secc = SecurityContext(crypto, key_file=args.keyfile, cert_file=args.cert,
|
||||
debug=1)
|
||||
|
||||
if args.id:
|
||||
desc = entities_descriptor(eds, valid_for, args.name, args.id,
|
||||
|
Loading…
Reference in New Issue
Block a user